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