| 321 } |
320 } |
| 322 |
321 |
| 323 return (endptr != &buf[len]); |
322 return (endptr != &buf[len]); |
| 324 } |
323 } |
| 325 |
324 |
| 326 static int add_state(CxJson *p, int state) { |
325 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { |
| 327 CxArrayReallocator alloc = cx_array_reallocator(NULL, p->states_internal); |
326 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue)); |
| 328 size_t size = p->nstates + 1; |
327 if (v == NULL) { |
| 329 size_t capacity = p->states_alloc; |
328 return NULL; |
| 330 // TODO: fix that nstates does not denote the size of the array |
329 } |
| 331 // TODO: replace with a 16 bit (or maybe even 8 bit) version of cx_array_add() |
330 |
| 332 int result = cx_array_add( |
331 // initialize the value |
| 333 &p->states, |
332 if (type == CX_JSON_ARRAY) { |
| 334 &size, |
333 cx_array_initialize_a(json->allocator, v->value.array.array, 16); |
| 335 &capacity, |
334 if (v->value.array.array == NULL) { |
| 336 sizeof(int), |
335 cxFree(json->allocator, v); |
| 337 &state, |
336 return NULL; |
| 338 &alloc |
337 } |
| 339 ); |
338 } else if (type == CX_JSON_OBJECT) { |
| 340 if (result == 0) { |
339 cx_array_initialize_a(json->allocator, v->value.object.values, 16); |
| 341 p->nstates = size - 1; |
340 if (v->value.object.values == NULL) { |
| 342 p->states_alloc = capacity; |
341 cxFree(json->allocator, v); |
| 343 } |
342 return NULL; |
| 344 return result; |
343 } |
| 345 } |
344 } else { |
| 346 |
345 memset(v, 0, sizeof(CxJsonValue)); |
| 347 static void end_elm(CxJson *p, CxJsonReaderType type) { |
346 } |
| 348 p->reader_type = type; |
347 v->type = type; |
| 349 p->nstates--; |
348 v->allocator = json->allocator; |
| 350 } |
349 |
| 351 |
350 // add the new value to a possible parent |
| 352 #define JP_STATE_VALUE_BEGIN 0 |
351 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); |
| 353 #define JP_STATE_VALUE_BEGIN_OBJ 1 |
352 if (json->vbuf_size > 0) { |
| 354 #define JP_STATE_VALUE_BEGIN_AR 2 |
353 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; |
| 355 #define JP_STATE_ARRAY_SEP_OR_CLOSE 3 |
354 if (parent->type == CX_JSON_ARRAY) { |
| 356 #define JP_STATE_OBJ_NAME_OR_CLOSE 4 |
355 cx_array_simple_add_a(&value_realloc, parent->value.array.array, v); |
| 357 #define JP_STATE_OBJ_NAME 5 |
356 } else if (parent->type == CX_JSON_OBJECT) { |
| 358 #define JP_STATE_OBJ_COLON 6 |
357 assert(parent->value.object.values_size > 0); |
| 359 #define JP_STATE_OBJ_SEP_OR_CLOSE 7 |
358 assert(parent->value.object.values[parent->value.object.values_size - 1].value == NULL); |
| 360 |
359 parent->value.object.values[parent->value.object.values_size - 1].value = v; |
| 361 static int next_state_after_value(int current) { |
360 } else { |
| 362 switch (current) { |
361 assert(false); |
| 363 default: |
362 } |
| 364 return -1; |
363 } |
| 365 // after value JSON complete, expect nothing |
364 |
| 366 case JP_STATE_VALUE_BEGIN: |
365 // add the new value to the stack, if it is an array or object |
| 367 return -1; |
366 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) { |
| 368 // after obj value, expect ',' or '}' |
367 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal); |
| 369 case JP_STATE_VALUE_BEGIN_OBJ: |
368 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) { |
| 370 return JP_STATE_OBJ_SEP_OR_CLOSE; |
369 cxFree(json->allocator, v); |
| 371 // after array value, expect ',' or ']' |
370 return NULL; |
| 372 case JP_STATE_VALUE_BEGIN_AR: |
371 } |
| 373 return JP_STATE_ARRAY_SEP_OR_CLOSE; |
372 } |
| 374 } |
373 |
| 375 } |
374 // if currently no value is parsed, this is now the value of interest |
| 376 |
375 if (json->parsed == NULL) { |
| 377 static void clear_valuename(CxJson *p) { |
376 json->parsed = v; |
| 378 free(p->value_name); |
377 } |
| 379 p->value_name = NULL; |
378 |
| 380 p->value_name_len = 0; |
379 return v; |
| 381 } |
380 } |
| 382 |
381 |
| 383 static void clear_values(CxJson *p) { |
382 static int json_obj_add_entry(CxJson *json, char *name) { |
| 384 free(p->value_str); |
383 CxJsonObjValue kv = {name, NULL}; |
| 385 p->value_str = NULL; |
384 assert(json->vbuf_size > 0); |
| 386 p->value_str_len = 0; |
385 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; |
| 387 p->value_int = 0; |
386 assert(parent != NULL); |
| 388 p->value_double = 0; |
387 assert(parent->type == CX_JSON_OBJECT); |
| 389 } |
388 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); |
| 390 |
389 return cx_array_simple_add_a(&value_realloc, parent->value.object.values, kv); |
| 391 static int json_read(CxJson *p) { |
390 } |
| 392 int state = p->states[p->nstates]; |
391 |
| 393 clear_values(p); |
392 #define JP_STATE_VALUE_BEGIN 0 |
| 394 CxJsonToken token = json_parser_next_token(p); |
393 #define JP_STATE_VALUE_END 10 |
| 395 p->reader_token = token; |
394 #define JP_STATE_VALUE_BEGIN_OBJ 1 |
| 396 |
395 #define JP_STATE_OBJ_SEP_OR_CLOSE 11 |
| 397 p->value_ready = 0; |
396 #define JP_STATE_VALUE_BEGIN_AR 2 |
| 398 |
397 #define JP_STATE_ARRAY_SEP_OR_CLOSE 12 |
| |
398 #define JP_STATE_OBJ_NAME_OR_CLOSE 5 |
| |
399 #define JP_STATE_OBJ_NAME 6 |
| |
400 #define JP_STATE_OBJ_COLON 7 |
| |
401 |
| |
402 void cxJsonInit(CxJson *json, const CxAllocator *allocator) { |
| |
403 if (allocator == NULL) { |
| |
404 allocator = cxDefaultAllocator; |
| |
405 } |
| |
406 |
| |
407 memset(json, 0, sizeof(CxJson)); |
| |
408 json->allocator = allocator; |
| |
409 |
| |
410 json->states = json->states_internal; |
| |
411 json->states_capacity = cx_nmemb(json->states_internal); |
| |
412 json->states[0] = JP_STATE_VALUE_BEGIN; |
| |
413 json->states_size = 1; |
| |
414 |
| |
415 json->vbuf = json->vbuf_internal; |
| |
416 json->vbuf_capacity = cx_nmemb(json->vbuf_internal); |
| |
417 } |
| |
418 |
| |
419 void cxJsonDestroy(CxJson *json) { |
| |
420 if (json->states != json->states_internal) { |
| |
421 free(json->states); |
| |
422 } |
| |
423 if (json->vbuf != json->vbuf_internal) { |
| |
424 free(json->vbuf); |
| |
425 } |
| |
426 cxJsonValueFree(json->parsed); |
| |
427 json->parsed = NULL; |
| |
428 } |
| |
429 |
| |
430 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { |
| |
431 // TODO: implement rescue buffer like in CxProperties to allow subsequent fills |
| |
432 json->buffer = buf; |
| |
433 json->size = size; |
| |
434 json->pos = 0; |
| |
435 return 0; |
| |
436 } |
| |
437 |
| |
438 static void json_add_state(CxJson *json, int state) { |
| |
439 // we have guaranteed the necessary space with cx_array_simple_reserve() |
| |
440 // therefore, we can safely add the state in the simplest way possible |
| |
441 json->states[json->states_size++] = state; |
| |
442 } |
| |
443 |
| |
444 #define return_rec(code) \ |
| |
445 token_destroy(&token); \ |
| |
446 return code |
| |
447 |
| |
448 static int json_parse(CxJson *json) { |
| |
449 // Reserve a pointer for a possibly read value |
| |
450 CxJsonValue *vbuf = NULL; |
| |
451 |
| |
452 // grab the next token |
| |
453 CxJsonToken token = token_parse_next(json); |
| 399 if (token.tokentype == CX_JSON_NO_TOKEN) { |
454 if (token.tokentype == CX_JSON_NO_TOKEN) { |
| |
455 // nothing found, wait for more data |
| 400 return 0; |
456 return 0; |
| 401 } |
457 } |
| 402 |
458 |
| 403 int ret = 1; |
459 // pop the current state |
| 404 |
460 assert(json->states_size > 0); |
| 405 // 0 JP_STATE_VALUE_BEGIN value begin |
461 int state = json->states[--json->states_size]; |
| 406 // 1 JP_STATE_VALUE_BEGIN_OBJ value begin (inside object) |
462 |
| 407 // 2 JP_STATE_VALUE_BEGIN_AR value begin (inside array) |
463 // guarantee that at least two more states fit on the stack |
| 408 // 3 JP_STATE_ARRAY_SEP_OR_CLOSE array, expect separator or arrayclose |
464 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); |
| 409 // 4 JP_STATE_OBJ_NAME_OR_CLOSE object, expect name or objclose |
465 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { |
| 410 // 5 JP_STATE_OBJ_NAME object, expect name |
466 return -1; |
| 411 // 6 JP_STATE_OBJ_COLON object, expect ':' |
467 } |
| 412 // 7 JP_STATE_OBJ_SEP_OR_CLOSE object, expect separator, objclose |
468 |
| 413 |
469 |
| 414 if (state == JP_STATE_VALUE_BEGIN_AR || state == JP_STATE_OBJ_SEP_OR_CLOSE) { |
470 // 0 JP_STATE_VALUE_BEGIN value begin |
| 415 clear_valuename(p); |
471 // 10 JP_STATE_VALUE_END expect value end |
| 416 } |
472 // 1 JP_STATE_VALUE_BEGIN_OBJ value begin (inside object) |
| |
473 // 11 JP_STATE_OBJ_SEP_OR_CLOSE object, expect separator, objclose |
| |
474 // 2 JP_STATE_VALUE_BEGIN_AR value begin (inside array) |
| |
475 // 12 JP_STATE_ARRAY_SEP_OR_CLOSE array, expect separator or arrayclose |
| |
476 // 5 JP_STATE_OBJ_NAME_OR_CLOSE object, expect name or objclose |
| |
477 // 6 JP_STATE_OBJ_NAME object, expect name |
| |
478 // 7 JP_STATE_OBJ_COLON object, expect ':' |
| 417 |
479 |
| 418 if (state < 3) { |
480 if (state < 3) { |
| 419 // expect value |
481 // push expected end state to the stack |
| 420 p->states[p->nstates] = next_state_after_value(state); |
482 json_add_state(json, 10 + state); |
| 421 p->value_ready = 1; |
|
| 422 switch (token.tokentype) { |
483 switch (token.tokentype) { |
| 423 case CX_JSON_TOKEN_BEGIN_ARRAY: { |
484 case CX_JSON_TOKEN_BEGIN_ARRAY: { |
| 424 p->reader_type = CX_JSON_READER_ARRAY_BEGIN; |
485 if (create_json_value(json, CX_JSON_ARRAY) == NULL) { |
| 425 ret = add_state(p, JP_STATE_VALUE_BEGIN_AR) ? -1 : 1; |
486 // TODO: error code - no memory |
| 426 break; |
487 return_rec(-1); |
| |
488 } |
| |
489 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
| |
490 return_rec(1); |
| 427 } |
491 } |
| 428 case CX_JSON_TOKEN_BEGIN_OBJECT: { |
492 case CX_JSON_TOKEN_BEGIN_OBJECT: { |
| 429 p->reader_type = CX_JSON_READER_OBJECT_BEGIN; |
493 if (create_json_value(json, CX_JSON_OBJECT) == NULL) { |
| 430 ret = add_state(p, JP_STATE_OBJ_NAME_OR_CLOSE) ? -1 : 1; |
494 // TODO: error code - no memory |
| 431 break; |
495 return_rec(-1); |
| 432 } |
496 } |
| 433 case CX_JSON_TOKEN_END_ARRAY: { |
497 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); |
| 434 p->value_ready = 0; |
498 return_rec(1); |
| 435 end_elm(p, CX_JSON_READER_ARRAY_END); |
|
| 436 break; |
|
| 437 } |
499 } |
| 438 case CX_JSON_TOKEN_STRING: { |
500 case CX_JSON_TOKEN_STRING: { |
| 439 p->reader_type = CX_JSON_READER_STRING; |
501 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) { |
| 440 cxmutstr str = unescape_string(p->allocator, token.content, token.length); |
502 // TODO: error code - no memory |
| 441 if (str.ptr) { |
503 return_rec(-1); |
| 442 p->value_str = str.ptr; |
504 } |
| 443 p->value_str_len = str.length; |
505 cxmutstr str = unescape_string(json->allocator, token.content, token.length); |
| |
506 if (str.ptr == NULL) { |
| |
507 // TODO: error code - no memory |
| |
508 return_rec(-1); |
| |
509 } |
| |
510 vbuf->value.string = str; |
| |
511 return_rec(1); |
| |
512 } |
| |
513 case CX_JSON_TOKEN_INTEGER: |
| |
514 case CX_JSON_TOKEN_NUMBER: { |
| |
515 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
| |
516 if (NULL == (vbuf = create_json_value(json, type))) { |
| |
517 // TODO: error code - no memory |
| |
518 return_rec(-1); |
| |
519 } |
| |
520 if (parse_number(token.content, token.length, &vbuf->value,type == CX_JSON_INTEGER)) { |
| |
521 // TODO: error code - format error |
| |
522 return_rec(-1); |
| |
523 } |
| |
524 return_rec(1); |
| |
525 } |
| |
526 case CX_JSON_TOKEN_LITERAL: { |
| |
527 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { |
| |
528 // TODO: error code - no memory |
| |
529 return_rec(-1); |
| |
530 } |
| |
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; |
| |
535 } else if (token_len == 5 && !memcmp(l, "false", 5)) { |
| |
536 vbuf->value.literal = CX_JSON_FALSE; |
| 444 } else { |
537 } else { |
| 445 ret = -1; |
538 vbuf->value.literal = CX_JSON_NULL; |
| 446 } |
539 } |
| 447 break; |
540 return_rec(1); |
| 448 } |
541 } |
| 449 case CX_JSON_TOKEN_INTEGER: { |
542 default: { |
| 450 p->reader_type = CX_JSON_READER_INTEGER; |
543 // TODO: error code - unexpected token |
| 451 if (parse_number(token.content, token.length, |
544 return_rec(-1); |
| 452 &p->value_int, true)) { |
545 } |
| 453 ret = -1; |
|
| 454 } |
|
| 455 break; |
|
| 456 } |
|
| 457 case CX_JSON_TOKEN_NUMBER: { |
|
| 458 p->reader_type = CX_JSON_READER_NUMBER; |
|
| 459 if (parse_number(token.content, token.length, |
|
| 460 &p->value_double, false)) { |
|
| 461 ret = -1; |
|
| 462 } |
|
| 463 break; |
|
| 464 } |
|
| 465 case CX_JSON_TOKEN_LITERAL: { |
|
| 466 p->reader_type = CX_JSON_READER_LITERAL; |
|
| 467 break; |
|
| 468 } |
|
| 469 default: ret = -1; |
|
| 470 } |
546 } |
| 471 } else if (state == JP_STATE_ARRAY_SEP_OR_CLOSE) { |
547 } else if (state == JP_STATE_ARRAY_SEP_OR_CLOSE) { |
| 472 // expect ',' or ']' |
548 // expect ',' or ']' |
| 473 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
549 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
| 474 p->states[p->nstates] = JP_STATE_VALUE_BEGIN_AR; |
550 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
| 475 ret = json_read(p); |
551 return_rec(1); |
| 476 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { |
552 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { |
| 477 end_elm(p, CX_JSON_READER_ARRAY_END); |
553 // discard the array from the value buffer |
| 478 } else { |
554 json->vbuf_size--; |
| 479 ret = -1; |
555 return_rec(1); |
| |
556 } else { |
| |
557 // TODO: error code - unexpected token |
| |
558 return_rec(-1); |
| 480 } |
559 } |
| 481 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) { |
560 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) { |
| 482 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
561 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
| 483 clear_valuename(p); |
562 // discard the obj from the value buffer |
| 484 end_elm(p, CX_JSON_READER_OBJECT_END); |
563 json->vbuf_size--; |
| |
564 return_rec(1); |
| 485 } else { |
565 } else { |
| 486 // expect string |
566 // expect string |
| 487 if (token.tokentype != CX_JSON_TOKEN_STRING) return -1; |
567 if (token.tokentype != CX_JSON_TOKEN_STRING) { |
| 488 |
568 // TODO: error code - unexpected token |
| 489 if (p->value_name) free(p->value_name); |
569 return_rec(-1); |
| 490 cxmutstr valname = unescape_string(p->allocator, token.content, token.length); |
570 } |
| 491 p->value_name = valname.ptr; |
571 |
| 492 p->value_name_len = valname.length; |
572 // add new entry |
| |
573 cxmutstr name = unescape_string(json->allocator, token.content, token.length); |
| |
574 if (name.ptr == NULL) { |
| |
575 // TODO: error code - no mem |
| |
576 return_rec(-1); |
| |
577 } |
| |
578 json_obj_add_entry(json, name.ptr); |
| 493 |
579 |
| 494 // next state |
580 // next state |
| 495 p->states[p->nstates] = JP_STATE_OBJ_COLON; |
581 json_add_state(json, JP_STATE_OBJ_COLON); |
| 496 ret = json_read(p); |
582 return_rec(1); |
| 497 } |
583 } |
| 498 } else if (state == JP_STATE_OBJ_COLON) { |
584 } else if (state == JP_STATE_OBJ_COLON) { |
| 499 // expect ':' |
585 // expect ':' |
| 500 if (token.tokentype != CX_JSON_TOKEN_NAME_SEPARATOR) return -1; |
586 if (token.tokentype != CX_JSON_TOKEN_NAME_SEPARATOR) { |
| |
587 // TODO: error code - unexpected token |
| |
588 return_rec(-1); |
| |
589 } |
| 501 // next state |
590 // next state |
| 502 p->states[p->nstates] = JP_STATE_VALUE_BEGIN_OBJ; |
591 json_add_state(json, JP_STATE_VALUE_BEGIN_OBJ); |
| 503 ret = json_read(p); |
592 return_rec(1); |
| 504 } else if (state == JP_STATE_OBJ_SEP_OR_CLOSE) { |
593 } else if (state == JP_STATE_OBJ_SEP_OR_CLOSE) { |
| 505 // expect ',' or '}' |
594 // expect ',' or '}' |
| 506 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
595 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { |
| 507 p->states[p->nstates] = JP_STATE_OBJ_NAME; |
596 json_add_state(json, JP_STATE_OBJ_NAME); |
| 508 ret = json_read(p); |
597 return_rec(1); |
| 509 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
598 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { |
| 510 end_elm(p, CX_JSON_READER_OBJECT_END); |
599 // discard the obj from the value buffer |
| 511 } else { |
600 json->vbuf_size--; |
| 512 ret = -1; |
601 return_rec(1); |
| 513 } |
602 } else { |
| 514 } |
603 // TODO: error code - unexpected token |
| 515 |
604 return_rec(-1); |
| 516 if (token.alloc > 0) { |
605 } |
| 517 free((char*)token.content); |
|
| 518 } |
|
| 519 |
|
| 520 return ret; |
|
| 521 } |
|
| 522 |
|
| 523 static CxJsonLiteral json_reader_literal(CxJson *p) { |
|
| 524 const char *l = p->reader_token.content; |
|
| 525 size_t token_len = p->reader_token.length; |
|
| 526 if (token_len == 4 && !memcmp(l, "true", 4)) { |
|
| 527 return CX_JSON_TRUE; |
|
| 528 } else if (token_len == 5 && !memcmp(l, "false", 5)) { |
|
| 529 return CX_JSON_FALSE; |
|
| 530 } |
|
| 531 return CX_JSON_NULL; |
|
| 532 } |
|
| 533 |
|
| 534 /* -------------------- read value functions -------------------- */ |
|
| 535 |
|
| 536 static int setup_read_value(CxJson *p) { |
|
| 537 p->readvalue_alloc = PARSER_READVALUE_ALLOC; |
|
| 538 p->readvalue_nelm = 0; |
|
| 539 p->readvalue_stack = calloc(p->readvalue_alloc, sizeof(CxJsonValue *)); |
|
| 540 if (!p->readvalue_stack) return -1; |
|
| 541 |
|
| 542 p->read_value = NULL; |
|
| 543 p->readvalue_stack[0] = NULL; |
|
| 544 |
|
| 545 return 0; |
|
| 546 } |
|
| 547 |
|
| 548 static int add_to_parent(CxJson *p, CxJsonValue *parent, CxJsonValue *v) { |
|
| 549 if (!parent) { |
|
| 550 return -1; // shouldn't happen but who knows |
|
| 551 } |
|
| 552 |
|
| 553 CxArrayReallocator reallocator = cx_array_reallocator(p->allocator, NULL); |
|
| 554 if (parent->type == CX_JSON_OBJECT) { |
|
| 555 if (!p->value_name || p->value_name_len == 0) { |
|
| 556 return -1; |
|
| 557 } |
|
| 558 char *valuename = p->value_name; |
|
| 559 p->value_name = NULL; |
|
| 560 |
|
| 561 CxJsonObjValue newvalue; |
|
| 562 newvalue.name = valuename; |
|
| 563 newvalue.value = v; |
|
| 564 |
|
| 565 return cx_array_add( |
|
| 566 &parent->value.object.values, |
|
| 567 &parent->value.object.values_size, |
|
| 568 &parent->value.object.values_capacity, |
|
| 569 sizeof(CxJsonObjValue), |
|
| 570 &newvalue, |
|
| 571 &reallocator); |
|
| 572 } else if (parent->type == CX_JSON_ARRAY) { |
|
| 573 return cx_array_add( |
|
| 574 &parent->value.array.array, |
|
| 575 &parent->value.array.array_size, |
|
| 576 &parent->value.array.array_capacity, |
|
| 577 sizeof(CxJsonValue*), |
|
| 578 &v, |
|
| 579 &reallocator); |
|
| 580 } else { |
606 } else { |
| 581 return -1; // should also never happen |
607 // should be unreachable |
| 582 } |
608 assert(false); |
| 583 } |
609 return_rec(-1); |
| 584 |
610 } |
| 585 |
611 } |
| 586 static int readvaluestack_add(CxJson *p, CxJsonValue *v) { |
612 |
| 587 if (p->readvalue_nelm == p->readvalue_alloc) { |
613 int cxJsonNext(CxJson *json, CxJsonValue **value) { |
| 588 p->readvalue_alloc *= 2; |
|
| 589 if (cx_reallocate(&p->readvalue_stack, sizeof(CxJsonValue *) * p->readvalue_alloc)) { |
|
| 590 return -1; |
|
| 591 } |
|
| 592 } |
|
| 593 p->readvalue_stack[p->readvalue_nelm++] = v; |
|
| 594 return 0; |
|
| 595 } |
|
| 596 |
|
| 597 void cxJsonInit(const CxAllocator *allocator, CxJson *json) { |
|
| 598 if (allocator == NULL) { |
|
| 599 allocator = cxDefaultAllocator; |
|
| 600 } |
|
| 601 |
|
| 602 memset(json, 0, sizeof(CxJson)); |
|
| 603 json->allocator = allocator; |
|
| 604 json->states = json->states_internal; |
|
| 605 json->states_alloc = cx_nmemb(json->states_internal); |
|
| 606 // TODO: find better way to configure the initial allocation size for arrays and objects |
|
| 607 json->reader_array_alloc = 8; |
|
| 608 } |
|
| 609 |
|
| 610 void cxJsonDestroy(CxJson *p) { |
|
| 611 if (p->states != p->states_internal) { |
|
| 612 free(p->states); |
|
| 613 } |
|
| 614 free(p->readvalue_stack); |
|
| 615 cxJsonValueFree(p->read_value); |
|
| 616 free(p->value_name); |
|
| 617 free(p->value_str); |
|
| 618 } |
|
| 619 |
|
| 620 int cxJsonFilln(CxJson *p, const char *buf, size_t size) { |
|
| 621 // TODO: implement rescue buffer like in CxProperties to allow subsequent fills |
|
| 622 p->buffer = buf; |
|
| 623 p->size = size; |
|
| 624 p->pos = 0; |
|
| 625 return 0; |
|
| 626 } |
|
| 627 |
|
| 628 int cxJsonNext(CxJson *p, CxJsonValue **value) { |
|
| 629 // TODO: replace int with a status enum like in CxProperties |
614 // TODO: replace int with a status enum like in CxProperties |
| 630 |
615 |
| 631 *value = NULL; // TODO: maybe better initialize with NOTHING? |
616 // initialize output value |
| 632 if (!p->readvalue_stack) { |
617 *value = &cx_json_value_nothing; |
| 633 if (setup_read_value(p)) return -1; |
618 |
| 634 } |
619 // parse data |
| 635 |
620 int result; |
| 636 while (p->readvalue_nelm > 0 || !p->read_value) { |
621 do { |
| 637 if (p->value_ready) { |
622 result = json_parse(json); |
| 638 // value available without another read |
623 if (result == 1 && json->states_size == 1) { |
| 639 CxJsonValue *v = cxCalloc(p->allocator, 1, sizeof(CxJsonValue)); |
624 // final state reached |
| 640 if (!v) return -1; |
625 assert(json->states[0] == JP_STATE_VALUE_END); |
| 641 v->allocator = p->allocator; |
626 assert(json->vbuf_size == 0); |
| 642 |
627 |
| 643 if (p->readvalue_nelm > 0) { |
628 // write output value |
| 644 if (add_to_parent(p, p->readvalue_stack[p->readvalue_nelm - 1], v)) { |
629 *value = json->parsed; |
| 645 free(v); |
630 json->parsed = NULL; |
| 646 return -1; |
631 |
| 647 } |
632 // re-initialize state machine |
| 648 } else { |
633 json->states[0] = JP_STATE_VALUE_BEGIN; |
| 649 // set this value as root |
634 |
| 650 p->read_value = v; |
635 return 1; |
| 651 } |
636 } |
| 652 |
637 } while (result == 1); |
| 653 switch (p->reader_type) { |
638 |
| 654 case CX_JSON_READER_OBJECT_BEGIN: { |
639 return result; |
| 655 v->type = CX_JSON_OBJECT; |
|
| 656 if (readvaluestack_add(p, v)) { |
|
| 657 return -1; |
|
| 658 } |
|
| 659 break; |
|
| 660 } |
|
| 661 case CX_JSON_READER_OBJECT_END: |
|
| 662 return -1; // should not happen |
|
| 663 case CX_JSON_READER_ARRAY_BEGIN: { |
|
| 664 v->type = CX_JSON_ARRAY; |
|
| 665 if (readvaluestack_add(p, v)) { |
|
| 666 return -1; |
|
| 667 } |
|
| 668 break; |
|
| 669 } |
|
| 670 case CX_JSON_READER_ARRAY_END: |
|
| 671 return -1; // should not happen |
|
| 672 case CX_JSON_READER_STRING: { |
|
| 673 v->type = CX_JSON_STRING; |
|
| 674 if (p->value_str) { |
|
| 675 v->value.string.ptr = p->value_str; |
|
| 676 v->value.string.length = p->value_str_len; |
|
| 677 p->value_str = NULL; |
|
| 678 } |
|
| 679 break; |
|
| 680 } |
|
| 681 case CX_JSON_READER_INTEGER: { |
|
| 682 v->type = CX_JSON_INTEGER; |
|
| 683 v->value.integer = p->value_int; |
|
| 684 break; |
|
| 685 } |
|
| 686 case CX_JSON_READER_NUMBER: { |
|
| 687 v->type = CX_JSON_NUMBER; |
|
| 688 v->value.number = p->value_double; |
|
| 689 break; |
|
| 690 } |
|
| 691 case CX_JSON_READER_LITERAL: { |
|
| 692 v->type = CX_JSON_LITERAL; |
|
| 693 v->value.literal = json_reader_literal(p); |
|
| 694 break; |
|
| 695 } |
|
| 696 } |
|
| 697 } else if (p->readvalue_initialized) { |
|
| 698 CxJsonReaderType rt = p->reader_type; |
|
| 699 if (rt == CX_JSON_READER_OBJECT_END || rt == CX_JSON_READER_ARRAY_END) { |
|
| 700 p->readvalue_nelm--; |
|
| 701 } |
|
| 702 // else: p->value_ready is 1, this will be handled in the next run |
|
| 703 } |
|
| 704 |
|
| 705 if (p->readvalue_nelm > 0 || !p->read_value) { |
|
| 706 int r = json_read(p); |
|
| 707 if (r != 1) { |
|
| 708 p->readvalue_initialized = 0; |
|
| 709 return r; |
|
| 710 } |
|
| 711 p->readvalue_initialized = 1; |
|
| 712 } |
|
| 713 } |
|
| 714 |
|
| 715 *value = p->read_value; |
|
| 716 p->readvalue_initialized = 0; |
|
| 717 p->read_value = NULL; |
|
| 718 p->value_ready = 0; |
|
| 719 |
|
| 720 return 1; |
|
| 721 } |
640 } |
| 722 |
641 |
| 723 void cxJsonValueFree(CxJsonValue *value) { |
642 void cxJsonValueFree(CxJsonValue *value) { |
| 724 if (value == NULL || value == &cx_json_value_nothing) return; |
643 if (value == NULL || value == &cx_json_value_nothing) return; |
| 725 |
644 |