Line data Source code
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 "strerror_override.h"
16 :
17 : #include <ctype.h>
18 : #include <limits.h>
19 : #include <stdarg.h>
20 : #include <stddef.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 :
25 : #ifdef HAVE_SYS_TYPES_H
26 : #include <sys/types.h>
27 : #endif /* HAVE_SYS_TYPES_H */
28 :
29 : #ifdef HAVE_SYS_STAT_H
30 : #include <sys/stat.h>
31 : #endif /* HAVE_SYS_STAT_H */
32 :
33 : #ifdef HAVE_FCNTL_H
34 : #include <fcntl.h>
35 : #endif /* HAVE_FCNTL_H */
36 :
37 : #ifdef HAVE_UNISTD_H
38 : #include <unistd.h>
39 : #endif /* HAVE_UNISTD_H */
40 :
41 : #ifdef _WIN32
42 : #define WIN32_LEAN_AND_MEAN
43 : #include <io.h>
44 : #include <windows.h>
45 : #endif /* defined(_WIN32) */
46 :
47 : #if !defined(HAVE_OPEN) && defined(_WIN32)
48 : #define open _open
49 : #endif
50 :
51 : #include "snprintf_compat.h"
52 :
53 : #include "debug.h"
54 : #include "json_inttypes.h"
55 : #include "json_object.h"
56 : #include "json_object_private.h"
57 : #include "json_tokener.h"
58 : #include "json_util.h"
59 : #include "printbuf.h"
60 :
61 : #include "cpl_string.h"
62 :
63 : #if 0
64 : static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename);
65 : #endif
66 :
67 : static char _last_err[256] = "";
68 :
69 0 : const char *json_util_get_last_err()
70 : {
71 0 : if (_last_err[0] == '\0')
72 0 : return NULL;
73 0 : return _last_err;
74 : }
75 :
76 1 : void _json_c_set_last_err(const char *err_fmt, ...)
77 : {
78 : va_list ap;
79 1 : va_start(ap, err_fmt);
80 : // Ignore (attempted) overruns from snprintf
81 1 : (void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap);
82 1 : va_end(ap);
83 1 : }
84 :
85 0 : struct json_object *json_object_from_fd(int fd)
86 : {
87 0 : return json_object_from_fd_ex(fd, -1);
88 : }
89 0 : struct json_object *json_object_from_fd_ex(int fd, int in_depth)
90 : {
91 : struct printbuf *pb;
92 : struct json_object *obj;
93 : char buf[JSON_FILE_BUF_SIZE];
94 : int ret;
95 0 : int depth = JSON_TOKENER_DEFAULT_DEPTH;
96 : json_tokener *tok;
97 :
98 0 : if (!(pb = printbuf_new()))
99 : {
100 0 : _json_c_set_last_err("json_object_from_file: printbuf_new failed\n");
101 0 : return NULL;
102 : }
103 :
104 0 : if (in_depth != -1)
105 0 : depth = in_depth;
106 0 : tok = json_tokener_new_ex(depth);
107 0 : if (!tok)
108 : {
109 0 : _json_c_set_last_err(
110 : "json_object_from_fd: unable to allocate json_tokener(depth=%d): %s\n", depth,
111 0 : strerror(errno));
112 0 : printbuf_free(pb);
113 0 : return NULL;
114 : }
115 :
116 0 : while ((ret = (int)read(fd, buf, JSON_FILE_BUF_SIZE)) > 0)
117 : {
118 0 : printbuf_memappend(pb, buf, ret);
119 : }
120 0 : if (ret < 0)
121 : {
122 0 : _json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd,
123 0 : strerror(errno));
124 0 : json_tokener_free(tok);
125 0 : printbuf_free(pb);
126 0 : return NULL;
127 : }
128 :
129 0 : obj = json_tokener_parse_ex(tok, pb->buf, printbuf_length(pb));
130 0 : if (obj == NULL)
131 0 : _json_c_set_last_err("json_tokener_parse_ex failed: %s\n",
132 : json_tokener_error_desc(json_tokener_get_error(tok)));
133 :
134 0 : json_tokener_free(tok);
135 0 : printbuf_free(pb);
136 0 : return obj;
137 : }
138 :
139 0 : struct json_object *json_object_from_file(const char *filename)
140 : {
141 : struct json_object *obj;
142 : int fd;
143 :
144 0 : if ((fd = open(filename, O_RDONLY)) < 0)
145 : {
146 0 : _json_c_set_last_err("json_object_from_file: error opening file %s: %s\n", filename,
147 0 : strerror(errno));
148 0 : return NULL;
149 : }
150 0 : obj = json_object_from_fd(fd);
151 0 : close(fd);
152 0 : return obj;
153 : }
154 :
155 : // Unused by GDAL, and avoid a Coverity Scan warning in _json_object_to_fd()s
156 : #if 0
157 : /* extended "format and write to file" function */
158 : int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags)
159 : {
160 : int fd, ret;
161 : int saved_errno;
162 :
163 : if (!obj)
164 : {
165 : _json_c_set_last_err("json_object_to_file: object is null\n");
166 : return -1;
167 : }
168 :
169 : if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0)
170 : {
171 : _json_c_set_last_err("json_object_to_file: error opening file %s: %s\n", filename,
172 : strerror(errno));
173 : return -1;
174 : }
175 : ret = _json_object_to_fd(fd, obj, flags, filename);
176 : saved_errno = errno;
177 : close(fd);
178 : errno = saved_errno;
179 : return ret;
180 : }
181 :
182 : int json_object_to_fd(int fd, struct json_object *obj, int flags)
183 : {
184 : if (!obj)
185 : {
186 : _json_c_set_last_err("json_object_to_fd: object is null\n");
187 : return -1;
188 : }
189 :
190 : return _json_object_to_fd(fd, obj, flags, NULL);
191 : }
192 : static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename)
193 : {
194 : ssize_t ret;
195 : const char *json_str;
196 : unsigned int wpos, wsize;
197 :
198 : filename = filename ? filename : "(fd)";
199 :
200 : if (!(json_str = json_object_to_json_string_ext(obj, flags)))
201 : {
202 : return -1;
203 : }
204 :
205 : /* CAW: probably unnecessary, but the most 64bit safe */
206 : wsize = (unsigned int)(strlen(json_str) & UINT_MAX);
207 : wpos = 0;
208 : while (wpos < wsize)
209 : {
210 : /* coverity[overflow_sink] */
211 : if ((ret = write(fd, json_str + wpos, wsize - wpos)) < 0)
212 : {
213 : _json_c_set_last_err("json_object_to_file: error writing file %s: %s\n",
214 : filename, strerror(errno));
215 : return -1;
216 : }
217 :
218 : /* because of the above check for ret < 0, we can safely cast and add */
219 : wpos += (unsigned int)ret;
220 : }
221 :
222 : return 0;
223 : }
224 :
225 : // backwards compatible "format and write to file" function
226 :
227 : int json_object_to_file(const char *filename, struct json_object *obj)
228 : {
229 : return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
230 : }
231 : #endif
232 :
233 : // Deprecated json_parse_double function. See json_tokener_parse_double instead.
234 0 : int json_parse_double(const char *buf, double *retval)
235 : {
236 : char *end;
237 0 : *retval = CPLStrtod(buf, &end);
238 0 : return end == buf ? 1 : 0;
239 : }
240 :
241 35898 : int json_parse_int64(const char *buf, int64_t *retval)
242 : {
243 35898 : char *end = NULL;
244 : int64_t val;
245 :
246 35898 : errno = 0;
247 35898 : val = strtoll(buf, &end, 10);
248 35898 : if (end != buf)
249 35897 : *retval = val;
250 35898 : return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0;
251 : }
252 :
253 493551 : int json_parse_uint64(const char *buf, uint64_t *retval)
254 : {
255 493551 : char *end = NULL;
256 : uint64_t val;
257 :
258 493551 : errno = 0;
259 493551 : while (*buf == ' ')
260 0 : buf++;
261 493551 : if (*buf == '-')
262 0 : return 1; /* error: uint cannot be negative */
263 :
264 493551 : val = strtoull(buf, &end, 10);
265 493551 : if (end != buf)
266 493551 : *retval = val;
267 493551 : return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0;
268 : }
269 :
270 : #ifndef HAVE_REALLOC
271 : void *rpl_realloc(void *p, size_t n)
272 : {
273 : if (n == 0)
274 : n = 1;
275 : if (p == 0)
276 : return malloc(n);
277 : return realloc(p, n);
278 : }
279 : #endif
280 :
281 : #define NELEM(a) (sizeof(a) / sizeof(a[0]))
282 : /* clang-format off */
283 : static const char *json_type_name[] = {
284 : /* If you change this, be sure to update the enum json_type definition too */
285 : "null",
286 : "boolean",
287 : "double",
288 : "int",
289 : "object",
290 : "array",
291 : "string",
292 : };
293 : /* clang-format on */
294 :
295 0 : const char *json_type_to_name(enum json_type o_type)
296 : {
297 0 : int o_type_int = (int)o_type;
298 0 : if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))
299 : {
300 0 : _json_c_set_last_err("json_type_to_name: type %d is out of range [0,%u]\n", o_type,
301 : (unsigned)NELEM(json_type_name));
302 0 : return NULL;
303 : }
304 0 : return json_type_name[o_type];
305 : }
|