Coverage Report

Created: 2026-10-28 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/external/libucl/src/ucl_emitter_utils.c
Line
Count
Source
1
/* Copyright (c) 2014, Vsevolod Stakhov
2
 * All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions are met:
6
 *       * Redistributions of source code must retain the above copyright
7
 *         notice, this list of conditions and the following disclaimer.
8
 *       * Redistributions in binary form must reproduce the above copyright
9
 *         notice, this list of conditions and the following disclaimer in the
10
 *         documentation and/or other materials provided with the distribution.
11
 *
12
 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
 */
23
24
#ifdef HAVE_CONFIG_H
25
#include "config.h"
26
#endif
27
28
#include "ucl.h"
29
#include "ucl_internal.h"
30
#include "ucl_chartable.h"
31
32
#ifdef HAVE_FLOAT_H
33
#include <float.h>
34
#endif
35
#ifdef HAVE_MATH_H
36
#include <math.h>
37
#endif
38
39
extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
40
41
static const struct ucl_emitter_context ucl_standard_emitters[] = {
42
  [UCL_EMIT_JSON] = {
43
    .name = "json",
44
    .id = UCL_EMIT_JSON,
45
    .func = NULL,
46
    .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON]},
47
  [UCL_EMIT_JSON_COMPACT] = {.name = "json_compact", .id = UCL_EMIT_JSON_COMPACT, .func = NULL, .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]},
48
  [UCL_EMIT_CONFIG] = {.name = "config", .id = UCL_EMIT_CONFIG, .func = NULL, .ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]},
49
  [UCL_EMIT_YAML] = {.name = "yaml", .id = UCL_EMIT_YAML, .func = NULL, .ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]},
50
  [UCL_EMIT_MSGPACK] = {.name = "msgpack", .id = UCL_EMIT_MSGPACK, .func = NULL, .ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]}};
51
52
static inline void
53
_ucl_emitter_free(void *p)
54
0
{
55
56
0
  free(p);
57
0
}
58
59
/**
60
 * Get standard emitter context for a specified emit_type
61
 * @param emit_type type of emitter
62
 * @return context or NULL if input is invalid
63
 */
64
const struct ucl_emitter_context *
65
ucl_emit_get_standard_context(enum ucl_emitter emit_type)
66
0
{
67
0
  if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {
68
0
    return &ucl_standard_emitters[emit_type];
69
0
  }
70
71
0
  return NULL;
72
0
}
73
74
/**
75
 * Serialise string
76
 * @param str string to emit
77
 * @param buf target buffer
78
 */
79
void ucl_elt_string_write_json(const char *str, size_t size,
80
                 struct ucl_emitter_context *ctx)
81
0
{
82
0
  const char *p = str, *c = str;
83
0
  size_t len = 0;
84
0
  const struct ucl_emitter_functions *func = ctx->func;
85
86
0
  func->ucl_emitter_append_character('"', 1, func->ud);
87
88
0
  while (size) {
89
0
    if (ucl_test_character(*p, (UCL_CHARACTER_JSON_UNSAFE |
90
0
                  UCL_CHARACTER_DENIED |
91
0
                  UCL_CHARACTER_WHITESPACE_UNSAFE))) {
92
0
      if (len > 0) {
93
0
        func->ucl_emitter_append_len(c, len, func->ud);
94
0
      }
95
0
      switch (*p) {
96
0
      case '\n':
97
0
        func->ucl_emitter_append_len("\\n", 2, func->ud);
98
0
        break;
99
0
      case '\r':
100
0
        func->ucl_emitter_append_len("\\r", 2, func->ud);
101
0
        break;
102
0
      case '\b':
103
0
        func->ucl_emitter_append_len("\\b", 2, func->ud);
104
0
        break;
105
0
      case '\t':
106
0
        func->ucl_emitter_append_len("\\t", 2, func->ud);
107
0
        break;
108
0
      case '\f':
109
0
        func->ucl_emitter_append_len("\\f", 2, func->ud);
110
0
        break;
111
0
      case '\v':
112
0
        func->ucl_emitter_append_len("\\u000B", 6, func->ud);
113
0
        break;
114
0
      case '\\':
115
0
        func->ucl_emitter_append_len("\\\\", 2, func->ud);
116
0
        break;
117
0
      case ' ':
118
0
        func->ucl_emitter_append_character(' ', 1, func->ud);
119
0
        break;
120
0
      case '"':
121
0
        func->ucl_emitter_append_len("\\\"", 2, func->ud);
122
0
        break;
123
0
      default:
124
        /* Emit unicode unknown character */
125
0
        func->ucl_emitter_append_len("\\uFFFD", 6, func->ud);
126
0
        break;
127
0
      }
128
0
      len = 0;
129
0
      c = ++p;
130
0
    }
131
0
    else {
132
0
      p++;
133
0
      len++;
134
0
    }
135
0
    size--;
136
0
  }
137
138
0
  if (len > 0) {
139
0
    func->ucl_emitter_append_len(c, len, func->ud);
140
0
  }
141
142
0
  func->ucl_emitter_append_character('"', 1, func->ud);
143
0
}
144
145
void ucl_elt_string_write_squoted(const char *str, size_t size,
146
                  struct ucl_emitter_context *ctx)
147
0
{
148
0
  const char *p = str, *c = str;
149
0
  size_t len = 0;
150
0
  const struct ucl_emitter_functions *func = ctx->func;
151
152
0
  func->ucl_emitter_append_character('\'', 1, func->ud);
153
154
0
  while (size) {
155
0
    if (*p == '\'') {
156
0
      if (len > 0) {
157
0
        func->ucl_emitter_append_len(c, len, func->ud);
158
0
      }
159
160
0
      len = 0;
161
0
      c = ++p;
162
0
      func->ucl_emitter_append_len("\\\'", 2, func->ud);
163
0
    }
164
0
    else {
165
0
      p++;
166
0
      len++;
167
0
    }
168
0
    size--;
169
0
  }
170
171
0
  if (len > 0) {
172
0
    func->ucl_emitter_append_len(c, len, func->ud);
173
0
  }
174
175
0
  func->ucl_emitter_append_character('\'', 1, func->ud);
176
0
}
177
178
void ucl_elt_string_write_multiline(const char *str, size_t size,
179
                  struct ucl_emitter_context *ctx)
180
0
{
181
0
  const struct ucl_emitter_functions *func = ctx->func;
182
183
0
  func->ucl_emitter_append_len("<<EOD\n", sizeof("<<EOD\n") - 1, func->ud);
184
0
  func->ucl_emitter_append_len(str, size, func->ud);
185
0
  func->ucl_emitter_append_len("\nEOD", sizeof("\nEOD") - 1, func->ud);
186
0
}
187
188
/*
189
 * Generic utstring output
190
 */
191
static int
192
ucl_utstring_append_character(unsigned char c, size_t len, void *ud)
193
0
{
194
0
  UT_string *buf = ud;
195
196
0
  if (len == 1) {
197
0
    utstring_append_c(buf, c);
198
0
  }
199
0
  else {
200
0
    utstring_reserve(buf, len + 1);
201
0
    memset(&buf->d[buf->i], c, len);
202
0
    buf->i += len;
203
0
    buf->d[buf->i] = '\0';
204
0
  }
205
206
0
  return 0;
207
0
}
208
209
static int
210
ucl_utstring_append_len(const unsigned char *str, size_t len, void *ud)
211
0
{
212
0
  UT_string *buf = ud;
213
214
0
  utstring_append_len(buf, str, len);
215
216
0
  return 0;
217
0
}
218
219
static int
220
ucl_utstring_append_int(int64_t val, void *ud)
221
0
{
222
0
  UT_string *buf = ud;
223
224
0
  utstring_printf(buf, "%jd", (intmax_t) val);
225
0
  return 0;
226
0
}
227
228
static int
229
ucl_utstring_append_double(double val, void *ud)
230
0
{
231
0
  UT_string *buf = ud;
232
0
  const double delta = 0.0000001;
233
234
0
  if (val == (double) (int) val) {
235
0
    utstring_printf(buf, "%.1lf", val);
236
0
  }
237
0
  else if (fabs(val - (double) (int) val) < delta) {
238
    /* Write at maximum precision */
239
0
    utstring_printf(buf, "%.*lg", DBL_DIG, val);
240
0
  }
241
0
  else {
242
0
    utstring_printf(buf, "%lf", val);
243
0
  }
244
245
0
  return 0;
246
0
}
247
248
/*
249
 * Generic file output
250
 */
251
static int
252
ucl_file_append_character(unsigned char c, size_t len, void *ud)
253
0
{
254
0
  FILE *fp = ud;
255
256
0
  while (len--) {
257
0
    fputc(c, fp);
258
0
  }
259
260
0
  return 0;
261
0
}
262
263
static int
264
ucl_file_append_len(const unsigned char *str, size_t len, void *ud)
265
0
{
266
0
  FILE *fp = ud;
267
268
0
  fwrite(str, len, 1, fp);
269
270
0
  return 0;
271
0
}
272
273
static int
274
ucl_file_append_int(int64_t val, void *ud)
275
0
{
276
0
  FILE *fp = ud;
277
278
0
  fprintf(fp, "%jd", (intmax_t) val);
279
280
0
  return 0;
281
0
}
282
283
static int
284
ucl_file_append_double(double val, void *ud)
285
0
{
286
0
  FILE *fp = ud;
287
0
  const double delta = 0.0000001;
288
289
0
  if (val == (double) (int) val) {
290
0
    fprintf(fp, "%.1lf", val);
291
0
  }
292
0
  else if (fabs(val - (double) (int) val) < delta) {
293
    /* Write at maximum precision */
294
0
    fprintf(fp, "%.*lg", DBL_DIG, val);
295
0
  }
296
0
  else {
297
0
    fprintf(fp, "%lf", val);
298
0
  }
299
300
0
  return 0;
301
0
}
302
303
/*
304
 * Generic file descriptor writing functions
305
 */
306
static int
307
ucl_fd_append_character(unsigned char c, size_t len, void *ud)
308
0
{
309
0
  int fd = *(int *) ud;
310
0
  unsigned char *buf;
311
312
0
  if (len == 1) {
313
0
    return write(fd, &c, 1);
314
0
  }
315
0
  else {
316
0
    buf = malloc(len);
317
0
    if (buf == NULL) {
318
      /* Fallback */
319
0
      while (len--) {
320
0
        if (write(fd, &c, 1) == -1) {
321
0
          return -1;
322
0
        }
323
0
      }
324
0
    }
325
0
    else {
326
0
      memset(buf, c, len);
327
0
      if (write(fd, buf, len) == -1) {
328
0
        free(buf);
329
0
        return -1;
330
0
      }
331
0
      free(buf);
332
0
    }
333
0
  }
334
335
0
  return 0;
336
0
}
337
338
static int
339
ucl_fd_append_len(const unsigned char *str, size_t len, void *ud)
340
0
{
341
0
  int fd = *(int *) ud;
342
343
0
  return write(fd, str, len);
344
0
}
345
346
static int
347
ucl_fd_append_int(int64_t val, void *ud)
348
0
{
349
0
  int fd = *(int *) ud;
350
0
  char intbuf[64];
351
352
0
  snprintf(intbuf, sizeof(intbuf), "%jd", (intmax_t) val);
353
0
  return write(fd, intbuf, strlen(intbuf));
354
0
}
355
356
static int
357
ucl_fd_append_double(double val, void *ud)
358
0
{
359
0
  int fd = *(int *) ud;
360
0
  const double delta = 0.0000001;
361
0
  char nbuf[64];
362
363
0
  if (val == (double) (int) val) {
364
0
    snprintf(nbuf, sizeof(nbuf), "%.1lf", val);
365
0
  }
366
0
  else if (fabs(val - (double) (int) val) < delta) {
367
    /* Write at maximum precision */
368
0
    snprintf(nbuf, sizeof(nbuf), "%.*lg", DBL_DIG, val);
369
0
  }
370
0
  else {
371
0
    snprintf(nbuf, sizeof(nbuf), "%lf", val);
372
0
  }
373
374
0
  return write(fd, nbuf, strlen(nbuf));
375
0
}
376
377
struct ucl_emitter_functions *
378
ucl_object_emit_memory_funcs(void **pmem)
379
0
{
380
0
  struct ucl_emitter_functions *f;
381
0
  UT_string *s;
382
383
0
  f = calloc(1, sizeof(*f));
384
385
0
  if (f != NULL) {
386
0
    f->ucl_emitter_append_character = ucl_utstring_append_character;
387
0
    f->ucl_emitter_append_double = ucl_utstring_append_double;
388
0
    f->ucl_emitter_append_int = ucl_utstring_append_int;
389
0
    f->ucl_emitter_append_len = ucl_utstring_append_len;
390
0
    f->ucl_emitter_free_func = _ucl_emitter_free;
391
0
    utstring_new(s);
392
0
    f->ud = s;
393
0
    *pmem = s->d;
394
0
    s->pd = pmem;
395
0
  }
396
397
0
  return f;
398
0
}
399
400
struct ucl_emitter_functions *
401
ucl_object_emit_file_funcs(FILE *fp)
402
0
{
403
0
  struct ucl_emitter_functions *f;
404
405
0
  f = calloc(1, sizeof(*f));
406
407
0
  if (f != NULL) {
408
0
    f->ucl_emitter_append_character = ucl_file_append_character;
409
0
    f->ucl_emitter_append_double = ucl_file_append_double;
410
0
    f->ucl_emitter_append_int = ucl_file_append_int;
411
0
    f->ucl_emitter_append_len = ucl_file_append_len;
412
0
    f->ucl_emitter_free_func = NULL;
413
0
    f->ud = fp;
414
0
  }
415
416
0
  return f;
417
0
}
418
419
struct ucl_emitter_functions *
420
ucl_object_emit_fd_funcs(int fd)
421
0
{
422
0
  struct ucl_emitter_functions *f;
423
0
  int *ip;
424
425
0
  f = calloc(1, sizeof(*f));
426
427
0
  if (f != NULL) {
428
0
    ip = malloc(sizeof(fd));
429
0
    if (ip == NULL) {
430
0
      free(f);
431
0
      return NULL;
432
0
    }
433
434
0
    memcpy(ip, &fd, sizeof(fd));
435
0
    f->ucl_emitter_append_character = ucl_fd_append_character;
436
0
    f->ucl_emitter_append_double = ucl_fd_append_double;
437
0
    f->ucl_emitter_append_int = ucl_fd_append_int;
438
0
    f->ucl_emitter_append_len = ucl_fd_append_len;
439
0
    f->ucl_emitter_free_func = _ucl_emitter_free;
440
0
    f->ud = ip;
441
0
  }
442
443
0
  return f;
444
0
}
445
446
void ucl_object_emit_funcs_free(struct ucl_emitter_functions *f)
447
0
{
448
0
  if (f != NULL) {
449
0
    if (f->ucl_emitter_free_func != NULL) {
450
0
      f->ucl_emitter_free_func(f->ud);
451
0
    }
452
0
    free(f);
453
0
  }
454
0
}
455
456
457
unsigned char *
458
ucl_object_emit_single_json(const ucl_object_t *obj)
459
0
{
460
0
  UT_string *buf = NULL;
461
0
  unsigned char *res = NULL;
462
463
0
  if (obj == NULL) {
464
0
    return NULL;
465
0
  }
466
467
0
  utstring_new(buf);
468
469
0
  if (buf != NULL) {
470
0
    switch (obj->type) {
471
0
    case UCL_OBJECT:
472
0
      ucl_utstring_append_len("object", 6, buf);
473
0
      break;
474
0
    case UCL_ARRAY:
475
0
      ucl_utstring_append_len("array", 5, buf);
476
0
      break;
477
0
    case UCL_INT:
478
0
      ucl_utstring_append_int(obj->value.iv, buf);
479
0
      break;
480
0
    case UCL_FLOAT:
481
0
    case UCL_TIME:
482
0
      ucl_utstring_append_double(obj->value.dv, buf);
483
0
      break;
484
0
    case UCL_NULL:
485
0
      ucl_utstring_append_len("null", 4, buf);
486
0
      break;
487
0
    case UCL_BOOLEAN:
488
0
      if (obj->value.iv) {
489
0
        ucl_utstring_append_len("true", 4, buf);
490
0
      }
491
0
      else {
492
0
        ucl_utstring_append_len("false", 5, buf);
493
0
      }
494
0
      break;
495
0
    case UCL_STRING:
496
0
      ucl_utstring_append_len(obj->value.sv, obj->len, buf);
497
0
      break;
498
0
    case UCL_USERDATA:
499
0
      ucl_utstring_append_len("userdata", 8, buf);
500
0
      break;
501
0
    }
502
0
    res = utstring_body(buf);
503
0
    free(buf);
504
0
  }
505
506
0
  return res;
507
0
}
508
509
0
#define LONG_STRING_LIMIT 80
510
511
bool ucl_maybe_long_string(const ucl_object_t *obj)
512
0
{
513
0
  if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {
514
    /* String is long enough, so search for newline characters in it */
515
0
    if (memchr(obj->value.sv, '\n', obj->len) != NULL) {
516
0
      return true;
517
0
    }
518
0
  }
519
520
0
  return false;
521
0
}