1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov
2262395Sbapt * All rights reserved.
3262395Sbapt *
4262395Sbapt * Redistribution and use in source and binary forms, with or without
5262395Sbapt * modification, are permitted provided that the following conditions are met:
6262395Sbapt *       * Redistributions of source code must retain the above copyright
7262395Sbapt *         notice, this list of conditions and the following disclaimer.
8262395Sbapt *       * Redistributions in binary form must reproduce the above copyright
9262395Sbapt *         notice, this list of conditions and the following disclaimer in the
10262395Sbapt *         documentation and/or other materials provided with the distribution.
11262395Sbapt *
12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22262395Sbapt */
23262395Sbapt
24262395Sbapt#include "ucl.h"
25262395Sbapt#include "ucl_internal.h"
26262395Sbapt#include "ucl_chartable.h"
27262395Sbapt
28262395Sbapt#include <libgen.h> /* For dirname */
29262395Sbapt
30262395Sbapt#ifdef HAVE_OPENSSL
31262395Sbapt#include <openssl/err.h>
32262395Sbapt#include <openssl/sha.h>
33262395Sbapt#include <openssl/rsa.h>
34262395Sbapt#include <openssl/ssl.h>
35262395Sbapt#include <openssl/evp.h>
36262395Sbapt#endif
37262395Sbapt
38263032Sbapt#ifdef _WIN32
39263032Sbapt#include <windows.h>
40263032Sbapt
41263032Sbapt#define PROT_READ       1
42263032Sbapt#define PROT_WRITE      2
43263032Sbapt#define PROT_READWRITE  3
44263032Sbapt#define MAP_SHARED      1
45263032Sbapt#define MAP_PRIVATE     2
46263032Sbapt#define MAP_FAILED      ((void *) -1)
47263032Sbapt
48263032Sbaptstatic void *mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
49263032Sbapt{
50263032Sbapt	void *map = NULL;
51263032Sbapt	HANDLE handle = INVALID_HANDLE_VALUE;
52263032Sbapt
53263032Sbapt	switch (prot) {
54263032Sbapt	default:
55263032Sbapt	case PROT_READ:
56263032Sbapt		{
57263032Sbapt			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
58263032Sbapt			if (!handle) break;
59263032Sbapt			map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
60263032Sbapt			CloseHandle(handle);
61263032Sbapt			break;
62263032Sbapt		}
63263032Sbapt	case PROT_WRITE:
64263032Sbapt		{
65263032Sbapt			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
66263032Sbapt			if (!handle) break;
67263032Sbapt			map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
68263032Sbapt			CloseHandle(handle);
69263032Sbapt			break;
70263032Sbapt		}
71263032Sbapt	case PROT_READWRITE:
72263032Sbapt		{
73263032Sbapt			handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
74263032Sbapt			if (!handle) break;
75263032Sbapt			map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
76263032Sbapt			CloseHandle(handle);
77263032Sbapt			break;
78263032Sbapt		}
79263032Sbapt	}
80263032Sbapt	if (map == (void *) NULL) {
81263032Sbapt		return (void *) MAP_FAILED;
82263032Sbapt	}
83263032Sbapt	return (void *) ((char *) map + offset);
84263032Sbapt}
85263032Sbapt
86263032Sbaptstatic int munmap(void *map,size_t length)
87263032Sbapt{
88263032Sbapt	if (!UnmapViewOfFile(map)) {
89263032Sbapt		return(-1);
90263032Sbapt	}
91263032Sbapt	return(0);
92263032Sbapt}
93263032Sbapt
94263032Sbaptstatic char* realpath(const char *path, char *resolved_path) {
95263032Sbapt    char *p;
96263032Sbapt    char tmp[MAX_PATH + 1];
97263032Sbapt    strncpy(tmp, path, sizeof(tmp)-1);
98263032Sbapt    p = tmp;
99263032Sbapt    while(*p) {
100263032Sbapt        if (*p == '/') *p = '\\';
101263032Sbapt        p++;
102263032Sbapt    }
103263032Sbapt    return _fullpath(resolved_path, tmp, MAX_PATH);
104263032Sbapt}
105263032Sbapt#endif
106263032Sbapt
107262395Sbapt/**
108262395Sbapt * @file rcl_util.c
109262395Sbapt * Utilities for rcl parsing
110262395Sbapt */
111262395Sbapt
112262395Sbapt
113262395Sbaptstatic void
114262395Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec)
115262395Sbapt{
116262395Sbapt	ucl_object_t *sub, *tmp;
117262395Sbapt
118262395Sbapt	while (obj != NULL) {
119262395Sbapt		if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
120262395Sbapt			UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]);
121262395Sbapt		}
122262395Sbapt		if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
123262395Sbapt			UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
124262395Sbapt		}
125262395Sbapt
126262395Sbapt		if (obj->type == UCL_ARRAY) {
127262395Sbapt			sub = obj->value.av;
128262395Sbapt			while (sub != NULL) {
129262395Sbapt				tmp = sub->next;
130262395Sbapt				ucl_object_free_internal (sub, false);
131262395Sbapt				sub = tmp;
132262395Sbapt			}
133262395Sbapt		}
134262395Sbapt		else if (obj->type == UCL_OBJECT) {
135262395Sbapt			if (obj->value.ov != NULL) {
136262395Sbapt				ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref);
137262395Sbapt			}
138262395Sbapt		}
139262395Sbapt		tmp = obj->next;
140262395Sbapt		UCL_FREE (sizeof (ucl_object_t), obj);
141262395Sbapt		obj = tmp;
142262395Sbapt
143262395Sbapt		if (!allow_rec) {
144262395Sbapt			break;
145262395Sbapt		}
146262395Sbapt	}
147262395Sbapt}
148262395Sbapt
149262395Sbaptvoid
150262395Sbaptucl_object_free (ucl_object_t *obj)
151262395Sbapt{
152262395Sbapt	ucl_object_free_internal (obj, true);
153262395Sbapt}
154262395Sbapt
155262395Sbaptsize_t
156262395Sbaptucl_unescape_json_string (char *str, size_t len)
157262395Sbapt{
158262395Sbapt	char *t = str, *h = str;
159262395Sbapt	int i, uval;
160262395Sbapt
161262395Sbapt	/* t is target (tortoise), h is source (hare) */
162262395Sbapt
163262395Sbapt	while (len) {
164262395Sbapt		if (*h == '\\') {
165262395Sbapt			h ++;
166262395Sbapt			switch (*h) {
167262395Sbapt			case 'n':
168262395Sbapt				*t++ = '\n';
169262395Sbapt				break;
170262395Sbapt			case 'r':
171262395Sbapt				*t++ = '\r';
172262395Sbapt				break;
173262395Sbapt			case 'b':
174262395Sbapt				*t++ = '\b';
175262395Sbapt				break;
176262395Sbapt			case 't':
177262395Sbapt				*t++ = '\t';
178262395Sbapt				break;
179262395Sbapt			case 'f':
180262395Sbapt				*t++ = '\f';
181262395Sbapt				break;
182262395Sbapt			case '\\':
183262395Sbapt				*t++ = '\\';
184262395Sbapt				break;
185262395Sbapt			case '"':
186262395Sbapt				*t++ = '"';
187262395Sbapt				break;
188262395Sbapt			case 'u':
189262395Sbapt				/* Unicode escape */
190262395Sbapt				uval = 0;
191262395Sbapt				for (i = 0; i < 4; i++) {
192262395Sbapt					uval <<= 4;
193262395Sbapt					if (isdigit (h[i])) {
194262395Sbapt						uval += h[i] - '0';
195262395Sbapt					}
196262395Sbapt					else if (h[i] >= 'a' && h[i] <= 'f') {
197262395Sbapt						uval += h[i] - 'a' + 10;
198262395Sbapt					}
199262395Sbapt					else if (h[i] >= 'A' && h[i] <= 'F') {
200262395Sbapt						uval += h[i] - 'A' + 10;
201262395Sbapt					}
202262395Sbapt				}
203262395Sbapt				h += 3;
204262395Sbapt				len -= 3;
205262395Sbapt				/* Encode */
206262395Sbapt				if(uval < 0x80) {
207262395Sbapt					t[0] = (char)uval;
208262395Sbapt					t ++;
209262395Sbapt				}
210262395Sbapt				else if(uval < 0x800) {
211262395Sbapt					t[0] = 0xC0 + ((uval & 0x7C0) >> 6);
212262395Sbapt					t[1] = 0x80 + ((uval & 0x03F));
213262395Sbapt					t += 2;
214262395Sbapt				}
215262395Sbapt				else if(uval < 0x10000) {
216262395Sbapt					t[0] = 0xE0 + ((uval & 0xF000) >> 12);
217262395Sbapt					t[1] = 0x80 + ((uval & 0x0FC0) >> 6);
218262395Sbapt					t[2] = 0x80 + ((uval & 0x003F));
219262395Sbapt					t += 3;
220262395Sbapt				}
221262395Sbapt				else if(uval <= 0x10FFFF) {
222262395Sbapt					t[0] = 0xF0 + ((uval & 0x1C0000) >> 18);
223262395Sbapt					t[1] = 0x80 + ((uval & 0x03F000) >> 12);
224262395Sbapt					t[2] = 0x80 + ((uval & 0x000FC0) >> 6);
225262395Sbapt					t[3] = 0x80 + ((uval & 0x00003F));
226262395Sbapt					t += 4;
227262395Sbapt				}
228262395Sbapt				else {
229262395Sbapt					*t++ = '?';
230262395Sbapt				}
231262395Sbapt				break;
232262395Sbapt			default:
233262395Sbapt				*t++ = *h;
234262395Sbapt				break;
235262395Sbapt			}
236262395Sbapt			h ++;
237262395Sbapt			len --;
238262395Sbapt		}
239262395Sbapt		else {
240262395Sbapt			*t++ = *h++;
241262395Sbapt		}
242262395Sbapt		len --;
243262395Sbapt	}
244262395Sbapt	*t = '\0';
245262395Sbapt
246262395Sbapt	return (t - str);
247262395Sbapt}
248262395Sbapt
249263032SbaptUCL_EXTERN char *
250262395Sbaptucl_copy_key_trash (ucl_object_t *obj)
251262395Sbapt{
252262395Sbapt	if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
253262395Sbapt		obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1);
254262395Sbapt		if (obj->trash_stack[UCL_TRASH_KEY] != NULL) {
255262395Sbapt			memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen);
256262395Sbapt			obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0';
257262395Sbapt		}
258262395Sbapt		obj->key = obj->trash_stack[UCL_TRASH_KEY];
259262395Sbapt		obj->flags |= UCL_OBJECT_ALLOCATED_KEY;
260262395Sbapt	}
261262395Sbapt
262262395Sbapt	return obj->trash_stack[UCL_TRASH_KEY];
263262395Sbapt}
264262395Sbapt
265263032SbaptUCL_EXTERN char *
266262395Sbaptucl_copy_value_trash (ucl_object_t *obj)
267262395Sbapt{
268262395Sbapt	if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
269262395Sbapt		if (obj->type == UCL_STRING) {
270262395Sbapt			/* Special case for strings */
271262395Sbapt			obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1);
272262395Sbapt			if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
273262395Sbapt				memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len);
274262395Sbapt				obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0';
275262395Sbapt				obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE];
276262395Sbapt			}
277262395Sbapt		}
278262395Sbapt		else {
279262395Sbapt			/* Just emit value in json notation */
280262395Sbapt			obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj);
281262395Sbapt			obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]);
282262395Sbapt		}
283262395Sbapt		obj->flags |= UCL_OBJECT_ALLOCATED_VALUE;
284262395Sbapt	}
285262395Sbapt	return obj->trash_stack[UCL_TRASH_VALUE];
286262395Sbapt}
287262395Sbapt
288263032SbaptUCL_EXTERN ucl_object_t*
289262395Sbaptucl_parser_get_object (struct ucl_parser *parser)
290262395Sbapt{
291262395Sbapt	if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
292262395Sbapt		return ucl_object_ref (parser->top_obj);
293262395Sbapt	}
294262395Sbapt
295262395Sbapt	return NULL;
296262395Sbapt}
297262395Sbapt
298263032SbaptUCL_EXTERN void
299262395Sbaptucl_parser_free (struct ucl_parser *parser)
300262395Sbapt{
301262395Sbapt	struct ucl_stack *stack, *stmp;
302262395Sbapt	struct ucl_macro *macro, *mtmp;
303262395Sbapt	struct ucl_chunk *chunk, *ctmp;
304262395Sbapt	struct ucl_pubkey *key, *ktmp;
305262395Sbapt	struct ucl_variable *var, *vtmp;
306262395Sbapt
307262395Sbapt	if (parser->top_obj != NULL) {
308262395Sbapt		ucl_object_unref (parser->top_obj);
309262395Sbapt	}
310262395Sbapt
311262395Sbapt	LL_FOREACH_SAFE (parser->stack, stack, stmp) {
312262395Sbapt		free (stack);
313262395Sbapt	}
314262395Sbapt	HASH_ITER (hh, parser->macroes, macro, mtmp) {
315262395Sbapt		free (macro->name);
316262395Sbapt		HASH_DEL (parser->macroes, macro);
317262395Sbapt		UCL_FREE (sizeof (struct ucl_macro), macro);
318262395Sbapt	}
319262395Sbapt	LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) {
320262395Sbapt		UCL_FREE (sizeof (struct ucl_chunk), chunk);
321262395Sbapt	}
322262395Sbapt	LL_FOREACH_SAFE (parser->keys, key, ktmp) {
323262395Sbapt		UCL_FREE (sizeof (struct ucl_pubkey), key);
324262395Sbapt	}
325262395Sbapt	LL_FOREACH_SAFE (parser->variables, var, vtmp) {
326262395Sbapt		free (var->value);
327262395Sbapt		free (var->var);
328262395Sbapt		UCL_FREE (sizeof (struct ucl_variable), var);
329262395Sbapt	}
330262395Sbapt
331262395Sbapt	if (parser->err != NULL) {
332262395Sbapt		utstring_free(parser->err);
333262395Sbapt	}
334262395Sbapt
335262395Sbapt	UCL_FREE (sizeof (struct ucl_parser), parser);
336262395Sbapt}
337262395Sbapt
338263032SbaptUCL_EXTERN const char *
339262395Sbaptucl_parser_get_error(struct ucl_parser *parser)
340262395Sbapt{
341262395Sbapt	if (parser->err == NULL)
342262395Sbapt		return NULL;
343262395Sbapt
344262395Sbapt	return utstring_body(parser->err);
345262395Sbapt}
346262395Sbapt
347263032SbaptUCL_EXTERN bool
348262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
349262395Sbapt{
350262395Sbapt#ifndef HAVE_OPENSSL
351262395Sbapt	ucl_create_err (&parser->err, "cannot check signatures without openssl");
352262395Sbapt	return false;
353262395Sbapt#else
354262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
355262395Sbapt	ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported");
356262395Sbapt	return EXIT_FAILURE;
357262395Sbapt# else
358262395Sbapt	struct ucl_pubkey *nkey;
359262395Sbapt	BIO *mem;
360262395Sbapt
361262395Sbapt	mem = BIO_new_mem_buf ((void *)key, len);
362262395Sbapt	nkey = UCL_ALLOC (sizeof (struct ucl_pubkey));
363262395Sbapt	nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL);
364262395Sbapt	BIO_free (mem);
365262395Sbapt	if (nkey->key == NULL) {
366262395Sbapt		UCL_FREE (sizeof (struct ucl_pubkey), nkey);
367262395Sbapt		ucl_create_err (&parser->err, "%s",
368262395Sbapt				ERR_error_string (ERR_get_error (), NULL));
369262395Sbapt		return false;
370262395Sbapt	}
371262395Sbapt	LL_PREPEND (parser->keys, nkey);
372262395Sbapt# endif
373262395Sbapt#endif
374262395Sbapt	return true;
375262395Sbapt}
376262395Sbapt
377262395Sbapt#ifdef CURL_FOUND
378262395Sbaptstruct ucl_curl_cbdata {
379262395Sbapt	unsigned char *buf;
380262395Sbapt	size_t buflen;
381262395Sbapt};
382262395Sbapt
383262395Sbaptstatic size_t
384262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud)
385262395Sbapt{
386262395Sbapt	struct ucl_curl_cbdata *cbdata = ud;
387262395Sbapt	size_t realsize = size * nmemb;
388262395Sbapt
389262395Sbapt	cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1);
390262395Sbapt	if (cbdata->buf == NULL) {
391262395Sbapt		return 0;
392262395Sbapt	}
393262395Sbapt
394262395Sbapt	memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize);
395262395Sbapt	cbdata->buflen += realsize;
396262395Sbapt	cbdata->buf[cbdata->buflen] = 0;
397262395Sbapt
398262395Sbapt	return realsize;
399262395Sbapt}
400262395Sbapt#endif
401262395Sbapt
402262395Sbapt/**
403262395Sbapt * Fetch a url and save results to the memory buffer
404262395Sbapt * @param url url to fetch
405262395Sbapt * @param len length of url
406262395Sbapt * @param buf target buffer
407262395Sbapt * @param buflen target length
408262395Sbapt * @return
409262395Sbapt */
410262395Sbaptstatic bool
411262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen,
412262395Sbapt		UT_string **err, bool must_exist)
413262395Sbapt{
414262395Sbapt
415262395Sbapt#ifdef HAVE_FETCH_H
416262395Sbapt	struct url *fetch_url;
417262395Sbapt	struct url_stat us;
418262395Sbapt	FILE *in;
419262395Sbapt
420262395Sbapt	fetch_url = fetchParseURL (url);
421262395Sbapt	if (fetch_url == NULL) {
422262395Sbapt		ucl_create_err (err, "invalid URL %s: %s",
423262395Sbapt				url, strerror (errno));
424262395Sbapt		return false;
425262395Sbapt	}
426262395Sbapt	if ((in = fetchXGet (fetch_url, &us, "")) == NULL) {
427262395Sbapt		if (!must_exist) {
428262395Sbapt			ucl_create_err (err, "cannot fetch URL %s: %s",
429262395Sbapt				url, strerror (errno));
430262395Sbapt		}
431262395Sbapt		fetchFreeURL (fetch_url);
432262395Sbapt		return false;
433262395Sbapt	}
434262395Sbapt
435262395Sbapt	*buflen = us.size;
436262395Sbapt	*buf = malloc (*buflen);
437262395Sbapt	if (*buf == NULL) {
438262395Sbapt		ucl_create_err (err, "cannot allocate buffer for URL %s: %s",
439262395Sbapt				url, strerror (errno));
440262395Sbapt		fclose (in);
441262395Sbapt		fetchFreeURL (fetch_url);
442262395Sbapt		return false;
443262395Sbapt	}
444262395Sbapt
445262395Sbapt	if (fread (*buf, *buflen, 1, in) != 1) {
446262395Sbapt		ucl_create_err (err, "cannot read URL %s: %s",
447262395Sbapt				url, strerror (errno));
448262395Sbapt		fclose (in);
449262395Sbapt		fetchFreeURL (fetch_url);
450262395Sbapt		return false;
451262395Sbapt	}
452262395Sbapt
453262395Sbapt	fetchFreeURL (fetch_url);
454262395Sbapt	return true;
455262395Sbapt#elif defined(CURL_FOUND)
456262395Sbapt	CURL *curl;
457262395Sbapt	int r;
458262395Sbapt	struct ucl_curl_cbdata cbdata;
459262395Sbapt
460262395Sbapt	curl = curl_easy_init ();
461262395Sbapt	if (curl == NULL) {
462262395Sbapt		ucl_create_err (err, "CURL interface is broken");
463262395Sbapt		return false;
464262395Sbapt	}
465262395Sbapt	if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) {
466262395Sbapt		ucl_create_err (err, "invalid URL %s: %s",
467262395Sbapt				url, curl_easy_strerror (r));
468262395Sbapt		curl_easy_cleanup (curl);
469262395Sbapt		return false;
470262395Sbapt	}
471262395Sbapt	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback);
472262395Sbapt	cbdata.buf = *buf;
473262395Sbapt	cbdata.buflen = *buflen;
474262395Sbapt	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata);
475262395Sbapt
476262395Sbapt	if ((r = curl_easy_perform (curl)) != CURLE_OK) {
477262395Sbapt		if (!must_exist) {
478262395Sbapt			ucl_create_err (err, "error fetching URL %s: %s",
479262395Sbapt				url, curl_easy_strerror (r));
480262395Sbapt		}
481262395Sbapt		curl_easy_cleanup (curl);
482262395Sbapt		if (cbdata.buf) {
483262395Sbapt			free (cbdata.buf);
484262395Sbapt		}
485262395Sbapt		return false;
486262395Sbapt	}
487262395Sbapt	*buf = cbdata.buf;
488262395Sbapt	*buflen = cbdata.buflen;
489262395Sbapt
490262395Sbapt	return true;
491262395Sbapt#else
492262395Sbapt	ucl_create_err (err, "URL support is disabled");
493262395Sbapt	return false;
494262395Sbapt#endif
495262395Sbapt}
496262395Sbapt
497262395Sbapt/**
498262395Sbapt * Fetch a file and save results to the memory buffer
499262395Sbapt * @param filename filename to fetch
500262395Sbapt * @param len length of filename
501262395Sbapt * @param buf target buffer
502262395Sbapt * @param buflen target length
503262395Sbapt * @return
504262395Sbapt */
505262395Sbaptstatic bool
506262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen,
507262395Sbapt		UT_string **err, bool must_exist)
508262395Sbapt{
509262395Sbapt	int fd;
510262395Sbapt	struct stat st;
511262395Sbapt
512262395Sbapt	if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) {
513262395Sbapt		if (must_exist) {
514262395Sbapt			ucl_create_err (err, "cannot stat file %s: %s",
515262395Sbapt					filename, strerror (errno));
516262395Sbapt		}
517262395Sbapt		return false;
518262395Sbapt	}
519262395Sbapt	if (st.st_size == 0) {
520262395Sbapt		/* Do not map empty files */
521262395Sbapt		*buf = "";
522262395Sbapt		*buflen = 0;
523262395Sbapt	}
524262395Sbapt	else {
525262395Sbapt		if ((fd = open (filename, O_RDONLY)) == -1) {
526262395Sbapt			ucl_create_err (err, "cannot open file %s: %s",
527262395Sbapt					filename, strerror (errno));
528262395Sbapt			return false;
529262395Sbapt		}
530262395Sbapt		if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
531262395Sbapt			close (fd);
532262395Sbapt			ucl_create_err (err, "cannot mmap file %s: %s",
533262395Sbapt					filename, strerror (errno));
534262395Sbapt			return false;
535262395Sbapt		}
536262395Sbapt		*buflen = st.st_size;
537262395Sbapt		close (fd);
538262395Sbapt	}
539262395Sbapt
540262395Sbapt	return true;
541262395Sbapt}
542262395Sbapt
543262395Sbapt
544262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
545262395Sbaptstatic inline bool
546262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen,
547262395Sbapt		const unsigned char *sig, size_t siglen, struct ucl_parser *parser)
548262395Sbapt{
549262395Sbapt	struct ucl_pubkey *key;
550262395Sbapt	char dig[EVP_MAX_MD_SIZE];
551262395Sbapt	unsigned int diglen;
552262395Sbapt	EVP_PKEY_CTX *key_ctx;
553262395Sbapt	EVP_MD_CTX *sign_ctx = NULL;
554262395Sbapt
555262395Sbapt	sign_ctx = EVP_MD_CTX_create ();
556262395Sbapt
557262395Sbapt	LL_FOREACH (parser->keys, key) {
558262395Sbapt		key_ctx = EVP_PKEY_CTX_new (key->key, NULL);
559262395Sbapt		if (key_ctx != NULL) {
560262395Sbapt			if (EVP_PKEY_verify_init (key_ctx) <= 0) {
561262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
562262395Sbapt				continue;
563262395Sbapt			}
564262395Sbapt			if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
565262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
566262395Sbapt				continue;
567262395Sbapt			}
568262395Sbapt			if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
569262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
570262395Sbapt				continue;
571262395Sbapt			}
572262395Sbapt			EVP_DigestInit (sign_ctx, EVP_sha256 ());
573262395Sbapt			EVP_DigestUpdate (sign_ctx, data, datalen);
574262395Sbapt			EVP_DigestFinal (sign_ctx, dig, &diglen);
575262395Sbapt
576262395Sbapt			if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) {
577262395Sbapt				EVP_MD_CTX_destroy (sign_ctx);
578262395Sbapt				EVP_PKEY_CTX_free (key_ctx);
579262395Sbapt				return true;
580262395Sbapt			}
581262395Sbapt
582262395Sbapt			EVP_PKEY_CTX_free (key_ctx);
583262395Sbapt		}
584262395Sbapt	}
585262395Sbapt
586262395Sbapt	EVP_MD_CTX_destroy (sign_ctx);
587262395Sbapt
588262395Sbapt	return false;
589262395Sbapt}
590262395Sbapt#endif
591262395Sbapt
592262395Sbapt/**
593262395Sbapt * Include an url to configuration
594262395Sbapt * @param data
595262395Sbapt * @param len
596262395Sbapt * @param parser
597262395Sbapt * @param err
598262395Sbapt * @return
599262395Sbapt */
600262395Sbaptstatic bool
601262395Sbaptucl_include_url (const unsigned char *data, size_t len,
602262395Sbapt		struct ucl_parser *parser, bool check_signature, bool must_exist)
603262395Sbapt{
604262395Sbapt
605262395Sbapt	bool res;
606262395Sbapt	unsigned char *buf = NULL;
607262395Sbapt	size_t buflen = 0;
608262395Sbapt	struct ucl_chunk *chunk;
609262395Sbapt	char urlbuf[PATH_MAX];
610262395Sbapt	int prev_state;
611262395Sbapt
612262395Sbapt	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);
613262395Sbapt
614262395Sbapt	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) {
615262395Sbapt		return (!must_exist || false);
616262395Sbapt	}
617262395Sbapt
618262395Sbapt	if (check_signature) {
619262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
620262395Sbapt		unsigned char *sigbuf = NULL;
621262395Sbapt		size_t siglen = 0;
622262395Sbapt		/* We need to check signature first */
623262395Sbapt		snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data);
624262395Sbapt		if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) {
625262395Sbapt			return false;
626262395Sbapt		}
627262395Sbapt		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
628262395Sbapt			ucl_create_err (&parser->err, "cannot verify url %s: %s",
629262395Sbapt							urlbuf,
630262395Sbapt							ERR_error_string (ERR_get_error (), NULL));
631262395Sbapt			if (siglen > 0) {
632262395Sbapt				munmap (sigbuf, siglen);
633262395Sbapt			}
634262395Sbapt			return false;
635262395Sbapt		}
636262395Sbapt		if (siglen > 0) {
637262395Sbapt			munmap (sigbuf, siglen);
638262395Sbapt		}
639262395Sbapt#endif
640262395Sbapt	}
641262395Sbapt
642262395Sbapt	prev_state = parser->state;
643262395Sbapt	parser->state = UCL_STATE_INIT;
644262395Sbapt
645262395Sbapt	res = ucl_parser_add_chunk (parser, buf, buflen);
646262395Sbapt	if (res == true) {
647262395Sbapt		/* Remove chunk from the stack */
648262395Sbapt		chunk = parser->chunks;
649262395Sbapt		if (chunk != NULL) {
650262395Sbapt			parser->chunks = chunk->next;
651262395Sbapt			UCL_FREE (sizeof (struct ucl_chunk), chunk);
652262395Sbapt		}
653262395Sbapt	}
654262395Sbapt
655262395Sbapt	parser->state = prev_state;
656262395Sbapt	free (buf);
657262395Sbapt
658262395Sbapt	return res;
659262395Sbapt}
660262395Sbapt
661262395Sbapt/**
662262395Sbapt * Include a file to configuration
663262395Sbapt * @param data
664262395Sbapt * @param len
665262395Sbapt * @param parser
666262395Sbapt * @param err
667262395Sbapt * @return
668262395Sbapt */
669262395Sbaptstatic bool
670262395Sbaptucl_include_file (const unsigned char *data, size_t len,
671262395Sbapt		struct ucl_parser *parser, bool check_signature, bool must_exist)
672262395Sbapt{
673262395Sbapt	bool res;
674262395Sbapt	struct ucl_chunk *chunk;
675262395Sbapt	unsigned char *buf = NULL;
676262395Sbapt	size_t buflen;
677262395Sbapt	char filebuf[PATH_MAX], realbuf[PATH_MAX];
678262395Sbapt	int prev_state;
679262395Sbapt
680262395Sbapt	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
681262395Sbapt	if (realpath (filebuf, realbuf) == NULL) {
682262395Sbapt		if (!must_exist) {
683262395Sbapt			return true;
684262395Sbapt		}
685262395Sbapt		ucl_create_err (&parser->err, "cannot open file %s: %s",
686262395Sbapt									filebuf,
687262395Sbapt									strerror (errno));
688262395Sbapt		return false;
689262395Sbapt	}
690262395Sbapt
691262395Sbapt	if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
692262395Sbapt		return (!must_exist || false);
693262395Sbapt	}
694262395Sbapt
695262395Sbapt	if (check_signature) {
696262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L)
697262395Sbapt		unsigned char *sigbuf = NULL;
698262395Sbapt		size_t siglen = 0;
699262395Sbapt		/* We need to check signature first */
700262395Sbapt		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);
701262395Sbapt		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) {
702262395Sbapt			return false;
703262395Sbapt		}
704262395Sbapt		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) {
705262395Sbapt			ucl_create_err (&parser->err, "cannot verify file %s: %s",
706262395Sbapt							filebuf,
707262395Sbapt							ERR_error_string (ERR_get_error (), NULL));
708262395Sbapt			if (siglen > 0) {
709262395Sbapt				munmap (sigbuf, siglen);
710262395Sbapt			}
711262395Sbapt			return false;
712262395Sbapt		}
713262395Sbapt		if (siglen > 0) {
714262395Sbapt			munmap (sigbuf, siglen);
715262395Sbapt		}
716262395Sbapt#endif
717262395Sbapt	}
718262395Sbapt
719262395Sbapt	ucl_parser_set_filevars (parser, realbuf, false);
720262395Sbapt
721262395Sbapt	prev_state = parser->state;
722262395Sbapt	parser->state = UCL_STATE_INIT;
723262395Sbapt
724262395Sbapt	res = ucl_parser_add_chunk (parser, buf, buflen);
725262395Sbapt	if (res == true) {
726262395Sbapt		/* Remove chunk from the stack */
727262395Sbapt		chunk = parser->chunks;
728262395Sbapt		if (chunk != NULL) {
729262395Sbapt			parser->chunks = chunk->next;
730262395Sbapt			UCL_FREE (sizeof (struct ucl_chunk), chunk);
731262395Sbapt		}
732262395Sbapt	}
733262395Sbapt
734262395Sbapt	parser->state = prev_state;
735262395Sbapt
736262395Sbapt	if (buflen > 0) {
737262395Sbapt		munmap (buf, buflen);
738262395Sbapt	}
739262395Sbapt
740262395Sbapt	return res;
741262395Sbapt}
742262395Sbapt
743262395Sbapt/**
744262395Sbapt * Handle include macro
745262395Sbapt * @param data include data
746262395Sbapt * @param len length of data
747262395Sbapt * @param ud user data
748262395Sbapt * @param err error ptr
749262395Sbapt * @return
750262395Sbapt */
751263032SbaptUCL_EXTERN bool
752262395Sbaptucl_include_handler (const unsigned char *data, size_t len, void* ud)
753262395Sbapt{
754262395Sbapt	struct ucl_parser *parser = ud;
755262395Sbapt
756262395Sbapt	if (*data == '/' || *data == '.') {
757262395Sbapt		/* Try to load a file */
758262395Sbapt		return ucl_include_file (data, len, parser, false, true);
759262395Sbapt	}
760262395Sbapt
761262395Sbapt	return ucl_include_url (data, len, parser, false, true);
762262395Sbapt}
763262395Sbapt
764262395Sbapt/**
765262395Sbapt * Handle includes macro
766262395Sbapt * @param data include data
767262395Sbapt * @param len length of data
768262395Sbapt * @param ud user data
769262395Sbapt * @param err error ptr
770262395Sbapt * @return
771262395Sbapt */
772263032SbaptUCL_EXTERN bool
773262395Sbaptucl_includes_handler (const unsigned char *data, size_t len, void* ud)
774262395Sbapt{
775262395Sbapt	struct ucl_parser *parser = ud;
776262395Sbapt
777262395Sbapt	if (*data == '/' || *data == '.') {
778262395Sbapt		/* Try to load a file */
779262395Sbapt		return ucl_include_file (data, len, parser, true, true);
780262395Sbapt	}
781262395Sbapt
782262395Sbapt	return ucl_include_url (data, len, parser, true, true);
783262395Sbapt}
784262395Sbapt
785262395Sbapt
786263032SbaptUCL_EXTERN bool
787262395Sbaptucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
788262395Sbapt{
789262395Sbapt	struct ucl_parser *parser = ud;
790262395Sbapt
791262395Sbapt	if (*data == '/' || *data == '.') {
792262395Sbapt		/* Try to load a file */
793262395Sbapt		return ucl_include_file (data, len, parser, false, false);
794262395Sbapt	}
795262395Sbapt
796262395Sbapt	return ucl_include_url (data, len, parser, false, false);
797262395Sbapt}
798262395Sbapt
799263032SbaptUCL_EXTERN bool
800262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
801262395Sbapt{
802262395Sbapt	char realbuf[PATH_MAX], *curdir;
803262395Sbapt
804262395Sbapt	if (filename != NULL) {
805262395Sbapt		if (need_expand) {
806262395Sbapt			if (realpath (filename, realbuf) == NULL) {
807262395Sbapt				return false;
808262395Sbapt			}
809262395Sbapt		}
810262395Sbapt		else {
811262395Sbapt			ucl_strlcpy (realbuf, filename, sizeof (realbuf));
812262395Sbapt		}
813262395Sbapt
814262395Sbapt		/* Define variables */
815262395Sbapt		ucl_parser_register_variable (parser, "FILENAME", realbuf);
816262395Sbapt		curdir = dirname (realbuf);
817262395Sbapt		ucl_parser_register_variable (parser, "CURDIR", curdir);
818262395Sbapt	}
819262395Sbapt	else {
820262395Sbapt		/* Set everything from the current dir */
821262395Sbapt		curdir = getcwd (realbuf, sizeof (realbuf));
822262395Sbapt		ucl_parser_register_variable (parser, "FILENAME", "undef");
823262395Sbapt		ucl_parser_register_variable (parser, "CURDIR", curdir);
824262395Sbapt	}
825262395Sbapt
826262395Sbapt	return true;
827262395Sbapt}
828262395Sbapt
829263032SbaptUCL_EXTERN bool
830262395Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename)
831262395Sbapt{
832262395Sbapt	unsigned char *buf;
833262395Sbapt	size_t len;
834262395Sbapt	bool ret;
835262395Sbapt	char realbuf[PATH_MAX];
836262395Sbapt
837262395Sbapt	if (realpath (filename, realbuf) == NULL) {
838262395Sbapt		ucl_create_err (&parser->err, "cannot open file %s: %s",
839262395Sbapt				filename,
840262395Sbapt				strerror (errno));
841262395Sbapt		return false;
842262395Sbapt	}
843262395Sbapt
844262395Sbapt	if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) {
845262395Sbapt		return false;
846262395Sbapt	}
847262395Sbapt
848262395Sbapt	ucl_parser_set_filevars (parser, realbuf, false);
849262395Sbapt	ret = ucl_parser_add_chunk (parser, buf, len);
850262395Sbapt
851262395Sbapt	if (len > 0) {
852262395Sbapt		munmap (buf, len);
853262395Sbapt	}
854262395Sbapt
855262395Sbapt	return ret;
856262395Sbapt}
857262395Sbapt
858262395Sbaptsize_t
859262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz)
860262395Sbapt{
861262395Sbapt	char *d = dst;
862262395Sbapt	const char *s = src;
863262395Sbapt	size_t n = siz;
864262395Sbapt
865262395Sbapt	/* Copy as many bytes as will fit */
866262395Sbapt	if (n != 0) {
867262395Sbapt		while (--n != 0) {
868262395Sbapt			if ((*d++ = *s++) == '\0') {
869262395Sbapt				break;
870262395Sbapt			}
871262395Sbapt		}
872262395Sbapt	}
873262395Sbapt
874262395Sbapt	if (n == 0 && siz != 0) {
875262395Sbapt		*d = '\0';
876262395Sbapt	}
877262395Sbapt
878262395Sbapt	return (s - src - 1);    /* count does not include NUL */
879262395Sbapt}
880262395Sbapt
881262395Sbaptsize_t
882262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz)
883262395Sbapt{
884262395Sbapt	memcpy (dst, src, siz - 1);
885262395Sbapt	dst[siz - 1] = '\0';
886262395Sbapt
887262395Sbapt	return siz - 1;
888262395Sbapt}
889262395Sbapt
890262395Sbaptsize_t
891262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz)
892262395Sbapt{
893262395Sbapt	char *d = dst;
894262395Sbapt	const char *s = src;
895262395Sbapt	size_t n = siz;
896262395Sbapt
897262395Sbapt	/* Copy as many bytes as will fit */
898262395Sbapt	if (n != 0) {
899262395Sbapt		while (--n != 0) {
900262395Sbapt			if ((*d++ = tolower (*s++)) == '\0') {
901262395Sbapt				break;
902262395Sbapt			}
903262395Sbapt		}
904262395Sbapt	}
905262395Sbapt
906262395Sbapt	if (n == 0 && siz != 0) {
907262395Sbapt		*d = '\0';
908262395Sbapt	}
909262395Sbapt
910262395Sbapt	return (s - src);    /* count does not include NUL */
911262395Sbapt}
912262395Sbapt
913262395Sbaptucl_object_t *
914262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags)
915262395Sbapt{
916262395Sbapt	ucl_object_t *obj;
917262395Sbapt	const char *start, *end, *p, *pos;
918262395Sbapt	char *dst, *d;
919262395Sbapt	size_t escaped_len;
920262395Sbapt
921262395Sbapt	if (str == NULL) {
922262395Sbapt		return NULL;
923262395Sbapt	}
924262395Sbapt
925262395Sbapt	obj = ucl_object_new ();
926262395Sbapt	if (obj) {
927262395Sbapt		if (len == 0) {
928262395Sbapt			len = strlen (str);
929262395Sbapt		}
930262395Sbapt		if (flags & UCL_STRING_TRIM) {
931262395Sbapt			/* Skip leading spaces */
932262395Sbapt			for (start = str; (size_t)(start - str) < len; start ++) {
933262395Sbapt				if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
934262395Sbapt					break;
935262395Sbapt				}
936262395Sbapt			}
937262395Sbapt			/* Skip trailing spaces */
938262395Sbapt			for (end = str + len - 1; end > start; end --) {
939262395Sbapt				if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
940262395Sbapt					break;
941262395Sbapt				}
942262395Sbapt			}
943262395Sbapt			end ++;
944262395Sbapt		}
945262395Sbapt		else {
946262395Sbapt			start = str;
947262395Sbapt			end = str + len;
948262395Sbapt		}
949262395Sbapt
950262395Sbapt		obj->type = UCL_STRING;
951262395Sbapt		if (flags & UCL_STRING_ESCAPE) {
952262395Sbapt			for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) {
953262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
954262395Sbapt					escaped_len ++;
955262395Sbapt				}
956262395Sbapt			}
957262395Sbapt			dst = malloc (escaped_len + 1);
958262395Sbapt			if (dst != NULL) {
959262395Sbapt				for (p = start, d = dst; p < end; p ++, d ++) {
960262395Sbapt					if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
961262395Sbapt						switch (*p) {
962262395Sbapt						case '\n':
963262395Sbapt							*d++ = '\\';
964262395Sbapt							*d = 'n';
965262395Sbapt							break;
966262395Sbapt						case '\r':
967262395Sbapt							*d++ = '\\';
968262395Sbapt							*d = 'r';
969262395Sbapt							break;
970262395Sbapt						case '\b':
971262395Sbapt							*d++ = '\\';
972262395Sbapt							*d = 'b';
973262395Sbapt							break;
974262395Sbapt						case '\t':
975262395Sbapt							*d++ = '\\';
976262395Sbapt							*d = 't';
977262395Sbapt							break;
978262395Sbapt						case '\f':
979262395Sbapt							*d++ = '\\';
980262395Sbapt							*d = 'f';
981262395Sbapt							break;
982262395Sbapt						case '\\':
983262395Sbapt							*d++ = '\\';
984262395Sbapt							*d = '\\';
985262395Sbapt							break;
986262395Sbapt						case '"':
987262395Sbapt							*d++ = '\\';
988262395Sbapt							*d = '"';
989262395Sbapt							break;
990262395Sbapt						}
991262395Sbapt					}
992262395Sbapt					else {
993262395Sbapt						*d = *p;
994262395Sbapt					}
995262395Sbapt				}
996262395Sbapt				*d = '\0';
997262395Sbapt				obj->value.sv = dst;
998262395Sbapt				obj->trash_stack[UCL_TRASH_VALUE] = dst;
999262395Sbapt				obj->len = escaped_len;
1000262395Sbapt			}
1001262395Sbapt		}
1002262395Sbapt		else {
1003262395Sbapt			dst = malloc (end - start + 1);
1004262395Sbapt			if (dst != NULL) {
1005262395Sbapt				ucl_strlcpy_unsafe (dst, start, end - start + 1);
1006262395Sbapt				obj->value.sv = dst;
1007262395Sbapt				obj->trash_stack[UCL_TRASH_VALUE] = dst;
1008262395Sbapt				obj->len = end - start;
1009262395Sbapt			}
1010262395Sbapt		}
1011262395Sbapt		if ((flags & UCL_STRING_PARSE) && dst != NULL) {
1012262395Sbapt			/* Parse what we have */
1013262395Sbapt			if (flags & UCL_STRING_PARSE_BOOLEAN) {
1014262395Sbapt				if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) {
1015262395Sbapt					ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1016262395Sbapt							flags & UCL_STRING_PARSE_DOUBLE,
1017262395Sbapt							flags & UCL_STRING_PARSE_BYTES);
1018262395Sbapt				}
1019262395Sbapt			}
1020262395Sbapt			else {
1021262395Sbapt				ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos,
1022262395Sbapt						flags & UCL_STRING_PARSE_DOUBLE,
1023262395Sbapt						flags & UCL_STRING_PARSE_BYTES);
1024262395Sbapt			}
1025262395Sbapt		}
1026262395Sbapt	}
1027262395Sbapt
1028262395Sbapt	return obj;
1029262395Sbapt}
1030262395Sbapt
1031262395Sbaptstatic ucl_object_t *
1032262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
1033262395Sbapt		const char *key, size_t keylen, bool copy_key, bool merge, bool replace)
1034262395Sbapt{
1035262395Sbapt	ucl_object_t *found, *cur;
1036262395Sbapt	ucl_object_iter_t it = NULL;
1037262395Sbapt	const char *p;
1038262395Sbapt
1039262395Sbapt	if (elt == NULL || key == NULL) {
1040262395Sbapt		return NULL;
1041262395Sbapt	}
1042262395Sbapt
1043262395Sbapt	if (top == NULL) {
1044262395Sbapt		top = ucl_object_new ();
1045262395Sbapt		top->type = UCL_OBJECT;
1046262395Sbapt	}
1047262395Sbapt
1048262395Sbapt	if (top->type != UCL_OBJECT) {
1049262395Sbapt		/* It is possible to convert NULL type to an object */
1050262395Sbapt		if (top->type == UCL_NULL) {
1051262395Sbapt			top->type = UCL_OBJECT;
1052262395Sbapt		}
1053262395Sbapt		else {
1054262395Sbapt			/* Refuse converting of other object types */
1055262395Sbapt			return top;
1056262395Sbapt		}
1057262395Sbapt	}
1058262395Sbapt
1059262395Sbapt	if (top->value.ov == NULL) {
1060262395Sbapt		top->value.ov = ucl_hash_create ();
1061262395Sbapt	}
1062262395Sbapt
1063262395Sbapt	if (keylen == 0) {
1064262395Sbapt		keylen = strlen (key);
1065262395Sbapt	}
1066262395Sbapt
1067262395Sbapt	for (p = key; p < key + keylen; p ++) {
1068262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) {
1069262395Sbapt			elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1070262395Sbapt			break;
1071262395Sbapt		}
1072262395Sbapt	}
1073262395Sbapt
1074262395Sbapt	elt->key = key;
1075262395Sbapt	elt->keylen = keylen;
1076262395Sbapt
1077262395Sbapt	if (copy_key) {
1078262395Sbapt		ucl_copy_key_trash (elt);
1079262395Sbapt	}
1080262395Sbapt
1081262395Sbapt	found = ucl_hash_search_obj (top->value.ov, elt);
1082262395Sbapt
1083262395Sbapt	if (!found) {
1084262395Sbapt		top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1085262395Sbapt		DL_APPEND (found, elt);
1086262395Sbapt	}
1087262395Sbapt	else {
1088262395Sbapt		if (replace) {
1089262395Sbapt			ucl_hash_delete (top->value.ov, found);
1090262395Sbapt			ucl_object_unref (found);
1091262395Sbapt			top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1092262395Sbapt			found = NULL;
1093262395Sbapt			DL_APPEND (found, elt);
1094262395Sbapt		}
1095262395Sbapt		else if (merge) {
1096262395Sbapt			if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
1097262395Sbapt				/* Insert old elt to new one */
1098262395Sbapt				elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false);
1099262395Sbapt				ucl_hash_delete (top->value.ov, found);
1100262395Sbapt				top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
1101262395Sbapt			}
1102262395Sbapt			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
1103262395Sbapt				/* Insert new to old */
1104262395Sbapt				found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false);
1105262395Sbapt			}
1106262395Sbapt			else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) {
1107262395Sbapt				/* Mix two hashes */
1108262395Sbapt				while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) {
1109262395Sbapt					ucl_object_ref (cur);
1110262395Sbapt					found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false);
1111262395Sbapt				}
1112262395Sbapt				ucl_object_unref (elt);
1113262395Sbapt			}
1114262395Sbapt			else {
1115262395Sbapt				/* Just make a list of scalars */
1116262395Sbapt				DL_APPEND (found, elt);
1117262395Sbapt			}
1118262395Sbapt		}
1119262395Sbapt		else {
1120262395Sbapt			DL_APPEND (found, elt);
1121262395Sbapt		}
1122262395Sbapt	}
1123262395Sbapt
1124262395Sbapt	return top;
1125262395Sbapt}
1126262395Sbapt
1127263032Sbaptbool
1128263032Sbaptucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen)
1129263032Sbapt{
1130263032Sbapt	ucl_object_t *found;
1131263032Sbapt
1132263032Sbapt	found = ucl_object_find_keyl(top, key, keylen);
1133263032Sbapt
1134263032Sbapt	if (found == NULL)
1135263032Sbapt		return false;
1136263032Sbapt
1137263032Sbapt	ucl_hash_delete(top->value.ov, found);
1138263032Sbapt	ucl_object_unref (found);
1139263032Sbapt	top->len --;
1140263032Sbapt
1141263032Sbapt	return true;
1142263032Sbapt}
1143263032Sbapt
1144263032Sbaptbool
1145263032Sbaptucl_object_delete_key(ucl_object_t *top, const char *key)
1146263032Sbapt{
1147263032Sbapt	return ucl_object_delete_keyl(top, key, 0);
1148263032Sbapt}
1149263032Sbapt
1150262395Sbaptucl_object_t *
1151262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
1152262395Sbapt		const char *key, size_t keylen, bool copy_key)
1153262395Sbapt{
1154262395Sbapt	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false);
1155262395Sbapt}
1156262395Sbapt
1157262395Sbaptucl_object_t *
1158262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
1159262395Sbapt		const char *key, size_t keylen, bool copy_key)
1160262395Sbapt{
1161262395Sbapt	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false);
1162262395Sbapt}
1163262395Sbapt
1164262395Sbaptucl_object_t *
1165262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
1166262395Sbapt		const char *key, size_t keylen, bool copy_key)
1167262395Sbapt{
1168262395Sbapt	return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
1169262395Sbapt}
1170262395Sbapt
1171262395Sbaptucl_object_t *
1172262395Sbaptucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen)
1173262395Sbapt{
1174262395Sbapt	ucl_object_t *ret, srch;
1175262395Sbapt
1176262395Sbapt	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1177262395Sbapt		return NULL;
1178262395Sbapt	}
1179262395Sbapt
1180262395Sbapt	srch.key = key;
1181262395Sbapt	srch.keylen = klen;
1182262395Sbapt	ret = ucl_hash_search_obj (obj->value.ov, &srch);
1183262395Sbapt
1184262395Sbapt	return ret;
1185262395Sbapt}
1186262395Sbapt
1187262395Sbaptucl_object_t *
1188262395Sbaptucl_object_find_key (ucl_object_t *obj, const char *key)
1189262395Sbapt{
1190262395Sbapt	size_t klen;
1191262395Sbapt	ucl_object_t *ret, srch;
1192262395Sbapt
1193262395Sbapt	if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
1194262395Sbapt		return NULL;
1195262395Sbapt	}
1196262395Sbapt
1197262395Sbapt	klen = strlen (key);
1198262395Sbapt	srch.key = key;
1199262395Sbapt	srch.keylen = klen;
1200262395Sbapt	ret = ucl_hash_search_obj (obj->value.ov, &srch);
1201262395Sbapt
1202262395Sbapt	return ret;
1203262395Sbapt}
1204262395Sbapt
1205262395Sbaptucl_object_t*
1206262395Sbaptucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
1207262395Sbapt{
1208262395Sbapt	ucl_object_t *elt;
1209262395Sbapt
1210262395Sbapt	if (expand_values) {
1211262395Sbapt		switch (obj->type) {
1212262395Sbapt		case UCL_OBJECT:
1213262395Sbapt			return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
1214262395Sbapt			break;
1215262395Sbapt		case UCL_ARRAY:
1216262395Sbapt			elt = *iter;
1217262395Sbapt			if (elt == NULL) {
1218262395Sbapt				elt = obj->value.av;
1219262395Sbapt				if (elt == NULL) {
1220262395Sbapt					return NULL;
1221262395Sbapt				}
1222262395Sbapt			}
1223262395Sbapt			else if (elt == obj->value.av) {
1224262395Sbapt				return NULL;
1225262395Sbapt			}
1226262395Sbapt			*iter = elt->next ? elt->next : obj->value.av;
1227262395Sbapt			return elt;
1228262395Sbapt		default:
1229262395Sbapt			/* Go to linear iteration */
1230262395Sbapt			break;
1231262395Sbapt		}
1232262395Sbapt	}
1233262395Sbapt	/* Treat everything as a linear list */
1234262395Sbapt	elt = *iter;
1235262395Sbapt	if (elt == NULL) {
1236262395Sbapt		elt = obj;
1237262395Sbapt		if (elt == NULL) {
1238262395Sbapt			return NULL;
1239262395Sbapt		}
1240262395Sbapt	}
1241262395Sbapt	else if (elt == obj) {
1242262395Sbapt		return NULL;
1243262395Sbapt	}
1244262395Sbapt	*iter = elt->next ? elt->next : obj;
1245262395Sbapt	return elt;
1246262395Sbapt
1247262395Sbapt	/* Not reached */
1248262395Sbapt	return NULL;
1249262395Sbapt}
1250