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
39extern const struct ucl_emitter_operations ucl_standartd_emitter_ops[];
40
41static 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
74static 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 */
86const struct ucl_emitter_context *
87ucl_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 */
101void
102ucl_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
168void
169ucl_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
202void
203ucl_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 */
216static int
217ucl_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
234static int
235ucl_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
244static int
245ucl_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
253static int
254ucl_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 */
276static int
277ucl_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
288static int
289ucl_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
298static int
299ucl_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
308static int
309ucl_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 */
331static int
332ucl_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
363static int
364ucl_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
371static int
372ucl_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
381static int
382ucl_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
402struct ucl_emitter_functions*
403ucl_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
425struct ucl_emitter_functions*
426ucl_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
444struct ucl_emitter_functions*
445ucl_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
471void
472ucl_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
483unsigned char *
484ucl_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
537bool
538ucl_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