MACSio  0.9
Multi-purpose, Application-Centric, Scalable I/O Proxy App
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
json_util.c
Go to the documentation of this file.
1 /*
2  * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $
3  *
4  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
5  * Michael Clark <michael@metaparadigm.com>
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the MIT license. See COPYING for details.
9  *
10  */
11 
12 #include "config.h"
13 #undef realloc
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stddef.h>
18 #include <limits.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <ctype.h>
22 
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif /* HAVE_SYS_TYPES_H */
26 
27 #ifdef HAVE_SYS_STAT_H
28 #include <sys/stat.h>
29 #endif /* HAVE_SYS_STAT_H */
30 
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif /* HAVE_FCNTL_H */
34 
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 
39 #ifdef WIN32
40 # define WIN32_LEAN_AND_MEAN
41 # include <windows.h>
42 # include <io.h>
43 #endif /* defined(WIN32) */
44 
45 #if !defined(HAVE_OPEN) && defined(WIN32)
46 # define open _open
47 #endif
48 
49 #if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)
50  /* MSC has the version as _snprintf */
51 # define snprintf _snprintf
52 #elif !defined(HAVE_SNPRINTF)
53 # error You do not have snprintf on your system.
54 #endif /* HAVE_SNPRINTF */
55 
56 #include "bits.h"
57 #include "debug.h"
58 #include "printbuf.h"
59 #include "json_inttypes.h"
60 #include "json_object.h"
61 #include "json_tokener.h"
62 #include "json_util.h"
63 
64 static int sscanf_is_broken = 0;
66 static void sscanf_is_broken_test(void);
67 
69 {
70  struct printbuf *pb;
71  struct json_object *obj;
72  char buf[JSON_FILE_BUF_SIZE];
73  int fd, ret;
74 
75  if((fd = open(filename, O_RDONLY)) < 0) {
76  MC_ERROR("json_object_from_file: error opening file %s: %s\n",
77  filename, strerror(errno));
78  return NULL;
79  }
80  if(!(pb = printbuf_new())) {
81  close(fd);
82  MC_ERROR("json_object_from_file: printbuf_new failed\n");
83  return NULL;
84  }
85  while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
86  printbuf_memappend(pb, buf, ret);
87  }
88  close(fd);
89  if(ret < 0) {
90  MC_ERROR("json_object_from_file: error reading file %s: %s\n",
91  filename, strerror(errno));
92  printbuf_free(pb);
93  return NULL;
94  }
95  obj = json_tokener_parse(pb->buf);
96  printbuf_free(pb);
97  return obj;
98 }
99 
100 /* extended "format and write to file" function */
101 
102 int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags)
103 {
104  const char *json_str;
105  int fd, ret;
106  unsigned int wpos, wsize;
107 
108  if(!obj) {
109  MC_ERROR("json_object_to_file: object is null\n");
110  return -1;
111  }
112 
113  if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
114  MC_ERROR("json_object_to_file: error opening file %s: %s\n",
115  filename, strerror(errno));
116  return -1;
117  }
118 
119  if(!(json_str = json_object_to_json_string_ext(obj,flags))) {
120  close(fd);
121  return -1;
122  }
123 
124  wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
125  wpos = 0;
126  while(wpos < wsize) {
127  if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
128  close(fd);
129  MC_ERROR("json_object_to_file: error writing file %s: %s\n",
130  filename, strerror(errno));
131  return -1;
132  }
133 
134  /* because of the above check for ret < 0, we can safely cast and add */
135  wpos += (unsigned int)ret;
136  }
137 
138  close(fd);
139  return 0;
140 }
141 
142 // backwards compatible "format and write to file" function
143 
144 int json_object_to_file(const char *filename, struct json_object *obj)
145 {
146  return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
147 }
148 
149 int json_parse_double(const char *buf, double *retval)
150 {
151  return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
152 }
153 
154 /*
155  * Not all implementations of sscanf actually work properly.
156  * Check whether the one we're currently using does, and if
157  * it's broken, enable the workaround code.
158  */
160 {
161  int64_t num64;
162  int ret_errno, is_int64_min, ret_errno2, is_int64_max;
163 
164  (void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64);
165  ret_errno = errno;
166 #ifdef INT64_MIN
167  is_int64_min = (num64 == INT64_MIN);
168 #else
169  is_int64_min = (num64 == INT_MIN);
170 #endif
171 
172  (void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64);
173  ret_errno2 = errno;
174 #ifdef INT64_MAX
175  is_int64_max = (num64 == INT64_MAX);
176 #else
177  is_int64_max = (num64 == INT_MAX);
178 #endif
179 
180  if (ret_errno != ERANGE || !is_int64_min ||
181  ret_errno2 != ERANGE || !is_int64_max)
182  {
183  MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n");
184  sscanf_is_broken = 1;
185  }
186 }
187 
188 int json_parse_int64(const char *buf, int64_t *retval)
189 {
190  int64_t num64;
191  const char *buf_sig_digits;
192  int orig_has_neg;
193  int saved_errno;
194 
196  {
199  }
200 
201  // Skip leading spaces
202  while (isspace((int)*buf) && *buf)
203  buf++;
204 
205  errno = 0; // sscanf won't always set errno, so initialize
206  if (sscanf(buf, "%" SCNd64, &num64) != 1)
207  {
208  MC_DEBUG("Failed to parse, sscanf != 1\n");
209  return 1;
210  }
211 
212  saved_errno = errno;
213  buf_sig_digits = buf;
214  orig_has_neg = 0;
215  if (*buf_sig_digits == '-')
216  {
217  buf_sig_digits++;
218  orig_has_neg = 1;
219  }
220 
221  // Not all sscanf implementations actually work
222  if (sscanf_is_broken && saved_errno != ERANGE)
223  {
224  char buf_cmp[100];
225  char *buf_cmp_start = buf_cmp;
226  int recheck_has_neg = 0;
227  int buf_cmp_len;
228 
229  // Skip leading zeros, but keep at least one digit
230  while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0')
231  buf_sig_digits++;
232  if (num64 == 0) // assume all sscanf impl's will parse -0 to 0
233  orig_has_neg = 0; // "-0" is the same as just plain "0"
234 
235  snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
236  if (*buf_cmp_start == '-')
237  {
238  recheck_has_neg = 1;
239  buf_cmp_start++;
240  }
241  // No need to skip leading spaces or zeros here.
242 
243  buf_cmp_len = strlen(buf_cmp_start);
250  if (orig_has_neg != recheck_has_neg ||
251  strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
252  ((int)strlen(buf_sig_digits) != buf_cmp_len &&
253  isdigit((int)buf_sig_digits[buf_cmp_len])
254  )
255  )
256  {
257  saved_errno = ERANGE;
258  }
259  }
260 
261  // Not all sscanf impl's set the value properly when out of range.
262  // Always do this, even for properly functioning implementations,
263  // since it shouldn't slow things down much.
264  if (saved_errno == ERANGE)
265  {
266  if (orig_has_neg)
267 #ifdef INT64_MIN
268  num64 = INT64_MIN;
269 #else
270  num64 = INT_MIN;
271 #endif
272  else
273 #ifdef INT64_MAX
274  num64 = INT64_MAX;
275 #else
276  num64 = INT_MAX;
277 #endif
278  }
279  *retval = num64;
280  return 0;
281 }
282 
283 #ifndef HAVE_REALLOC
284 void* rpl_realloc(void* p, size_t n)
285 {
286  if (n == 0)
287  n = 1;
288  if (p == 0)
289  return malloc(n);
290  return realloc(p, n);
291 }
292 #endif
293 
294 #define NELEM(a) (sizeof(a) / sizeof(a[0]))
295 static const char* json_type_name[] = {
296  /* If you change this, be sure to update the enum json_type definition too */
297  "null",
298  "boolean",
299  "double",
300  "int",
301  "object",
302  "array",
303  "string",
304  "extarr",
305  "enum"
306 };
307 
309 {
310  int o_type_int = (int)o_type;
311  if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))
312  {
313  MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name));
314  return NULL;
315  }
316  return json_type_name[o_type];
317 }
318 
319 static const char* json_extarr_type_name[] = {
320  /* If you change this, be sure to update the enum json_extarr_type definition too */
321  "null",
322  "bit01",
323  "byt08",
324  "int32",
325  "int64",
326  "flot32",
327  "flt64"
328 };
329 
331 {
332  int o_type_int = (int)o_type;
333  if (o_type_int < 0 || o_type_int >= (int)NELEM(json_extarr_type_name))
334  {
335  MC_ERROR("json_extarr_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_extarr_type_name));
336  return NULL;
337  }
339 }
340 
342 {
343  switch (o_type)
344  {
345  case json_extarr_type_null: return 0;
346  case json_extarr_type_bit01: return 1;
347  case json_extarr_type_byt08: return 8;
348  case json_extarr_type_int32: return 32;
349  case json_extarr_type_int64: return 64;
350  case json_extarr_type_flt32: return 32;
351  case json_extarr_type_flt64: return 64;
352  }
353  return -1;
354 }
355 
357 {
358  int nbits = json_extarr_type_nbits(o_type);
359  if (nbits <= 0) return -1;
360  return nbits / 8;
361 }
#define PRId64
Definition: json_inttypes.h:23
static const char * filename
Definition: macsio_hdf5.c:683
const char * json_extarr_type_to_name(enum json_extarr_type o_type)
Definition: json_util.c:330
#define JSON_FILE_BUF_SIZE
Definition: json_util.h:21
int json_parse_double(const char *buf, double *retval)
Definition: json_util.c:149
int json_object_to_file(const char *filename, struct json_object *obj)
Definition: json_util.c:144
int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags)
Definition: json_util.c:102
int json_parse_int64(const char *buf, int64_t *retval)
Definition: json_util.c:188
static int sscanf_is_broken_testdone
Definition: json_util.c:65
static const char * json_extarr_type_name[]
Definition: json_util.c:319
const char * json_type_to_name(enum json_type o_type)
Definition: json_util.c:308
int json_extarr_type_nbits(enum json_extarr_type o_type)
Definition: json_util.c:341
struct printbuf * printbuf_new(void)
Definition: printbuf.c:34
void * rpl_realloc(void *p, size_t n)
Definition: json_util.c:284
json_extarr_type
Definition: json_object.h:120
static const char * json_type_name[]
Definition: json_util.c:295
#define MC_ERROR(x,...)
Definition: debug.h:51
enum json_type o_type
int json_extarr_type_nbytes(enum json_extarr_type o_type)
Definition: json_util.c:356
void printbuf_free(struct printbuf *p)
Definition: printbuf.c:186
int printbuf_memappend(struct printbuf *p, const char *buf, int size)
Definition: printbuf.c:79
static void sscanf_is_broken_test(void)
Definition: json_util.c:159
static int sscanf_is_broken
Definition: json_util.c:64
char * buf
Definition: printbuf.h:24
#define MC_DEBUG(x,...)
Definition: debug.h:63
#define SCNd64
Definition: json_inttypes.h:26
#define NELEM(a)
Definition: json_util.c:294
const char * json_object_to_json_string_ext(struct json_object *obj, int flags)
Definition: json_object.c:277
struct json_object * json_tokener_parse(const char *str)
Definition: json_tokener.c:158
#define JSON_C_TO_STRING_PLAIN
Definition: json_object.h:40
json_type
Definition: json_object.h:107
struct json_object * json_object_from_file(const char *filename)
Definition: json_util.c:68