]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/objson/object.c
objson now accepts empty array and object values if STRICT_JSON_READ is not defined
[Evergreen.git] / OpenSRF / src / objson / object.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service 
3 Bill Erickson <highfalutin@gmail.com>
4
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.
9
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.
14 */
15
16 #include "object.h"
17 #include "json_parser.h"
18 #include <fcntl.h>
19
20
21
22 /* ---------------------------------------------------------------------- */
23 /* See object.h for function info */
24 /* ---------------------------------------------------------------------- */
25
26 object* new_object(char* string_value) {
27         return _init_object(string_value);
28 }
29
30
31 object* new_int_object(long num) {
32         object* o = new_object(NULL);
33         o->is_null = 0;
34         o->is_number = 1;
35         o->num_value = num;
36         return o;
37 }
38
39 object* new_double_object(double num) {
40         object* o = new_object(NULL);
41         o->is_null = 0;
42         o->is_double = 1;
43         o->double_value = num;
44         return o;
45 }
46
47 object* _init_object(char* string_value) {
48
49         object* obj                     = (object*) safe_malloc(sizeof(object));
50         obj->size                       = 0;
51         obj->data                       = NULL;
52
53         obj->push                       = &object_push;
54         obj->set_index          = &object_set_index;
55         obj->add_key            = &object_add_key;
56         obj->get_index          = &object_get_index;
57         obj->get_key            = &object_get_key;
58         obj->get_string = &object_get_string;
59         obj->set_string = &object_set_string;
60         obj->set_number = &object_set_number;
61         obj->set_class          = &object_set_class;
62         obj->set_double = &object_set_double;
63         obj->remove_index = &object_remove_index;
64         obj->remove_key = &object_remove_key;
65         obj->to_json            = &object_to_json;
66         obj->set_comment        = &object_set_comment;
67
68         if(string_value) {
69                 obj->is_string = 1;
70                 obj->string_data = strdup(string_value);
71         } else
72                 obj->is_null = 1;
73
74         return obj;
75 }
76
77 object_node* new_object_node(object* obj) {
78         object_node* node = (object_node*) safe_malloc(sizeof(object_node));
79         node->item = obj;
80         node->next = NULL;
81         node->index = -1;
82         return node;
83 }
84
85 unsigned long object_push(object* obj, object* new_obj) {
86         assert(obj != NULL);
87         object_clear_type(obj);
88         obj->is_array = 1;
89
90         if(new_obj == NULL) {
91                 new_obj = new_object(NULL);
92                 new_obj->is_null = 1;
93         }
94
95         object_node* node = new_object_node(new_obj);
96         node->index = obj->size++;
97
98         if( obj->size > MAX_OBJECT_NODES )
99                 return -1;
100
101         if(obj->data == NULL) {
102                 obj->data = node;
103
104         } else {
105                 /* append the node onto the end */
106                 object_node* tmp = obj->data;
107                 while(tmp) {
108                         if(tmp->next == NULL) break;
109                         tmp = tmp->next;
110                 }
111                 tmp->next = node;
112         }
113         return obj->size;
114 }
115
116 unsigned long  object_set_index(object* obj, unsigned long index, object* new_obj) {
117         assert(obj != NULL && index <= MAX_OBJECT_NODES);
118         object_clear_type(obj);
119         obj->is_array = 1;
120
121         if(obj->size <= index)
122                 obj->size = index + 1;
123
124         if(new_obj == NULL) {
125                 new_obj = new_object(NULL);
126                 new_obj->is_null = 1;
127         }
128
129         object_node* node = new_object_node(new_obj);
130         node->index = index;
131         
132         if( obj->data == NULL ) {
133                 obj->data = node;
134
135         } else {
136
137                 if(obj->data->index == index) {
138                         object_node* tmp = obj->data->next;
139                         free_object_node(obj->data);
140                         obj->data = node;
141                         node->next = tmp;
142
143                 } else {
144                 
145                         object_node* prev = obj->data;
146                         object_node* cur = prev->next;
147                         int inserted = 0;
148
149                         while(cur != NULL) {
150
151                                 /* replace an existing node */
152                                 if( cur->index == index ) {
153                                         object_node* tmp = cur->next;
154                                         free_object_node(cur);
155                                         node->next = tmp;
156                                         prev->next = node;
157                                         inserted = 1;
158                                         break;
159                                         
160                                         /* instert between two nodes */
161                                 } else if( prev->index < index && cur->index > index ) {
162                                         prev->next = node;
163                                         node->next = cur;
164                                         inserted = 1;
165                                         break;
166                                 }
167                                 prev = cur;
168                                 cur = cur->next;
169                         }
170
171                         /* shove on to the end */
172                         if(!inserted) 
173                                 prev->next = node;
174                 }
175         }
176
177         return obj->size;
178 }
179
180
181 void object_shift_index(object* obj, unsigned long index) {
182         assert(obj && index <= MAX_OBJECT_NODES);
183         if(obj->data == NULL) {
184                 obj->size = 0;
185                 return;
186         }
187
188         object_node* data = obj->data;
189         while(data) {
190                 if(data->index >= index)
191                         data->index--;
192                 data = data->next;
193         }
194         obj->size--;
195 }
196
197 unsigned long object_remove_index(object* obj, unsigned long index) {
198         assert(obj != NULL && index <= MAX_OBJECT_NODES);
199         if(obj->data == NULL) return 0;
200
201         /* removing the first item in the list */
202         if(obj->data->index == index) {
203                 object_node* tmp = obj->data->next;
204                 free_object_node(obj->data);
205                 obj->data = tmp;
206                 object_shift_index(obj,index);
207                 return obj->size;
208         }
209
210
211         object_node* prev = obj->data;
212         object_node* cur = prev->next;
213
214         while(cur) {
215                 if(cur->index == index) {
216                         object_node* tmp = cur->next;
217                         free_object_node(cur);
218                         prev->next = tmp;
219                         object_shift_index(obj,index);
220                         break;
221                 }
222                 prev = cur;
223                 cur = cur->next;
224         }
225
226         return obj->size;       
227 }
228
229
230 unsigned long object_remove_key(object* obj, char* key) {
231         assert(obj && key);
232         if(obj->data == NULL) return 0;
233
234         /* removing the first item in the list */
235         if(!strcmp(obj->data->key, key)) {
236                 object_node* tmp = obj->data->next;
237                 free_object_node(obj->data);
238                 obj->data = tmp;
239                 if(!obj->data) 
240                         obj->size = 0;
241
242                 return obj->size;
243         }
244
245         object_node* prev = obj->data;
246         object_node* cur = prev->next;
247
248         while(cur) {
249                 if(!strcmp(cur->key,key)) {
250                         object_node* tmp = cur->next;
251                         free_object_node(cur);
252                         prev->next = tmp;
253                         obj->size--;
254                         break;
255                 }
256                 prev = cur;
257                 cur = cur->next;
258         }
259
260         return obj->size;
261 }
262
263
264 unsigned long object_add_key(object* obj, char* key, object* new_obj) {
265
266         assert(obj != NULL && key != NULL);
267         object_clear_type(obj);
268         obj->is_hash = 1;
269
270
271         if(new_obj == NULL) {
272                 new_obj = new_object(NULL);
273                 new_obj->is_null = 1;
274         }
275
276         object_node* node = new_object_node(new_obj);
277         node->key = strdup(key);
278         
279         if( obj->data == NULL ) {
280                 obj->data = node;
281                 obj->size++;
282
283         } else {
284
285                 /* replace the first node */
286                 if(!strcmp(obj->data->key, key)) {
287                         object_node* tmp = obj->data->next;
288                         free_object_node(obj->data);
289                         obj->data = node;
290                         node->next = tmp;
291
292                 } else {
293                 
294                         object_node* prev = obj->data;
295                         object_node* cur = prev->next;
296                         int inserted = 0;
297
298                         while(cur != NULL) {
299
300                                 /* replace an existing node */
301                                 if( !strcmp(cur->key, key) ) {
302                                         object_node* tmp = cur->next;
303                                         free_object_node(cur);
304                                         node->next = tmp;
305                                         prev->next = node;
306                                         inserted = 1;
307                                         break;
308                                 }
309                                         
310                                 prev = cur;
311                                 cur = cur->next;
312                         }
313
314                         /* shove on to the end */
315                         if(!inserted) {
316                                 prev->next = node;
317                                 obj->size++;
318                         }
319                 }
320         }
321
322         return obj->size;
323 }
324
325
326 void free_object(object* obj) {
327
328         if(obj == NULL) return;
329         if(obj->classname) free(obj->classname);
330         if(obj->comment) free(obj->comment);
331
332         while(obj->data) {
333                 object_node* tmp = obj->data->next;
334                 free_object_node(obj->data);
335                 obj->data = tmp;
336         }
337
338         if(obj->string_data) 
339                 free(obj->string_data);
340         free(obj);
341 }
342
343 void free_object_node(object_node* node) {
344         if(node == NULL) return;
345         if(node->key) free(node->key);
346         free_object(node->item);
347         free(node);
348 }
349
350 object* object_get_index( object* obj, unsigned long index ) {
351         assert(obj != NULL && index <= MAX_OBJECT_NODES);
352         object_node* node = obj->data;
353         while(node) {
354                 if(node->index == index)
355                         return node->item;
356                 node = node->next;
357         }
358         return NULL;
359 }
360
361 object* object_get_key( object* obj, char* key ) {
362         assert(obj && key);
363         object_node* node = obj->data;
364
365         while(node) {
366                 if(node->key && !strcmp(node->key, key))
367                         return node->item;
368                 node = node->next;
369         }       
370
371         return NULL;
372 }
373
374 char* object_get_string(object* obj) {
375         assert(obj != NULL);
376         return obj->string_data;
377 }
378
379 void object_set_string(object* obj, char* string) {
380         assert(obj);
381         object_clear_type(obj);
382         obj->is_string = 1;
383         if(string)
384                 obj->string_data = strdup(string);
385 }
386
387
388 void object_set_number(object* obj, long num) {
389         assert(obj);
390         object_clear_type(obj);
391         obj->is_number = 1;
392         obj->num_value = num;
393 }
394
395 void object_set_double(object* obj, double num) {
396         assert(obj);
397         object_clear_type(obj);
398         obj->is_double = 1;
399         obj->double_value = num;
400 }
401
402
403 void object_set_class(object* obj, char* classname) {
404         assert(obj && classname);
405         obj->classname = strdup(classname);
406 }
407
408
409
410 char* object_to_json(object* obj) {
411
412         if(obj == NULL)
413                 return strdup("null");
414
415         growing_buffer* buf = buffer_init(64);
416
417         /* add class hints if we have a class name */
418         if(obj->classname) {
419                 buffer_add(buf,"/*--S ");
420                 buffer_add(buf,obj->classname);
421                 buffer_add(buf, "--*/");
422         }
423
424         if(obj->is_bool && obj->bool_value)
425                         buffer_add(buf, "true"); 
426
427         else if(obj->is_bool && ! obj->bool_value)
428                         buffer_add(buf, "false"); 
429
430         else if(obj->is_number) {
431                 char b[128];
432                 memset(b, 0, 128);
433                 sprintf(b, "%ld", obj->num_value);
434                 buffer_add(buf, b);
435         }
436
437         else if(obj->is_double) {
438                 char b[128];
439                 memset(b, 0, 128);
440                 sprintf(b, "%lf", obj->double_value);
441                 buffer_add(buf, b);
442         }
443
444         else if(obj->is_null)
445                 buffer_add(buf, "null");
446
447         else if (obj->is_string) {
448
449                 buffer_add(buf, "\"");
450                 char* data = obj->string_data;
451                 int len = strlen(data);
452                 
453                 char* output = uescape(data, len, 1);
454                 buffer_add(buf, output);
455                 free(output);
456                 buffer_add(buf, "\"");
457
458         }  else if(obj->is_array) {
459
460                 buffer_add(buf, "[");
461                 int i;
462                 for( i = 0; i!= obj->size; i++ ) {
463                         char* data = object_to_json(obj->get_index(obj,i));
464 #ifdef STRICT_JSON_WRITE
465                         buffer_add(buf, data);
466 #else
467                         if(strcmp(data,"null")) /* only add the string if it isn't null */
468                                 buffer_add(buf, data);
469 #endif
470                         free(data);
471                         if(i != obj->size - 1)
472                                 buffer_add(buf, ",");
473                 }
474                 buffer_add(buf, "]");
475
476         } else if(obj->is_hash) {
477                 buffer_add(buf, "{");
478                 object_iterator* itr = new_iterator(obj);
479                 object_node* tmp;
480                 while( (tmp = itr->next(itr)) ) {
481                         buffer_add(buf, "\"");
482                         buffer_add(buf, tmp->key);
483                         buffer_add(buf, "\":");
484                         char* data =  object_to_json(tmp->item);
485
486 #ifdef STRICT_JSON_WRITE
487                         buffer_add(buf, data);
488 #else
489                         if(strcmp(data,"null")) /* only add the string if it isn't null */
490                                 buffer_add(buf, data);
491 #endif
492
493                         if(itr->has_next(itr))
494                                 buffer_add(buf, ",");
495                         free(data);
496                 }
497                 free_iterator(itr);
498                 buffer_add(buf, "}");
499         }
500
501         /* close out the object hint */
502         if(obj->classname) {
503                 buffer_add(buf, "/*--E ");
504                 buffer_add(buf, obj->classname);
505                 buffer_add(buf, "--*/");
506         }
507
508         if(obj->comment) {
509                 buffer_add(buf, " /*");
510                 buffer_add(buf, obj->comment);
511                 buffer_add(buf, "*/");
512         }
513
514         char* data = buffer_data(buf);
515         buffer_free(buf);
516         return data;
517
518 }
519
520
521 void object_clear_type(object* obj) {
522         if(obj == NULL) return;
523         obj->is_string = 0;
524         obj->is_hash    = 0;
525         obj->is_array   = 0;
526         obj->is_bool    = 0;
527         obj->is_null    = 0;
528 }
529
530
531 void object_set_comment(object* obj, char* com) {
532         assert(obj && com);
533         obj->comment = strdup(com);
534 }
535
536
537
538 /* ---------------------------------------------------------------------- */
539 /* Iterator */
540
541 object_iterator* new_iterator(object* obj) {
542         object_iterator* iter = safe_malloc(sizeof(object_iterator));
543         iter->obj = obj;
544         iter->current = obj->data;
545         iter->next = &object_iterator_next;
546         iter->has_next = &object_iterator_has_next;
547         return iter;
548 }
549
550 object_node* object_iterator_next(object_iterator* itr) {
551         assert( itr != NULL );
552
553         object_node* tmp = itr->current;
554         if(tmp == NULL) return NULL;
555         itr->current = itr->current->next;
556
557         return tmp;
558 }
559
560 void free_iterator(object_iterator* iter) { 
561         if(iter == NULL) return;
562         free(iter);
563 }
564
565 int object_iterator_has_next(object_iterator* itr) {
566         assert(itr);
567         if(itr->current) return 1;
568         return 0;
569 }
570
571