1 /*
2 Copyright (c) 1994 - 2010, Lawrence Livermore National Security, LLC.
3 LLNL-CODE-425250.
4 All rights reserved.
5 
6 This file is part of Silo. For details, see silo.llnl.gov.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11 
12    * Redistributions of source code must retain the above copyright
13      notice, this list of conditions and the disclaimer below.
14    * Redistributions in binary form must reproduce the above copyright
15      notice, this list of conditions and the disclaimer (as noted
16      below) in the documentation and/or other materials provided with
17      the distribution.
18    * Neither the name of the LLNS/LLNL nor the names of its
19      contributors may be used to endorse or promote products derived
20      from this software without specific prior written permission.
21 
22 THIS SOFTWARE  IS PROVIDED BY  THE COPYRIGHT HOLDERS  AND CONTRIBUTORS
23 "AS  IS" AND  ANY EXPRESS  OR IMPLIED  WARRANTIES, INCLUDING,  BUT NOT
24 LIMITED TO, THE IMPLIED  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A  PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN  NO  EVENT SHALL  LAWRENCE
26 LIVERMORE  NATIONAL SECURITY, LLC,  THE U.S.  DEPARTMENT OF  ENERGY OR
27 CONTRIBUTORS BE LIABLE FOR  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR  CONSEQUENTIAL DAMAGES  (INCLUDING, BUT NOT  LIMITED TO,
29 PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS  OF USE,  DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 LIABILITY, WHETHER  IN CONTRACT, STRICT LIABILITY,  OR TORT (INCLUDING
32 NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT  OF THE USE  OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 
35 This work was produced at Lawrence Livermore National Laboratory under
36 Contract No.  DE-AC52-07NA27344 with the DOE.
37 
38 Neither the  United States Government nor  Lawrence Livermore National
39 Security, LLC nor any of  their employees, makes any warranty, express
40 or  implied,  or  assumes  any  liability or  responsibility  for  the
41 accuracy, completeness,  or usefulness of  any information, apparatus,
42 product, or  process disclosed, or  represents that its use  would not
43 infringe privately-owned rights.
44 
45 Any reference herein to  any specific commercial products, process, or
46 services by trade name,  trademark, manufacturer or otherwise does not
47 necessarily  constitute or imply  its endorsement,  recommendation, or
48 favoring  by  the  United  States  Government  or  Lawrence  Livermore
49 National Security,  LLC. The views  and opinions of  authors expressed
50 herein do not necessarily state  or reflect those of the United States
51 Government or Lawrence Livermore National Security, LLC, and shall not
52 be used for advertising or product endorsement purposes.
53 */
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <float.h>
57 #include <limits.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <unistd.h>
61 
62 #include <silo_private.h>
63 
64 #include <silo_json.h>
65 #include <json/json.h>
66 #include <json/json_object_private.h>
67 #include <json/printbuf.h>
68 
69 #define EXTPTR_HDRSTR "\":{\"ptr\":\"0x"
70 
indent(struct printbuf * pb,int level,int flags)71 static void indent(struct printbuf *pb, int level, int flags)
72 {
73     if (flags & JSON_C_TO_STRING_PRETTY)
74     {
75         printbuf_memset(pb, -1, ' ', level * 2);
76     }
77 }
78 
json_object_object_length(struct json_object * o)79 static int json_object_object_length(struct json_object *o)
80 {
81     struct lh_table *t = json_object_get_object(o);
82     return t->count;
83 }
84 
json_object_object_get_member_count(struct json_object * o)85 static int json_object_object_get_member_count(struct json_object *o)
86 {
87     int n = 0;
88     struct json_object_iter jiter;
89     json_object_object_foreachC(o, jiter)
90     {
91         n++;
92     }
93     return n;
94 }
95 
json_object_set_serializer(json_object * jso,json_object_to_json_string_fn to_string_func,void * userdata,json_object_delete_fn * user_delete)96 static void json_object_set_serializer(json_object *jso,
97     json_object_to_json_string_fn to_string_func,
98     void * userdata, json_object_delete_fn * user_delete)
99 {
100     jso->_to_json_string = to_string_func;
101 }
102 
json_object_set_deleter(json_object * jso,json_object_delete_fn delete_func)103 static void json_object_set_deleter(json_object *jso,
104     json_object_delete_fn delete_func)
105 {
106     jso->_delete = delete_func;
107 }
108 
109 void
json_object_extptr_delete(struct json_object * jso)110 json_object_extptr_delete(struct json_object *jso)
111 {
112     void *extptr = json_object_get_extptr_ptr(jso);
113     if (extptr) free(extptr);
114     json_object_put(jso);
115 }
116 
117 static int
json_object_extptr_to_json_string(struct json_object * jso,struct printbuf * pb,int level,int flags)118 json_object_extptr_to_json_string(struct json_object* jso,
119     struct printbuf *pb, int level, int flags)
120 {
121         int had_children = 0;
122         int ii;
123         char *p;
124         int datatype, nvals, ndims, dims[32];
125         struct json_object *darr, *subobj;
126         int retval;
127 
128         sprintbuf(pb, "{\"ptr\":%s", json_object_to_json_string(json_object_object_get(jso, "ptr")));
129         sprintbuf(pb, ",\"datatype\":%s", json_object_to_json_string(json_object_object_get(jso, "datatype")));
130         sprintbuf(pb, ",\"ndims\":%s", json_object_to_json_string(json_object_object_get(jso, "ndims")));
131         sprintbuf(pb, ",\"dims\":%s", json_object_to_json_string(json_object_object_get(jso, "dims")));
132 
133         p = (char*) json_object_get_strptr(json_object_object_get(jso, "ptr"));
134         datatype = json_object_get_int(json_object_object_get(jso, "datatype"));
135         ndims = json_object_get_int(json_object_object_get(jso, "ndims"));
136         darr = json_object_object_get(jso, "dims");
137         nvals = 1;
138         for (ii = 0; ii < ndims; ii++)
139         {
140             dims[ii] = json_object_get_int(json_object_array_get_idx(darr, ii));
141             nvals *= dims[ii];
142         }
143 
144         if (flags & JSON_C_TO_STRING_EXTPTR_AS_BINARY)
145         {
146             sprintbuf(pb, ",\"nvals\":%d", nvals);
147             sprintbuf(pb, ",\"data\":[");
148             printbuf_memappend(pb, p, nvals*db_GetMachDataSize(datatype));
149         }
150         else if (flags & JSON_C_TO_STRING_EXTPTR_SKIP)
151         {
152             return sprintbuf(pb, "}");
153         }
154         else
155         {
156 
157             sprintbuf(pb, ",\"data\":[");
158             if (flags & JSON_C_TO_STRING_PRETTY)
159                     sprintbuf(pb, "\n");
160 
161             for(ii=0; ii < nvals; ii++)
162             {
163                     struct json_object *val;
164                     if (had_children)
165                     {
166                             sprintbuf(pb, ",");
167                             if (flags & JSON_C_TO_STRING_PRETTY)
168                                     sprintbuf(pb, "\n");
169                     }
170                     had_children = 1;
171                     if (flags & JSON_C_TO_STRING_SPACED)
172                             sprintbuf(pb, " ");
173                     indent(pb, level + 1, flags);
174 
175                     switch (datatype)
176                     {
177                         case DB_CHAR:
178                         {
179                             sprintbuf(pb, "%c", *((char*)p));
180                             p += sizeof(char);
181                             break;
182                         }
183                         case DB_SHORT:
184                         {
185                             sprintbuf(pb, "%hd", *((short*)p));
186                             p += sizeof(short);
187                             break;
188                         }
189                         case DB_INT:
190                         {
191                             sprintbuf(pb, "%d", *((int*)p));
192                             p += sizeof(int);
193                             break;
194                         }
195                         case DB_LONG:
196                         {
197                             sprintbuf(pb, "%ld", *((long*)p));
198                             p += sizeof(long);
199                             break;
200                         }
201                         case DB_LONG_LONG:
202                         {
203                             sprintbuf(pb, "%lld", *((long long*)p));
204                             p += sizeof(long long);
205                             break;
206                         }
207                         case DB_FLOAT:
208                         {
209                             sprintbuf(pb, "%f", *((float*)p));
210                             p += sizeof(float);
211                             break;
212                         }
213                         case DB_DOUBLE:
214                         {
215                             sprintbuf(pb, "%f", *((double*)p));
216                             p += sizeof(double);
217                             break;
218                         }
219                     }
220             }
221         }
222         if (flags & JSON_C_TO_STRING_PRETTY)
223         {
224                 if (had_children)
225                         sprintbuf(pb, "\n");
226                 indent(pb,level,flags);
227         }
228 
229         if (flags & JSON_C_TO_STRING_SPACED)
230                 retval = sprintbuf(pb, " ]}");
231         else
232                 retval = sprintbuf(pb, "]}");
233 
234         return retval;
235 }
236 
237 struct json_object *
json_object_new_strptr(void * p)238 json_object_new_strptr(void *p)
239 {
240     static char tmp[32];
241     if (sizeof(p) == sizeof(unsigned))
242         snprintf(tmp, sizeof(tmp), "0x%016x", (unsigned) p);
243     else if (sizeof(p) == sizeof(unsigned long))
244         snprintf(tmp, sizeof(tmp), "0x%016lx", (unsigned long) p);
245     else if (sizeof(p) == sizeof(unsigned long long))
246         snprintf(tmp, sizeof(tmp), "0x%016llx", (unsigned long long) p);
247 
248     return json_object_new_string(tmp);
249 }
250 
251 void *
json_object_get_strptr(struct json_object * o)252 json_object_get_strptr(struct json_object *o)
253 {
254     void *p;
255     char const *strptr = json_object_get_string(o);
256     if (sscanf(strptr, "%p", &p) == 1)
257         return p;
258     else
259         return 0;
260 }
261 
262 struct json_object *
json_object_new_extptr(void * p,int ndims,int const * dims,int datatype)263 json_object_new_extptr(void *p, int ndims, int const *dims, int datatype)
264 {
265     int i;
266     struct json_object *jobj = json_object_new_object();
267     struct json_object *jarr = json_object_new_array();
268 
269     json_object_set_serializer(jobj, json_object_extptr_to_json_string, 0, 0);
270     json_object_set_deleter(jobj, json_object_extptr_delete);
271 
272     for (i = 0; i < ndims; i++)
273         json_object_array_add(jarr, json_object_new_int(dims[i]));
274 
275     json_object_object_add(jobj, "ptr", json_object_new_strptr(p));
276     json_object_object_add(jobj, "datatype", json_object_new_int(datatype));
277     json_object_object_add(jobj, "ndims", json_object_new_int(ndims));
278     json_object_object_add(jobj, "dims", jarr);
279 
280     return jobj;
281 }
282 
283 int
json_object_is_extptr(struct json_object * obj)284 json_object_is_extptr(struct json_object *obj)
285 {
286     if (json_object_object_get_ex(obj, "ptr", 0) &&
287         json_object_object_get_ex(obj, "datatype", 0) &&
288         json_object_object_get_ex(obj, "ndims", 0) &&
289         json_object_object_get_ex(obj, "dims", 0))
290         return 1;
291     return 0;
292 }
293 
294 int
json_object_get_extptr_ndims(struct json_object * obj)295 json_object_get_extptr_ndims(struct json_object *obj)
296 {
297     struct json_object *sobj = 0;
298     if (json_object_object_get_ex(obj, "ptr", 0) &&
299         json_object_object_get_ex(obj, "datatype", 0) &&
300         json_object_object_get_ex(obj, "ndims", &sobj) &&
301         json_object_object_get_ex(obj, "dims", 0) && sobj)
302         return json_object_get_int(sobj);
303     return -1;
304 }
305 
306 int
json_object_get_extptr_datatype(struct json_object * obj)307 json_object_get_extptr_datatype(struct json_object *obj)
308 {
309     struct json_object *sobj = 0;
310     if (json_object_object_get_ex(obj, "ptr", 0) &&
311         json_object_object_get_ex(obj, "datatype", &sobj) &&
312         json_object_object_get_ex(obj, "ndims", 0) &&
313         json_object_object_get_ex(obj, "dims", 0) && sobj)
314         return json_object_get_int(sobj);
315     return -1;
316 }
317 
318 int
json_object_get_extptr_dims_idx(struct json_object * obj,int idx)319 json_object_get_extptr_dims_idx(struct json_object *obj, int idx)
320 {
321     struct json_object *sobj = 0;
322     if (json_object_object_get_ex(obj, "ptr", 0) &&
323         json_object_object_get_ex(obj, "datatype", 0) &&
324         json_object_object_get_ex(obj, "ndims", 0) &&
325         json_object_object_get_ex(obj, "dims", &sobj) && sobj)
326         return json_object_get_int(json_object_array_get_idx(sobj, idx));
327     return 0;
328 }
329 
330 void *
json_object_get_extptr_ptr(struct json_object * obj)331 json_object_get_extptr_ptr(struct json_object *obj)
332 {
333     struct json_object *sobj = 0;
334     if (json_object_object_get_ex(obj, "ptr", &sobj) &&
335         json_object_object_get_ex(obj, "datatype", 0) &&
336         json_object_object_get_ex(obj, "ndims", 0) &&
337         json_object_object_get_ex(obj, "dims", 0) && sobj)
338         return json_object_get_strptr(sobj);
339     return 0;
340 }
341 
342 int
json_object_to_binary_buf(struct json_object * obj,int flags,void ** buf,int * len)343 json_object_to_binary_buf(struct json_object *obj, int flags, void **buf, int *len)
344 {
345     char const *pjhdr;
346     struct printbuf *pb = printbuf_new();
347 
348     /* first, stringify the json object as normal but skipping extptr data */
349     char const *jhdr = json_object_to_json_string_ext(obj, flags|JSON_C_TO_STRING_EXTPTR_SKIP);
350     sprintbuf(pb, "%s", jhdr);
351     sprintbuf(pb, "%c", '\0'); /* so header is null-terminated */
352 
353     /* now, handle all extptr objects by appending their binary data onto the end,
354        and over-writing the "ptr" value with offset within the buffer */
355     pjhdr = jhdr;
356     while (*pjhdr)
357     {
358         if (!strncmp(pjhdr, EXTPTR_HDRSTR, sizeof(EXTPTR_HDRSTR)-1))
359         {
360             char tmp[64];
361             int pblen;
362             struct json_object *extptr_obj = json_tokener_parse(pjhdr+2); /* walk past '":' */
363             void *p = json_object_get_strptr(json_object_object_get(extptr_obj, "ptr"));
364             int datatype = json_object_get_int(json_object_object_get(extptr_obj, "datatype"));
365             int ndims = json_object_get_int(json_object_object_get(extptr_obj, "ndims"));
366             struct json_object *darr = json_object_object_get(extptr_obj, "dims");
367             int ii, nvals = 1;
368             for (ii = 0; ii < ndims; ii++)
369                 nvals *= json_object_get_int(json_object_array_get_idx(darr, ii));
370             pblen = printbuf_length(pb);
371             printbuf_memappend_fast(pb, p, nvals*db_GetMachDataSize(datatype));
372             /* Use of a hexadecimal value works ok here because a scanf can read it */
373             sprintf(tmp,"%-.16x",pblen); /* overwrite ptr value w/buffer-offset */
374             memcpy(pb->buf + (pjhdr+12-jhdr),tmp,strlen(tmp)); /* overwrite ptr value w/buffer-offset */
375             pjhdr += sizeof(EXTPTR_HDRSTR);
376             json_object_put(extptr_obj);
377         }
378         pjhdr++;
379     }
380     if (len) *len = printbuf_length(pb);
381     if (buf) *buf = pb->buf;
382     free(pb);
383     return 0;
384 }
385 
386 static void
json_object_from_binary_buf_recurse(struct json_object * jso,void * buf)387 json_object_from_binary_buf_recurse(struct json_object *jso, void *buf)
388 {
389     /* first, reconstitute the header */
390     struct json_object_iter iter;
391 
392     json_object_object_foreachC(jso, iter)
393     {
394         json_type jtype = json_object_get_type(iter.val);
395         if (jtype == json_type_object)
396         {
397             if (json_object_object_get_ex(iter.val, "ptr", 0) &&
398                 json_object_object_get_ex(iter.val, "datatype", 0) &&
399                 json_object_object_get_ex(iter.val, "ndims", 0) &&
400                 json_object_object_get_ex(iter.val, "dims", 0))
401             {
402                 char strptr[128];
403                 void *p;
404                 int i, offset, nvals=1;
405                 char const *offstr = json_object_get_string(json_object_object_get(iter.val, "ptr"));
406                 int datatype = json_object_get_int(json_object_object_get(iter.val, "datatype"));
407                 int ndims = json_object_get_int(json_object_object_get(iter.val, "ndims"));
408                 struct json_object *darr = json_object_object_get(iter.val, "dims");
409                 for (i = 0; i < ndims; i++)
410                     nvals *= json_object_get_int(json_object_array_get_idx(darr, i));
411                 sscanf(offstr, "%x", &offset);
412                 p = malloc(nvals*db_GetMachDataSize(datatype));
413                 memcpy(p, buf+offset, nvals*db_GetMachDataSize(datatype));
414                 json_object_object_del(iter.val,"ptr");
415                 snprintf(strptr, sizeof(strptr), "%p", p);
416                 json_object_object_add(iter.val, "ptr", json_object_new_string(strptr));
417             }
418             else
419             {
420                 json_object_from_binary_buf_recurse(iter.val, buf);
421             }
422         }
423     }
424 }
425 
426 struct json_object *
json_object_from_binary_buf(void * buf,int len)427 json_object_from_binary_buf(void *buf, int len)
428 {
429     struct json_object *retval = json_tokener_parse((char*)buf);
430     json_object_from_binary_buf_recurse(retval, buf);
431     return retval;
432 }
433 
434 struct json_object *
json_object_from_binary_file(char const * filename)435 json_object_from_binary_file(char const *filename)
436 {
437     struct json_object *retval;
438     void *buf;
439     int fd;
440 
441 #ifndef SIZEOF_OFF64_T
442 #error missing definition for SIZEOF_OFF64_T in silo_private.h
443 #else
444     struct stat s;
445 #endif
446 
447     errno = 0;
448     memset(&s, 0, sizeof(s));
449 
450 #if SIZEOF_OFF64_T > 4
451     if (stat64(filename, &s) != 0 || errno != 0)
452         return 0;
453 #else
454     if (stat(filename, &s) != 0 || errno != 0)
455         return 0;
456 #endif
457 
458     fd = open(filename, O_RDONLY);
459     if (fd < 0)
460         return 0;
461     buf = malloc(s.st_size);
462     if (read(fd, buf, (size_t) s.st_size) != (ssize_t) s.st_size)
463     {
464         free(buf);
465         return 0;
466     }
467     close(fd);
468     retval = json_object_from_binary_buf(buf, (int) s.st_size);
469     free(buf);
470 
471     return retval;
472 }
473 
474 int
json_object_to_binary_file(char const * filename,struct json_object * obj)475 json_object_to_binary_file(char const *filename, struct json_object *obj)
476 {
477     void *buf; int len; int fd;
478 
479     json_object_to_binary_buf(obj, 0, &buf, &len);
480     fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
481     write(fd, buf, len);
482     close(fd);
483     free(buf);
484     return 0;
485 }
486 
487 int
json_object_reconstitute_extptrs(struct json_object * obj)488 json_object_reconstitute_extptrs(struct json_object *obj)
489 {
490     struct json_object_iter jiter;
491     struct json_object *parent_jobjs_with_extptr_members[1000];
492     char const *extptr_member_keys[1000];
493     int k, num_to_remove = 0;
494 
495     json_object_object_foreachC(obj, jiter)
496     {
497         struct json_object *ptr_obj, *datatype_obj, *ndims_obj, *dims_obj, *data_obj;
498 
499         struct json_object *mobj = jiter.val;
500         char const *mname = jiter.key;
501 
502         if (json_object_get_type(mobj) != json_type_object)
503             continue;
504 
505         if (!(json_object_object_get_ex(mobj, "ptr", &ptr_obj ) &&
506               json_object_object_get_ex(mobj, "datatype", &datatype_obj) &&
507               json_object_object_get_ex(mobj, "ndims", &ndims_obj) &&
508               json_object_object_get_ex(mobj, "dims", &dims_obj) &&
509               json_object_object_get_ex(mobj, "data", &data_obj)))
510         {
511             json_object_reconstitute_extptrs(mobj);
512             continue;
513         }
514 
515         if (!(json_object_get_type(ptr_obj) == json_type_string &&
516               json_object_get_type(datatype_obj) == json_type_int &&
517               json_object_get_type(ndims_obj) == json_type_int &&
518               json_object_get_type(dims_obj) == json_type_array &&
519               json_object_get_type(data_obj) == json_type_array))
520         {
521             json_object_reconstitute_extptrs(mobj);
522             continue;
523         }
524 
525         if (json_object_object_get_member_count(mobj) != 5)
526             continue;
527 
528         extptr_member_keys[num_to_remove] = mname;
529         parent_jobjs_with_extptr_members[num_to_remove] = obj;
530         num_to_remove++;
531     }
532 
533     for (k = 0; k < num_to_remove; k++)
534     {
535         struct json_object *ptr_obj, *datatype_obj, *ndims_obj, *dims_obj, *data_obj;
536         char *mname = strdup(extptr_member_keys[k]);
537         struct json_object *pobj = parent_jobjs_with_extptr_members[k];
538         struct json_object *extptr_obj;
539 
540         json_object_object_get_ex(pobj, mname, &extptr_obj);
541         json_object_object_get_ex(extptr_obj, "ptr", &ptr_obj );
542         json_object_object_get_ex(extptr_obj, "datatype", &datatype_obj);
543         json_object_object_get_ex(extptr_obj, "ndims", &ndims_obj);
544         json_object_object_get_ex(extptr_obj, "dims", &dims_obj);
545         json_object_object_get_ex(extptr_obj, "data", &data_obj);
546 
547         /* We're at an extptr object that was serialized to a 'standard' json string.
548          * So, lets reconstitute it. */
549         {
550             int i, n = 1;
551             int datatype = json_object_get_int(datatype_obj);
552             int ndims = json_object_get_int(ndims_obj);
553             int *dims = (int *) malloc(ndims * sizeof(int));
554             int jdtype = json_object_get_type(json_object_array_get_idx(data_obj, 0));
555             char *p;
556             void *pdata;
557 
558             /* get the array dimension sizes */
559             for (i = 0; i < ndims; i++)
560             {
561                 dims[i] = json_object_get_int(json_object_array_get_idx(dims_obj, i));
562                 n *= dims[i];
563             }
564 
565             /* get the array data */
566             pdata = (void *) malloc(n * db_GetMachDataSize(datatype));
567             for (i = 0, p = pdata; i < n; i++, p += db_GetMachDataSize(datatype))
568             {
569                 switch (jdtype)
570                 {
571                     case json_type_int:
572                     {
573                         int ival = json_object_get_int(json_object_array_get_idx(data_obj, i));
574                         if (datatype == DB_CHAR)
575                             *((char*)p) = (unsigned char) ival;
576                         else if (datatype == DB_SHORT)
577                             *((short*)p) = (short) ival;
578                         else if (datatype == DB_INT)
579                             *((int*)p) = ival;
580                         else if (datatype == DB_LONG)
581                             *((long*)p) = (long) ival;
582                         break;
583                     }
584                     case json_type_double:
585                     {
586                         double dval = json_object_get_double(json_object_array_get_idx(data_obj, i));
587                         if (datatype == DB_DOUBLE)
588                             *((double*)p) = dval;
589                         else
590                             *((float*)p) = (float) dval;
591                         break;
592                     }
593                 }
594             }
595 
596             /* delete the old object */
597             json_object_object_del(pobj, mname);
598 
599             /* Add the reconstituted extptr object */
600             json_object_object_add(pobj, mname,
601                 json_object_new_extptr(pdata, ndims, dims, datatype));
602 
603             free(mname);
604         }
605     }
606 
607     return 0;
608 }
609 
610 #if 0
611 /* Difference methods
612  *
613  * Easiest thing to develop is a thing to test equality. Given two objects, they
614  * are equal if all their sub-components are equal. But, that isn't the same as
615  * computing the difference itself.
616  *
617  * Given two json objects, what is the difference object?
618  * If both objects contain a member in common (e.g. same key/idx and value-type), diff that member
619  *     If their difference is "zero", return json_type_null
620  *     If their difference is non-zero, return a new json_object holding the difference
621  * If there is an object in one but not the other,
622  *     Ignore it or copy it to the difference object
623  *
624  * If caller wants just to 'print' the differences, then caller passes a stream
625  * or a printbuf into which the difference details are sprint'd
626  *
627  * If caller simply wants to know if the objects are different or not
628  *
629  * Options
630  *     * just return if the objecs are equal or not (e.g. check if diff is zero)
631  *         * ignoring exclusive members
632  *     * Compute a difference object
633  *         * ignoring exclusive members
634  *         * compute a 'total' difference or only map
635  *     * print the differences
636  *         * ignore exclusive members
637  *         * compute a total difference
638  *
639  * Consider the following example cases
640  *     Diffing an array of integer values (or extptr thingy)
641  *         1. stop on first diff, return false then, otherwise true
642  *         2. create a new array with zeros (json_type_null or special zero object) where diffs<tol and diffs otherwise
643  *         3. create a new array with only the diffs>tol and their indx's
644  *     Diffing an object with same name/type members
645  *         1. stop on first diff, return false then, otherwise true
646  *         2. create a new object with zeros (json_type_null or special zero object) where diffs<tol and diffs otherwise
647  *         3. create a new object with only the different members and their names
648  *     Diffing a single primitive
649  *         1. return 1 if different otherwise 0
650  *         2. return a null or zero object if diff<tol
651  *         3. create a new primitive object with the difference
652  *     Diffing primitives of differing type
653  *         Promotion order: boolean->int->double->string
654  *                                    ^    ^
655  *                      string(int)-->|    |
656  *                      string(real)------>|
657  *         Always promote to highest and diff there
658  *     Diffing arbitrary objects
659  *         What constitutes a diff?
660  *             tolerances
661  *             ignore exclusive members (structure)
662  *             match idx/key but not type
663  *         How is diff returned?
664  *             as a bool
665  *             as an object
666  *                 modifications (e.g. map) or toleranced diffs (e.g. total), insertions, deletions
667  *             as a printbuf
668  *                 modifications (e.g. map) or toleranced diffs (e.g. total), insertions, deletions
669  *
670  *
671  *     String output might look like...
672  *     left { foo:5, bar:123.5, gorfo:{a:5, b:0.002567, c:"abc"}, q="mark", p=0}
673  *     right { foo:5, bar:123.6, gorfo:{a:5, s:41.1, b:0.002573, c:"abq"}, q="Mark", p=0}
674  *
675  *     left              right          diff          name/type
676  *     --------------------------------------------------------
677  *      5                  5              0            foo::int
678  *      123.5             123.6           0.1          bar::float
679  *                                                     gorfo::{
680  *      5                  5              0                a::int
681  *      <?>                41.1                            s::float
682  *      0.002567           0.002573       0.000006         b::float
683  *      "abc"              "abq"          "==!"            c::string
684  *                                                     }
685  *      "mark"             "Mark"         "!==="       q::string
686  *      0                  0              0            p::int
687  *
688  *      As an object... holds only the difference 'values'
689  *      {foo:0, bar:0.1, gorfo:{a:0, b:0.0006, c:"==!", additions:{s:41.1}}, q:"!===", p:0}
690  *
691  *
692  *               null     boolean     int     double     string     extpr    array     object
693  *
694  *       null     ok        REV       REV      REV        REV        REV      REV       REV
695 
696  *    boolean     ok        ok        REV      REV        REV        REV      REV       REV
697 
698  *        int     ok      non-zero    ok       REV        REV        REV      REV       REV
699 
700  *     double     ok      non-zero    cast     ok         REV        REV      REV       REV
701 
702  *     string     ok      non-empty   strtol  strtod      ok         REV      REV       REV
703 
704  *      extpr     trunc   non-empty   size=1  size=1      chars      ok       REV       REV
705 
706  *      array     trunc   non-empty   size=1  size=1      chars    diff       ok        REV
707 
708  *     object     trunc   non-empty   size=1  size=1      ???      diff      diff       MAIN
709  *
710  *     There is a 2D array of function pointers, diff_matrix_funcs, which holds pointers
711  *     to all functions. The REV functions are just calls to the symmetric method with
712  *     left/right reversed and a flag to indicate a reversal was made.
713  *
714  *     The object/object method is main entry point for caller. The object/array and object/
715  *     object methods are also called recursively. Extptr is not a recursive call. Note that
716  *     things like object names, depth of recursion, reversal flag, etc. need to get passed
717  *     recusively. This stuff is not appropriate for caller to worry about so need some kind
718  *     of wrapper method for caller that turns around and calls the main recursive entry
719  *     here.
720  *
721  *     An object/non-object method is a clear diff. If diff-only is desired return value, then
722  *     execution is complete at that point. If inclusive only, the execution is complete then
723  *     too. Otherwise, it would descend recursively on the object and null on the other.
724  *
725  *     When does recursion complete? When both objects' precedence <= 4;
726  *
727  *     Need to know when diffs are strict or not (is a boolean 1 same as an int 1, depends
728  *     on strictness)?
729  *
730  *     Naming of functions in the matrix
731  *
732  *     json_diff_<left-type>_<right-type>();
733  *
734  *     json_diff_null_null()
735  *     json_diff_null_bool(), e.g. json_diff_bool_null is a REV-wrapper to json_diff_null_bool()
736  *     json_diff_null_int()
737  *     json_diff_null_double()
738  *     json_diff_null_string()
739  *     json_diff_null_extptr()
740  *     json_diff_null_array()  will have to recurse on array members
741  *     json_diff_null_object() will have to recurse on object members but so too for int_object
742  *         and double_object, etc. Thats a lot of duplicated code. We need to punt here.
743  *
744  *     More involved methods
745  *
746  *     json_diff_extptr_extptr() /* non-recursive but like an int/int or double/double or maybe int/double */
747  *     json_diff_extptr_array()  /* left is a 'datatype'd number; right is a json object which might be a number */
748  *     json_diff_extptr_object()
749  *     json_diff_array_array()   /* recurses on both left and right */
750  *     json_diff_array_object()  /* recurses on both left and right */
751  *     json_diff_object_object() /* recurses on both left and right */
752 
753  *
754  *     Args these methods need to take...
755  *     left object, right object, left-name, right-name,
756  *     depth, mode, flags (incl rev), tolerances, retval
757  *
758  *     Caller's call to wrapper turns around and uses "LEFT-OBJECT" "RIGHT-OBJECT" names.
759  *     depth=0, mode, flags and tolerances determined by caller.
760  *
761  *     Need a way to set/push return 'value' (int 0/1, printbuf-str, object). Might be
762  *     best as macro'd code. At the point where you know you have a diff of some kind
763  *     you then 'handle-diff' which may be an early return, printing to a buffer or
764  *     constructing 'additions'/'deletions' of an object. Macro'd code allows for
765  *     logic handling early return to be written only once.
766  *
767  *
768  */
769 
770 #define HANDLE_DIFF()
771 { \
772     int *ret_intp                =                (int *) retval;
773     struct printbuf *ret_pbuf   =    (struct printbuf *) retval;
774     struct json_object *ret_obj = (struct json_object *) retval;
775 
776     if (mode == json_diff_bool)
777     {
778         *ret_intp = is_diff;
779     }
780     else if (mode == json_diff_string)
781     {
782         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
783         {
784             if (flags & JSON_C_DIFF_REVERSE_LR)
785             {
786             }
787             else
788             {
789                 if (flags & JSON_C_DIFF_RADIX_DECIMAL)
790                     sprintbuf(ret_pbuf, "%s%-20s int    %20d%20d%20d\n", indent[depth], name, lval, rval, dval);
791                 else if (flags & JSON_C_DIFF_RADIX_BINARY)
792             }
793         }
794     }
795     else if (mode == json_diff_object)
796     {
797         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
798         {
799             if (flags & JSON_C_DIFF_REVERS_LR)
800             {
801             }
802             else
803             {
804                 if (json_object_get_type(lobj) == json_type_null &&
805                     json_object_get_type(robj) != json_type_null)
806                 {
807                     struct json_object *adds_obj;
808                     if (!json_object_object_get_ex(ret_obj, "additions", &adds_obj))
809                     {
810                         adds_obj = json_object_new_object();
811                         json_object_object_add(ret_obj, "additions", adds_obj);
812                     }
813 
814                     /* add robj to additions */
815                     json_object_object_add(adds_obj, rkey, robj);
816                 }
817                 else if (json_object_get_type(lobj) != json_type_null &&
818                          json_object_get_type(robj) == json_type_null)
819                 {
820                     struct json_object *dels_obj;
821                     if (!json_object_object_get_ex(ret_obj, "deletions", &dels_obj))
822                     {
823                         dels_obj = json_object_new_object();
824                         json_object_object_add(ret_obj, "deletions", dels_obj);
825                     }
826 
827                     /* add lobj deletions */
828                     json_object_object_add(dels_obj, lkey, lobj);
829                 }
830                 else
831                 {
832                     /* add normal */
833                     json_object_object_add(ret_obj, lkey, diff_obj);
834                 }
835             }
836         }
837     }
838 }
839 
840 void json_diff_null_null(
841     struct json_object const *lobj, char const *lkey,
842     struct json_object const *robj, char const *rkey,
843     int depth, enum json_diff_mode dmode, int flags,
844     double const tols[3], void *retval)
845 {
846     HANDLE_DIFF();
847 }
848 
849 void json_diff_int_int(
850     struct json_object const *lobj, char const *ltag,
851     struct json_object const *robj, char const *rtag,
852     int depth, enum json_diff_mode dmode, int flags,
853     double const tols[3], void *retval)
854 {
855     int lval = json_object_get_int(lobj);
856     int rval = json_object_get_int(robj);
857     int dval = lval - rval;
858 
859     if (flags & JSON_C_DIFF_REVERSE_LR) dval = -dval;
860 
861     is_diff = DBIsDifferentLongLong(lval, rval, tols[0], tols[1], tols[2]);
862 
863     HANDLE_DIFF();
864 }
865 
866 
867 
868 
869 
870 void json_object_int_diff(
871     int depth, char const *tag,
872     struct json_object *lobj, struct json_object *robj,
873     enum json_diff_mode mode, int flags, double const tols[3],
874     void *retthing)
875 {
876     int *ret_intp                =                (int *) retthing;
877     struct printbuf *ret_pbufp   =    (struct printbuf *) retthing;
878     struct json_object *ret_objp = (struct json_object *) retthing;
879     int lval, rval;
880     double abstol, reltol, reltol_eps;
881 
882     if (retthing == 0) return;
883 
884     if (flags & JSON_C_DIFF_ZERO_TOLS)
885         tols[0] = tols[1] = tols[2] = 0;
886 
887     abstol = tols[0];
888     reltol = tols[1];
889     retol_eps = tols[2];
890 
891     lval = json_object_get_int(lobj);
892     rval = json_object_get_int(robj);
893     dval = lval - rval;
894 
895     is_diff = DBIsDifferentDouble(lval, rval, abstol, reltol, reltol_eps);
896 
897     switch (mode)
898     {
899         case json_diff_bool:
900             *ret_intp = is_diff;
901             return;
902         case json_diff_string:
903             if (is_diff || (flags & JSON_C_DIFF_TOTAL))
904                 sprintbuf(*ret_pbp, "%s%-20s int    %20d%20d%20d\n", indent[depth], name, lval, rval, dval);
905             return;
906         case json_diff_object:
907             if (is_diff || (flags & JSON_C_DIFF_TOTAL))
908                 json_object_object_add(ret_objp, name, json_object_new_int(dval));
909             return;
910     }
911 }
912 
913 /* Return type precedence of json object according to generality of type */
914 int json_object_type_precedence(struct json_object *obj)
915 {
916     switch (json_object_get_type(obj))
917     {
918         case json_type_null:                return 0; /* primitive */
919         case json_type_boolean:             return 1; /* primitive */
920         case json_type_int:                 return 2; /* primitive */
921         case json_type_double:              return 3; /* primitive */
922         case json_type_string:              return 4; /* primitive */
923         case json_type_array:               return 6; /* recursive */
924         case json_type_object:
925         {
926             if (json_object_is_extptr(obj)) return 5; /* primitive */
927                                             return 7; /* recursive */
928         }
929     }
930     return -1;
931 }
932 
933 void json_object_diff(struct json_object *lobj, struct json_object *robj,
934     enum json_diff_mode dmode, int flags, double const tols[3],
935     void *retval)
936 {
937     if (retval == 0) return;
938 
939     /* zero the tolerances if we need to */
940     if (flags & JSON_C_DIFF_ZERO_TOLS)
941         tols[0] = tols[1] = tols[2] = 0;
942 
943     lprec = json_type_precedence(lobj);
944     rprec = json_type_precedence(robj);
945 
946     /* Call correct json_object differencing function */
947     (*diff_matrix_func)(lobj, robj,
948 
949 
950 
951 
952 }
953 
954 void json_object_diff(
955     int depth,
956     struct json_object *lobj, char const *lnm,
957     struct json_object *robj, char const *rnm,
958     enum json_diff_mode mode, int flags, double const tols[3],
959     void *retthing)
960 {
961     int *ret_intp                =                (int *) retthing;
962     struct printbuf *ret_pbufp   =    (struct printbuf *) retthing;
963     struct json_object *ret_objp = (struct json_object *) retthing;
964 
965     if (json_object_is_type(lobj, json_type_object))
966     {
967         if (json_object_is_type(robj, json_type_object))
968         {
969             struct json_object_iterator liter, lend;
970             struct json_object_iterator riter, rend;
971 
972             /* First, iterate over lobj members */
973             liter = json_object_iter_begin(lobj);
974             lend = json_object_iter_end(lobj);
975             while (!json_object_iter_equal(&liter, &lend))
976             {
977                 char const *lsubnm = json_object_iter_peek_name(&liter);
978                 struct json_object *lsubobj = json_object_iter_peek_value(&liter);
979                 struct json_object *rsubobj;
980 
981                 if (json_object_object_get_ex(robj, lsubnm, &rsubojb))
982                 {
983                     /* Recurse on the two object's members */
984                     json_object_diff(depth+1,lsubobj,lsubnm,rsubobj,lsubnm,mode,flags,tols,retting);
985                     if (mode == json_diff_bool && *ret_intp != 0) return;
986                 }
987                 else if (!(flags&JSON_DIFF_EXCLUSIVE_ONLY))
988                 {
989                     if (mode == json_diff_bool)
990                     {
991                         *ret_intp = 1;
992                         return;
993                     }
994                     json_object_diff(depth+1,lsubobj,lsubnm,0,"***DEL***",mode,flags,tols,retting);
995                 }
996             }
997 
998             /* At this point, we've examined robj only for those names in lobj.
999              * So, now, iterate over robj members we haven't already visited.
1000              * Anything we encounter at this point is treated as an 'addition.' */
1001             if (!(flags&JSON_DIFF_EXCLUSIVE_ONLY))
1002             {
1003                 riter = json_object_iter_begin(robj);
1004                 rend = json_object_iter_end(robj);
1005                 while (!json_object_iter_equal(&riter, &rend))
1006                 {
1007                     char const *rsubnm = json_object_iter_peek_name(&riter);
1008                     if (json_object_object_get_ex(lobj, rsubnm, 0)) continue;
1009 
1010                     if (mode == json_diff_bool)
1011                     {
1012                         *ret_intp = 1;
1013                         return;
1014                     }
1015                     json_object_diff(depth+1,0,"***ADD***",rsubobj,rsubnm,mode,flags,tols,retting);
1016                 }
1017             }
1018         }
1019         else if (!(flags&JSON_DIFF_MIXED_TYPE))
1020         {
1021             if (mode == json_diff_bool)
1022             {
1023                 *ret_intp = 1;
1024                 return;
1025             }
1026             else if (mode == json_diff_string)
1027             {
1028             }
1029             else
1030             {
1031             }
1032         }
1033         else if (json_object_is_type(robj, json_type_array))
1034         {
1035         }
1036         else
1037         {
1038         }
1039     }
1040     else if (json_object_is_type(lobj, json_type_array))
1041     {
1042         if (json_object_is_type(robj, json_type_array))
1043         {
1044             int llen = json_object_array_length(lobj);
1045             int rlen = json_object_array_length(robj);
1046             int done = 0, i = 0;
1047             while (!done)
1048             {
1049                 struct json_object *lsubobj = json_object_array_get_idx(lobj, i);
1050                 struct json_object *rsubobj = json_object_array_get_idx(robj, i);
1051                 if (i < llen && i < rlen)
1052                 {
1053                     char subnm[32];
1054                     snprintf(subnm, sizeof(subnm), "[%03d]", i);
1055 
1056                     /* Recurse on the two object's members */
1057                     json_object_diff(depth+1,lsubobj,subnm,rsubobj,subnm,mode,flags,tols,retting);
1058                     if (mode == json_diff_bool && *ret_intp != 0) return;
1059                 }
1060                 else if (i < llen && !(flags&JSON_DIFF_EXCLUSIVE_ONLY)) /* We're off the end of robj array */
1061                 {
1062                     if (mode == json_diff_bool)
1063                     {
1064                         *ret_intp = 1;
1065                         return;
1066                     }
1067                     json_object_diff(depth+1,lsubobj,subnm,0,"***DEL***",mode,flags,tols,retting);
1068                 }
1069                 else if (!(flags&JSON_DIFF_EXCLUSIV_ONLY))/* We're off the end of lobj array */
1070                 {
1071                     if (mode == json_diff_bool)
1072                     {
1073                         *ret_intp = 1;
1074                         return;
1075                     }
1076                     json_object_diff(depth+1,0,"***ADD***",rsubobj,subnm,mode,flags,tols,retting);
1077                 }
1078             }
1079         }
1080         else
1081         {
1082         }
1083     }
1084     else if (json_object_is_type(robj, json_type_array))
1085     {
1086     }
1087 }
1088 
1089 void json_object_object_diff(
1090     int depth,
1091     struct json_object *left, char const *lnm,
1092     struct json_object *right, char const *rnm,
1093     enum json_diff_mode mode, int flags, double const tols[3],
1094     void *retthing)
1095 {
1096 
1097     int *ret_intp                =                (int *) retthing;
1098     struct printbuf *ret_pbufp   =    (struct printbuf *) retthing;
1099     struct json_object *ret_objp = (struct json_object *) retthing;
1100 
1101     if (retthing == 0) return;
1102 
1103     if (flags & JSON_C_DIFF_ZERO_TOLS)
1104         tols[0] = tols[1] = tols[2] = 0;
1105 
1106     if (json_object_get_type(left) == json_object_get_type(right))
1107     {
1108         /* Diffing two objects of the same, primitive type is easy */
1109         switch (json_object_get_type(left))
1110         {
1111             case json_type_null:
1112             {
1113                 switch (mode)
1114                 {
1115                     case json_diff_bool:
1116                         *ret_intp = 0;
1117                         return;
1118                     case json_diff_string:
1119                         if (flags & JSON_C_DIFF_TOTAL)
1120                             sprintbuf(*ret_pbp, "%s%-20s null   %20d%20d%20d\n", indent[depth], lnm, 0, 0, 0);
1121                         return;
1122                     case json_diff_object:
1123                         if (flags & JSON_C_DIFF_TOTAL)
1124                             json_object_object_add(ret_objp, lnm, json_object_new_int(0));
1125                         return;
1126                 }
1127             }
1128             case json_type_bool:
1129             {
1130                 switch (mode)
1131                 {
1132                     int is_diff = json_object_is_boolean_diff(left, right);
1133                     case json_diff_bool:
1134                         *ret_intp = is_diff;
1135                         return;
1136                     case json_diff_string:
1137                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1138                             sprintbuf(*ret_pbp, "%s%-20s bool   %20d%20d%20d\n", indent[depth],
1139                                 lnm, json_object_get_boolean(left), json_object_get_boolean(right),
1140                                 json_object_get_boolean_diff_string(left, right));
1141                         return;
1142                     case json_diff_object:
1143                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1144                             json_object_object_add(ret_objp, lnm, json_object_get_boolean_diff_object(left, right));
1145                         return;
1146                 }
1147             }
1148             case json_type_int:
1149             {
1150                 int is_diff = json_object_is_int_diff(left, right, tols[0], tols[1], tols[2]);
1151                 switch (mode)
1152                 {
1153                     case json_diff_bool:
1154                         *ret_intp = is_diff;
1155                         return;
1156                     case json_diff_string:
1157                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1158                             sprintbuf(*ret_pbp, "%s%-20s int    %20d%20d%20d\n", indent[depth],
1159                                 lnm, json_object_get_int(left), json_object_get_int(right),
1160                                 json_object_get_int_diff_string(left, right, tols[0], tols[1], tols[2]));
1161                     case json_diff_object:
1162                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1163                             json_object_object_add(ret_objp, lnm, json_object_get_int_diff_object(left, right, tols[0], tols[1], tols[2]));
1164                 }
1165             }
1166             case json_type_double:
1167             {
1168                 int is_diff = json_object_is_double_diff(left, right, tols[0], tols[1], tols[2]);
1169                 switch (mode)
1170                 {
1171                     case json_diff_bool:
1172                         *ret_intp = is_diff;
1173                         return;
1174                     case json_diff_string:
1175                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1176                             sprintbuf(*ret_pbp, "%s%-20s double %16g%16g%16g\n", indent[depth],
1177                                 lnm, json_object_get_double(left), json_object_get_double(right),
1178                                 json_object_get_double_diff_string(left, right, tols[0], tols[1], tols[2]));
1179                         return;
1180                     case json_diff_object:
1181                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1182                             json_object_object_add(ret_objp, lnm, json_object_get_double_diff_object(left, right, tols[0], tols[1], tols[2]));
1183                         return;
1184                 }
1185             }
1186             case json_type_string:
1187             {
1188             }
1189             case json_type_array:
1190             {
1191                 int is_diff = json_object_is_array_diff(left, right, tols[0], tols[1], tols[2]);
1192                 switch (mode)
1193                 {
1194                     case json_diff_bool:
1195                         *ret_intp = is_diff;
1196                         return;
1197                     case json_diff_string:
1198                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1199                         {
1200                             int leftcnt = json_object_array_length(left);
1201                             int rightcnt = json_object_array_length(right);
1202                             int mincnt = leftcnt < rightcnt ? leftcnt : rightcnt;
1203                             int maxcnt = leftcnt < rightcnt ? rightcnt : leftcnt;
1204                             sprintbuf(*ret_pbp, "%s%-20s array\n", indent[depth], lnm);
1205                             for (i = 0 i < mincnt; i++)
1206                             {
1207                                 char const subnm[32];
1208                                 json_object struct *subleft = json_object_array_get_idx(left, i);
1209                                 json_object struct *subright = json_object_array_get_idx(right, i);
1210                                 sprintf(subnm, "%s[%03d]", lnm, i);
1211                                 json_object_object_diff(depth+1, subleft, subright, subnm, subnm, mode, flags, tols, retthing);
1212                             }
1213                             if (!(flags & JSON_C_DIFF_INCLUSIVE))
1214                             {
1215                                 for (i = mincnt; i < maxcnt; i++)
1216                                 {
1217                                     char const subnm[32];
1218                                     json_object struct *subleft = json_object_array_get_idx(left, i);
1219                                     json_object struct *subright = json_object_array_get_idx(right, i);
1220                                     sprintf(subnm, "%s[%03d]", lnm, i);
1221                                     json_object_object_diff(depth+1, subleft, subright, subnm, subnm, mode, flags, tols, retthing);
1222                                 }
1223                             }
1224                         }
1225                         return;
1226                     case json_diff_object:
1227                         if (is_diff || (flags & JSON_C_DIFF_TOTAL))
1228                         {
1229                         }
1230                         return;
1231                 }
1232             }
1233             case json_type_object:
1234             {
1235             }
1236         }
1237     }
1238     else if (flags & JSON_C_DIFF_MIX_PRIM_TYPE)
1239     {
1240 
1241 
1242 
1243 
1244 
1245 
1246     }
1247     else
1248     {
1249     }
1250 
1251 
1252 
1253 
1254 
1255 
1256     struct printbuf *pb_retval = printbuf_new();        /* prepare for pb return */
1257     struct json_object *jso_retval = json_object_new(); /* prepare for obj return */
1258 }
1259 
1260 int json_object_get_boolean_diff(struct json_object *left, struct json_object *right)
1261 {
1262     json_bool leftval, rightval;
1263 
1264     if (!json_object_is_type(left, json_type_boolean) ||
1265         !json_object_is_type(right, json_type_boolean))
1266         return -2; /* invalid diff */
1267 
1268     leftval = json_object_get_boolean(left);
1269     rightval = json_object_get_boolean(right);
1270 
1271     return (int) leftval - (int) rightval;
1272 }
1273 
1274 int json_object_get_int_diff(struct json_object *left, struct json_object *right,
1275     double abstol, double reltol, double reltol_eps)
1276 {
1277     int leftval, rightval, diff;
1278 
1279     if (!json_object_is_type(left, json_type_int) ||
1280         !json_object_is_type(right, json_type_int))
1281         return -INT_MAX; /* invalid diff */
1282 
1283     leftval = json_object_get_int(left);
1284     rightval = json_object_get_int(right);
1285     diff = leftval - rightval;
1286     if (DBIsDifferentDouble(leftval, rightval, abstol, reltol, reltol_eps))
1287         return diff;
1288     return 0;
1289 }
1290 
1291 double json_object_get_double_diff(struct json_object *left, struct json_object *right,
1292     double abstol, double reltol, double reltol_eps)
1293 {
1294     double leftval, rightval, diff;
1295 
1296     if (!json_object_is_type(left, json_type_double) ||
1297         !json_object_is_type(right, json_type_double))
1298         return -DBL_MAX; /* invalid diff */
1299 
1300     leftval = json_object_get_double(left);
1301     rightval = json_object_get_double(right);
1302     diff = leftval - rightval;
1303     if (DBIsDifferentDouble(leftval, rightval, abstol, reltol, reltol_eps))
1304         return diff;
1305     return 0;
1306 }
1307 
1308 char const *json_object_get_string_diff(struct json_object *left, struct json_object *right)
1309 {
1310     if (!json_object_is_type(left, json_type_string) ||
1311         !json_object_is_type(right, json_type_string))
1312         return 0; /* invalid diff */
1313 
1314     /* MAJOR HACK. To be consistent with rest of json-c interface, we would like to return
1315      * a garbage collected string here. But, we're not going to create any new json
1316      * objects here. So, our solution is to use the left operand's printbuf to hold
1317      * the returned string. This is 'ok' because any future attempt to to_json_string()
1318      * on the left operand will reset the left opeand's printbuf before stringifying the
1319      * left operand json object. */
1320     printbuf_reset(left->_pb);
1321 
1322     {
1323         char const *leftval  = json_object_get_string(left);
1324         int leftlen  = json_object_get_string_len(left);
1325         char const *rightval = json_object_get_string(right);
1326         int rightlen = json_object_get_string_len(right);
1327         int i, hasdiffs = 0, hasextras = 0, maxlen;
1328 
1329         maxlen = leftlen < rightlen ? rightlen : leftlen;
1330 
1331         for (i = 0; i < maxlen; i++)
1332         {
1333             char leftc  = i < leftlen  ? leftval[i]  : '<';
1334             char rightc = i < rightlen ? rightval[i] : '>';
1335 
1336             if (i < leftlen && i < rightlen)
1337             {
1338                 if (leftc == rightc)
1339                 {
1340                     sprintfbuf(left->_pb, "=");
1341                 }
1342                 else
1343                 {
1344                     hasdiffs = 1;
1345                     sprintfbuf(left->_pb, "!");
1346                 }
1347             }
1348             else
1349             {
1350                 if (hasextras == 0)
1351                     hasextras = i;
1352                 if (i < leftlen)
1353                     sprintfbuf(left->_pb, "%c", hasdiffs ? '<' : leftc);
1354                 else
1355                     sprintfbuf(left->_pb, "%c", hasdiffs ? '>' : rightc);
1356             }
1357         }
1358 
1359         if (!hasdiffs && !hasextras)
1360         {
1361             printbuf_reset(left->_pb);
1362             return "";
1363         }
1364 
1365         return left->_pb->buf;
1366     }
1367 }
1368 
1369 struct json_object *json_object_array_get_idx_diff(
1370     struct json_object *left, struct json_object *right, int idx,
1371     double abstol, double reltol, double reltol_eps)
1372 {
1373     struct json_object *leftidx, *rightidx;
1374 
1375     if (!json_object_is_type(left, json_type_array) ||
1376         !json_object_is_type(right, json_type_array))
1377         return json_type_null; /* invalid diff */
1378 
1379     if (idx >= json_object_array_length(left) ||
1380         idx >= json_object_array_length(right))
1381         return json_type_null; /* invalid diff */
1382 
1383     leftidx = json_object_array_get_idx(left, idx);
1384     rightidx = json_object_array_get_idx(right, idx);
1385 
1386     return json_object_object_get_diff(leftidx, rightidx);
1387 }
1388 
1389 int json_object_is_boolean_diff(struct json_object *left, struct json_object *right)
1390 {
1391     return json_object_get_boolean_diff(left, right) == 0;
1392 }
1393 
1394 int json_object_is_int_diff(struct json_object *left, struct json_object *right,
1395     double abstol, double reltol, double reltol_eps)
1396 {
1397     return json_object_get_int_diff(left, right, abstol, reltol, reltol_eps) == 0;
1398 }
1399 
1400 int json_object_is_double_diff(struct json_object *left, struct json_object *right,
1401     double abstol, double reltol, double reltol_eps)
1402 {
1403     return json_object_get_double_diff(left, right, abstol, reltol, reltol_eps) == 0;
1404 }
1405 
1406 int json_object_is_string_diff(struct json_object *left, struct json_object *right)
1407 {
1408     char const *diffval = json_object_get_string_diff(left, right);
1409     if (!diffval) return 1;
1410     if (strlen(diffval) == 0) return 0;
1411     return 1;
1412 }
1413 
1414 char const *
1415 json_object_get_boolean_diff_string(struct json_object *left, struct json_object *right)
1416 {
1417     int diffval = json_object_get_boolean_diff(left, right);
1418     /* MAJOR HACK. To be consistent with rest of json-c interface, we would like to return
1419      * a garbage collected string here. But, we're not going to create any new json
1420      * objects here. So, our solution is to use the left operand's printbuf to hold
1421      * the returned string. This is 'ok' because any future attempt to to_json_string()
1422      * on the left operand will reset the left opeand's printbuf before stringifying the
1423      * left operand json object. */
1424     printbuf_reset(left->_pb);
1425     if (diffval == -2)
1426         sprintbuf(left->_pb, "incompatible objects");
1427     else if (diffval != 0)
1428         sprintbuf(left->_pb, "%d", diffval);
1429     else
1430         sprintbuf(left->_pb, "");
1431     return left->_pb->buf;
1432 }
1433 
1434 char const *
1435 json_object_get_int_diff_string(struct json_object *left, struct json_object *right,
1436     double abstol, double reltol, double reltol_eps)
1437 {
1438     int diffval = json_object_get_int_diff(left, right, abstol, reltol, reltol_eps);
1439     /* MAJOR HACK. To be consistent with rest of json-c interface, we would like to return
1440      * a garbage collected string here. But, we're not going to create any new json
1441      * objects here. So, our solution is to use the left operand's printbuf to hold
1442      * the returned string. This is 'ok' because any future attempt to to_json_string()
1443      * on the left operand will reset the left opeand's printbuf before stringifying the
1444      * left operand json object. */
1445     printbuf_reset(left->_pb);
1446     if (diffval == -INT_MAX)
1447         sprintbuf(left->_pb, "incompatible objects");
1448     else if (diffval != 0)
1449         sprintbuf(left->_pb, "%d", diffval);
1450     else
1451         sprintbuf(left->_pb, "");
1452     return left->_pb->buf;
1453 }
1454 
1455 char const *
1456 json_object_get_double_diff_string(struct json_object *left, struct json_object *right,
1457     double abstol, double reltol, double reltol_eps)
1458 {
1459     double diffval = json_object_get_double_diff(left, right, abstol, reltol, reltol_eps);
1460     /* MAJOR HACK. To be consistent with rest of json-c interface, we would like to return
1461      * a garbage collected string here. But, we're not going to create any new json
1462      * objects here. So, our solution is to use the left operand's printbuf to hold
1463      * the returned string. This is 'ok' because any future attempt to to_json_string()
1464      * on the left operand will reset the left opeand's printbuf before stringifying the
1465      * left operand json object. */
1466     printbuf_reset(left->_pb);
1467     if (diffval == -DBL_MAX)
1468         sprintbuf(left->_pb, "incompatible objects");
1469     else if (diffval != 0)
1470         sprintbuf(left->_pb, "%16g", diffval);
1471     else
1472         sprintbuf(left->_pb, "");
1473     return left->_pb->buf;
1474 }
1475 
1476 char const *
1477 json_object_get_string_diff_string(struct json_object *left, struct json_object *right)
1478 {
1479     return json_object_get_string_diff(left, right);
1480 }
1481 
1482 
1483 
1484 
1485 struct json_object *
1486 json_object_get_boolean_diff_object(struct json_object *left, struct json_object *right)
1487 {
1488     return json_object_new_boolean(json_object_get_boolean_diff(left, right));
1489 }
1490 
1491 struct json_object *
1492 json_object_get_int_diff_object(struct json_object *left, struct json_object *right,
1493     double abstol, double reltol, double reltol_eps)
1494 {
1495     return json_object_new_int(json_object_get_int_diff(left, right, abstol, reltol, reltol_eps));
1496 }
1497 
1498 struct json_object *
1499 json_object_get_double_diff_object(struct json_object *left, struct json_object *right,
1500     double abstol, double reltol, double reltol_eps)
1501 {
1502     return json_object_new_double(json_object_get_double_diff(left, right, abstol, reltol, reltol_eps));
1503 }
1504 
1505 struct json_object *
1506 json_object_get_string_diff_object(struct json_object *left, struct json_object *right)
1507 {
1508     return json_object_new_string(json_object_get_string_diff(left, right));
1509 }
1510 
1511 struct json_object *json_object_get_array_diff(struct json_object *left, struct json_object *right,
1512     double abstol, double reltol, double reltol_eps)
1513 {
1514     if (!json_object_is_type(left, json_type_array) ||
1515         !json_object_is_type(right, json_type_array))
1516         return json_object_invalid; /* invalid diff */
1517 
1518     leftlen = json_object_get_array_length(left);
1519     rightlen = json_object_get_array_length(right);
1520     if (leftlen > rightlen)
1521     {
1522         maxlen = leftlen;
1523         minlen = rightlen;
1524     }
1525     else
1526     {
1527         maxlen = rightlen;
1528         minlen = leftlen;
1529     }
1530 
1531     retval = json_object_new_array();
1532 
1533     for (i = 0; i < minlen; i++)
1534     {
1535         json_object_array_add(retval, json_object_object_get_diff());
1536     }
1537 
1538 }
1539 
1540 struct json_object *json_object_object_get_diff(struct json_object *left, struct json_object *right,
1541     double abstol, double reltol, double reltol_eps)
1542 {
1543     if (json_object_get_type(left) != json_object_get_type(right))
1544         return json_object_invalid; /* invalid diff */
1545 
1546     switch (json_object_get_type(left))
1547     {
1548         case json_type_null:
1549         {
1550             return json_type_null;
1551         }
1552         case json_type_boolean:
1553         {
1554              return json_object_get_boolean_diff_object(left, right);
1555         }
1556         case json_type_int:
1557         {
1558             return json_object_get_int_diff_object(left, right, abstol, reltol, reltol_eps);
1559         }
1560         case json_type_double:
1561         {
1562             return json_object_get_double_diff_object(left, right, abstol, reltol, reltol_eps);
1563         }
1564         case json_type_string:
1565         {
1566             return json_object_get_string_diff_object(left, right);
1567         }
1568         case json_type_array:
1569         {
1570             return json_object_get_array_diff_object(left, right, abstol, reltol, reltol_eps);
1571         }
1572         case json_type_object:
1573         {
1574             /* check for extptr case here */
1575         }
1576     }
1577 }
1578 
1579 
1580 int json_object_diff_object(struct json_object *objL, struct json_object *objR)
1581 {
1582     struct json_object_iterator jiter, jend;
1583 
1584     jiter = json_object_iter_begin(objL);
1585     jend = json_object_iter_end(objL);
1586     while (!json_object_iter_equal(&jiter, &jend))
1587     {
1588         char const *mnameL = json_object_iter_peek_name(&jiter);
1589         struct json_object *subobjL = json_object_iter_peek_value(&jiter);
1590         struct json_object *subobjR;
1591 
1592         if (!json_object_object_get_ex(objR, mnameL, &subobjR))
1593 
1594     }
1595 }
1596 #endif
1597 
1598 /* Return a Silo object as a Json Object. Bulk data passed using funky exptr */
1599 PUBLIC struct json_object *
DBGetJsonObject(DBfile * dbfile,char const * objname)1600 DBGetJsonObject(DBfile *dbfile, char const *objname)
1601 {
1602     int i;
1603     struct json_object *jobj = json_object_new_object();
1604     DBobject *sobj = DBGetObject(dbfile, objname);
1605     if (!sobj) return jobj;
1606 
1607     json_object_object_add(jobj, "silo_name", json_object_new_string(sobj->name));
1608     json_object_object_add(jobj, "silo_type", json_object_new_int(DBGetObjtypeTag(sobj->type)));
1609 
1610     for (i = 0; i < sobj->ncomponents; i++)
1611     {
1612         char cat_comp_name[1024];
1613         snprintf(cat_comp_name, sizeof(cat_comp_name), "%s_%s", objname, sobj->comp_names[i]);
1614              if (!strncmp(sobj->pdb_names[i], "'<i>", 4))
1615         {
1616             json_object_object_add(jobj, sobj->comp_names[i],
1617                 json_object_new_int(strtol(sobj->pdb_names[i]+4, NULL, 0)));
1618         }
1619         else if (!strncmp(sobj->pdb_names[i], "'<f>", 4))
1620         {
1621             json_object_object_add(jobj, sobj->comp_names[i],
1622                 json_object_new_double(strtod(sobj->pdb_names[i]+4, NULL)));
1623         }
1624         else if (!strncmp(sobj->pdb_names[i], "'<d>", 4))
1625         {
1626             json_object_object_add(jobj, sobj->comp_names[i],
1627                 json_object_new_double(strtod(sobj->pdb_names[i]+4, NULL)));
1628         }
1629         else if (!strncmp(sobj->pdb_names[i], "'<s>", 4))
1630         {
1631             char tmp[256];
1632             size_t len = strlen(sobj->pdb_names[i])-5;
1633             memset(tmp, 0, sizeof(tmp));
1634             strncpy(tmp, sobj->pdb_names[i]+4, len);
1635             if (DBInqVarExists(dbfile, tmp))
1636             {
1637                 if (DBInqVarType(dbfile, tmp) == DB_VARIABLE)
1638                 {
1639                     void *p;
1640                     int ndims, dims[32];
1641                     int dtype = DBGetVarType(dbfile, tmp);
1642                     ndims = DBGetVarDims(dbfile, tmp, sizeof(dims)/sizeof(dims[0]), dims);
1643                     p = DBGetVar(dbfile, tmp);
1644                     json_object_object_add(jobj, sobj->comp_names[i],
1645                         json_object_new_extptr(p, ndims, dims, dtype));
1646                 }
1647                 else
1648                 {
1649                     json_object_object_add(jobj, sobj->comp_names[i],
1650                         DBGetJsonObject(dbfile, tmp));
1651                 }
1652             }
1653             else
1654             {
1655                 json_object_object_add(jobj, sobj->comp_names[i],
1656                     json_object_new_string(tmp));
1657             }
1658         }
1659         else if (DBInqVarType(dbfile, cat_comp_name) == DB_VARIABLE)
1660         {
1661             void *p;
1662             int ndims, dims[32];
1663             int dtype = DBGetVarType(dbfile, cat_comp_name);
1664             ndims = DBGetVarDims(dbfile, cat_comp_name, sizeof(dims)/sizeof(dims[0]), dims);
1665             p = DBGetVar(dbfile, cat_comp_name);
1666             json_object_object_add(jobj, sobj->comp_names[i],
1667                 json_object_new_extptr(p, ndims, dims, dtype));
1668         }
1669         else if (DBInqVarExists(dbfile, sobj->comp_names[i]))
1670         {
1671             json_object_object_add(jobj, sobj->comp_names[i],
1672                 DBGetJsonObject(dbfile, sobj->comp_names[i]));
1673         }
1674         else /* some component we do not know how to handle */
1675         {
1676             json_object_object_add(jobj, sobj->comp_names[i],
1677                 json_object_new_string("<unknown>"));
1678         }
1679     }
1680     DBFreeObject(sobj);
1681     return jobj;
1682 }
1683 
DBWriteJsonObject(DBfile * dbfile,struct json_object * jobj)1684 int DBWriteJsonObject(DBfile *dbfile, struct json_object *jobj)
1685 {
1686     static int cnt = 0;
1687     int retval;
1688     DBobject *sobj;
1689     char objnm[256];
1690     struct json_object_iterator jiter, jend;
1691     memset(objnm, 0, sizeof(objnm));
1692     if (json_object_object_get_ex(jobj, "silo_type", 0) &&
1693         json_object_object_get_ex(jobj, "silo_name", 0))
1694     {
1695         json_object *silo_type_obj = json_object_object_get(jobj, "silo_type");
1696         json_object *silo_name_obj = json_object_object_get(jobj, "silo_name");
1697         strncpy(objnm, json_object_get_string(silo_name_obj), sizeof(objnm));
1698         sobj = DBMakeObject(objnm,
1699             json_object_get_int(silo_type_obj),
1700             json_object_object_length(jobj)+10
1701         );
1702     }
1703     else
1704     {
1705         snprintf(objnm, sizeof(objnm), "anon_%d", cnt++);
1706         sobj = DBMakeObject(objnm, DB_USERDEF, json_object_object_length(jobj)+10);
1707     }
1708     jiter = json_object_iter_begin(jobj);
1709     jend = json_object_iter_end(jobj);
1710 
1711     /* use foreachC macro instead */
1712     while (!json_object_iter_equal(&jiter, &jend))
1713     {
1714         struct json_object *mobj = json_object_iter_peek_value(&jiter);
1715         char const *mname = json_object_iter_peek_name(&jiter);
1716         json_type jtype = json_object_get_type(mobj);
1717 
1718         switch (jtype)
1719         {
1720             case json_type_array:
1721             case json_type_null: break;
1722 
1723             case json_type_boolean:
1724             case json_type_int:
1725             {
1726                 int val = 0;
1727                 if (jtype == json_type_boolean && json_object_get_boolean(mobj))
1728                     val = 1;
1729                 else
1730                     val = json_object_get_int(mobj);
1731                 DBAddIntComponent(sobj, mname, val);
1732                 break;
1733             }
1734             case json_type_double:
1735             {
1736                 DBAddDblComponent(sobj, mname, json_object_get_double(mobj));
1737                 break;
1738             }
1739             case json_type_string:
1740             {
1741                 if (strlen(json_object_get_string(mobj)))
1742                     DBAddStrComponent(sobj, mname, json_object_get_string(mobj));
1743                 break;
1744             }
1745 
1746 /* warning STRDUPS ARE LEAKS */
1747 
1748             case json_type_object: /* must be extptr array reference */
1749             {
1750                 if (json_object_object_get_ex(mobj, "ptr", 0) &&
1751                     json_object_object_get_ex(mobj, "datatype", 0) &&
1752                     json_object_object_get_ex(mobj, "ndims", 0) &&
1753                     json_object_object_get_ex(mobj, "dims", 0))
1754                 {
1755                     int i;
1756                     long dims[32];
1757                     void *p = json_object_get_strptr(json_object_object_get(mobj, "ptr"));
1758                     int datatype = json_object_get_int(json_object_object_get(mobj, "datatype"));
1759                     int ndims = json_object_get_int(json_object_object_get(mobj, "ndims"));
1760                     struct json_object *darr = json_object_object_get(mobj, "dims");
1761                     for (i = 0; i < ndims; i++)
1762                         dims[i] = (long) json_object_get_int(json_object_array_get_idx(darr, i));
1763                     DBWriteComponent(dbfile, sobj, mname, strdup(objnm),
1764                         db_GetDatatypeString(datatype), p, ndims, dims);
1765                 }
1766                 else
1767                 {
1768                     json_object *silo_type_subobj=0, *silo_name_subobj=0;
1769                     int has_silo_type, has_silo_name;
1770                     char tmp[32];
1771                     has_silo_type = json_object_object_get_ex(mobj, "silo_type", &silo_type_subobj);
1772                     has_silo_name = json_object_object_get_ex(mobj, "silo_name", &silo_name_subobj);
1773                     snprintf(tmp, sizeof(tmp), "anon_%d", cnt);
1774 
1775                     if (has_silo_name && has_silo_type)
1776                         DBAddStrComponent(sobj, mname, strdup(json_object_get_string(silo_name_subobj)));
1777                     else
1778                         DBAddStrComponent(sobj, mname, strdup(tmp));
1779                     DBWriteJsonObject(dbfile, mobj);
1780                 }
1781 
1782                 break;
1783             }
1784         }
1785         json_object_iter_next(&jiter);
1786     }
1787     retval = DBWriteObject(dbfile, sobj, 0);
1788     DBFreeObject(sobj);
1789     return retval;
1790 }
1791