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 obj->type = JSON_STRING;
35 obj->value.s = strdup(stringValue);
41 jsonObject* jsonNewObjectFmt( const char* stringValue, ... ) {
43 jsonObject* obj = (jsonObject*) safe_malloc(sizeof(jsonObject));
45 obj->type = JSON_NULL;
48 VA_LIST_TO_STRING(stringValue);
49 obj->type = JSON_STRING;
50 obj->value.s = strdup(VA_BUF);
59 jsonObject* jsonNewNumberObject( double num ) {
60 jsonObject* o = jsonNewObject(NULL);
61 o->type = JSON_NUMBER;
68 jsonObjectNode* jsonNewObjectNode( jsonObject* obj ) {
69 jsonObjectNode* node = (jsonObjectNode*) safe_malloc(sizeof(jsonObjectNode));
76 unsigned long jsonObjectPush( jsonObject* obj, jsonObject* new_obj) {
79 obj->type = JSON_ARRAY;
82 new_obj = jsonNewObject(NULL);
83 new_obj->type = JSON_NULL;
86 jsonObjectNode* node = jsonNewObjectNode(new_obj);
87 node->index = obj->size++;
89 if(obj->value.c == NULL) {
93 /* append the node onto the end */
94 jsonObjectNode* tmp = obj->value.c;
96 if(tmp->next == NULL) break;
104 unsigned long jsonObjectSetIndex( jsonObject* obj, unsigned long index, jsonObject* new_obj) {
105 if( obj == NULL ) return -1;
106 obj->type = JSON_ARRAY;
108 if(obj->size <= index)
109 obj->size = index + 1;
111 if(new_obj == NULL) {
112 new_obj = jsonNewObject(NULL);
113 new_obj->type = JSON_NULL;
116 jsonObjectNode* node = jsonNewObjectNode(new_obj);
119 if( obj->value.c == NULL ) {
124 if(obj->value.c->index == index) {
125 jsonObjectNode* tmp = obj->value.c->next;
126 jsonObjectNodeFree(obj->value.c);
132 jsonObjectNode* prev = obj->value.c;
133 jsonObjectNode* cur = prev->next;
138 /* replace an existing node */
139 if( cur->index == index ) {
140 jsonObjectNode* tmp = cur->next;
141 jsonObjectNodeFree(cur);
147 /* instert between two nodes */
148 } else if( prev->index < index && cur->index > index ) {
158 /* shove on to the end */
168 void _jsonObjectShifIndex( jsonObject* obj, unsigned long index) {
169 if( obj == NULL || index < 0 ) return;
171 if(obj->value.c == NULL) {
176 jsonObjectNode* data = obj->value.c;
178 if(data->index >= index)
185 unsigned long jsonObjectRemoveIndex( jsonObject* obj, unsigned long index) {
186 if( obj == NULL || index < 0 ) return -1;
188 if(obj->value.c == NULL) return 0;
190 /* removing the first item in the list */
191 if(obj->value.c->index == index) {
192 jsonObjectNode* tmp = obj->value.c->next;
193 jsonObjectNodeFree(obj->value.c);
195 _jsonObjectShiftIndex(obj,index);
200 jsonObjectNode* prev = obj->value.c;
201 jsonObjectNode* cur = prev->next;
204 if(cur->index == index) {
205 jsonObjectNode* tmp = cur->next;
206 jsonObjectNodeFree(cur);
208 _jsonObjectShiftIndex(obj, index);
219 void _jsonObjectShiftIndex(jsonObject* obj, unsigned long index) {
223 if(obj->value.c == NULL) {
228 jsonObjectNode* data = obj->value.c;
230 if(data->index >= index)
238 unsigned long jsonObjectRemoveKey( jsonObject* obj, const char* key) {
239 if( obj == NULL || key == NULL ) return -1;
241 if(obj->value.c == NULL) return 0;
243 /* removing the first item in the list */
244 if(!strcmp(obj->value.c->key, key)) {
246 jsonObjectNode* tmp = obj->value.c->next;
247 jsonObjectNodeFree(obj->value.c);
250 if(!obj->value.c) obj->size = 0;
254 jsonObjectNode* prev = obj->value.c;
255 jsonObjectNode* cur = prev->next;
258 if(!strcmp(cur->key,key)) {
260 jsonObjectNode* tmp = cur->next;
261 jsonObjectNodeFree(cur);
274 unsigned long jsonObjectSetKey( jsonObject* obj, const char* key, jsonObject* new_obj ) {
275 if( obj == NULL || key == NULL ) return -1;
276 obj->type = JSON_HASH;
278 if(new_obj == NULL) {
279 new_obj = jsonNewObject(NULL);
280 new_obj->type = JSON_NULL;
283 jsonObjectNode* node = jsonNewObjectNode(new_obj);
284 node->key = strdup(key);
286 if( obj->value.c == NULL ) {
292 /* replace the first node */
293 if(!strcmp(obj->value.c->key, key)) {
294 jsonObjectNode* tmp = obj->value.c->next;
295 jsonObjectNodeFree(obj->value.c);
301 jsonObjectNode* prev = obj->value.c;
302 jsonObjectNode* cur = prev->next;
307 /* replace an existing node */
308 if( !strcmp(cur->key, key) ) {
309 jsonObjectNode* tmp = cur->next;
310 jsonObjectNodeFree(cur);
321 /* shove on to the end */
333 void jsonObjectFree( jsonObject* obj) {
334 if(obj == NULL) return;
336 free(obj->classname);
339 if( obj->type == JSON_ARRAY || obj->type == JSON_HASH ) {
340 while(obj->value.c) {
341 jsonObjectNode* tmp = obj->value.c->next;
342 jsonObjectNodeFree(obj->value.c);
347 if(obj->type == JSON_STRING)
353 void jsonObjectNodeFree( jsonObjectNode* node ) {
354 if(node == NULL) return;
356 jsonObjectFree(node->item);
360 jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
362 if( obj && index >= 0 &&
363 index < obj->size && obj->type == JSON_ARRAY ) {
365 jsonObjectNode* node = obj->value.c;
367 if(node->index == index)
376 jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key ) {
378 if( obj && key && obj->type == JSON_HASH ) {
380 jsonObjectNode* node = obj->value.c;
383 if(node->key && !strcmp(node->key, key))
392 char* jsonObjectGetString( const jsonObject* obj ) {
393 if( obj && obj->type == JSON_STRING ) return obj->value.s;
397 double jsonObjectGetNumber( const jsonObject* obj ) {
398 if( obj && obj->type == JSON_NUMBER ) return obj->value.n;
402 void jsonObjectSetString( jsonObject* obj, const char* string) {
404 obj->type = JSON_STRING;
405 if(string) obj->value.s = strdup(string);
406 else obj->value.s = NULL;
411 void jsonObjectSetNumber( jsonObject* obj, double num) {
413 obj->type = JSON_NUMBER;
419 void jsonObjectSetClass( jsonObject* obj, const char* classname) {
420 if( obj == NULL || classname == NULL ) return;
421 obj->classname = strdup(classname);
426 char* jsonObjectToJSON( const jsonObject* obj ) {
428 if(obj == NULL) return strdup("null");
430 growing_buffer* buf = buffer_init(64);
432 /* add class hints if we have a class name */
434 buffer_add(buf,"/*--S ");
435 buffer_add(buf,obj->classname);
436 buffer_add(buf, "--*/");
439 switch( obj->type ) {
442 if(obj->value.b) buffer_add(buf, "true");
443 else buffer_add(buf, "false");
447 double x = obj->value.n;
449 /* if the number does not need to be a double,
450 turn it into an int on the way out */
452 INT_TO_STRING((int)x);
453 buffer_add(buf, INTSTR);
457 buffer_add(buf, DOUBLESTR);
463 buffer_add(buf, "null");
467 buffer_add(buf, "\"");
468 char* data = obj->value.s;
469 int len = strlen(data);
471 char* output = uescape(data, len, 1);
472 buffer_add(buf, output);
474 buffer_add(buf, "\"");
478 buffer_add(buf, "[");
480 for( i = 0; i!= obj->size; i++ ) {
481 const jsonObject* x = jsonObjectGetIndex(obj,i);
482 char* data = jsonObjectToJSON(x);
484 #ifdef STRICT_JSON_WRITE
485 buffer_add(buf, data);
487 if(strcmp(data,"null")) /* only add the string if it isn't null */
488 buffer_add(buf, data);
492 if(i != obj->size - 1)
493 buffer_add(buf, ",");
495 buffer_add(buf, "]");
500 buffer_add(buf, "{");
501 jsonObjectIterator* itr = jsonNewObjectIterator(obj);
504 while( (tmp = jsonObjectIteratorNext(itr)) ) {
506 buffer_add(buf, "\"");
507 buffer_add(buf, tmp->key);
508 buffer_add(buf, "\":");
509 char* data = jsonObjectToJSON(tmp->item);
511 #ifdef STRICT_JSON_WRITE
512 buffer_add(buf, data);
514 if(strcmp(data,"null")) /* only add the string if it isn't null */
515 buffer_add(buf, data);
518 if(jsonObjectIteratorHasNext(itr))
519 buffer_add(buf, ",");
523 jsonObjectIteratorFree(itr);
524 buffer_add(buf, "}");
528 fprintf(stderr, "Unknown object type %d\n", obj->type);
533 /* close out the object hint */
535 buffer_add(buf, "/*--E ");
536 buffer_add(buf, obj->classname);
537 buffer_add(buf, "--*/");
541 buffer_add(buf, " /*");
542 buffer_add(buf, obj->comment);
543 buffer_add(buf, "*/");
546 char* data = buffer_data(buf);
553 void jsonObjectSetComment( jsonObject* obj, const char* com) {
554 if( obj == NULL || com == NULL ) return;
555 obj->comment = strdup(com);
559 char* __tabs(int count) {
560 growing_buffer* buf = buffer_init(24);
562 for(i=0;i!=count;i++) buffer_add(buf, " ");
563 char* final = buffer_data( buf );
568 char* jsonFormatString( const char* string ) {
570 if(!string) return strdup("");
572 growing_buffer* buf = buffer_init(64);
577 for(i=0; i!= strlen(string); i++) {
579 if( string[i] == '{' || string[i] == '[' ) {
581 tab = __tabs(++depth);
582 buffer_fadd( buf, "%c\n%s", string[i], tab);
585 } else if( string[i] == '}' || string[i] == ']' ) {
587 tab = __tabs(--depth);
588 buffer_fadd( buf, "\n%s%c", tab, string[i]);
591 if(string[i+1] != ',') {
593 buffer_fadd( buf, "\n%s", tab );
597 } else if( string[i] == ',' ) {
600 buffer_fadd(buf, ",\n%s", tab);
603 } else { buffer_add_char(buf, string[i]); }
607 char* result = buffer_data(buf);
614 jsonObject* jsonObjectClone(const jsonObject* o) {
616 char* json = jsonObjectToJSON(o);
617 jsonObject* newo = jsonParseString(json);
624 /* ---------------------------------------------------------------------- */
627 jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
629 if(!obj) return NULL;
630 jsonObjectIterator* iter = safe_malloc(sizeof(jsonObjectIterator));
633 if( obj->type == JSON_HASH || obj->type == JSON_ARRAY )
634 iter->current = obj->value.c;
635 else iter->current = NULL;
639 jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
640 if( itr == NULL ) return NULL;
642 jsonObjectNode* tmp = itr->current;
643 if(tmp == NULL) return NULL;
644 itr->current = itr->current->next;
649 void jsonObjectIteratorFree(jsonObjectIterator* iter) {
653 int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
654 return (itr && itr->current);
658 jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
659 if(!obj || !format || strlen(format) < 1) return NULL;
661 VA_LIST_TO_STRING(format);
664 /* tmp storage for strtok_r */
666 //bzero(tokbuf, len);
671 char* tt; /* strtok storage */
673 /* copy the path before strtok_r destroys it */
674 char* pathcopy = strdup(buf);
676 /* grab the root of the path */
677 token = strtok_r(t, "/", &tt);
678 if(!token) return NULL;
680 /* special case where path starts with // (start anywhere) */
681 if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
682 jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
691 obj = jsonObjectGetKey(obj, token);
692 } while( (token = strtok_r(NULL, "/", &tt)) && obj);
694 return jsonObjectClone(obj);
697 /* --------------------------------------------------------------- */
701 jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
703 if(!obj || ! root || !path) return NULL;
705 /* collect all of the potential objects */
706 jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
708 /* container for fully matching objects */
709 jsonObject* newarr = jsonParseString("[]");
712 /* path is just /root or /root/ */
713 if( strlen(root) + 2 >= strlen(path) ) {
718 /* gather all of the sub-objects that match the full path */
719 for( i = 0; i < arr->size; i++ ) {
720 jsonObject* a = jsonObjectGetIndex(arr, i);
721 jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1);
723 if(thing) { //jsonObjectPush(newarr, thing);
724 if(thing->type == JSON_ARRAY) {
726 for( i = 0; i != thing->size; i++ )
727 jsonObjectPush(newarr, jsonObjectClone(jsonObjectGetIndex(thing,i)));
728 jsonObjectFree(thing);
731 jsonObjectPush(newarr, thing);
741 jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
743 jsonObject* arr = jsonParseString("[]");
748 /* if the current object has a node that matches, add it */
750 jsonObject* o = jsonObjectGetKey(obj, root);
751 if(o) jsonObjectPush( arr, jsonObjectClone(o) );
753 jsonObjectNode* tmp = NULL;
754 jsonObject* childarr;
755 jsonObjectIterator* itr = jsonNewObjectIterator(obj);
757 /* recurse through the children and find all potential nodes */
758 while( (tmp = jsonObjectIteratorNext(itr)) ) {
759 childarr = __jsonObjectFindPathRecurse(tmp->item, root);
760 if(childarr && childarr->size > 0) {
761 for( i = 0; i!= childarr->size; i++ ) {
762 jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
765 jsonObjectFree(childarr);
768 jsonObjectIteratorFree(itr);
774 char* jsonObjectToSimpleString( const jsonObject* o ) {
782 if( o->value.n == (int) o->value.n ) {
783 INT_TO_STRING((int) o->value.n);
784 value = strdup(INTSTR);
787 DOUBLE_TO_STRING(o->value.n);
788 value = strdup(DOUBLESTR);
795 value = strdup(o->value.s);