2 Copyright (C) 2005 Georgia Public Library Service
3 Bill Erickson <highfalutin@gmail.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
17 #include "json_parser.h"
20 /* ---------------------------------------------------------------------- */
21 /* See object.h for function info */
22 /* ---------------------------------------------------------------------- */
25 char* __tabs(int count);
27 jsonObject* jsonNewObject( const char* stringValue, ... ) {
29 jsonObject* obj = (jsonObject*) safe_malloc(sizeof(jsonObject));
31 obj->type = JSON_NULL;
34 VA_LIST_TO_STRING(stringValue);
35 obj->type = JSON_STRING;
36 obj->value.s = strdup(VA_BUF);
45 jsonObject* jsonNewNumberObject( double num ) {
46 jsonObject* o = jsonNewObject(NULL);
47 o->type = JSON_NUMBER;
54 jsonObjectNode* jsonNewObjectNode( jsonObject* obj ) {
55 jsonObjectNode* node = (jsonObjectNode*) safe_malloc(sizeof(jsonObjectNode));
62 unsigned long jsonObjectPush( jsonObject* obj, jsonObject* new_obj) {
65 obj->type = JSON_ARRAY;
68 new_obj = jsonNewObject(NULL);
69 new_obj->type = JSON_NULL;
72 jsonObjectNode* node = jsonNewObjectNode(new_obj);
73 node->index = obj->size++;
75 if(obj->value.c == NULL) {
79 /* append the node onto the end */
80 jsonObjectNode* tmp = obj->value.c;
82 if(tmp->next == NULL) break;
90 unsigned long jsonObjectSetIndex( jsonObject* obj, unsigned long index, jsonObject* new_obj) {
91 if( obj == NULL ) return -1;
92 obj->type = JSON_ARRAY;
94 if(obj->size <= index)
95 obj->size = index + 1;
98 new_obj = jsonNewObject(NULL);
99 new_obj->type = JSON_NULL;
102 jsonObjectNode* node = jsonNewObjectNode(new_obj);
105 if( obj->value.c == NULL ) {
110 if(obj->value.c->index == index) {
111 jsonObjectNode* tmp = obj->value.c->next;
112 jsonObjectNodeFree(obj->value.c);
118 jsonObjectNode* prev = obj->value.c;
119 jsonObjectNode* cur = prev->next;
124 /* replace an existing node */
125 if( cur->index == index ) {
126 jsonObjectNode* tmp = cur->next;
127 jsonObjectNodeFree(cur);
133 /* instert between two nodes */
134 } else if( prev->index < index && cur->index > index ) {
144 /* shove on to the end */
154 void _jsonObjectShifIndex( jsonObject* obj, unsigned long index) {
155 if( obj == NULL || index < 0 ) return;
157 if(obj->value.c == NULL) {
162 jsonObjectNode* data = obj->value.c;
164 if(data->index >= index)
171 unsigned long jsonObjectRemoveIndex( jsonObject* obj, unsigned long index) {
172 if( obj == NULL || index < 0 ) return -1;
174 if(obj->value.c == NULL) return 0;
176 /* removing the first item in the list */
177 if(obj->value.c->index == index) {
178 jsonObjectNode* tmp = obj->value.c->next;
179 jsonObjectNodeFree(obj->value.c);
181 _jsonObjectShiftIndex(obj,index);
186 jsonObjectNode* prev = obj->value.c;
187 jsonObjectNode* cur = prev->next;
190 if(cur->index == index) {
191 jsonObjectNode* tmp = cur->next;
192 jsonObjectNodeFree(cur);
194 _jsonObjectShiftIndex(obj, index);
205 void _jsonObjectShiftIndex(jsonObject* obj, unsigned long index) {
209 if(obj->value.c == NULL) {
214 jsonObjectNode* data = obj->value.c;
216 if(data->index >= index)
224 unsigned long jsonObjectRemoveKey( jsonObject* obj, const char* key) {
225 if( obj == NULL || key == NULL ) return -1;
227 if(obj->value.c == NULL) return 0;
229 /* removing the first item in the list */
230 if(!strcmp(obj->value.c->key, key)) {
232 jsonObjectNode* tmp = obj->value.c->next;
233 jsonObjectNodeFree(obj->value.c);
236 if(!obj->value.c) obj->size = 0;
240 jsonObjectNode* prev = obj->value.c;
241 jsonObjectNode* cur = prev->next;
244 if(!strcmp(cur->key,key)) {
246 jsonObjectNode* tmp = cur->next;
247 jsonObjectNodeFree(cur);
260 unsigned long jsonObjectSetKey( jsonObject* obj, const char* key, jsonObject* new_obj ) {
261 if( obj == NULL || key == NULL ) return -1;
262 obj->type = JSON_HASH;
264 if(new_obj == NULL) {
265 new_obj = jsonNewObject(NULL);
266 new_obj->type = JSON_NULL;
269 jsonObjectNode* node = jsonNewObjectNode(new_obj);
270 node->key = strdup(key);
272 if( obj->value.c == NULL ) {
278 /* replace the first node */
279 if(!strcmp(obj->value.c->key, key)) {
280 jsonObjectNode* tmp = obj->value.c->next;
281 jsonObjectNodeFree(obj->value.c);
287 jsonObjectNode* prev = obj->value.c;
288 jsonObjectNode* cur = prev->next;
293 /* replace an existing node */
294 if( !strcmp(cur->key, key) ) {
295 jsonObjectNode* tmp = cur->next;
296 jsonObjectNodeFree(cur);
307 /* shove on to the end */
319 void jsonObjectFree( jsonObject* obj) {
320 if(obj == NULL) return;
322 free(obj->classname);
325 if( obj->type == JSON_ARRAY || obj->type == JSON_HASH ) {
326 while(obj->value.c) {
327 jsonObjectNode* tmp = obj->value.c->next;
328 jsonObjectNodeFree(obj->value.c);
333 if(obj->type == JSON_STRING)
339 void jsonObjectNodeFree( jsonObjectNode* node ) {
340 if(node == NULL) return;
342 jsonObjectFree(node->item);
346 jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
348 if( obj && index >= 0 &&
349 index < obj->size && obj->type == JSON_ARRAY ) {
351 jsonObjectNode* node = obj->value.c;
353 if(node->index == index)
362 jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key ) {
364 if( obj && key && obj->type == JSON_HASH ) {
366 jsonObjectNode* node = obj->value.c;
369 if(node->key && !strcmp(node->key, key))
378 char* jsonObjectGetString( const jsonObject* obj ) {
379 if( obj && obj->type == JSON_STRING ) return obj->value.s;
383 double jsonObjectGetNumber( const jsonObject* obj ) {
384 if( obj && obj->type == JSON_NUMBER ) return obj->value.n;
388 void jsonObjectSetString( jsonObject* obj, const char* string) {
390 obj->type = JSON_STRING;
391 if(string) obj->value.s = strdup(string);
392 else obj->value.s = NULL;
397 void jsonObjectSetNumber( jsonObject* obj, double num) {
399 obj->type = JSON_NUMBER;
405 void jsonObjectSetClass( jsonObject* obj, const char* classname) {
406 if( obj == NULL || classname == NULL ) return;
407 obj->classname = strdup(classname);
412 char* jsonObjectToJSON( const jsonObject* obj ) {
414 if(obj == NULL) return strdup("null");
416 growing_buffer* buf = buffer_init(64);
418 /* add class hints if we have a class name */
420 buffer_add(buf,"/*--S ");
421 buffer_add(buf,obj->classname);
422 buffer_add(buf, "--*/");
425 switch( obj->type ) {
428 if(obj->value.b) buffer_add(buf, "true");
429 else buffer_add(buf, "false");
433 double x = obj->value.n;
435 /* if the number does not need to be a double,
436 turn it into an int on the way out */
438 INT_TO_STRING((int)x);
439 buffer_add(buf, INTSTR);
443 buffer_add(buf, DOUBLESTR);
449 buffer_add(buf, "null");
453 buffer_add(buf, "\"");
454 char* data = obj->value.s;
455 int len = strlen(data);
457 char* output = uescape(data, len, 1);
458 buffer_add(buf, output);
460 buffer_add(buf, "\"");
464 buffer_add(buf, "[");
466 for( i = 0; i!= obj->size; i++ ) {
467 const jsonObject* x = jsonObjectGetIndex(obj,i);
468 char* data = jsonObjectToJSON(x);
470 #ifdef STRICT_JSON_WRITE
471 buffer_add(buf, data);
473 if(strcmp(data,"null")) /* only add the string if it isn't null */
474 buffer_add(buf, data);
478 if(i != obj->size - 1)
479 buffer_add(buf, ",");
481 buffer_add(buf, "]");
486 buffer_add(buf, "{");
487 jsonObjectIterator* itr = jsonNewObjectIterator(obj);
490 while( (tmp = jsonObjectIteratorNext(itr)) ) {
492 buffer_add(buf, "\"");
493 buffer_add(buf, tmp->key);
494 buffer_add(buf, "\":");
495 char* data = jsonObjectToJSON(tmp->item);
497 #ifdef STRICT_JSON_WRITE
498 buffer_add(buf, data);
500 if(strcmp(data,"null")) /* only add the string if it isn't null */
501 buffer_add(buf, data);
504 if(jsonObjectIteratorHasNext(itr))
505 buffer_add(buf, ",");
509 jsonObjectIteratorFree(itr);
510 buffer_add(buf, "}");
514 fprintf(stderr, "Unknown object type %d\n", obj->type);
519 /* close out the object hint */
521 buffer_add(buf, "/*--E ");
522 buffer_add(buf, obj->classname);
523 buffer_add(buf, "--*/");
527 buffer_add(buf, " /*");
528 buffer_add(buf, obj->comment);
529 buffer_add(buf, "*/");
532 char* data = buffer_data(buf);
539 void jsonObjectSetComment( jsonObject* obj, const char* com) {
540 if( obj == NULL || com == NULL ) return;
541 obj->comment = strdup(com);
545 char* __tabs(int count) {
546 growing_buffer* buf = buffer_init(24);
548 for(i=0;i!=count;i++) buffer_add(buf, " ");
549 char* final = buffer_data( buf );
554 char* jsonFormatString( const char* string ) {
556 if(!string) return strdup("");
558 growing_buffer* buf = buffer_init(64);
563 for(i=0; i!= strlen(string); i++) {
565 if( string[i] == '{' || string[i] == '[' ) {
567 tab = __tabs(++depth);
568 buffer_fadd( buf, "%c\n%s", string[i], tab);
571 } else if( string[i] == '}' || string[i] == ']' ) {
573 tab = __tabs(--depth);
574 buffer_fadd( buf, "\n%s%c", tab, string[i]);
577 if(string[i+1] != ',') {
579 buffer_fadd( buf, "\n%s", tab );
583 } else if( string[i] == ',' ) {
586 buffer_fadd(buf, ",\n%s", tab);
589 } else { buffer_add_char(buf, string[i]); }
593 char* result = buffer_data(buf);
600 jsonObject* jsonObjectClone(const jsonObject* o) {
602 char* json = jsonObjectToJSON(o);
603 jsonObject* newo = jsonParseString(json);
610 /* ---------------------------------------------------------------------- */
613 jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
615 if(!obj) return NULL;
616 jsonObjectIterator* iter = safe_malloc(sizeof(jsonObjectIterator));
619 if( obj->type == JSON_HASH || obj->type == JSON_ARRAY )
620 iter->current = obj->value.c;
621 else iter->current = NULL;
625 jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
626 if( itr == NULL ) return NULL;
628 jsonObjectNode* tmp = itr->current;
629 if(tmp == NULL) return NULL;
630 itr->current = itr->current->next;
635 void jsonObjectIteratorFree(jsonObjectIterator* iter) {
639 int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
640 return (itr && itr->current);
644 jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
645 if(!obj || !format || strlen(format) < 1) return NULL;
647 VA_LIST_TO_STRING(format);
650 /* tmp storage for strtok_r */
652 //bzero(tokbuf, len);
657 char* tt; /* strtok storage */
659 /* copy the path before strtok_r destroys it */
660 char* pathcopy = strdup(buf);
662 /* grab the root of the path */
663 token = strtok_r(t, "/", &tt);
664 if(!token) return NULL;
666 /* special case where path starts with // (start anywhere) */
667 if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
668 jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
677 obj = jsonObjectGetKey(obj, token);
678 } while( (token = strtok_r(NULL, "/", &tt)) && obj);
680 return jsonObjectClone(obj);
683 /* --------------------------------------------------------------- */
687 jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
689 if(!obj || ! root || !path) return NULL;
691 /* collect all of the potential objects */
692 jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
694 /* container for fully matching objects */
695 jsonObject* newarr = jsonParseString("[]");
698 /* path is just /root or /root/ */
699 if( strlen(root) + 2 >= strlen(path) ) {
704 /* gather all of the sub-objects that match the full path */
705 for( i = 0; i < arr->size; i++ ) {
706 jsonObject* a = jsonObjectGetIndex(arr, i);
707 jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1);
709 if(thing) { //jsonObjectPush(newarr, thing);
710 if(thing->type == JSON_ARRAY) {
712 for( i = 0; i != thing->size; i++ )
713 jsonObjectPush(newarr, jsonObjectClone(jsonObjectGetIndex(thing,i)));
714 jsonObjectFree(thing);
717 jsonObjectPush(newarr, thing);
727 jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
729 jsonObject* arr = jsonParseString("[]");
734 /* if the current object has a node that matches, add it */
736 jsonObject* o = jsonObjectGetKey(obj, root);
737 if(o) jsonObjectPush( arr, jsonObjectClone(o) );
739 jsonObjectNode* tmp = NULL;
740 jsonObject* childarr;
741 jsonObjectIterator* itr = jsonNewObjectIterator(obj);
743 /* recurse through the children and find all potential nodes */
744 while( (tmp = jsonObjectIteratorNext(itr)) ) {
745 childarr = __jsonObjectFindPathRecurse(tmp->item, root);
746 if(childarr && childarr->size > 0) {
747 for( i = 0; i!= childarr->size; i++ ) {
748 jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
751 jsonObjectFree(childarr);
754 jsonObjectIteratorFree(itr);
760 char* jsonObjectToSimpleString( const jsonObject* o ) {
768 if( o->value.n == (int) o->value.n ) {
769 INT_TO_STRING((int) o->value.n);
770 value = strdup(INTSTR);
773 DOUBLE_TO_STRING(o->value.n);
774 value = strdup(DOUBLESTR);
781 value = strdup(o->value.s);