1: /*************************************************************************
2: * (C) 2017 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
6: * $Id: json.c,v 1.1.2.2 2017/11/24 15:52:57 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2017
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /* JSON error strings */
50: const char *jerrstr[] = {
51: "No error",
52: "Not enough tokens were provided",
53: "Invalid character",
54: "JSON string isn't full",
55: "Invalid parameter",
56: NULL
57: };
58:
59:
60: /*
61: * json_init() - Initialize JSON handler
62: *
63: * @json = JSON handler, if there is NULL then dynamically will be allocated
64: * @jstrict = JSON strict mode, when we select strict mode every unquoted value is error
65: * return: =NULL error or !=NULL ready for use JSON handler and should be free with json_free()
66: */
67: json_t *
68: json_init(json_t * __restrict json, int jstrict)
69: {
70: json_t *j = json;
71:
72: if (!j) {
73: j = e_malloc(sizeof(json_t));
74: if (!j) {
75: LOGERR;
76: return NULL;
77: }
78: }
79:
80: memset(j, 0, sizeof(json_t));
81: j->h_parent = -1;
82: j->h_strict = jstrict;
83:
84: /* handler is dynamically allocated! */
85: if (!json)
86: j->h_alloc = j;
87:
88: return j;
89: }
90:
91: /*
92: * json_free() - Free JSON handler
93: *
94: * @json = JSON handler
95: * return: none
96: */
97: void
98: json_free(json_t * __restrict json)
99: {
100: if (json) {
101: if (json->h_alloc)
102: e_free(json);
103: else
104: memset(json, 0, sizeof(json_t));
105: }
106: }
107:
108: /*
109: * json_parse() - Parse JSON string
110: *
111: * @json = JSON handler
112: * @jstr = JSON string
113: * @jlen = JSON string length
114: * @jtoks = Token array
115: * @toksnum = Token array size, return number of allocated tokens in array
116: * return: -1 error or number of found tokens
117: */
118: u_int
119: json_parse(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
120: {
121: register int i;
122: register u_int cx;
123: jtype_t type;
124: jtok_t *tok;
125: char ch;
126:
127: if (!json || !jstr || (!jtoks && toksnum)) {
128: elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
129: return (u_int) -1;
130: }
131:
132: for (cx = json->h_next; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
133: switch ((ch = jstr[json->h_pos])) {
134: case '{':
135: case '[':
136: cx++; /* start new token */
137: if (!jtoks)
138: break;
139:
140: tok = json_gettoken(json, jtoks, toksnum);
141: if (!tok) {
142: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
143: return (u_int) -1;
144: }
145: if (json->h_parent != -1) {
146: jtoks[json->h_parent].tok_size++;
147: tok->tok_parent = json->h_parent;
148: }
149: tok->tok_type = (ch == '{' ? J_OBJECT : J_ARRAY);
150: tok->tok_start = json->h_pos;
151: json->h_parent = json->h_next - 1;
152: break;
153: case '}':
154: case ']':
155: if (!jtoks)
156: break;
157:
158: if (json->h_next < 1) {
159: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
160: return (u_int) -1;
161: }
162:
163: type = (ch == '}' ? J_OBJECT : J_ARRAY);
164: tok = &jtoks[json->h_next - 1];
165: while (42) {
166: if (tok->tok_start != -1 && tok->tok_end == -1) {
167: if (tok->tok_type != type) {
168: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
169: return (u_int) -1;
170: }
171: tok->tok_end = json->h_pos + 1;
172: json->h_parent = tok->tok_parent;
173: break;
174: }
175: if (tok->tok_parent == -1) {
176: if (tok->tok_type != type || json->h_parent == -1) {
177: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
178: return (u_int) -1;
179: }
180: break;
181: }
182: tok = &jtoks[tok->tok_parent];
183: }
184: break;
185: case '\"':
186: if (json_parse_string(json, jstr, jlen, jtoks, toksnum) == -1) {
187: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
188: return (u_int) -1;
189: }
190: cx++;
191: if (jtoks && json->h_parent != -1)
192: jtoks[json->h_parent].tok_size++;
193: break;
194: case '\t':
195: case '\r':
196: case '\n':
197: case ' ':
198: /* whitespace, skip */
199: break;
200: case ':':
201: json->h_parent = json->h_next - 1;
202: break;
203: case ',':
204: if (jtoks && json->h_parent != -1 &&
205: jtoks[json->h_parent].tok_type != J_OBJECT &&
206: jtoks[json->h_parent].tok_type != J_ARRAY)
207: json->h_parent = jtoks[json->h_parent].tok_parent;
208: break;
209: case '-':
210: case '0':
211: case '1':
212: case '2':
213: case '3':
214: case '4':
215: case '5':
216: case '6':
217: case '7':
218: case '8':
219: case '9':
220: case 't':
221: case 'f':
222: case 'n':
223: if (!json->h_strict)
224: break;
225:
226: if (jtoks && json->h_parent != -1) {
227: /* they must not be keys of the object */
228: if (jtoks[json->h_parent].tok_type == J_OBJECT ||
229: (jtoks[json->h_parent].tok_type == J_STRING &&
230: jtoks[json->h_parent].tok_size)) {
231: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
232: return (u_int) -1;
233: }
234: }
235:
236: if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
237: return (u_int) -1;
238: cx++;
239: if (jtoks && json->h_parent != -1)
240: jtoks[json->h_parent].tok_size++;
241: break;
242: default:
243: if (json->h_strict) {
244: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
245: return (u_int) -1;
246: }
247:
248: if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
249: return (u_int) -1;
250: cx++;
251: if (jtoks && json->h_parent != -1)
252: jtoks[json->h_parent].tok_size++;
253: break;
254: }
255: }
256:
257: if (jtoks) {
258: for (i = json->h_next - 1; i >= 0; i--) {
259: /* unmatched opened object or array */
260: if (jtoks[i].tok_start != -1 && jtoks[i].tok_end == -1) {
261: elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
262: return (u_int) -1;
263: }
264: }
265: }
266:
267: return cx;
268: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>