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