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