40 #define PARSER_READVALUE_ALLOC 32 |
40 #define PARSER_READVALUE_ALLOC 32 |
41 |
41 |
42 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING}; |
42 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING}; |
43 |
43 |
44 static void token_destroy(CxJsonToken *token) { |
44 static void token_destroy(CxJsonToken *token) { |
45 if (token->alloc > 0) { |
45 if (token->allocated) { |
46 free((char*) token->content); |
46 cx_strfree(&token->content); |
47 } |
47 } |
48 } |
48 } |
49 |
49 |
50 static int token_append(CxJsonToken *token, const char *buf, size_t len) { |
|
51 if (len == 0) { |
|
52 return 0; |
|
53 } |
|
54 |
|
55 size_t newlen = token->length + len; |
|
56 if (token->alloc < newlen) { |
|
57 char *newbuf = realloc( |
|
58 token->alloc == 0 ? NULL : (char *) token->content, |
|
59 newlen); |
|
60 if (!newbuf) { |
|
61 return 1; |
|
62 } |
|
63 token->content = newbuf; |
|
64 token->alloc = newlen; |
|
65 } |
|
66 |
|
67 memcpy((char *) token->content + token->length, buf, len); |
|
68 token->length = newlen; |
|
69 return 0; |
|
70 } |
|
71 |
|
72 static CxJsonToken token_create(CxJson *json, size_t start, size_t end) { |
|
73 CxJsonToken token = {0}; |
|
74 size_t len = end - start; |
|
75 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { |
|
76 token.content = json->buffer + start; |
|
77 token.length = len; |
|
78 } else { |
|
79 if (token_append(&json->uncompleted, json->buffer + start, len)) { |
|
80 // TODO: this does certainly not lead to correct error handling |
|
81 return (CxJsonToken){0}; |
|
82 } |
|
83 token = json->uncompleted; |
|
84 } |
|
85 json->uncompleted = (CxJsonToken){0}; |
|
86 return token; |
|
87 } |
|
88 |
50 |
89 static int token_isliteral(const char *content, size_t length) { |
51 static int token_isliteral(const char *content, size_t length) { |
90 if (length == 4) { |
52 if (length == 4) { |
91 if (!memcmp(content, "true", 4)) { |
53 if (!memcmp(content, "true", 4)) { |
92 return 1; |
54 return 1; |
175 } |
167 } |
176 } |
168 } |
177 return CX_JSON_NO_TOKEN; |
169 return CX_JSON_NO_TOKEN; |
178 } |
170 } |
179 |
171 |
180 static CxJsonToken token_parse_next(CxJson *json) { |
172 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { |
|
173 // check if there is data in the buffer |
|
174 if (json->pos >= json->size) { |
|
175 return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ? |
|
176 CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA; |
|
177 } |
|
178 |
|
179 // sanity check |
|
180 if (json->buffer == NULL) { |
|
181 return CX_JSON_NULL_INPUT; |
|
182 } |
|
183 |
181 // current token type and start index |
184 // current token type and start index |
182 CxJsonTokenType ttype = json->uncompleted.tokentype; |
185 CxJsonTokenType ttype = json->uncompleted.tokentype; |
183 size_t token_start = json->pos; |
186 size_t token_start = json->pos; |
184 |
187 |
185 for (size_t i = json->pos; i < json->size; i++) { |
188 for (size_t i = json->pos; i < json->size; i++) { |
186 char c = json->buffer[i]; |
189 char c = json->buffer[i]; |
187 if (ttype != CX_JSON_TOKEN_STRING) { |
190 if (ttype != CX_JSON_TOKEN_STRING) { |
188 // currently non-string token |
191 // currently non-string token |
189 |
|
190 CxJsonTokenType ctype = char2ttype(c); // start of new token? |
192 CxJsonTokenType ctype = char2ttype(c); // start of new token? |
191 |
|
192 if (ttype == CX_JSON_NO_TOKEN) { |
193 if (ttype == CX_JSON_NO_TOKEN) { |
193 if (ctype == CX_JSON_TOKEN_SPACE) { |
194 if (ctype == CX_JSON_TOKEN_SPACE) { |
194 continue; |
195 continue; |
195 } else if (ctype == CX_JSON_TOKEN_STRING) { |
196 } else if (ctype == CX_JSON_TOKEN_STRING) { |
196 // begin string |
197 // begin string |
197 ttype = CX_JSON_TOKEN_STRING; |
198 ttype = CX_JSON_TOKEN_STRING; |
198 token_start = i; |
199 token_start = i; |
199 } else if (ctype != CX_JSON_NO_TOKEN) { |
200 } else if (ctype != CX_JSON_NO_TOKEN) { |
200 // single-char token |
201 // single-char token |
201 json->pos = i + 1; |
202 json->pos = i + 1; |
202 CxJsonToken token = {ctype, NULL, 0, 0}; |
203 *result = (CxJsonToken){ctype, NULL, 0, 0}; |
203 return token; |
204 return CX_JSON_NO_ERROR; |
204 } else { |
205 } else { |
205 ttype = CX_JSON_TOKEN_LITERAL; // number or literal |
206 ttype = CX_JSON_TOKEN_LITERAL; // number or literal |
206 token_start = i; |
207 token_start = i; |
207 } |
208 } |
208 } else { |
209 } else { |
209 // finish token |
210 // finish token |
210 if (ctype != CX_JSON_NO_TOKEN) { |
211 if (ctype != CX_JSON_NO_TOKEN) { |
211 CxJsonToken ret = token_create(json, token_start, i); |
212 *result = token_create(json, false, token_start, i); |
212 if (token_isliteral(ret.content, ret.length)) { |
213 if (result->tokentype == CX_JSON_NO_TOKEN) { |
213 ret.tokentype = CX_JSON_TOKEN_LITERAL; |
214 return CX_JSON_BUFFER_ALLOC_FAILED; |
214 } else { |
215 } |
215 ret.tokentype = token_numbertype(ret.content, ret.length); |
216 if (result->tokentype == CX_JSON_TOKEN_ERROR) { |
|
217 return CX_JSON_FORMAT_ERROR_NUMBER; |
216 } |
218 } |
217 json->pos = i; |
219 json->pos = i; |
218 return ret; |
220 return CX_JSON_NO_ERROR; |
219 } |
221 } |
220 } |
222 } |
221 } else { |
223 } else { |
222 // currently inside a string |
224 // currently inside a string |
223 if (json->tokenizer_escape) { |
225 if (json->tokenizer_escape) { |
224 json->tokenizer_escape = false; |
226 json->tokenizer_escape = false; |
225 } else { |
227 } else { |
226 if (c == '"') { |
228 if (c == '"') { |
227 CxJsonToken ret = token_create(json, token_start, i + 1); |
229 *result = token_create(json, true, token_start, i + 1); |
228 ret.tokentype = CX_JSON_TOKEN_STRING; |
230 if (result->tokentype == CX_JSON_NO_TOKEN) { |
|
231 return CX_JSON_BUFFER_ALLOC_FAILED; |
|
232 } |
229 json->pos = i + 1; |
233 json->pos = i + 1; |
230 return ret; |
234 return CX_JSON_NO_ERROR; |
231 } else if (c == '\\') { |
235 } else if (c == '\\') { |
232 json->tokenizer_escape = true; |
236 json->tokenizer_escape = true; |
233 } |
237 } |
234 } |
238 } |
235 } |
239 } |
238 if (ttype != CX_JSON_NO_TOKEN) { |
242 if (ttype != CX_JSON_NO_TOKEN) { |
239 // uncompleted token |
243 // uncompleted token |
240 size_t uncompeted_len = json->size - token_start; |
244 size_t uncompeted_len = json->size - token_start; |
241 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { |
245 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { |
242 // current token is uncompleted |
246 // current token is uncompleted |
243 // save current token content in p->uncompleted |
247 // save current token content |
244 CxJsonToken uncompleted; |
248 CxJsonToken uncompleted = { |
245 uncompleted.tokentype = ttype; |
249 ttype, true, |
246 uncompleted.length = uncompeted_len; |
250 cx_strdup(cx_strn(json->buffer + token_start, uncompeted_len)) |
247 uncompleted.alloc = uncompeted_len + 16; |
251 }; |
248 char *tmp = malloc(uncompleted.alloc); |
252 if (uncompleted.content.ptr == NULL) { |
249 if (tmp) { |
253 return CX_JSON_BUFFER_ALLOC_FAILED; |
250 memcpy(tmp, json->buffer + token_start, uncompeted_len); |
254 } |
251 uncompleted.content = tmp; |
255 json->uncompleted = uncompleted; |
252 json->uncompleted = uncompleted; |
|
253 } else { |
|
254 json->error = 1; |
|
255 } |
|
256 } else { |
256 } else { |
257 // previously we also had an uncompleted token |
257 // previously we also had an uncompleted token |
258 // combine the uncompleted token with the current token |
258 // combine the uncompleted token with the current token |
259 if (token_append(&json->uncompleted, json->buffer + token_start, uncompeted_len)) { |
259 assert(json->uncompleted.allocated); |
260 json->error = 1; |
260 cxmutstr str = cx_strcat_m(json->uncompleted.content, 1, |
261 } |
261 cx_strn(json->buffer + token_start, uncompeted_len)); |
262 } |
262 if (str.ptr == NULL) { |
263 } |
263 return CX_JSON_BUFFER_ALLOC_FAILED; |
264 |
264 } |
265 CxJsonToken ret = {CX_JSON_NO_TOKEN, NULL, 0, 0}; |
265 json->uncompleted.content = str; |
266 return ret; |
266 } |
267 } |
267 } |
268 |
268 |
269 static cxmutstr unescape_string(const CxAllocator *a, const char *str, size_t len) { |
269 return CX_JSON_INCOMPLETE_DATA; |
|
270 } |
|
271 |
|
272 static cxmutstr unescape_string(const CxAllocator *a, cxmutstr str) { |
270 // TODO: support more escape sequences |
273 // TODO: support more escape sequences |
271 // we know that the unescaped string will be shorter by at least 2 chars |
274 // we know that the unescaped string will be shorter by at least 2 chars |
272 cxmutstr result; |
275 cxmutstr result; |
273 result.length = 0; |
276 result.length = 0; |
274 result.ptr = cxMalloc(a, len - 1); |
277 result.ptr = cxMalloc(a, str.length - 1); |
275 if (result.ptr == NULL) { |
278 if (result.ptr == NULL) { |
276 return result; |
279 return result; |
277 } |
280 } |
278 |
281 |
279 bool u = false; |
282 bool u = false; |
280 for (size_t i = 1; i < len - 1; i++) { |
283 for (size_t i = 1; i < str.length - 1; i++) { |
281 char c = str[i]; |
284 char c = str.ptr[i]; |
282 if (u) { |
285 if (u) { |
283 u = false; |
286 u = false; |
284 if (c == 'n') { |
287 if (c == 'n') { |
285 c = '\n'; |
288 c = '\n'; |
286 } else if (c == 't') { |
289 } else if (c == 't') { |
443 |
446 |
444 #define return_rec(code) \ |
447 #define return_rec(code) \ |
445 token_destroy(&token); \ |
448 token_destroy(&token); \ |
446 return code |
449 return code |
447 |
450 |
448 static int json_parse(CxJson *json) { |
451 static enum cx_json_status json_parse(CxJson *json) { |
449 // Reserve a pointer for a possibly read value |
452 // Reserve a pointer for a possibly read value |
450 CxJsonValue *vbuf = NULL; |
453 CxJsonValue *vbuf = NULL; |
451 |
454 |
452 // grab the next token |
455 // grab the next token |
453 CxJsonToken token = token_parse_next(json); |
456 CxJsonToken token; |
454 if (token.tokentype == CX_JSON_NO_TOKEN) { |
457 { |
455 // nothing found, wait for more data |
458 enum cx_json_status ret = token_parse_next(json, &token); |
456 return 0; |
459 if (ret != CX_JSON_NO_ERROR) { |
|
460 return ret; |
|
461 } |
457 } |
462 } |
458 |
463 |
459 // pop the current state |
464 // pop the current state |
460 assert(json->states_size > 0); |
465 assert(json->states_size > 0); |
461 int state = json->states[--json->states_size]; |
466 int state = json->states[--json->states_size]; |
462 |
467 |
463 // guarantee that at least two more states fit on the stack |
468 // guarantee that at least two more states fit on the stack |
464 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); |
469 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); |
465 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { |
470 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { |
466 return -1; |
471 return CX_JSON_BUFFER_ALLOC_FAILED; |
467 } |
472 } |
468 |
473 |
469 |
474 |
470 // 0 JP_STATE_VALUE_BEGIN value begin |
475 // 0 JP_STATE_VALUE_BEGIN value begin |
471 // 10 JP_STATE_VALUE_END expect value end |
476 // 10 JP_STATE_VALUE_END expect value end |
481 // push expected end state to the stack |
486 // push expected end state to the stack |
482 json_add_state(json, 10 + state); |
487 json_add_state(json, 10 + state); |
483 switch (token.tokentype) { |
488 switch (token.tokentype) { |
484 case CX_JSON_TOKEN_BEGIN_ARRAY: { |
489 case CX_JSON_TOKEN_BEGIN_ARRAY: { |
485 if (create_json_value(json, CX_JSON_ARRAY) == NULL) { |
490 if (create_json_value(json, CX_JSON_ARRAY) == NULL) { |
486 // TODO: error code - no memory |
491 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
487 return_rec(-1); |
|
488 } |
492 } |
489 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
493 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
490 return_rec(1); |
494 return_rec(CX_JSON_NO_ERROR); |
491 } |
495 } |
492 case CX_JSON_TOKEN_BEGIN_OBJECT: { |
496 case CX_JSON_TOKEN_BEGIN_OBJECT: { |
493 if (create_json_value(json, CX_JSON_OBJECT) == NULL) { |
497 if (create_json_value(json, CX_JSON_OBJECT) == NULL) { |
494 // TODO: error code - no memory |
498 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
495 return_rec(-1); |
|
496 } |
499 } |
497 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); |
500 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); |
498 return_rec(1); |
501 return_rec(CX_JSON_NO_ERROR); |
499 } |
502 } |
500 case CX_JSON_TOKEN_STRING: { |
503 case CX_JSON_TOKEN_STRING: { |
501 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) { |
504 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) { |
502 // TODO: error code - no memory |
505 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
503 return_rec(-1); |
506 } |
504 } |
507 cxmutstr str = unescape_string(json->allocator, token.content); |
505 cxmutstr str = unescape_string(json->allocator, token.content, token.length); |
|
506 if (str.ptr == NULL) { |
508 if (str.ptr == NULL) { |
507 // TODO: error code - no memory |
509 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
508 return_rec(-1); |
|
509 } |
510 } |
510 vbuf->value.string = str; |
511 vbuf->value.string = str; |
511 return_rec(1); |
512 return_rec(CX_JSON_NO_ERROR); |
512 } |
513 } |
513 case CX_JSON_TOKEN_INTEGER: |
514 case CX_JSON_TOKEN_INTEGER: |
514 case CX_JSON_TOKEN_NUMBER: { |
515 case CX_JSON_TOKEN_NUMBER: { |
515 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
516 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
516 if (NULL == (vbuf = create_json_value(json, type))) { |
517 if (NULL == (vbuf = create_json_value(json, type))) { |
517 // TODO: error code - no memory |
518 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
518 return_rec(-1); |
519 } |
519 } |
520 if (parse_number(token.content, &vbuf->value,type == CX_JSON_INTEGER)) { |
520 if (parse_number(token.content, token.length, &vbuf->value,type == CX_JSON_INTEGER)) { |
521 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
521 // TODO: error code - format error |
522 } |
522 return_rec(-1); |
523 return_rec(CX_JSON_NO_ERROR); |
523 } |
|
524 return_rec(1); |
|
525 } |
524 } |
526 case CX_JSON_TOKEN_LITERAL: { |
525 case CX_JSON_TOKEN_LITERAL: { |
527 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { |
526 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { |
528 // TODO: error code - no memory |
527 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
529 return_rec(-1); |
528 } |
530 } |
529 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { |
531 const char *l = token.content; |
|
532 size_t token_len = token.length; |
|
533 if (token_len == 4 && !memcmp(l, "true", 4)) { |
|
534 vbuf->value.literal = CX_JSON_TRUE; |
530 vbuf->value.literal = CX_JSON_TRUE; |
535 } else if (token_len == 5 && !memcmp(l, "false", 5)) { |
531 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { |
536 vbuf->value.literal = CX_JSON_FALSE; |
532 vbuf->value.literal = CX_JSON_FALSE; |
537 } else { |
533 } else { |
538 vbuf->value.literal = CX_JSON_NULL; |
534 vbuf->value.literal = CX_JSON_NULL; |
539 } |
535 } |
540 return_rec(1); |
536 return_rec(CX_JSON_NO_ERROR); |
541 } |
537 } |
542 default: { |
538 default: { |
543 // TODO: error code - unexpected token |
539 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
544 return_rec(-1); |
|
545 } |
540 } |
546 } |
541 } |
547 } else if (state == JP_STATE_ARRAY_SEP_OR_CLOSE) { |
542 } else if (state == JP_STATE_ARRAY_SEP_OR_CLOSE) { |
548 // expect ',' or ']' |
543 // expect ',' or ']' |
549 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
544 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
550 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
545 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
551 return_rec(1); |
546 return_rec(CX_JSON_NO_ERROR); |
552 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { |
547 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { |
553 // discard the array from the value buffer |
548 // discard the array from the value buffer |
554 json->vbuf_size--; |
549 json->vbuf_size--; |
555 return_rec(1); |
550 return_rec(CX_JSON_NO_ERROR); |
556 } else { |
551 } else { |
557 // TODO: error code - unexpected token |
552 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
558 return_rec(-1); |
|
559 } |
553 } |
560 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) { |
554 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) { |
561 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
555 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
562 // discard the obj from the value buffer |
556 // discard the obj from the value buffer |
563 json->vbuf_size--; |
557 json->vbuf_size--; |
564 return_rec(1); |
558 return_rec(CX_JSON_NO_ERROR); |
565 } else { |
559 } else { |
566 // expect string |
560 // expect string |
567 if (token.tokentype != CX_JSON_TOKEN_STRING) { |
561 if (token.tokentype != CX_JSON_TOKEN_STRING) { |
568 // TODO: error code - unexpected token |
562 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
569 return_rec(-1); |
|
570 } |
563 } |
571 |
564 |
572 // add new entry |
565 // add new entry |
573 cxmutstr name = unescape_string(json->allocator, token.content, token.length); |
566 cxmutstr name = unescape_string(json->allocator, token.content); |
574 if (name.ptr == NULL) { |
567 if (name.ptr == NULL) { |
575 // TODO: error code - no mem |
568 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
576 return_rec(-1); |
|
577 } |
569 } |
578 json_obj_add_entry(json, name.ptr); |
570 json_obj_add_entry(json, name.ptr); |
579 |
571 |
580 // next state |
572 // next state |
581 json_add_state(json, JP_STATE_OBJ_COLON); |
573 json_add_state(json, JP_STATE_OBJ_COLON); |
582 return_rec(1); |
574 return_rec(CX_JSON_NO_ERROR); |
583 } |
575 } |
584 } else if (state == JP_STATE_OBJ_COLON) { |
576 } else if (state == JP_STATE_OBJ_COLON) { |
585 // expect ':' |
577 // expect ':' |
586 if (token.tokentype != CX_JSON_TOKEN_NAME_SEPARATOR) { |
578 if (token.tokentype != CX_JSON_TOKEN_NAME_SEPARATOR) { |
587 // TODO: error code - unexpected token |
579 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
588 return_rec(-1); |
|
589 } |
580 } |
590 // next state |
581 // next state |
591 json_add_state(json, JP_STATE_VALUE_BEGIN_OBJ); |
582 json_add_state(json, JP_STATE_VALUE_BEGIN_OBJ); |
592 return_rec(1); |
583 return_rec(CX_JSON_NO_ERROR); |
593 } else if (state == JP_STATE_OBJ_SEP_OR_CLOSE) { |
584 } else if (state == JP_STATE_OBJ_SEP_OR_CLOSE) { |
594 // expect ',' or '}' |
585 // expect ',' or '}' |
595 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
586 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
596 json_add_state(json, JP_STATE_OBJ_NAME); |
587 json_add_state(json, JP_STATE_OBJ_NAME); |
597 return_rec(1); |
588 return_rec(CX_JSON_NO_ERROR); |
598 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
589 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
599 // discard the obj from the value buffer |
590 // discard the obj from the value buffer |
600 json->vbuf_size--; |
591 json->vbuf_size--; |
601 return_rec(1); |
592 return_rec(CX_JSON_NO_ERROR); |
602 } else { |
593 } else { |
603 // TODO: error code - unexpected token |
594 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
604 return_rec(-1); |
|
605 } |
595 } |
606 } else { |
596 } else { |
607 // should be unreachable |
597 // should be unreachable |
608 assert(false); |
598 assert(false); |
609 return_rec(-1); |
599 return_rec(-1); |
610 } |
600 } |
611 } |
601 } |
612 |
602 |
613 int cxJsonNext(CxJson *json, CxJsonValue **value) { |
603 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) { |
614 // TODO: replace int with a status enum like in CxProperties |
|
615 |
|
616 // initialize output value |
604 // initialize output value |
617 *value = &cx_json_value_nothing; |
605 *value = &cx_json_value_nothing; |
618 |
606 |
619 // parse data |
607 // parse data |
620 int result; |
608 CxJsonStatus result; |
621 do { |
609 do { |
622 result = json_parse(json); |
610 result = json_parse(json); |
623 if (result == 1 && json->states_size == 1) { |
611 if (result == CX_JSON_NO_ERROR && json->states_size == 1) { |
624 // final state reached |
612 // final state reached |
625 assert(json->states[0] == JP_STATE_VALUE_END); |
613 assert(json->states[0] == JP_STATE_VALUE_END); |
626 assert(json->vbuf_size == 0); |
614 assert(json->vbuf_size == 0); |
627 |
615 |
628 // write output value |
616 // write output value |