Coverage Report

Created: 2026-02-26 06:48

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
  },
48
  [UCL_EMIT_JSON_COMPACT] = {
49
    .name = "json_compact",
50
    .id = UCL_EMIT_JSON_COMPACT,
51
    .func = NULL,
52
    .ops = &ucl_standartd_emitter_ops[UCL_EMIT_JSON_COMPACT]
53
  },
54
  [UCL_EMIT_CONFIG] = {
55
    .name = "config",
56
    .id = UCL_EMIT_CONFIG,
57
    .func = NULL,
58
    .ops = &ucl_standartd_emitter_ops[UCL_EMIT_CONFIG]
59
  },
60
  [UCL_EMIT_YAML] = {
61
    .name = "yaml",
62
    .id = UCL_EMIT_YAML,
63
    .func = NULL,
64
    .ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML]
65
  },
66
  [UCL_EMIT_MSGPACK] = {
67
    .name = "msgpack",
68
    .id = UCL_EMIT_MSGPACK,
69
    .func = NULL,
70
    .ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK]
71
  }
72
};
73
74
static inline void
75
_ucl_emitter_free(void *p)
76
0
{
77
78
0
    free(p);
79
0
}
80
81
/**
82
 * Get standard emitter context for a specified emit_type
83
 * @param emit_type type of emitter
84
 * @return context or NULL if input is invalid
85
 */
86
const struct ucl_emitter_context *
87
ucl_emit_get_standard_context (enum ucl_emitter emit_type)
88
0
{
89
0
  if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) {
90
0
    return &ucl_standard_emitters[emit_type];
91
0
  }
92
93
0
  return NULL;
94
0
}
95
96
/**
97
 * Serialise string
98
 * @param str string to emit
99
 * @param buf target buffer
100
 */
101
void
102
ucl_elt_string_write_json (const char *str, size_t size,
103
    struct ucl_emitter_context *ctx)
104
0
{
105
0
  const char *p = str, *c = str;
106
0
  size_t len = 0;
107
0
  const struct ucl_emitter_functions *func = ctx->func;
108
109
0
  func->ucl_emitter_append_character ('"', 1, func->ud);
110
111
0
  while (size) {
112
0
    if (ucl_test_character (*p, (UCL_CHARACTER_JSON_UNSAFE|
113
0
        UCL_CHARACTER_DENIED|
114
0
        UCL_CHARACTER_WHITESPACE_UNSAFE))) {
115
0
      if (len > 0) {
116
0
        func->ucl_emitter_append_len (c, len, func->ud);
117
0
      }
118
0
      switch (*p) {
119
0
      case '\n':
120
0
        func->ucl_emitter_append_len ("\\n", 2, func->ud);
121
0
        break;
122
0
      case '\r':
123
0
        func->ucl_emitter_append_len ("\\r", 2, func->ud);
124
0
        break;
125
0
      case '\b':
126
0
        func->ucl_emitter_append_len ("\\b", 2, func->ud);
127
0
        break;
128
0
      case '\t':
129
0
        func->ucl_emitter_append_len ("\\t", 2, func->ud);
130
0
        break;
131
0
      case '\f':
132
0
        func->ucl_emitter_append_len ("\\f", 2, func->ud);
133
0
        break;
134
0
      case '\v':
135
0
        func->ucl_emitter_append_len ("\\u000B", 6, func->ud);
136
0
        break;
137
0
      case '\\':
138
0
        func->ucl_emitter_append_len ("\\\\", 2, func->ud);
139
0
        break;
140
0
      case ' ':
141
0
        func->ucl_emitter_append_character (' ', 1, func->ud);
142
0
        break;
143
0
      case '"':
144
0
        func->ucl_emitter_append_len ("\\\"", 2, func->ud);
145
0
        break;
146
0
      default:
147
        /* Emit unicode unknown character */
148
0
        func->ucl_emitter_append_len ("\\uFFFD", 6, func->ud);
149
0
        break;
150
0
      }
151
0
      len = 0;
152
0
      c = ++p;
153
0
    }
154
0
    else {
155
0
      p ++;
156
0
      len ++;
157
0
    }
158
0
    size --;
159
0
  }
160
161
0
  if (len > 0) {
162
0
    func->ucl_emitter_append_len (c, len, func->ud);
163
0
  }
164
165
0
  func->ucl_emitter_append_character ('"', 1, func->ud);
166
0
}
167
168
void
169
ucl_elt_string_write_squoted (const char *str, size_t size,
170
    struct ucl_emitter_context *ctx)
171
0
{
172
0
  const char *p = str, *c = str;
173
0
  size_t len = 0;
174
0
  const struct ucl_emitter_functions *func = ctx->func;
175
176
0
  func->ucl_emitter_append_character ('\'', 1, func->ud);
177
178
0
  while (size) {
179
0
    if (*p == '\'') {
180
0
      if (len > 0) {
181
0
        func->ucl_emitter_append_len (c, len, func->ud);
182
0
      }
183
184
0
      len = 0;
185
0
      c = ++p;
186
0
      func->ucl_emitter_append_len ("\\\'", 2, func->ud);
187
0
    }
188
0
    else {
189
0
      p ++;
190
0
      len ++;
191
0
    }
192
0
    size --;
193
0
  }
194
195
0
  if (len > 0) {
196
0
    func->ucl_emitter_append_len (c, len, func->ud);
197
0
  }
198
199
0
  func->ucl_emitter_append_character ('\'', 1, func->ud);
200
0
}
201
202
void
203
ucl_elt_string_write_multiline (const char *str, size_t size,
204
    struct ucl_emitter_context *ctx)
205
0
{
206
0
  const struct ucl_emitter_functions *func = ctx->func;
207
208
0
  func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud);
209
0
  func->ucl_emitter_append_len (str, size, func->ud);
210
0
  func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud);
211
0
}
212
213
/*
214
 * Generic utstring output
215
 */
216
static int
217
ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
218
0
{
219
0
  UT_string *buf = ud;
220
221
0
  if (len == 1) {
222
0
    utstring_append_c (buf, c);
223
0
  }
224
0
  else {
225
0
    utstring_reserve (buf, len + 1);
226
0
    memset (&buf->d[buf->i], c, len);
227
0
    buf->i += len;
228
0
    buf->d[buf->i] = '\0';
229
0
  }
230
231
0
  return 0;
232
0
}
233
234
static int
235
ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud)
236
0
{
237
0
  UT_string *buf = ud;
238
239
0
  utstring_append_len (buf, str, len);
240
241
0
  return 0;
242
0
}
243
244
static int
245
ucl_utstring_append_int (int64_t val, void *ud)
246
0
{
247
0
  UT_string *buf = ud;
248
249
0
  utstring_printf (buf, "%jd", (intmax_t)val);
250
0
  return 0;
251
0
}
252
253
static int
254
ucl_utstring_append_double (double val, void *ud)
255
0
{
256
0
  UT_string *buf = ud;
257
0
  const double delta = 0.0000001;
258
259
0
  if (val == (double)(int)val) {
260
0
    utstring_printf (buf, "%.1lf", val);
261
0
  }
262
0
  else if (fabs (val - (double)(int)val) < delta) {
263
    /* Write at maximum precision */
264
0
    utstring_printf (buf, "%.*lg", DBL_DIG, val);
265
0
  }
266
0
  else {
267
0
    utstring_printf (buf, "%lf", val);
268
0
  }
269
270
0
  return 0;
271
0
}
272
273
/*
274
 * Generic file output
275
 */
276
static int
277
ucl_file_append_character (unsigned char c, size_t len, void *ud)
278
0
{
279
0
  FILE *fp = ud;
280
281
0
  while (len --) {
282
0
    fputc (c, fp);
283
0
  }
284
285
0
  return 0;
286
0
}
287
288
static int
289
ucl_file_append_len (const unsigned char *str, size_t len, void *ud)
290
0
{
291
0
  FILE *fp = ud;
292
293
0
  fwrite (str, len, 1, fp);
294
295
0
  return 0;
296
0
}
297
298
static int
299
ucl_file_append_int (int64_t val, void *ud)
300
0
{
301
0
  FILE *fp = ud;
302
303
0
  fprintf (fp, "%jd", (intmax_t)val);
304
305
0
  return 0;
306
0
}
307
308
static int
309
ucl_file_append_double (double val, void *ud)
310
0
{
311
0
  FILE *fp = ud;
312
0
  const double delta = 0.0000001;
313
314
0
  if (val == (double)(int)val) {
315
0
    fprintf (fp, "%.1lf", val);
316
0
  }
317
0
  else if (fabs (val - (double)(int)val) < delta) {
318
    /* Write at maximum precision */
319
0
    fprintf (fp, "%.*lg", DBL_DIG, val);
320
0
  }
321
0
  else {
322
0
    fprintf (fp, "%lf", val);
323
0
  }
324
325
0
  return 0;
326
0
}
327
328
/*
329
 * Generic file descriptor writing functions
330
 */
331
static int
332
ucl_fd_append_character (unsigned char c, size_t len, void *ud)
333
0
{
334
0
  int fd = *(int *)ud;
335
0
  unsigned char *buf;
336
337
0
  if (len == 1) {
338
0
    return write (fd, &c, 1);
339
0
  }
340
0
  else {
341
0
    buf = malloc (len);
342
0
    if (buf == NULL) {
343
      /* Fallback */
344
0
      while (len --) {
345
0
        if (write (fd, &c, 1) == -1) {
346
0
          return -1;
347
0
        }
348
0
      }
349
0
    }
350
0
    else {
351
0
      memset (buf, c, len);
352
0
      if (write (fd, buf, len) == -1) {
353
0
        free(buf);
354
0
        return -1;
355
0
      }
356
0
      free (buf);
357
0
    }
358
0
  }
359
360
0
  return 0;
361
0
}
362
363
static int
364
ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
365
0
{
366
0
  int fd = *(int *)ud;
367
368
0
  return write (fd, str, len);
369
0
}
370
371
static int
372
ucl_fd_append_int (int64_t val, void *ud)
373
0
{
374
0
  int fd = *(int *)ud;
375
0
  char intbuf[64];
376
377
0
  snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
378
0
  return write (fd, intbuf, strlen (intbuf));
379
0
}
380
381
static int
382
ucl_fd_append_double (double val, void *ud)
383
0
{
384
0
  int fd = *(int *)ud;
385
0
  const double delta = 0.0000001;
386
0
  char nbuf[64];
387
388
0
  if (val == (double)(int)val) {
389
0
    snprintf (nbuf, sizeof (nbuf), "%.1lf", val);
390
0
  }
391
0
  else if (fabs (val - (double)(int)val) < delta) {
392
    /* Write at maximum precision */
393
0
    snprintf (nbuf, sizeof (nbuf), "%.*lg", DBL_DIG, val);
394
0
  }
395
0
  else {
396
0
    snprintf (nbuf, sizeof (nbuf), "%lf", val);
397
0
  }
398
399
0
  return write (fd, nbuf, strlen (nbuf));
400
0
}
401
402
struct ucl_emitter_functions*
403
ucl_object_emit_memory_funcs (void **pmem)
404
0
{
405
0
  struct ucl_emitter_functions *f;
406
0
  UT_string *s;
407
408
0
  f = calloc (1, sizeof (*f));
409
410
0
  if (f != NULL) {
411
0
    f->ucl_emitter_append_character = ucl_utstring_append_character;
412
0
    f->ucl_emitter_append_double = ucl_utstring_append_double;
413
0
    f->ucl_emitter_append_int = ucl_utstring_append_int;
414
0
    f->ucl_emitter_append_len = ucl_utstring_append_len;
415
0
    f->ucl_emitter_free_func = _ucl_emitter_free;
416
0
    utstring_new (s);
417
0
    f->ud = s;
418
0
    *pmem = s->d;
419
0
    s->pd = pmem;
420
0
  }
421
422
0
  return f;
423
0
}
424
425
struct ucl_emitter_functions*
426
ucl_object_emit_file_funcs (FILE *fp)
427
0
{
428
0
  struct ucl_emitter_functions *f;
429
430
0
  f = calloc (1, sizeof (*f));
431
432
0
  if (f != NULL) {
433
0
    f->ucl_emitter_append_character = ucl_file_append_character;
434
0
    f->ucl_emitter_append_double = ucl_file_append_double;
435
0
    f->ucl_emitter_append_int = ucl_file_append_int;
436
0
    f->ucl_emitter_append_len = ucl_file_append_len;
437
0
    f->ucl_emitter_free_func = NULL;
438
0
    f->ud = fp;
439
0
  }
440
441
0
  return f;
442
0
}
443
444
struct ucl_emitter_functions*
445
ucl_object_emit_fd_funcs (int fd)
446
0
{
447
0
  struct ucl_emitter_functions *f;
448
0
  int *ip;
449
450
0
  f = calloc (1, sizeof (*f));
451
452
0
  if (f != NULL) {
453
0
    ip = malloc (sizeof (fd));
454
0
    if (ip == NULL) {
455
0
      free (f);
456
0
      return NULL;
457
0
    }
458
459
0
    memcpy (ip, &fd, sizeof (fd));
460
0
    f->ucl_emitter_append_character = ucl_fd_append_character;
461
0
    f->ucl_emitter_append_double = ucl_fd_append_double;
462
0
    f->ucl_emitter_append_int = ucl_fd_append_int;
463
0
    f->ucl_emitter_append_len = ucl_fd_append_len;
464
0
    f->ucl_emitter_free_func = _ucl_emitter_free;
465
0
    f->ud = ip;
466
0
  }
467
468
0
  return f;
469
0
}
470
471
void
472
ucl_object_emit_funcs_free (struct ucl_emitter_functions *f)
473
0
{
474
0
  if (f != NULL) {
475
0
    if (f->ucl_emitter_free_func != NULL) {
476
0
      f->ucl_emitter_free_func (f->ud);
477
0
    }
478
0
    free (f);
479
0
  }
480
0
}
481
482
483
unsigned char *
484
ucl_object_emit_single_json (const ucl_object_t *obj)
485
0
{
486
0
  UT_string *buf = NULL;
487
0
  unsigned char *res = NULL;
488
489
0
  if (obj == NULL) {
490
0
    return NULL;
491
0
  }
492
493
0
  utstring_new (buf);
494
495
0
  if (buf != NULL) {
496
0
    switch (obj->type) {
497
0
    case UCL_OBJECT:
498
0
      ucl_utstring_append_len ("object", 6, buf);
499
0
      break;
500
0
    case UCL_ARRAY:
501
0
      ucl_utstring_append_len ("array", 5, buf);
502
0
      break;
503
0
    case UCL_INT:
504
0
      ucl_utstring_append_int (obj->value.iv, buf);
505
0
      break;
506
0
    case UCL_FLOAT:
507
0
    case UCL_TIME:
508
0
      ucl_utstring_append_double (obj->value.dv, buf);
509
0
      break;
510
0
    case UCL_NULL:
511
0
      ucl_utstring_append_len ("null", 4, buf);
512
0
      break;
513
0
    case UCL_BOOLEAN:
514
0
      if (obj->value.iv) {
515
0
        ucl_utstring_append_len ("true", 4, buf);
516
0
      }
517
0
      else {
518
0
        ucl_utstring_append_len ("false", 5, buf);
519
0
      }
520
0
      break;
521
0
    case UCL_STRING:
522
0
      ucl_utstring_append_len (obj->value.sv, obj->len, buf);
523
0
      break;
524
0
    case UCL_USERDATA:
525
0
      ucl_utstring_append_len ("userdata", 8, buf);
526
0
      break;
527
0
    }
528
0
    res = utstring_body (buf);
529
0
    free (buf);
530
0
  }
531
532
0
  return res;
533
0
}
534
535
0
#define LONG_STRING_LIMIT 80
536
537
bool
538
ucl_maybe_long_string (const ucl_object_t *obj)
539
0
{
540
0
  if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {
541
    /* String is long enough, so search for newline characters in it */
542
0
    if (memchr (obj->value.sv, '\n', obj->len) != NULL) {
543
0
      return true;
544
0
    }
545
0
  }
546
547
0
  return false;
548
0
}