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 && obj->type == JSON_ARRAY ) {
350 jsonObjectNode* node = obj->value.c;
352 if(node->index == index)
361 jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key ) {
363 if( obj && key && obj->type == JSON_HASH ) {
365 jsonObjectNode* node = obj->value.c;
368 if(node->key && !strcmp(node->key, key))
377 char* jsonObjectGetString( const jsonObject* obj ) {
378 if( obj && obj->type == JSON_STRING ) return obj->value.s;
382 double jsonObjectGetNumber( const jsonObject* obj ) {
383 if( obj && obj->type == JSON_NUMBER ) return obj->value.n;
387 void jsonObjectSetString( jsonObject* obj, const char* string) {
389 obj->type = JSON_STRING;
390 if(string) obj->value.s = strdup(string);
391 else obj->value.s = NULL;
396 void jsonObjectSetNumber( jsonObject* obj, double num) {
398 obj->type = JSON_NUMBER;
404 void jsonObjectSetClass( jsonObject* obj, const char* classname) {
405 if( obj == NULL || classname == NULL ) return;
406 obj->classname = strdup(classname);
411 char* jsonObjectToJSON( const jsonObject* obj ) {
413 if(obj == NULL) return strdup("null");
415 growing_buffer* buf = buffer_init(64);
417 /* add class hints if we have a class name */
419 buffer_add(buf,"/*--S ");
420 buffer_add(buf,obj->classname);
421 buffer_add(buf, "--*/");
424 switch( obj->type ) {
427 if(obj->value.b) buffer_add(buf, "true");
428 else buffer_add(buf, "false");
432 double x = obj->value.n;
434 /* if the number does not need to be a double,
435 turn it into an int on the way out */
437 INT_TO_STRING((int)x);
438 buffer_add(buf, INTSTR);
442 buffer_add(buf, DOUBLESTR);
448 buffer_add(buf, "null");
452 buffer_add(buf, "\"");
453 char* data = obj->value.s;
454 int len = strlen(data);
456 char* output = uescape(data, len, 1);
457 buffer_add(buf, output);
459 buffer_add(buf, "\"");
463 buffer_add(buf, "[");
465 for( i = 0; i!= obj->size; i++ ) {
466 const jsonObject* x = jsonObjectGetIndex(obj,i);
467 char* data = jsonObjectToJSON(x);
469 #ifdef STRICT_JSON_WRITE
470 buffer_add(buf, data);
472 if(strcmp(data,"null")) /* only add the string if it isn't null */
473 buffer_add(buf, data);
477 if(i != obj->size - 1)
478 buffer_add(buf, ",");
480 buffer_add(buf, "]");
485 buffer_add(buf, "{");
486 jsonObjectIterator* itr = jsonNewObjectIterator(obj);
489 while( (tmp = jsonObjectIteratorNext(itr)) ) {
491 buffer_add(buf, "\"");
492 buffer_add(buf, tmp->key);
493 buffer_add(buf, "\":");
494 char* data = jsonObjectToJSON(tmp->item);
496 #ifdef STRICT_JSON_WRITE
497 buffer_add(buf, data);
499 if(strcmp(data,"null")) /* only add the string if it isn't null */
500 buffer_add(buf, data);
503 if(jsonObjectIteratorHasNext(itr))
504 buffer_add(buf, ",");
508 jsonObjectIteratorFree(itr);
509 buffer_add(buf, "}");
513 fprintf(stderr, "Unknown object type %d\n", obj->type);
518 /* close out the object hint */
520 buffer_add(buf, "/*--E ");
521 buffer_add(buf, obj->classname);
522 buffer_add(buf, "--*/");
526 buffer_add(buf, " /*");
527 buffer_add(buf, obj->comment);
528 buffer_add(buf, "*/");
531 char* data = buffer_data(buf);
538 void jsonObjectSetComment( jsonObject* obj, const char* com) {
539 if( obj == NULL || com == NULL ) return;
540 obj->comment = strdup(com);
544 char* __tabs(int count) {
545 growing_buffer* buf = buffer_init(24);
547 for(i=0;i!=count;i++) buffer_add(buf, " ");
548 char* final = buffer_data( buf );
553 char* jsonFormatString( const char* string ) {
555 if(!string) return strdup("");
557 growing_buffer* buf = buffer_init(64);
562 for(i=0; i!= strlen(string); i++) {
564 if( string[i] == '{' || string[i] == '[' ) {
566 tab = __tabs(++depth);
567 buffer_fadd( buf, "%c\n%s", string[i], tab);
570 } else if( string[i] == '}' || string[i] == ']' ) {
572 tab = __tabs(--depth);
573 buffer_fadd( buf, "\n%s%c", tab, string[i]);
576 if(string[i+1] != ',') {
578 buffer_fadd( buf, "\n%s", tab );
582 } else if( string[i] == ',' ) {
585 buffer_fadd(buf, ",\n%s", tab);
588 } else { buffer_add_char(buf, string[i]); }
592 char* result = buffer_data(buf);
599 jsonObject* jsonObjectClone(const jsonObject* o) {
601 char* json = jsonObjectToJSON(o);
602 jsonObject* newo = jsonParseString(json);
609 /* ---------------------------------------------------------------------- */
612 jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
614 if(!obj) return NULL;
615 jsonObjectIterator* iter = safe_malloc(sizeof(jsonObjectIterator));
618 if( obj->type == JSON_HASH || obj->type == JSON_ARRAY )
619 iter->current = obj->value.c;
620 else iter->current = NULL;
624 jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
625 if( itr == NULL ) return NULL;
627 jsonObjectNode* tmp = itr->current;
628 if(tmp == NULL) return NULL;
629 itr->current = itr->current->next;
634 void jsonObjectIteratorFree(jsonObjectIterator* iter) {
638 int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
639 return (itr && itr->current);
643 jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
644 if(!obj || !format || strlen(format) < 1) return NULL;
646 VA_LIST_TO_STRING(format);
649 /* tmp storage for strtok_r */
657 /* copy the path before strtok_r destroys it */
658 char* pathcopy = strdup(buf);
660 /* grab the root of the path */
661 token = strtok_r(t, "/", &tt);
662 if(!token) return NULL;
664 /* special case where path starts with // (start anywhere) */
665 if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
666 jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
675 obj = jsonObjectGetKey(obj, token);
676 } while( (token = strtok_r(NULL, "/", &tt)) && obj);
678 return jsonObjectClone(obj);
681 /* --------------------------------------------------------------- */
685 jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
687 if(!obj || ! root || !path) return NULL;
689 /* collect all of the potential objects */
690 jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
692 /* container for fully matching objects */
693 jsonObject* newarr = jsonParseString("[]");
696 /* path is just /root or /root/ */
697 if( strlen(root) + 2 >= strlen(path) ) {
702 /* gather all of the sub-objects that match the full path */
703 for( i = 0; i < arr->size; i++ ) {
704 jsonObject* a = jsonObjectGetIndex(arr, i);
705 jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1);
707 if(thing) { //jsonObjectPush(newarr, thing);
708 if(thing->type == JSON_ARRAY) {
710 for( i = 0; i != thing->size; i++ )
711 jsonObjectPush(newarr, jsonObjectGetIndex(thing,i));
714 jsonObjectPush(newarr, thing);
724 jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
726 jsonObject* arr = jsonParseString("[]");
731 /* if the current object has a node that matches, add it */
733 jsonObject* o = jsonObjectGetKey(obj, root);
734 if(o) jsonObjectPush( arr, jsonObjectClone(o) );
736 jsonObjectNode* tmp = NULL;
737 jsonObject* childarr;
738 jsonObjectIterator* itr = jsonNewObjectIterator(obj);
740 /* recurse through the children and find all potential nodes */
741 while( (tmp = jsonObjectIteratorNext(itr)) ) {
742 childarr = __jsonObjectFindPathRecurse(tmp->item, root);
743 if(childarr && childarr->size > 0) {
744 for( i = 0; i!= childarr->size; i++ ) {
745 jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
748 jsonObjectFree(childarr);
751 jsonObjectIteratorFree(itr);
757 char* jsonObjectToSimpleString( const jsonObject* o ) {
765 if( o->value.n == (int) o->value.n ) {
766 INT_TO_STRING((int) o->value.n);
767 value = strdup(INTSTR);
770 DOUBLE_TO_STRING(o->value.n);
771 value = strdup(DOUBLESTR);
778 value = strdup(o->value.s);