src/json.c

changeset 1002
1483c47063a8
parent 1000
1aecddf7e209
child 1007
81b2986d2b04
equal deleted inserted replaced
1001:5c9ec5a0a4ef 1002:1483c47063a8
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;
143 } 105 }
144 106
145 return type; 107 return type;
146 } 108 }
147 109
110 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) {
111 cxmutstr str = cx_mutstrn((char*)json->buffer + start, end - start);
112 bool allocated = false;
113 if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) {
114 allocated = true;
115 str = cx_strcat_m(json->uncompleted.content, 1, str);
116 if (str.ptr == NULL) {
117 return (CxJsonToken){CX_JSON_NO_TOKEN, false, 0, 0};
118 }
119 }
120 json->uncompleted = (CxJsonToken){0};
121 CxJsonTokenType ttype;
122 if (isstring) {
123 ttype = CX_JSON_TOKEN_STRING;
124 } else {
125 if (token_isliteral(str.ptr, str.length)) {
126 ttype = CX_JSON_TOKEN_LITERAL;
127 } else {
128 ttype = token_numbertype(str.ptr, str.length);
129 }
130 }
131 if (ttype == CX_JSON_TOKEN_ERROR) {
132 if (allocated) {
133 cx_strfree(&str);
134 }
135 return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, 0, 0};
136 }
137 return (CxJsonToken){ttype, allocated, str};
138 }
139
148 static CxJsonTokenType char2ttype(char c) { 140 static CxJsonTokenType char2ttype(char c) {
149 switch (c) { 141 switch (c) {
150 case '[': { 142 case '[': {
151 return CX_JSON_TOKEN_BEGIN_ARRAY; 143 return CX_JSON_TOKEN_BEGIN_ARRAY;
152 } 144 }
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') {
298 result.ptr[result.length] = 0; 301 result.ptr[result.length] = 0;
299 302
300 return result; 303 return result;
301 } 304 }
302 305
303 static int parse_number(const char *str, size_t len, void *value, bool asint) { 306 static int parse_number(cxmutstr str, void *value, bool asint) {
304 char *endptr = NULL; 307 char *endptr = NULL;
305 char buf[32]; 308 char buf[32];
306 if (len > 30) { 309 if (str.length > 30) {
307 return 1; 310 return 1;
308 } 311 }
309 // TODO: if we can guarantee that we are working on a copied string already, we can avoid this memcpy 312 // TODO: if we can guarantee that we are working on a copied string already, we can avoid this memcpy
310 memcpy(buf, str, len); 313 memcpy(buf, str.ptr, str.length);
311 buf[len] = 0; 314 buf[str.length] = 0;
312 315
313 if (asint) { 316 if (asint) {
314 long long v = strtoll(buf, &endptr, 10); 317 long long v = strtoll(buf, &endptr, 10);
315 *((int64_t*)value) = (int64_t) v; 318 *((int64_t*)value) = (int64_t) v;
316 } else { 319 } else {
317 // TODO: proper JSON spec number parser 320 // TODO: proper JSON spec number parser
318 double v = strtod(buf, &endptr); 321 double v = strtod(buf, &endptr);
319 *((double*)value) = v; 322 *((double*)value) = v;
320 } 323 }
321 324
322 return (endptr != &buf[len]); 325 return (endptr != &buf[str.length]);
323 } 326 }
324 327
325 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { 328 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) {
326 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue)); 329 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue));
327 if (v == NULL) { 330 if (v == NULL) {
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
630 json->parsed = NULL; 618 json->parsed = NULL;
631 619
632 // re-initialize state machine 620 // re-initialize state machine
633 json->states[0] = JP_STATE_VALUE_BEGIN; 621 json->states[0] = JP_STATE_VALUE_BEGIN;
634 622
635 return 1; 623 return CX_JSON_NO_ERROR;
636 } 624 }
637 } while (result == 1); 625 } while (result == CX_JSON_NO_ERROR);
626
627 // the parser might think there is no data
628 // but when we did not reach the final state,
629 // we know that there must be more to come
630 if (result == CX_JSON_NO_DATA && json->states_size > 1) {
631 return CX_JSON_INCOMPLETE_DATA;
632 }
638 633
639 return result; 634 return result;
640 } 635 }
641 636
642 void cxJsonValueFree(CxJsonValue *value) { 637 void cxJsonValueFree(CxJsonValue *value) {

mercurial