@@ -338,14 +338,20 @@ static fossil_media_json_value_t *parse_array(ctx_t *c, fossil_media_json_error_
338338 skip_ws (c );
339339 fossil_media_json_value_t * arr = fossil_media_json_new_array ();
340340 if (!arr ) { set_error (err ,1 ,c -> i ,"OOM" ); return NULL ; }
341+ skip_ws (c );
341342 if (c -> s [c -> i ] == ']' ) { c -> i ++ ; return arr ; }
342343 while (1 ) {
343344 skip_ws (c );
344345 fossil_media_json_value_t * elem = parse_value (c , err );
345346 if (!elem ) { fossil_media_json_free (arr ); return NULL ; }
346347 if (fossil_media_json_array_append (arr , elem ) != 0 ) { fossil_media_json_free (elem ); fossil_media_json_free (arr ); set_error (err ,1 ,c -> i ,"OOM" ); return NULL ; }
347348 skip_ws (c );
348- if (c -> s [c -> i ] == ',' ) { c -> i ++ ; continue ; }
349+ if (c -> s [c -> i ] == ',' ) {
350+ c -> i ++ ;
351+ skip_ws (c );
352+ if (c -> s [c -> i ] == ']' ) { fossil_media_json_free (arr ); set_error (err ,1 ,c -> i ,"Trailing comma in array" ); return NULL ; }
353+ continue ;
354+ }
349355 else if (c -> s [c -> i ] == ']' ) { c -> i ++ ; break ; }
350356 else { fossil_media_json_free (arr ); set_error (err ,1 ,c -> i ,"Expected ',' or ']' in array" ); return NULL ; }
351357 }
@@ -361,6 +367,7 @@ static fossil_media_json_value_t *parse_object(ctx_t *c, fossil_media_json_error
361367 skip_ws (c );
362368 fossil_media_json_value_t * obj = fossil_media_json_new_object ();
363369 if (!obj ) { set_error (err ,1 ,c -> i ,"OOM" ); return NULL ; }
370+ skip_ws (c );
364371 if (c -> s [c -> i ] == '}' ) { c -> i ++ ; return obj ; }
365372 while (1 ) {
366373 skip_ws (c );
@@ -390,7 +397,12 @@ static fossil_media_json_value_t *parse_object(ctx_t *c, fossil_media_json_error
390397 obj -> u .object .values [obj -> u .object .count ] = val ;
391398 obj -> u .object .count ++ ;
392399 skip_ws (c );
393- if (c -> s [c -> i ] == ',' ) { c -> i ++ ; continue ; }
400+ if (c -> s [c -> i ] == ',' ) {
401+ c -> i ++ ;
402+ skip_ws (c );
403+ if (c -> s [c -> i ] == '}' ) { fossil_media_json_free (obj ); set_error (err ,1 ,c -> i ,"Trailing comma in object" ); return NULL ; }
404+ continue ;
405+ }
394406 else if (c -> s [c -> i ] == '}' ) { c -> i ++ ; break ; }
395407 else { fossil_media_json_free (obj ); set_error (err ,1 ,c -> i ,"Expected ',' or '}' in object" ); return NULL ; }
396408 }
@@ -451,10 +463,10 @@ static void append_escaped(char **bufp, size_t *lenp, size_t *cap, const char *s
451463 add = 6 ;
452464 }
453465 if (esc ) {
454- if (* lenp + add + 1 > * cap ) { * cap = (* lenp + add + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
466+ if (* lenp + add + 1 > * cap ) { * cap = (* lenp + add + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return ; }
455467 memcpy (* bufp + * lenp , esc , add ); * lenp += add ; continue ;
456468 }
457- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
469+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return ; }
458470 (* bufp )[(* lenp )++ ] = c ;
459471 }
460472}
@@ -465,82 +477,83 @@ static int stringify_value(const fossil_media_json_value_t *v, char **bufp, size
465477 if (* bufp == NULL ) { * cap = 256 ; * bufp = fm_malloc (* cap ); if (!* bufp ) return -1 ; * lenp = 0 ; }
466478 switch (v -> type ) {
467479 case FOSSIL_MEDIA_JSON_NULL :
468- if (* lenp + 5 > * cap ) { * cap = (* lenp + 5 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
480+ if (* lenp + 5 > * cap ) { * cap = (* lenp + 5 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
469481 memcpy (* bufp + * lenp , "null" , 4 ); * lenp += 4 ;
470482 break ;
471483 case FOSSIL_MEDIA_JSON_BOOL : {
472484 const char * t = v -> u .boolean ? "true" : "false" ;
473485 size_t n = v -> u .boolean ? 4 : 5 ;
474- if (* lenp + n + 1 > * cap ) { * cap = (* lenp + n + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
486+ if (* lenp + n + 1 > * cap ) { * cap = (* lenp + n + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
475487 memcpy (* bufp + * lenp , t , n ); * lenp += n ;
476488 break ;
477489 }
478490 case FOSSIL_MEDIA_JSON_NUMBER : {
479491 char tmp [64 ];
480492 int n = snprintf (tmp , sizeof (tmp ), "%.17g" , v -> u .number );
481- if (* lenp + (size_t )n + 1 > * cap ) { * cap = (* lenp + n + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
493+ if (n < 0 ) return -1 ;
494+ if (* lenp + (size_t )n + 1 > * cap ) { * cap = (* lenp + n + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (!* bufp ) return -1 ; }
482495 memcpy (* bufp + * lenp , tmp , n ); * lenp += n ;
483496 break ;
484497 }
485498 case FOSSIL_MEDIA_JSON_STRING : {
486- if (* lenp + 3 > * cap ) { * cap = (* lenp + 3 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
499+ if (* lenp + 3 > * cap ) { * cap = (* lenp + 3 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
487500 (* bufp )[(* lenp )++ ] = '"' ;
488501 append_escaped (bufp , lenp , cap , v -> u .string ? v -> u .string : "" );
489- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
502+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
490503 (* bufp )[(* lenp )++ ] = '"' ;
491504 break ;
492505 }
493506 case FOSSIL_MEDIA_JSON_ARRAY : {
494- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
507+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
495508 (* bufp )[(* lenp )++ ] = '[' ;
496509 for (size_t i = 0 ; i < v -> u .array .count ; ++ i ) {
497510 if (i ) {
498- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
511+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
499512 (* bufp )[(* lenp )++ ] = ',' ;
500513 }
501514 if (pretty ) {
502- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
515+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
503516 (* bufp )[(* lenp )++ ] = '\n' ;
504517 for (int d = 0 ; d < depth + 1 ; ++ d ) {
505- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
518+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
506519 (* bufp )[(* lenp )++ ] = '\t' ;
507520 }
508521 }
509522 if (stringify_value (v -> u .array .items [i ], bufp , lenp , cap , pretty , depth + 1 ) != 0 ) return -1 ;
510523 }
511524 if (pretty && v -> u .array .count ) {
512- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
525+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
513526 (* bufp )[(* lenp )++ ] = '\n' ;
514527 for (int d = 0 ; d < depth ; ++ d ) {
515- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
528+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
516529 (* bufp )[(* lenp )++ ] = '\t' ;
517530 }
518531 }
519- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
532+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
520533 (* bufp )[(* lenp )++ ] = ']' ;
521534 break ;
522535 }
523536 case FOSSIL_MEDIA_JSON_OBJECT : {
524- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
537+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
525538 (* bufp )[(* lenp )++ ] = '{' ;
526539 for (size_t i = 0 ; i < v -> u .object .count ; ++ i ) {
527540 if (i ) {
528- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
541+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
529542 (* bufp )[(* lenp )++ ] = ',' ;
530543 }
531544 if (pretty ) {
532- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
545+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
533546 (* bufp )[(* lenp )++ ] = '\n' ;
534547 for (int d = 0 ; d < depth + 1 ; ++ d ) {
535- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
548+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
536549 (* bufp )[(* lenp )++ ] = '\t' ;
537550 }
538551 }
539552 /* key */
540- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
553+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
541554 (* bufp )[(* lenp )++ ] = '"' ;
542555 append_escaped (bufp , lenp , cap , v -> u .object .keys [i ]);
543- if (* lenp + 3 > * cap ) { * cap = (* lenp + 3 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
556+ if (* lenp + 3 > * cap ) { * cap = (* lenp + 3 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
544557 (* bufp )[(* lenp )++ ] = '"' ;
545558 (* bufp )[(* lenp )++ ] = ':' ;
546559 if (pretty ) {
@@ -549,14 +562,14 @@ static int stringify_value(const fossil_media_json_value_t *v, char **bufp, size
549562 if (stringify_value (v -> u .object .values [i ], bufp , lenp , cap , pretty , depth + 1 ) != 0 ) return -1 ;
550563 }
551564 if (pretty && v -> u .object .count ) {
552- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
565+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
553566 (* bufp )[(* lenp )++ ] = '\n' ;
554567 for (int d = 0 ; d < depth ; ++ d ) {
555- if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
568+ if (* lenp + 2 > * cap ) { * cap = (* lenp + 2 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
556569 (* bufp )[(* lenp )++ ] = '\t' ;
557570 }
558571 }
559- if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); }
572+ if (* lenp + 1 > * cap ) { * cap = (* lenp + 1 ) * 2 ; * bufp = fm_realloc (* bufp , * cap ); if (! * bufp ) return -1 ; }
560573 (* bufp )[(* lenp )++ ] = '}' ;
561574 break ;
562575 }
@@ -580,7 +593,7 @@ char *fossil_media_json_stringify(const fossil_media_json_value_t *v, int pretty
580593}
581594
582595char * fossil_media_json_roundtrip (const char * json_text , int pretty , fossil_media_json_error_t * err_out ) {
583- fossil_media_json_error_t err ;
596+ fossil_media_json_error_t err = { 0 , 0 , "" } ;
584597 fossil_media_json_value_t * v = fossil_media_json_parse (json_text , & err );
585598 if (!v ) { if (err_out ) * err_out = err ; return NULL ; }
586599 char * s = fossil_media_json_stringify (v , pretty , & err );
@@ -646,6 +659,8 @@ static fossil_media_json_value_t *fossil_media_json_clone_internal(const fossil_
646659 }
647660 }
648661 break ;
662+ default :
663+ break ;
649664 }
650665 return copy ;
651666}
@@ -657,7 +672,8 @@ fossil_media_json_clone(const fossil_media_json_value_t *src) {
657672
658673int fossil_media_json_equals (const fossil_media_json_value_t * a ,
659674 const fossil_media_json_value_t * b ) {
660- if (!a || !b ) return -1 ;
675+ if (!a && !b ) return -1 ;
676+ if (!a || !b ) return 0 ;
661677 if (a -> type != b -> type ) return 0 ;
662678
663679 switch (a -> type ) {
@@ -668,6 +684,8 @@ int fossil_media_json_equals(const fossil_media_json_value_t *a,
668684 case FOSSIL_MEDIA_JSON_NUMBER :
669685 return a -> u .number == b -> u .number ;
670686 case FOSSIL_MEDIA_JSON_STRING :
687+ if (!a -> u .string && !b -> u .string ) return 1 ;
688+ if (!a -> u .string || !b -> u .string ) return 0 ;
671689 return strcmp (a -> u .string , b -> u .string ) == 0 ;
672690 case FOSSIL_MEDIA_JSON_ARRAY :
673691 if (a -> u .array .count != b -> u .array .count ) return 0 ;
@@ -683,7 +701,14 @@ int fossil_media_json_equals(const fossil_media_json_value_t *a,
683701 if (!val_b || !fossil_media_json_equals (a -> u .object .values [i ], val_b ))
684702 return 0 ;
685703 }
704+ for (size_t i = 0 ; i < b -> u .object .count ; i ++ ) {
705+ fossil_media_json_value_t * val_a = fossil_media_json_object_get (a , b -> u .object .keys [i ]);
706+ if (!val_a || !fossil_media_json_equals (b -> u .object .values [i ], val_a ))
707+ return 0 ;
708+ }
686709 return 1 ;
710+ default :
711+ break ;
687712 }
688713 return 0 ;
689714}
@@ -713,7 +738,7 @@ int fossil_media_json_array_reserve(fossil_media_json_value_t *arr, size_t capac
713738 if (capacity <= arr -> u .array .capacity ) return 0 ;
714739
715740 fossil_media_json_value_t * * new_items =
716- realloc (arr -> u .array .items , capacity * sizeof (* new_items ));
741+ fm_realloc (arr -> u .array .items , capacity * sizeof (* new_items ));
717742 if (!new_items ) return -1 ;
718743
719744 arr -> u .array .items = new_items ;
@@ -725,9 +750,9 @@ int fossil_media_json_object_reserve(fossil_media_json_value_t *obj, size_t capa
725750 if (!obj || obj -> type != FOSSIL_MEDIA_JSON_OBJECT ) return -1 ;
726751 if (capacity <= obj -> u .object .capacity ) return 0 ;
727752
728- char * * new_keys = realloc (obj -> u .object .keys , capacity * sizeof (* new_keys ));
753+ char * * new_keys = fm_realloc (obj -> u .object .keys , capacity * sizeof (* new_keys ));
729754 fossil_media_json_value_t * * new_vals =
730- realloc (obj -> u .object .values , capacity * sizeof (* new_vals ));
755+ fm_realloc (obj -> u .object .values , capacity * sizeof (* new_vals ));
731756 if (!new_keys || !new_vals ) return -1 ;
732757
733758 obj -> u .object .keys = new_keys ;
@@ -823,7 +848,7 @@ void fossil_media_json_debug_dump(const fossil_media_json_value_t *v, int indent
823848 printf ("%*sValue: %g\n" , indent + 2 , "" , v -> u .number );
824849 break ;
825850 case FOSSIL_MEDIA_JSON_STRING :
826- printf ("%*sValue: \"%s\"\n" , indent + 2 , "" , v -> u .string );
851+ printf ("%*sValue: \"%s\"\n" , indent + 2 , "" , v -> u .string ? v -> u . string : "(null)" );
827852 break ;
828853 case FOSSIL_MEDIA_JSON_ARRAY :
829854 for (size_t i = 0 ; i < v -> u .array .count ; i ++ ) {
@@ -841,9 +866,14 @@ void fossil_media_json_debug_dump(const fossil_media_json_value_t *v, int indent
841866}
842867
843868int fossil_media_json_validate (const char * json_text , fossil_media_json_error_t * err_out ) {
844- fossil_media_json_value_t * v = fossil_media_json_parse (json_text , err_out );
845- if (!v ) return -1 ;
869+ fossil_media_json_error_t errtmp = {0 ,0 ,"" };
870+ fossil_media_json_value_t * v = fossil_media_json_parse (json_text , & errtmp );
871+ if (!v ) {
872+ if (err_out ) * err_out = errtmp ;
873+ return 1 ;
874+ }
846875 fossil_media_json_free (v );
876+ if (err_out ) * err_out = errtmp ;
847877 return 0 ;
848878}
849879
0 commit comments