1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "zbxjson.h"
22 #include "json_parser.h"
23 #include "json.h"
24 #include "jsonpath.h"
25 
26 /******************************************************************************
27  *                                                                            *
28  * Function: zbx_json_strerror                                                *
29  *                                                                            *
30  * Purpose: return string describing json error                               *
31  *                                                                            *
32  * Return value: pointer to the null terminated string                        *
33  *                                                                            *
34  * Author: Eugene Grigorjev                                                   *
35  *                                                                            *
36  ******************************************************************************/
37 #define ZBX_JSON_MAX_STRERROR	255
38 
39 static ZBX_THREAD_LOCAL char	zbx_json_strerror_message[ZBX_JSON_MAX_STRERROR];
40 
zbx_json_strerror(void)41 const char	*zbx_json_strerror(void)
42 {
43 	return zbx_json_strerror_message;
44 }
45 
zbx_set_json_strerror(const char * fmt,...)46 void	zbx_set_json_strerror(const char *fmt, ...)
47 {
48 	size_t	sz;
49 	va_list	args;
50 
51 	va_start(args, fmt);
52 
53 	sz = zbx_vsnprintf(zbx_json_strerror_message, sizeof(zbx_json_strerror_message), fmt, args);
54 
55 	if (sizeof(zbx_json_strerror_message) - 1 == sz)
56 	{
57 		/* ensure that the string is not cut in the middle of UTF-8 sequence */
58 		size_t	idx = sz - 1;
59 		while (0x80 == (0xc0 & zbx_json_strerror_message[idx]) && 0 < idx)
60 			idx--;
61 
62 		if (zbx_utf8_char_len(zbx_json_strerror_message + idx) != sz - idx)
63 			zbx_json_strerror_message[idx] = '\0';
64 	}
65 
66 	va_end(args);
67 }
68 
69 /******************************************************************************
70  *                                                                            *
71  * Function: __zbx_json_realloc                                               *
72  *                                                                            *
73  * Author: Alexander Vladishev                                                *
74  *                                                                            *
75  ******************************************************************************/
__zbx_json_realloc(struct zbx_json * j,size_t need)76 static void	__zbx_json_realloc(struct zbx_json *j, size_t need)
77 {
78 	int	realloc = 0;
79 
80 	if (NULL == j->buffer)
81 	{
82 		if (need > sizeof(j->buf_stat))
83 		{
84 			j->buffer_allocated = need;
85 			j->buffer = (char *)zbx_malloc(j->buffer, j->buffer_allocated);
86 		}
87 		else
88 		{
89 			j->buffer_allocated = sizeof(j->buf_stat);
90 			j->buffer = j->buf_stat;
91 		}
92 		return;
93 	}
94 
95 	while (need > j->buffer_allocated)
96 	{
97 		if (0 == j->buffer_allocated)
98 			j->buffer_allocated = 1024;
99 		else
100 			j->buffer_allocated *= 2;
101 		realloc = 1;
102 	}
103 
104 	if (1 == realloc)
105 	{
106 		if (j->buffer == j->buf_stat)
107 		{
108 			j->buffer = NULL;
109 			j->buffer = (char *)zbx_malloc(j->buffer, j->buffer_allocated);
110 			memcpy(j->buffer, j->buf_stat, sizeof(j->buf_stat));
111 		}
112 		else
113 			j->buffer = (char *)zbx_realloc(j->buffer, j->buffer_allocated);
114 	}
115 }
116 
zbx_json_init(struct zbx_json * j,size_t allocate)117 void	zbx_json_init(struct zbx_json *j, size_t allocate)
118 {
119 	assert(j);
120 
121 	j->buffer = NULL;
122 	j->buffer_allocated = 0;
123 	j->buffer_offset = 0;
124 	j->buffer_size = 0;
125 	j->status = ZBX_JSON_EMPTY;
126 	j->level = 0;
127 	__zbx_json_realloc(j, allocate);
128 	*j->buffer = '\0';
129 
130 	zbx_json_addobject(j, NULL);
131 }
132 
zbx_json_initarray(struct zbx_json * j,size_t allocate)133 void	zbx_json_initarray(struct zbx_json *j, size_t allocate)
134 {
135 	assert(j);
136 
137 	j->buffer = NULL;
138 	j->buffer_allocated = 0;
139 	j->buffer_offset = 0;
140 	j->buffer_size = 0;
141 	j->status = ZBX_JSON_EMPTY;
142 	j->level = 0;
143 	__zbx_json_realloc(j, allocate);
144 	*j->buffer = '\0';
145 
146 	zbx_json_addarray(j, NULL);
147 }
148 
zbx_json_setempty(struct zbx_json * j)149 static void	zbx_json_setempty(struct zbx_json *j)
150 {
151 	j->buffer_offset = 0;
152 	j->buffer_size = 0;
153 	j->status = ZBX_JSON_EMPTY;
154 	j->level = 0;
155 	*j->buffer = '\0';
156 }
157 
zbx_json_cleanarray(struct zbx_json * j)158 void	zbx_json_cleanarray(struct zbx_json *j)
159 {
160 	zbx_json_setempty(j);
161 	zbx_json_addarray(j, NULL);
162 }
163 
zbx_json_clean(struct zbx_json * j)164 void	zbx_json_clean(struct zbx_json *j)
165 {
166 	zbx_json_setempty(j);
167 	zbx_json_addobject(j, NULL);
168 }
169 
zbx_json_free(struct zbx_json * j)170 void	zbx_json_free(struct zbx_json *j)
171 {
172 	assert(j);
173 
174 	if (j->buffer != j->buf_stat)
175 		zbx_free(j->buffer);
176 }
177 
__zbx_json_stringsize(const char * string,zbx_json_type_t type)178 static size_t	__zbx_json_stringsize(const char *string, zbx_json_type_t type)
179 {
180 	size_t		len = 0;
181 	const char	*sptr;
182 	char		buffer[] = {"null"};
183 
184 	for (sptr = (NULL != string ? string : buffer); '\0' != *sptr; sptr++)
185 	{
186 		switch (*sptr)
187 		{
188 			case '"':  /* quotation mark */
189 			case '\\': /* reverse solidus */
190 			/* We do not escape '/' (solidus). https://www.rfc-editor.org/errata_search.php?rfc=4627 */
191 			/* says: "/" and "\/" are both allowed and both produce the same result. */
192 			case '\b': /* backspace */
193 			case '\f': /* formfeed */
194 			case '\n': /* newline */
195 			case '\r': /* carriage return */
196 			case '\t': /* horizontal tab */
197 				len += 2;
198 				break;
199 			default:
200 				/* RFC 8259 requires escaping control characters U+0000 - U+001F */
201 				if (0x1f >= (unsigned char)*sptr)
202 					len += 6;
203 				else
204 					len++;
205 		}
206 	}
207 
208 	if (NULL != string && ZBX_JSON_TYPE_STRING == type)
209 		len += 2; /* "" */
210 
211 	return len;
212 }
213 
214 /******************************************************************************
215  *                                                                            *
216  * Function: zbx_num2hex                                                      *
217  *                                                                            *
218  * Purpose: convert parameter c (0-15) to hexadecimal value ('0'-'f')         *
219  *                                                                            *
220  * Parameters:                                                                *
221  *      c - number 0-15                                                       *
222  *                                                                            *
223  * Return value:                                                              *
224  *      '0'-'f'                                                               *
225  *                                                                            *
226  * Author: Alexander Vladishev                                                *
227  *                                                                            *
228  ******************************************************************************/
zbx_num2hex(unsigned char c)229 static char	zbx_num2hex(unsigned char c)
230 {
231 	if (c >= 10)
232 		return (char)(c + 0x57);	/* a-f */
233 	else
234 		return (char)(c + 0x30);	/* 0-9 */
235 }
236 
__zbx_json_insstring(char * p,const char * string,zbx_json_type_t type)237 static char	*__zbx_json_insstring(char *p, const char *string, zbx_json_type_t type)
238 {
239 	const char	*sptr;
240 	char		buffer[] = {"null"};
241 
242 	if (NULL != string && ZBX_JSON_TYPE_STRING == type)
243 		*p++ = '"';
244 
245 	for (sptr = (NULL != string ? string : buffer); '\0' != *sptr; sptr++)
246 	{
247 		switch (*sptr)
248 		{
249 			case '"':		/* quotation mark */
250 				*p++ = '\\';
251 				*p++ = '"';
252 				break;
253 			case '\\':		/* reverse solidus */
254 				*p++ = '\\';
255 				*p++ = '\\';
256 				break;
257 			/* We do not escape '/' (solidus). https://www.rfc-editor.org/errata_search.php?rfc=4627 */
258 			/* says: "/" and "\/" are both allowed and both produce the same result. */
259 			case '\b':		/* backspace */
260 				*p++ = '\\';
261 				*p++ = 'b';
262 				break;
263 			case '\f':		/* formfeed */
264 				*p++ = '\\';
265 				*p++ = 'f';
266 				break;
267 			case '\n':		/* newline */
268 				*p++ = '\\';
269 				*p++ = 'n';
270 				break;
271 			case '\r':		/* carriage return */
272 				*p++ = '\\';
273 				*p++ = 'r';
274 				break;
275 			case '\t':		/* horizontal tab */
276 				*p++ = '\\';
277 				*p++ = 't';
278 				break;
279 			default:
280 				/* RFC 8259 requires escaping control characters U+0000 - U+001F */
281 				if (0x1f >= (unsigned char)*sptr)
282 				{
283 					*p++ = '\\';
284 					*p++ = 'u';
285 					*p++ = '0';
286 					*p++ = '0';
287 					*p++ = zbx_num2hex((((unsigned char)*sptr) >> 4) & 0xf);
288 					*p++ = zbx_num2hex(((unsigned char)*sptr) & 0xf);
289 				}
290 				else
291 					*p++ = *sptr;
292 		}
293 	}
294 
295 	if (NULL != string && ZBX_JSON_TYPE_STRING == type)
296 		*p++ = '"';
297 
298 	return p;
299 }
300 
zbx_json_escape(char ** string)301 void	zbx_json_escape(char **string)
302 {
303 	size_t	size;
304 	char	*buffer;
305 
306 	if (0 == (size = __zbx_json_stringsize(*string, ZBX_JSON_TYPE_UNKNOWN)))
307 		return;
308 
309 	buffer = zbx_malloc(NULL, size + 1);
310 	buffer[size] = '\0';
311 	__zbx_json_insstring(buffer, *string, ZBX_JSON_TYPE_UNKNOWN);
312 	zbx_free(*string);
313 	*string = buffer;
314 }
315 
__zbx_json_addobject(struct zbx_json * j,const char * name,int object)316 static void	__zbx_json_addobject(struct zbx_json *j, const char *name, int object)
317 {
318 	size_t	len = 2; /* brackets */
319 	char	*p, *psrc, *pdst;
320 
321 	assert(j);
322 
323 	if (ZBX_JSON_COMMA == j->status)
324 		len++; /* , */
325 
326 	if (NULL != name)
327 	{
328 		len += __zbx_json_stringsize(name, ZBX_JSON_TYPE_STRING);
329 		len += 1; /* : */
330 	}
331 
332 	__zbx_json_realloc(j, j->buffer_size + len + 1/*'\0'*/);
333 
334 	psrc = j->buffer + j->buffer_offset;
335 	pdst = j->buffer + j->buffer_offset + len;
336 
337 	memmove(pdst, psrc, j->buffer_size - j->buffer_offset + 1/*'\0'*/);
338 
339 	p = psrc;
340 
341 	if (ZBX_JSON_COMMA == j->status)
342 		*p++ = ',';
343 
344 	if (NULL != name)
345 	{
346 		p = __zbx_json_insstring(p, name, ZBX_JSON_TYPE_STRING);
347 		*p++ = ':';
348 	}
349 
350 	*p++ = object ? '{' : '[';
351 	*p = object ? '}' : ']';
352 
353 	j->buffer_offset = p - j->buffer;
354 	j->buffer_size += len;
355 	j->level++;
356 	j->status = ZBX_JSON_EMPTY;
357 }
358 
zbx_json_addobject(struct zbx_json * j,const char * name)359 void	zbx_json_addobject(struct zbx_json *j, const char *name)
360 {
361 	__zbx_json_addobject(j, name, 1);
362 }
363 
zbx_json_addarray(struct zbx_json * j,const char * name)364 void	zbx_json_addarray(struct zbx_json *j, const char *name)
365 {
366 	__zbx_json_addobject(j, name, 0);
367 }
368 
zbx_json_addstring(struct zbx_json * j,const char * name,const char * string,zbx_json_type_t type)369 void	zbx_json_addstring(struct zbx_json *j, const char *name, const char *string, zbx_json_type_t type)
370 {
371 	size_t	len = 0;
372 	char	*p, *psrc, *pdst;
373 
374 	assert(j);
375 
376 	if (ZBX_JSON_COMMA == j->status)
377 		len++; /* , */
378 
379 	if (NULL != name)
380 	{
381 		len += __zbx_json_stringsize(name, ZBX_JSON_TYPE_STRING);
382 		len += 1; /* : */
383 	}
384 	len += __zbx_json_stringsize(string, type);
385 
386 	__zbx_json_realloc(j, j->buffer_size + len + 1/*'\0'*/);
387 
388 	psrc = j->buffer + j->buffer_offset;
389 	pdst = j->buffer + j->buffer_offset + len;
390 
391 	memmove(pdst, psrc, j->buffer_size - j->buffer_offset + 1/*'\0'*/);
392 
393 	p = psrc;
394 
395 	if (ZBX_JSON_COMMA == j->status)
396 		*p++ = ',';
397 
398 	if (NULL != name)
399 	{
400 		p = __zbx_json_insstring(p, name, ZBX_JSON_TYPE_STRING);
401 		*p++ = ':';
402 	}
403 	p = __zbx_json_insstring(p, string, type);
404 
405 	j->buffer_offset = p - j->buffer;
406 	j->buffer_size += len;
407 	j->status = ZBX_JSON_COMMA;
408 }
409 
zbx_json_addraw(struct zbx_json * j,const char * name,const char * data)410 void	zbx_json_addraw(struct zbx_json *j, const char *name, const char *data)
411 {
412 	size_t	len = 0, len_data;
413 	char	*p, *psrc, *pdst;
414 
415 	assert(j);
416 	len_data = strlen(data);
417 
418 	if (ZBX_JSON_COMMA == j->status)
419 		len++; /* , */
420 
421 	if (NULL != name)
422 	{
423 		len += __zbx_json_stringsize(name, ZBX_JSON_TYPE_STRING);
424 		len += 1; /* : */
425 	}
426 	len += len_data;
427 
428 	__zbx_json_realloc(j, j->buffer_size + len + 1/*'\0'*/);
429 
430 	psrc = j->buffer + j->buffer_offset;
431 	pdst = j->buffer + j->buffer_offset + len;
432 
433 	memmove(pdst, psrc, j->buffer_size - j->buffer_offset + 1/*'\0'*/);
434 
435 	p = psrc;
436 
437 	if (ZBX_JSON_COMMA == j->status)
438 		*p++ = ',';
439 
440 	if (NULL != name)
441 	{
442 		p = __zbx_json_insstring(p, name, ZBX_JSON_TYPE_STRING);
443 		*p++ = ':';
444 	}
445 
446 	memcpy(p, data, len_data);
447 	p += len_data;
448 
449 	j->buffer_offset = p - j->buffer;
450 	j->buffer_size += len;
451 	j->status = ZBX_JSON_COMMA;
452 }
453 
zbx_json_adduint64(struct zbx_json * j,const char * name,zbx_uint64_t value)454 void	zbx_json_adduint64(struct zbx_json *j, const char *name, zbx_uint64_t value)
455 {
456 	char	buffer[MAX_ID_LEN];
457 
458 	zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, value);
459 	zbx_json_addstring(j, name, buffer, ZBX_JSON_TYPE_INT);
460 }
461 
zbx_json_addint64(struct zbx_json * j,const char * name,zbx_int64_t value)462 void	zbx_json_addint64(struct zbx_json *j, const char *name, zbx_int64_t value)
463 {
464 	char	buffer[MAX_ID_LEN];
465 
466 	zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_I64, value);
467 	zbx_json_addstring(j, name, buffer, ZBX_JSON_TYPE_INT);
468 }
469 
zbx_json_addfloat(struct zbx_json * j,const char * name,double value)470 void	zbx_json_addfloat(struct zbx_json *j, const char *name, double value)
471 {
472 	char	buffer[MAX_ID_LEN];
473 
474 	zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_DBL, value);
475 	zbx_json_addstring(j, name, buffer, ZBX_JSON_TYPE_INT);
476 }
477 
zbx_json_close(struct zbx_json * j)478 int	zbx_json_close(struct zbx_json *j)
479 {
480 	if (1 == j->level)
481 	{
482 		zbx_set_json_strerror("cannot close top level object");
483 		return FAIL;
484 	}
485 
486 	j->level--;
487 	j->buffer_offset++;
488 	j->status = ZBX_JSON_COMMA;
489 
490 	return SUCCEED;
491 }
492 
493 /******************************************************************************
494  *                                                                            *
495  * Function: __zbx_json_type                                                  *
496  *                                                                            *
497  * Purpose: return type of pointed value                                      *
498  *                                                                            *
499  * Return value: type of pointed value                                        *
500  *                                                                            *
501  * Author: Alexander Vladishev                                                *
502  *                                                                            *
503  ******************************************************************************/
__zbx_json_type(const char * p)504 static zbx_json_type_t	__zbx_json_type(const char *p)
505 {
506 	if ('"' == *p)
507 		return ZBX_JSON_TYPE_STRING;
508 	if (('0' <= *p && *p <= '9') || '-' == *p)
509 		return ZBX_JSON_TYPE_INT;
510 	if ('[' == *p)
511 		return ZBX_JSON_TYPE_ARRAY;
512 	if ('{' == *p)
513 		return ZBX_JSON_TYPE_OBJECT;
514 	if ('n' == p[0] && 'u' == p[1] && 'l' == p[2] && 'l' == p[3])
515 		return ZBX_JSON_TYPE_NULL;
516 	if ('t' == p[0] && 'r' == p[1] && 'u' == p[2] && 'e' == p[3])
517 		return ZBX_JSON_TYPE_TRUE;
518 	if ('f' == p[0] && 'a' == p[1] && 'l' == p[2] && 's' == p[3] && 'e' == p[4])
519 		return ZBX_JSON_TYPE_FALSE;
520 
521 	zbx_set_json_strerror("invalid type of JSON value \"%.64s\"", p);
522 
523 	return ZBX_JSON_TYPE_UNKNOWN;
524 }
525 
526 /******************************************************************************
527  *                                                                            *
528  * Function: __zbx_json_rbracket                                              *
529  *                                                                            *
530  * Purpose: return position of right bracket                                  *
531  *                                                                            *
532  * Return value: position of right bracket                                    *
533  *               NULL - an error occurred                                     *
534  *                                                                            *
535  * Author: Alexander Vladishev                                                *
536  *                                                                            *
537  ******************************************************************************/
__zbx_json_rbracket(const char * p)538 static const char	*__zbx_json_rbracket(const char *p)
539 {
540 	int	level = 0;
541 	int	state = 0; /* 0 - outside string; 1 - inside string */
542 	char	lbracket, rbracket;
543 
544 	assert(p);
545 
546 	lbracket = *p;
547 
548 	if ('{' != lbracket && '[' != lbracket)
549 		return NULL;
550 
551 	rbracket = ('{' == lbracket ? '}' : ']');
552 
553 	while ('\0' != *p)
554 	{
555 		switch (*p)
556 		{
557 			case '"':
558 				state = (0 == state ? 1 : 0);
559 				break;
560 			case '\\':
561 				if (1 == state)
562 					if ('\0' == *++p)
563 						return NULL;
564 				break;
565 			case '[':
566 			case '{':
567 				if (0 == state)
568 					level++;
569 				break;
570 			case ']':
571 			case '}':
572 				if (0 == state)
573 				{
574 					level--;
575 					if (0 == level)
576 						return (rbracket == *p ? p : NULL);
577 				}
578 				break;
579 		}
580 		p++;
581 	}
582 
583 	return NULL;
584 }
585 
586 /******************************************************************************
587  *                                                                            *
588  * Function: zbx_json_open                                                    *
589  *                                                                            *
590  * Purpose: open json buffer and check for brackets                           *
591  *                                                                            *
592  * Return value: SUCCESS - processed successfully                             *
593  *               FAIL - an error occurred                                     *
594  *                                                                            *
595  ******************************************************************************/
zbx_json_open(const char * buffer,struct zbx_json_parse * jp)596 int	zbx_json_open(const char *buffer, struct zbx_json_parse *jp)
597 {
598 	char		*error = NULL;
599 	zbx_int64_t	len;
600 
601 	SKIP_WHITESPACE(buffer);
602 
603 	/* return immediate failure without logging when opening empty string */
604 	if ('\0' == *buffer)
605 		return FAIL;
606 
607 	jp->start = buffer;
608 	jp->end = NULL;
609 
610 	if (0 == (len = zbx_json_validate(jp->start, &error)))
611 	{
612 		if (NULL != error)
613 		{
614 			zbx_set_json_strerror("cannot parse as a valid JSON object: %s", error);
615 			zbx_free(error);
616 		}
617 		else
618 		{
619 			zbx_set_json_strerror("cannot parse as a valid JSON object \"%.64s\"", buffer);
620 		}
621 
622 		return FAIL;
623 	}
624 
625 	jp->end = jp->start + len - 1;
626 
627 	return SUCCEED;
628 }
629 
630 /******************************************************************************
631  *                                                                            *
632  * Function: zbx_json_next                                                    *
633  *                                                                            *
634  * Purpose: locate next pair or element                                       *
635  *                                                                            *
636  * Return value: NULL - no more values                                        *
637  *               NOT NULL - pointer to pair or element                        *
638  *      {"name",...    or  "array":["name", ... ,1,null]                      *
639  * p =   ^                                         ^                          *
640  *                                                                            *
641  * Author: Alexander Vladishev                                                *
642  *                                                                            *
643  ******************************************************************************/
zbx_json_next(const struct zbx_json_parse * jp,const char * p)644 const char	*zbx_json_next(const struct zbx_json_parse *jp, const char *p)
645 {
646 	int	level = 0;
647 	int	state = 0;	/* 0 - outside string; 1 - inside string */
648 
649 	if (1 == jp->end - jp->start)	/* empty object or array */
650 		return NULL;
651 
652 	if (NULL == p)
653 	{
654 		p = jp->start + 1;
655 		SKIP_WHITESPACE(p);
656 		return p;
657 	}
658 
659 	while (p <= jp->end)
660 	{
661 		switch (*p)
662 		{
663 			case '"':
664 				state = (0 == state) ? 1 : 0;
665 				break;
666 			case '\\':
667 				if (1 == state)
668 					p++;
669 				break;
670 			case '[':
671 			case '{':
672 				if (0 == state)
673 					level++;
674 				break;
675 			case ']':
676 			case '}':
677 				if (0 == state)
678 				{
679 					if (0 == level)
680 						return NULL;
681 					level--;
682 				}
683 				break;
684 			case ',':
685 				if (0 == state && 0 == level)
686 				{
687 					p++;
688 					SKIP_WHITESPACE(p);
689 					return p;
690 				}
691 				break;
692 		}
693 		p++;
694 	}
695 
696 	return NULL;
697 }
698 
699 /******************************************************************************
700  *                                                                            *
701  * Function: zbx_is_valid_json_hex                                            *
702  *                                                                            *
703  * Purpose: check if a 4 character sequence is a valid hex number 0000 - FFFF *
704  *                                                                            *
705  * Parameters:                                                                *
706  *      p - pointer to the 1st character                                      *
707  *                                                                            *
708  * Return value: SUCCEED or FAIL                                              *
709  *                                                                            *
710  ******************************************************************************/
zbx_is_valid_json_hex(const char * p)711 static int	zbx_is_valid_json_hex(const char *p)
712 {
713 	int	i;
714 
715 	for (i = 0; i < 4; ++i, ++p)
716 	{
717 		if (0 == isxdigit(*p))
718 			return FAIL;
719 	}
720 
721 	return SUCCEED;
722 }
723 
724 /******************************************************************************
725  *                                                                            *
726  * Function: zbx_hex2num                                                      *
727  *                                                                            *
728  * Purpose: convert hexit c ('0'-'9''a'-'f''A'-'F') to number (0-15)          *
729  *                                                                            *
730  * Parameters:                                                                *
731  *      c - char ('0'-'9''a'-'f''A'-'F')                                      *
732  *                                                                            *
733  * Return value:                                                              *
734  *      0-15                                                                  *
735  *                                                                            *
736  * Author: Alexander Vladishev                                                *
737  *                                                                            *
738  ******************************************************************************/
zbx_hex2num(char c)739 static unsigned int	zbx_hex2num(char c)
740 {
741 	int	res;
742 
743 	if (c >= 'a')
744 		res = c - 'a' + 10;	/* a-f */
745 	else if (c >= 'A')
746 		res = c - 'A' + 10;	/* A-F */
747 	else
748 		res = c - '0';		/* 0-9 */
749 
750 	return (unsigned int)res;
751 }
752 
753 /******************************************************************************
754  *                                                                            *
755  * Function: zbx_json_decode_character                                        *
756  *                                                                            *
757  * Purpose: decodes JSON escape character into UTF-8                          *
758  *                                                                            *
759  * Parameters: p - [IN/OUT] a pointer to the first character in string        *
760  *             bytes - [OUT] a 4-element array where 1 - 4 bytes of character *
761  *                     UTF-8 representation are written                       *
762  *                                                                            *
763  * Return value: number of UTF-8 bytes written into 'bytes' array or          *
764  *               0 on error (invalid escape sequence)                         *
765  *                                                                            *
766  ******************************************************************************/
zbx_json_decode_character(const char ** p,unsigned char * bytes)767 static unsigned int	zbx_json_decode_character(const char **p, unsigned char *bytes)
768 {
769 	bytes[0] = '\0';
770 
771 	switch (**p)
772 	{
773 		case '"':
774 			bytes[0] = '"';
775 			break;
776 		case '\\':
777 			bytes[0] = '\\';
778 			break;
779 		case '/':
780 			bytes[0] = '/';
781 			break;
782 		case 'b':
783 			bytes[0] = '\b';
784 			break;
785 		case 'f':
786 			bytes[0] = '\f';
787 			break;
788 		case 'n':
789 			bytes[0] = '\n';
790 			break;
791 		case 'r':
792 			bytes[0] = '\r';
793 			break;
794 		case 't':
795 			bytes[0] = '\t';
796 			break;
797 		default:
798 			break;
799 	}
800 
801 	if ('\0' != bytes[0])
802 	{
803 		++*p;
804 		return 1;
805 	}
806 
807 	if ('u' == **p)		/* \u0000 - \uffff */
808 	{
809 		unsigned int	num;
810 
811 		if (FAIL == zbx_is_valid_json_hex(++*p))
812 			return 0;
813 
814 		num = zbx_hex2num(**p) << 12;
815 		num += zbx_hex2num(*(++*p)) << 8;
816 		num += zbx_hex2num(*(++*p)) << 4;
817 		num += zbx_hex2num(*(++*p));
818 		++*p;
819 
820 		if (0x007f >= num)	/* 0000 - 007f */
821 		{
822 			bytes[0] = (unsigned char)num;
823 			return 1;
824 		}
825 		else if (0x07ff >= num)	/* 0080 - 07ff */
826 		{
827 			bytes[0] = (unsigned char)(0xc0 | ((num >> 6) & 0x1f));
828 			bytes[1] = (unsigned char)(0x80 | (num & 0x3f));
829 			return 2;
830 		}
831 		else if (0xd7ff >= num || 0xe000 <= num)	/* 0800 - d7ff or e000 - ffff */
832 		{
833 			bytes[0] = (unsigned char)(0xe0 | ((num >> 12) & 0x0f));
834 			bytes[1] = (unsigned char)(0x80 | ((num >> 6) & 0x3f));
835 			bytes[2] = (unsigned char)(0x80 | (num & 0x3f));
836 			return 3;
837 		}
838 		else if (0xd800 <= num && num <= 0xdbff)	/* high surrogate d800 - dbff */
839 		{
840 			unsigned int	num_lo, uc;
841 
842 			/* collect the low surrogate */
843 
844 			if ('\\' != **p || 'u' != *(++*p) || FAIL == zbx_is_valid_json_hex(++*p))
845 				return 0;
846 
847 			num_lo = zbx_hex2num(**p) << 12;
848 			num_lo += zbx_hex2num(*(++*p)) << 8;
849 			num_lo += zbx_hex2num(*(++*p)) << 4;
850 			num_lo += zbx_hex2num(*(++*p));
851 			++*p;
852 
853 			if (num_lo < 0xdc00 || 0xdfff < num_lo)		/* low surrogate range is dc00 - dfff */
854 				return 0;
855 
856 			/* decode surrogate pair */
857 
858 			uc = 0x010000 + ((num & 0x03ff) << 10) + (num_lo & 0x03ff);
859 
860 			bytes[0] = (unsigned char)(0xf0 | ((uc >> 18) & 0x07));
861 			bytes[1] = (unsigned char)(0x80 | ((uc >> 12) & 0x3f));
862 			bytes[2] = (unsigned char)(0x80 | ((uc >> 6) & 0x3f));
863 			bytes[3] = (unsigned char)(0x80 | (uc & 0x3f));
864 			return 4;
865 		}
866 		/* error - low surrogate without high surrogate */
867 	}
868 
869 	return 0;
870 }
871 
872 /******************************************************************************
873  *                                                                            *
874  * Function: zbx_json_copy_string                                             *
875  *                                                                            *
876  * Purpose: copies json name/string value by omitting leading/trailing " and  *
877  *          converting escape sequences                                       *
878  *                                                                            *
879  * Parameters: p     - [IN] a pointer to the next character in string         *
880  *             out   - [OUT] the output buffer                                *
881  *             size  - [IN] the output buffer size                            *
882  *                                                                            *
883  * Return value: A pointer to the next character in input string or NULL if   *
884  *               string copying failed.                                       *
885  *                                                                            *
886  ******************************************************************************/
zbx_json_copy_string(const char * p,char * out,size_t size)887 static const char	*zbx_json_copy_string(const char *p, char *out, size_t size)
888 {
889 	char	*start = out;
890 
891 	if (0 == size)
892 		return NULL;
893 
894 	p++;
895 
896 	while ('\0' != *p)
897 	{
898 		switch (*p)
899 		{
900 			unsigned int	nbytes, i;
901 			unsigned char	uc[4];	/* decoded Unicode character takes 1-4 bytes in UTF-8 */
902 
903 			case '\\':
904 				++p;
905 				if (0 == (nbytes = zbx_json_decode_character(&p, uc)))
906 					return NULL;
907 
908 				if ((size_t)(out - start) + nbytes >= size)
909 					return NULL;
910 
911 				for (i = 0; i < nbytes; ++i)
912 					*out++ = (char)uc[i];
913 
914 				break;
915 			case '"':
916 				*out = '\0';
917 				return ++p;
918 			default:
919 				*out++ = *p++;
920 		}
921 
922 		if ((size_t)(out - start) == size)
923 			break;
924 	}
925 
926 	return NULL;
927 }
928 
929 /******************************************************************************
930  *                                                                            *
931  * Function: zbx_json_copy_value                                              *
932  *                                                                            *
933  * Purpose: copies unquoted (numeric, boolean) json value                     *
934  *                                                                            *
935  * Parameters: p     - [IN] a pointer to the next character in string         *
936  *             len   - [IN] the value length                                  *
937  *             out   - [OUT] the output buffer                                *
938  *             size  - [IN] the output buffer size                            *
939  *                                                                            *
940  * Return value: A pointer to the next character in input string or NULL if   *
941  *               string copying failed.                                       *
942  *                                                                            *
943  ******************************************************************************/
zbx_json_copy_unquoted_value(const char * p,size_t len,char * out,size_t size)944 static const char	*zbx_json_copy_unquoted_value(const char *p, size_t len, char *out, size_t size)
945 {
946 	if (size < len + 1)
947 		return NULL;
948 
949 	memcpy(out, p, len);
950 	out[len] = '\0';
951 
952 	return p + len;
953 }
954 
zbx_json_decodevalue(const char * p,char * string,size_t size,zbx_json_type_t * type)955 const char	*zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_json_type_t *type)
956 {
957 	size_t		len;
958 	zbx_json_type_t	type_local;
959 
960 	switch (type_local = __zbx_json_type(p))
961 	{
962 		case ZBX_JSON_TYPE_ARRAY:
963 		case ZBX_JSON_TYPE_OBJECT:
964 		case ZBX_JSON_TYPE_UNKNOWN:
965 			/* only primitive values are decoded */
966 			return NULL;
967 		default:
968 			if (0 == (len = json_parse_value(p, NULL)))
969 				return NULL;
970 	}
971 
972 	if (NULL != type)
973 		*type = type_local;
974 
975 	switch (type_local)
976 	{
977 		case ZBX_JSON_TYPE_STRING:
978 			return zbx_json_copy_string(p, string, size);
979 		case ZBX_JSON_TYPE_NULL:
980 			if (0 == size)
981 				return NULL;
982 			*string = '\0';
983 			return p + len;
984 		default: /* ZBX_JSON_TYPE_INT, ZBX_JSON_TYPE_TRUE, ZBX_JSON_TYPE_FALSE */
985 			return zbx_json_copy_unquoted_value(p, len, string, size);
986 	}
987 }
988 
zbx_json_decodevalue_dyn(const char * p,char ** string,size_t * string_alloc,zbx_json_type_t * type)989 const char	*zbx_json_decodevalue_dyn(const char *p, char **string, size_t *string_alloc, zbx_json_type_t *type)
990 {
991 	size_t		len;
992 	zbx_json_type_t	type_local;
993 
994 	switch (type_local = __zbx_json_type(p))
995 	{
996 		case ZBX_JSON_TYPE_ARRAY:
997 		case ZBX_JSON_TYPE_OBJECT:
998 		case ZBX_JSON_TYPE_UNKNOWN:
999 			/* only primitive values are decoded */
1000 			return NULL;
1001 		default:
1002 			if (0 == (len = json_parse_value(p, NULL)))
1003 				return NULL;
1004 	}
1005 
1006 	if (*string_alloc <= len)
1007 	{
1008 		*string_alloc = len + 1;
1009 		*string = (char *)zbx_realloc(*string, *string_alloc);
1010 	}
1011 
1012 	if (NULL != type)
1013 		*type = type_local;
1014 
1015 	switch (type_local)
1016 	{
1017 		case ZBX_JSON_TYPE_STRING:
1018 			return zbx_json_copy_string(p, *string, *string_alloc);
1019 		case ZBX_JSON_TYPE_NULL:
1020 			**string = '\0';
1021 			return p + len;
1022 		default: /* ZBX_JSON_TYPE_INT, ZBX_JSON_TYPE_TRUE, ZBX_JSON_TYPE_FALSE */
1023 			return zbx_json_copy_unquoted_value(p, len, *string, *string_alloc);
1024 	}
1025 }
1026 
zbx_json_pair_next(const struct zbx_json_parse * jp,const char * p,char * name,size_t len)1027 const char	*zbx_json_pair_next(const struct zbx_json_parse *jp, const char *p, char *name, size_t len)
1028 {
1029 	if (NULL == (p = zbx_json_next(jp, p)))
1030 		return NULL;
1031 
1032 	if (ZBX_JSON_TYPE_STRING != __zbx_json_type(p))
1033 		return NULL;
1034 
1035 	if (NULL == (p = zbx_json_copy_string(p, name, len)))
1036 		return NULL;
1037 
1038 	SKIP_WHITESPACE(p);
1039 
1040 	if (':' != *p++)
1041 		return NULL;
1042 
1043 	SKIP_WHITESPACE(p);
1044 
1045 	return p;
1046 }
1047 
1048 /******************************************************************************
1049  *                                                                            *
1050  * Function: zbx_json_pair_by_name                                            *
1051  *                                                                            *
1052  * Purpose: find pair by name and return pointer to value                     *
1053  *                                                                            *
1054  * Return value: pointer to value                                             *
1055  *        {"name":["a","b",...]}                                              *
1056  *                ^ - returned pointer                                        *
1057  *                                                                            *
1058  * Author: Alexander Vladishev                                                *
1059  *                                                                            *
1060  ******************************************************************************/
zbx_json_pair_by_name(const struct zbx_json_parse * jp,const char * name)1061 const char	*zbx_json_pair_by_name(const struct zbx_json_parse *jp, const char *name)
1062 {
1063 	char		buffer[MAX_STRING_LEN];
1064 	const char	*p = NULL;
1065 
1066 	while (NULL != (p = zbx_json_pair_next(jp, p, buffer, sizeof(buffer))))
1067 		if (0 == strcmp(name, buffer))
1068 			return p;
1069 
1070 	zbx_set_json_strerror("cannot find pair with name \"%s\"", name);
1071 
1072 	return NULL;
1073 }
1074 
1075 /******************************************************************************
1076  *                                                                            *
1077  * Function: zbx_json_next_value                                              *
1078  *                                                                            *
1079  * Author: Alexander Vladishev                                                *
1080  *                                                                            *
1081  ******************************************************************************/
zbx_json_next_value(const struct zbx_json_parse * jp,const char * p,char * string,size_t len,zbx_json_type_t * type)1082 const char	*zbx_json_next_value(const struct zbx_json_parse *jp, const char *p, char *string, size_t len,
1083 		zbx_json_type_t *type)
1084 {
1085 	if (NULL == (p = zbx_json_next(jp, p)))
1086 		return NULL;
1087 
1088 	return zbx_json_decodevalue(p, string, len, type);
1089 }
1090 
1091 /******************************************************************************
1092  *                                                                            *
1093  * Function: zbx_json_next_value_dyn                                          *
1094  *                                                                            *
1095  ******************************************************************************/
zbx_json_next_value_dyn(const struct zbx_json_parse * jp,const char * p,char ** string,size_t * string_alloc,zbx_json_type_t * type)1096 const char	*zbx_json_next_value_dyn(const struct zbx_json_parse *jp, const char *p, char **string,
1097 		size_t *string_alloc, zbx_json_type_t *type)
1098 {
1099 	if (NULL == (p = zbx_json_next(jp, p)))
1100 		return NULL;
1101 
1102 	return zbx_json_decodevalue_dyn(p, string, string_alloc, type);
1103 }
1104 
1105 /******************************************************************************
1106  *                                                                            *
1107  * Function: zbx_json_value_by_name                                           *
1108  *                                                                            *
1109  * Purpose: return value by pair name                                         *
1110  *                                                                            *
1111  * Return value: SUCCEED - if value successfully parsed, FAIL - otherwise     *
1112  *                                                                            *
1113  * Author: Alexander Vladishev                                                *
1114  *                                                                            *
1115  ******************************************************************************/
zbx_json_value_by_name(const struct zbx_json_parse * jp,const char * name,char * string,size_t len,zbx_json_type_t * type)1116 int	zbx_json_value_by_name(const struct zbx_json_parse *jp, const char *name, char *string, size_t len,
1117 		zbx_json_type_t *type)
1118 {
1119 	const char	*p;
1120 
1121 	if (NULL == (p = zbx_json_pair_by_name(jp, name)))
1122 		return FAIL;
1123 
1124 	if (NULL == zbx_json_decodevalue(p, string, len, type))
1125 		return FAIL;
1126 
1127 	return SUCCEED;
1128 }
1129 
1130 /******************************************************************************
1131  *                                                                            *
1132  * Function: zbx_json_value_by_name_dyn                                       *
1133  *                                                                            *
1134  * Purpose: return value by pair name                                         *
1135  *                                                                            *
1136  * Return value: SUCCEED - if value successfully parsed, FAIL - otherwise     *
1137  *                                                                            *
1138  * Author: Alexander Vladishev                                                *
1139  *                                                                            *
1140  ******************************************************************************/
zbx_json_value_by_name_dyn(const struct zbx_json_parse * jp,const char * name,char ** string,size_t * string_alloc,zbx_json_type_t * type)1141 int	zbx_json_value_by_name_dyn(const struct zbx_json_parse *jp, const char *name, char **string,
1142 		size_t *string_alloc, zbx_json_type_t *type)
1143 {
1144 	const char	*p;
1145 
1146 	if (NULL == (p = zbx_json_pair_by_name(jp, name)))
1147 		return FAIL;
1148 
1149 	if (NULL == zbx_json_decodevalue_dyn(p, string, string_alloc, type))
1150 		return FAIL;
1151 
1152 	return SUCCEED;
1153 }
1154 
1155 /******************************************************************************
1156  *                                                                            *
1157  * Function: zbx_json_brackets_open                                           *
1158  *                                                                            *
1159  * Return value: SUCCESS - processed successfully                             *
1160  *               FAIL - an error occurred                                     *
1161  *                                                                            *
1162  * Author: Alexander Vladishev                                                *
1163  *                                                                            *
1164  ******************************************************************************/
zbx_json_brackets_open(const char * p,struct zbx_json_parse * jp)1165 int	zbx_json_brackets_open(const char *p, struct zbx_json_parse *jp)
1166 {
1167 	if (NULL == (jp->end = __zbx_json_rbracket(p)))
1168 	{
1169 		zbx_set_json_strerror("cannot open JSON object or array \"%.64s\"", p);
1170 		return FAIL;
1171 	}
1172 
1173 	SKIP_WHITESPACE(p);
1174 
1175 	jp->start = p;
1176 
1177 	return SUCCEED;
1178 }
1179 
1180 /******************************************************************************
1181  *                                                                            *
1182  * Function: zbx_json_brackets_by_name                                        *
1183  *                                                                            *
1184  * Return value: SUCCESS - processed successfully                             *
1185  *               FAIL - an error occurred                                     *
1186  *                                                                            *
1187  * Author: Alexander Vladishev                                                *
1188  *                                                                            *
1189  ******************************************************************************/
zbx_json_brackets_by_name(const struct zbx_json_parse * jp,const char * name,struct zbx_json_parse * out)1190 int	zbx_json_brackets_by_name(const struct zbx_json_parse *jp, const char *name, struct zbx_json_parse *out)
1191 {
1192 	const char	*p;
1193 
1194 	if (NULL == (p = zbx_json_pair_by_name(jp, name)))
1195 		return FAIL;
1196 
1197 	if (FAIL == zbx_json_brackets_open(p, out))
1198 		return FAIL;
1199 
1200 	return SUCCEED;
1201 }
1202 
1203 /******************************************************************************
1204  *                                                                            *
1205  * Function: zbx_json_object_is_empty                                         *
1206  *                                                                            *
1207  * Return value: SUCCESS - if object is empty                                 *
1208  *               FAIL - if object contains data                               *
1209  *                                                                            *
1210  * Author: Alexander Vladishev                                                *
1211  *                                                                            *
1212  ******************************************************************************/
zbx_json_object_is_empty(const struct zbx_json_parse * jp)1213 int	zbx_json_object_is_empty(const struct zbx_json_parse *jp)
1214 {
1215 	return jp->end - jp->start > 1 ? FAIL : SUCCEED;
1216 }
1217 
1218 /******************************************************************************
1219  *                                                                            *
1220  * Function: zbx_json_count                                                   *
1221  *                                                                            *
1222  * Return value: number of elements in zbx_json_parse object                  *
1223  *                                                                            *
1224  * Author: Alexander Vladishev                                                *
1225  *                                                                            *
1226  ******************************************************************************/
zbx_json_count(const struct zbx_json_parse * jp)1227 int	zbx_json_count(const struct zbx_json_parse *jp)
1228 {
1229 	int		num = 0;
1230 	const char	*p = NULL;
1231 
1232 	while (NULL != (p = zbx_json_next(jp, p)))
1233 		num++;
1234 
1235 	return num;
1236 }
1237 
1238 /******************************************************************************
1239  *                                                                            *
1240  * Function: zbx_json_open_path                                               *
1241  *                                                                            *
1242  * Purpose: opens an object by definite json path                             *
1243  *                                                                            *
1244  * Return value: SUCCESS - processed successfully                             *
1245  *               FAIL - an error occurred                                     *
1246  *                                                                            *
1247  * Comments: Only direct path to single object in dot or bracket notation     *
1248  *           is supported.                                                    *
1249  *                                                                            *
1250  ******************************************************************************/
zbx_json_open_path(const struct zbx_json_parse * jp,const char * path,struct zbx_json_parse * out)1251 int	zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out)
1252 {
1253 	int			i, ret = FAIL;
1254 	struct zbx_json_parse	object;
1255 	zbx_jsonpath_t		jsonpath;
1256 
1257 	object = *jp;
1258 
1259 	if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
1260 		return FAIL;
1261 
1262 	if (0 == jsonpath.definite)
1263 	{
1264 		zbx_set_json_strerror("cannot use indefinite path when opening sub element");
1265 		goto out;
1266 	}
1267 
1268 	for (i = 0; i < jsonpath.segments_num; i++)
1269 	{
1270 		const char		*p;
1271 		zbx_jsonpath_segment_t	*segment = &jsonpath.segments[i];
1272 
1273 		if (ZBX_JSONPATH_SEGMENT_MATCH_LIST != segment->type)
1274 		{
1275 			zbx_set_json_strerror("jsonpath segment %d is not a name or index", i + 1);
1276 			goto out;
1277 		}
1278 
1279 		if (ZBX_JSONPATH_LIST_INDEX == segment->data.list.type)
1280 		{
1281 			int	index;
1282 
1283 			if ('[' != *object.start)
1284 				goto out;
1285 
1286 			memcpy(&index, segment->data.list.values->data, sizeof(int));
1287 
1288 			for (p = NULL; NULL != (p = zbx_json_next(&object, p)) && 0 != index; index--)
1289 				;
1290 
1291 			if (0 != index || NULL == p)
1292 			{
1293 				zbx_set_json_strerror("array index out of bounds in jsonpath segment %d", i + 1);
1294 				goto out;
1295 			}
1296 		}
1297 		else
1298 		{
1299 			if (NULL == (p = zbx_json_pair_by_name(&object, (char *)&segment->data.list.values->data)))
1300 			{
1301 				zbx_set_json_strerror("object not found in jsonpath segment %d", i + 1);
1302 				goto out;
1303 			}
1304 		}
1305 
1306 		object.start = p;
1307 
1308 		if (NULL == (object.end = __zbx_json_rbracket(p)))
1309 			object.end = p + json_parse_value(p, NULL) - 1;
1310 	}
1311 
1312 	*out = object;
1313 	ret = SUCCEED;
1314 out:
1315 	zbx_jsonpath_clear(&jsonpath);
1316 	return ret;
1317 }
1318