Coverage Report

Created: 2024-07-23 06:12

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