| 94 |
94 |
| 95 return type; |
95 return type; |
| 96 } |
96 } |
| 97 |
97 |
| 98 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) { |
98 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) { |
| 99 cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start); |
99 cxmutstr buf_str = cx_mutstrn(json->buffer.space + start, end - start); |
| 100 bool allocated = false; |
100 cxmutstr str; |
| 101 if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) { |
101 bool allocated; |
| |
102 if (json->uncompleted_tokentype != CX_JSON_NO_TOKEN) { |
| 102 allocated = true; |
103 allocated = true; |
| 103 str = cx_strcat_m(json->uncompleted.content, 1, str); |
104 str = json->uncompleted_content; |
| 104 if (str.ptr == NULL) { // LCOV_EXCL_START |
105 if (cx_strcat(&str, 1, buf_str)) { |
| 105 return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}}; |
106 return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}}; // LCOV_EXCL_LINE |
| 106 } // LCOV_EXCL_STOP |
107 } |
| 107 } |
108 json->uncompleted_content = (cxmutstr){NULL, 0}; |
| 108 json->uncompleted = (CxJsonToken){0}; |
109 json->uncompleted_tokentype = CX_JSON_NO_TOKEN; |
| |
110 } else { |
| |
111 allocated = false; |
| |
112 str = buf_str; |
| |
113 } |
| 109 CxJsonTokenType ttype; |
114 CxJsonTokenType ttype; |
| 110 if (isstring) { |
115 if (isstring) { |
| 111 ttype = CX_JSON_TOKEN_STRING; |
116 ttype = CX_JSON_TOKEN_STRING; |
| 112 } else { |
117 } else { |
| 113 cxstring s = cx_strcast(str); |
118 if (!cx_strcmp(str, "true") || !cx_strcmp(str, "false") |
| 114 if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false") |
119 || !cx_strcmp(str, "null")) { |
| 115 || !cx_strcmp(s, "null")) { |
|
| 116 ttype = CX_JSON_TOKEN_LITERAL; |
120 ttype = CX_JSON_TOKEN_LITERAL; |
| 117 } else { |
121 } else { |
| 118 ttype = token_numbertype(str.ptr, str.length); |
122 ttype = token_numbertype(str.ptr, str.length); |
| 119 } |
123 } |
| 120 } |
124 } |
| 160 } |
164 } |
| 161 |
165 |
| 162 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { |
166 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { |
| 163 // check if there is data in the buffer |
167 // check if there is data in the buffer |
| 164 if (cxBufferEof(&json->buffer)) { |
168 if (cxBufferEof(&json->buffer)) { |
| 165 return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ? |
169 return json->uncompleted_tokentype == CX_JSON_NO_TOKEN ? |
| 166 CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA; |
170 CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA; |
| 167 } |
171 } |
| 168 |
172 |
| 169 // current token type and start index |
173 // current token type and start index |
| 170 CxJsonTokenType ttype = json->uncompleted.tokentype; |
174 CxJsonTokenType ttype = json->uncompleted_tokentype; |
| 171 size_t token_part_start = json->buffer.pos; |
175 size_t token_part_start = json->buffer.pos; |
| 172 |
176 |
| 173 bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING |
177 bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING |
| 174 && json->uncompleted.content.ptr[json->uncompleted.content.length-1] == '\\'; |
178 && json->uncompleted_content.ptr[json->uncompleted_content.length-1] == '\\'; |
| 175 |
179 |
| 176 for (size_t i = json->buffer.pos; i < json->buffer.size; i++) { |
180 for (size_t i = json->buffer.pos; i < json->buffer.size; i++) { |
| 177 char c = json->buffer.space[i]; |
181 char c = json->buffer.space[i]; |
| 178 if (ttype != CX_JSON_TOKEN_STRING) { |
182 if (ttype != CX_JSON_TOKEN_STRING) { |
| 179 // currently non-string token |
183 // currently non-string token |
| 230 |
234 |
| 231 if (ttype == CX_JSON_NO_TOKEN) { |
235 if (ttype == CX_JSON_NO_TOKEN) { |
| 232 return CX_JSON_NO_DATA; |
236 return CX_JSON_NO_DATA; |
| 233 } else { |
237 } else { |
| 234 // uncompleted token |
238 // uncompleted token |
| 235 size_t uncompleted_len = json->buffer.size - token_part_start; |
239 cxstring uncompleted = cx_strn(json->buffer.space + token_part_start, json->buffer.size - token_part_start); |
| 236 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { |
240 if (json->uncompleted_tokentype == CX_JSON_NO_TOKEN) { |
| 237 // current token is uncompleted |
241 assert(json->uncompleted_content.ptr == NULL); |
| 238 // save current token content |
242 json->uncompleted_content = cx_strdup(uncompleted); |
| 239 CxJsonToken uncompleted = { |
243 if (json->uncompleted_content.ptr == NULL) { |
| 240 ttype, true, |
|
| 241 cx_strdup(cx_strn(json->buffer.space + token_part_start, uncompleted_len)) |
|
| 242 }; |
|
| 243 if (uncompleted.content.ptr == NULL) { |
|
| 244 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE |
244 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE |
| 245 } |
245 } |
| 246 json->uncompleted = uncompleted; |
246 json->uncompleted_tokentype = ttype; |
| 247 } else { |
247 } else { |
| 248 // previously we also had an uncompleted token |
248 // previously we also had an uncompleted token |
| 249 // combine the uncompleted token with the current token |
249 // combine the uncompleted token with the current token |
| 250 assert(json->uncompleted.allocated); |
250 if (cx_strcat(&json->uncompleted_content, 1, uncompleted)) { |
| 251 cxmutstr str = cx_strcat_m(json->uncompleted.content, 1, |
|
| 252 cx_strn(json->buffer.space + token_part_start, uncompleted_len)); |
|
| 253 if (str.ptr == NULL) { |
|
| 254 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE |
251 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE |
| 255 } |
252 } |
| 256 json->uncompleted.content = str; |
|
| 257 } |
253 } |
| 258 // advance the buffer position - we saved the stuff in the uncompleted token |
254 // advance the buffer position - we saved the stuff in the uncompleted token |
| 259 json->buffer.pos += uncompleted_len; |
255 json->buffer.pos += uncompleted.length; |
| 260 return CX_JSON_INCOMPLETE_DATA; |
256 return CX_JSON_INCOMPLETE_DATA; |
| 261 } |
257 } |
| 262 } |
258 } |
| 263 |
259 |
| 264 // converts a Unicode codepoint to utf8 |
260 // converts a Unicode codepoint to utf8 |
| 562 if (json->vbuf.data != json->vbuf_internal) { |
558 if (json->vbuf.data != json->vbuf_internal) { |
| 563 cx_array_free(json->vbuf); |
559 cx_array_free(json->vbuf); |
| 564 } |
560 } |
| 565 cxJsonValueFree(json->parsed); |
561 cxJsonValueFree(json->parsed); |
| 566 json->parsed = NULL; |
562 json->parsed = NULL; |
| 567 token_destroy(&json->uncompleted); |
563 json->uncompleted_tokentype = CX_JSON_NO_TOKEN; |
| |
564 cx_strfree(&json->uncompleted_content); |
| 568 cx_strfree_a(json->allocator, &json->uncompleted_member_name); |
565 cx_strfree_a(json->allocator, &json->uncompleted_member_name); |
| 569 } |
566 } |
| 570 |
567 |
| 571 void cxJsonReset(CxJson *json) { |
568 void cxJsonReset(CxJson *json) { |
| 572 const CxAllocator *allocator = json->allocator; |
569 const CxAllocator *allocator = json->allocator; |