287 result.ptr[result.length] = 0; |
287 result.ptr[result.length] = 0; |
288 |
288 |
289 return result; |
289 return result; |
290 } |
290 } |
291 |
291 |
292 static int parse_number(cxmutstr str, void *value, bool asint) { |
|
293 char *endptr = NULL; |
|
294 if (str.length > 30) { |
|
295 return 1; |
|
296 } |
|
297 // the buffer guarantees that we are working on a copied string |
|
298 char c = str.ptr[str.length]; |
|
299 str.ptr[str.length] = 0; |
|
300 |
|
301 if (asint) { |
|
302 errno = 0; |
|
303 long long v = strtoll(str.ptr, &endptr, 10); |
|
304 if (errno == ERANGE) { |
|
305 return 1; |
|
306 } |
|
307 *((int64_t*)value) = (int64_t) v; |
|
308 } else { |
|
309 // TODO: proper JSON spec number parser |
|
310 // TODO: also return an error when loss of precision is high |
|
311 double v = strtod(str.ptr, &endptr); |
|
312 *((double*)value) = v; |
|
313 } |
|
314 |
|
315 // recover from the hack |
|
316 str.ptr[str.length] = c; |
|
317 |
|
318 return endptr != &str.ptr[str.length]; |
|
319 } |
|
320 |
|
321 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { |
292 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { |
322 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue)); |
293 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue)); |
323 if (v == NULL) { |
294 if (v == NULL) { |
324 return NULL; |
295 return NULL; |
325 } |
296 } |
398 json->states[0] = JP_STATE_VALUE_BEGIN; |
369 json->states[0] = JP_STATE_VALUE_BEGIN; |
399 json->states_size = 1; |
370 json->states_size = 1; |
400 |
371 |
401 json->vbuf = json->vbuf_internal; |
372 json->vbuf = json->vbuf_internal; |
402 json->vbuf_capacity = cx_nmemb(json->vbuf_internal); |
373 json->vbuf_capacity = cx_nmemb(json->vbuf_internal); |
403 |
|
404 cxBufferInit(&json->buffer, NULL, 256, NULL, CX_BUFFER_AUTO_EXTEND); |
|
405 } |
374 } |
406 |
375 |
407 void cxJsonDestroy(CxJson *json) { |
376 void cxJsonDestroy(CxJson *json) { |
408 cxBufferDestroy(&json->buffer); |
377 cxBufferDestroy(&json->buffer); |
409 if (json->states != json->states_internal) { |
378 if (json->states != json->states_internal) { |
415 cxJsonValueFree(json->parsed); |
384 cxJsonValueFree(json->parsed); |
416 json->parsed = NULL; |
385 json->parsed = NULL; |
417 } |
386 } |
418 |
387 |
419 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { |
388 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { |
420 // we use the UCX buffer to write the data |
389 if (cxBufferEof(&json->buffer)) { |
421 // but reset the position immediately to enable parsing |
390 // reinitialize the buffer |
422 size_t old_pos = json->buffer.pos; |
391 cxBufferDestroy(&json->buffer); |
423 cxBufferSeek(&json->buffer, 0, SEEK_END); |
392 cxBufferInit(&json->buffer, (char*) buf, size, |
424 size_t written = cxBufferWrite(buf, 1, size, &json->buffer); |
393 NULL, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_COPY_ON_WRITE); |
425 if (0 == cxBufferTerminate(&json->buffer)) { |
394 json->buffer.size = size; |
426 written++; |
395 return 0; |
427 } |
396 } else { |
428 json->buffer.pos = old_pos; |
397 return size != cxBufferAppend(buf, 1, size, &json->buffer); |
429 return written != size + 1; |
398 } |
430 } |
399 } |
431 |
400 |
432 static void json_add_state(CxJson *json, int state) { |
401 static void json_add_state(CxJson *json, int state) { |
433 // we have guaranteed the necessary space with cx_array_simple_reserve() |
402 // we have guaranteed the necessary space with cx_array_simple_reserve() |
434 // therefore, we can safely add the state in the simplest way possible |
403 // therefore, we can safely add the state in the simplest way possible |
506 case CX_JSON_TOKEN_NUMBER: { |
475 case CX_JSON_TOKEN_NUMBER: { |
507 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
476 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
508 if (NULL == (vbuf = create_json_value(json, type))) { |
477 if (NULL == (vbuf = create_json_value(json, type))) { |
509 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
478 return_rec(CX_JSON_VALUE_ALLOC_FAILED); |
510 } |
479 } |
511 if (parse_number(token.content, &vbuf->value,type == CX_JSON_INTEGER)) { |
480 if (type == CX_JSON_INTEGER) { |
512 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
481 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { |
|
482 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
|
483 } |
|
484 } else { |
|
485 if (cx_strtod(token.content, &vbuf->value.number)) { |
|
486 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
|
487 } |
513 } |
488 } |
514 return_rec(CX_JSON_NO_ERROR); |
489 return_rec(CX_JSON_NO_ERROR); |
515 } |
490 } |
516 case CX_JSON_TOKEN_LITERAL: { |
491 case CX_JSON_TOKEN_LITERAL: { |
517 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { |
492 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { |
598 return_rec(-1); |
573 return_rec(-1); |
599 } |
574 } |
600 } |
575 } |
601 |
576 |
602 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) { |
577 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) { |
|
578 // check if buffer has been filled |
|
579 if (json->buffer.space == NULL) { |
|
580 return CX_JSON_NULL_DATA; |
|
581 } |
|
582 |
603 // initialize output value |
583 // initialize output value |
604 *value = &cx_json_value_nothing; |
584 *value = &cx_json_value_nothing; |
605 |
585 |
606 // parse data |
586 // parse data |
607 CxJsonStatus result; |
587 CxJsonStatus result; |
608 do { |
588 do { |
609 result = json_parse(json); |
589 result = json_parse(json); |
610 cxBufferShiftLeft(&json->buffer, json->buffer.pos); |
|
611 if (result == CX_JSON_NO_ERROR && json->states_size == 1) { |
590 if (result == CX_JSON_NO_ERROR && json->states_size == 1) { |
612 // final state reached |
591 // final state reached |
613 assert(json->states[0] == JP_STATE_VALUE_END); |
592 assert(json->states[0] == JP_STATE_VALUE_END); |
614 assert(json->vbuf_size == 0); |
593 assert(json->vbuf_size == 0); |
615 |
594 |