Coverage Report

Created: 2025-06-13 06:35

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