1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include <libwebsockets.h>
26d4afb5ceSopenharmony_ci#include <private-lib-core.h>
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#include <assert.h>
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_cisigned char
31d4afb5ceSopenharmony_cilws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason)
32d4afb5ceSopenharmony_ci{
33d4afb5ceSopenharmony_ci	lws_struct_args_t *a = (lws_struct_args_t *)ctx->user;
34d4afb5ceSopenharmony_ci	const lws_struct_map_t *map = a->map_st[ctx->pst_sp];
35d4afb5ceSopenharmony_ci	size_t n = a->map_entries_st[ctx->pst_sp], imp = 0;
36d4afb5ceSopenharmony_ci	lejp_callback cb = map->lejp_cb;
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_ci	if (reason == LEJPCB_PAIR_NAME && strcmp(ctx->path, "schema")) {
39d4afb5ceSopenharmony_ci		/*
40d4afb5ceSopenharmony_ci		 * If not "schema", the schema is implicit rather than
41d4afb5ceSopenharmony_ci		 * explicitly given, ie, he just goes ahead and starts using
42d4afb5ceSopenharmony_ci		 * member names that imply a particular type.  For example, he
43d4afb5ceSopenharmony_ci		 * may have an implicit type normally, and a different one for
44d4afb5ceSopenharmony_ci		 * exceptions that just starts using "error-message" or whatever
45d4afb5ceSopenharmony_ci		 * and we can understand that's the exception type now.
46d4afb5ceSopenharmony_ci		 *
47d4afb5ceSopenharmony_ci		 * Let's look into each of the maps in the top level array
48d4afb5ceSopenharmony_ci		 * and match the first one that mentions the name he gave here,
49d4afb5ceSopenharmony_ci		 * and bind to the associated type / create a toplevel object
50d4afb5ceSopenharmony_ci		 * of that type.
51d4afb5ceSopenharmony_ci		 */
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci		while (n--) {
54d4afb5ceSopenharmony_ci			int m, child_members = (int)map->child_map_size;
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ci			for (m = 0; m < child_members; m++) {
57d4afb5ceSopenharmony_ci				const lws_struct_map_t *child = &map->child_map[m];
58d4afb5ceSopenharmony_ci				if (!strcmp(ctx->path, child->colname)) {
59d4afb5ceSopenharmony_ci					/*
60d4afb5ceSopenharmony_ci					 * We matched on him... map is pointing
61d4afb5ceSopenharmony_ci					 * to the right toplevel type, let's
62d4afb5ceSopenharmony_ci					 * just pick up from there as if we
63d4afb5ceSopenharmony_ci					 * matched the explicit schema name...
64d4afb5ceSopenharmony_ci					 */
65d4afb5ceSopenharmony_ci					ctx->path_match = 1;
66d4afb5ceSopenharmony_ci					imp = 1;
67d4afb5ceSopenharmony_ci					goto matched;
68d4afb5ceSopenharmony_ci				}
69d4afb5ceSopenharmony_ci			}
70d4afb5ceSopenharmony_ci			map++;
71d4afb5ceSopenharmony_ci		}
72d4afb5ceSopenharmony_ci		lwsl_notice("%s: can't match implicit schema %s\n",
73d4afb5ceSopenharmony_ci			    __func__, ctx->path);
74d4afb5ceSopenharmony_ci
75d4afb5ceSopenharmony_ci		return -1;
76d4afb5ceSopenharmony_ci	}
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	if (reason != LEJPCB_VAL_STR_END || ctx->path_match != 1)
79d4afb5ceSopenharmony_ci		return 0;
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci	/* If "schema", then look for a matching name in the map array */
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci	while (n--) {
84d4afb5ceSopenharmony_ci		if (strcmp(ctx->buf, map->colname)) {
85d4afb5ceSopenharmony_ci			map++;
86d4afb5ceSopenharmony_ci			continue;
87d4afb5ceSopenharmony_ci		}
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_cimatched:
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci		a->dest = lwsac_use_zero(&a->ac, map->aux, a->ac_block_size);
92d4afb5ceSopenharmony_ci		if (!a->dest) {
93d4afb5ceSopenharmony_ci			lwsl_err("%s: OOT\n", __func__);
94d4afb5ceSopenharmony_ci
95d4afb5ceSopenharmony_ci			return 1;
96d4afb5ceSopenharmony_ci		}
97d4afb5ceSopenharmony_ci		a->dest_len = map->aux;
98d4afb5ceSopenharmony_ci		if (!ctx->pst_sp)
99d4afb5ceSopenharmony_ci			a->top_schema_index = (int)(map - a->map_st[ctx->pst_sp]);
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci		if (!cb)
102d4afb5ceSopenharmony_ci			cb = lws_struct_default_lejp_cb;
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci		lejp_parser_push(ctx, a->dest, &map->child_map[0].colname,
105d4afb5ceSopenharmony_ci				 (uint8_t)map->child_map_size, cb);
106d4afb5ceSopenharmony_ci		a->map_st[ctx->pst_sp] = map->child_map;
107d4afb5ceSopenharmony_ci		a->map_entries_st[ctx->pst_sp] = map->child_map_size;
108d4afb5ceSopenharmony_ci
109d4afb5ceSopenharmony_ci		// lwsl_notice("%s: child map ofs_clist %d\n", __func__,
110d4afb5ceSopenharmony_ci		// 		(int)a->map_st[ctx->pst_sp]->ofs_clist);
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci		if (imp)
113d4afb5ceSopenharmony_ci			return cb(ctx, reason);
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci		return 0;
116d4afb5ceSopenharmony_ci	}
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci	lwsl_notice("%s: unknown schema %s\n", __func__, ctx->buf);
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	return 1;
121d4afb5ceSopenharmony_ci}
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_cistatic int
124d4afb5ceSopenharmony_cilws_struct_lejp_push(struct lejp_ctx *ctx, lws_struct_args_t *args,
125d4afb5ceSopenharmony_ci		     const lws_struct_map_t *map, uint8_t *ch)
126d4afb5ceSopenharmony_ci{
127d4afb5ceSopenharmony_ci	lejp_callback cb = map->lejp_cb;
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	if (!cb)
130d4afb5ceSopenharmony_ci		cb = lws_struct_default_lejp_cb;
131d4afb5ceSopenharmony_ci
132d4afb5ceSopenharmony_ci	lejp_parser_push(ctx, ch, (const char * const*)map->child_map,
133d4afb5ceSopenharmony_ci			 (uint8_t)map->child_map_size, cb);
134d4afb5ceSopenharmony_ci
135d4afb5ceSopenharmony_ci	args->map_st[ctx->pst_sp] = map->child_map;
136d4afb5ceSopenharmony_ci	args->map_entries_st[ctx->pst_sp] = map->child_map_size;
137d4afb5ceSopenharmony_ci
138d4afb5ceSopenharmony_ci	return 0;
139d4afb5ceSopenharmony_ci}
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_cisigned char
142d4afb5ceSopenharmony_cilws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
143d4afb5ceSopenharmony_ci{
144d4afb5ceSopenharmony_ci	lws_struct_args_t *args = (lws_struct_args_t *)ctx->user;
145d4afb5ceSopenharmony_ci	const lws_struct_map_t *map, *pmap = NULL;
146d4afb5ceSopenharmony_ci	uint8_t *ch;
147d4afb5ceSopenharmony_ci	size_t n;
148d4afb5ceSopenharmony_ci	char *u;
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_ci	if (reason == LEJPCB_ARRAY_END) {
151d4afb5ceSopenharmony_ci		lejp_parser_pop(ctx);
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci		return 0;
154d4afb5ceSopenharmony_ci	}
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	if (reason == LEJPCB_ARRAY_START) {
157d4afb5ceSopenharmony_ci		if (!ctx->path_match)
158d4afb5ceSopenharmony_ci			lwsl_err("%s: ARRAY_START with ctx->path_match 0\n", __func__);
159d4afb5ceSopenharmony_ci		map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci		if (map->type == LSMT_LIST)
162d4afb5ceSopenharmony_ci			lws_struct_lejp_push(ctx, args, map, NULL);
163d4afb5ceSopenharmony_ci
164d4afb5ceSopenharmony_ci		return 0;
165d4afb5ceSopenharmony_ci	}
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci	if (ctx->pst_sp)
168d4afb5ceSopenharmony_ci		pmap = &args->map_st[ctx->pst_sp - 1]
169d4afb5ceSopenharmony_ci	                 [ctx->pst[ctx->pst_sp - 1].path_match - 1];
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci	if (reason == LEJPCB_OBJECT_START) {
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci		if (!ctx->path_match) {
174d4afb5ceSopenharmony_ci			ctx->pst[ctx->pst_sp].user = NULL;
175d4afb5ceSopenharmony_ci
176d4afb5ceSopenharmony_ci			return 0;
177d4afb5ceSopenharmony_ci		}
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci		map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
180d4afb5ceSopenharmony_ci		n = args->map_entries_st[ctx->pst_sp];
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci		if (map->type != LSMT_CHILD_PTR && map->type != LSMT_LIST) {
183d4afb5ceSopenharmony_ci			ctx->pst[ctx->pst_sp].user = NULL;
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci			return 0;
186d4afb5ceSopenharmony_ci		}
187d4afb5ceSopenharmony_ci		pmap = map;
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci		lws_struct_lejp_push(ctx, args, map, NULL);
190d4afb5ceSopenharmony_ci	}
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci	if (reason == LEJPCB_OBJECT_END && pmap) {
193d4afb5ceSopenharmony_ci		if (pmap->type == LSMT_CHILD_PTR)
194d4afb5ceSopenharmony_ci			lejp_parser_pop(ctx);
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_ci		if (ctx->pst_sp)
197d4afb5ceSopenharmony_ci			pmap = &args->map_st[ctx->pst_sp - 1]
198d4afb5ceSopenharmony_ci		                 [ctx->pst[ctx->pst_sp - 1].path_match - 1];
199d4afb5ceSopenharmony_ci	}
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	if (!ctx->path_match)
202d4afb5ceSopenharmony_ci		return 0;
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ci	map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
205d4afb5ceSopenharmony_ci	n = args->map_entries_st[ctx->pst_sp];
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ci	if (map->type == LSMT_SCHEMA) {
208d4afb5ceSopenharmony_ci
209d4afb5ceSopenharmony_ci		while (n--) {
210d4afb5ceSopenharmony_ci			if (strncmp(map->colname, ctx->buf, ctx->npos)) {
211d4afb5ceSopenharmony_ci				map++;
212d4afb5ceSopenharmony_ci				continue;
213d4afb5ceSopenharmony_ci			}
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci			/* instantiate the correct toplevel object */
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci			ch = lwsac_use_zero(&args->ac, map->aux,
218d4afb5ceSopenharmony_ci					    args->ac_block_size);
219d4afb5ceSopenharmony_ci			if (!ch) {
220d4afb5ceSopenharmony_ci				lwsl_err("OOM\n");
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci				return 1;
223d4afb5ceSopenharmony_ci			}
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci			lws_struct_lejp_push(ctx, args, map, ch);
226d4afb5ceSopenharmony_ci
227d4afb5ceSopenharmony_ci			return 0;
228d4afb5ceSopenharmony_ci		}
229d4afb5ceSopenharmony_ci		lwsl_notice("%s: unknown schema %.*s, tried %d\n", __func__,
230d4afb5ceSopenharmony_ci				ctx->npos, ctx->buf,
231d4afb5ceSopenharmony_ci				(int)args->map_entries_st[ctx->pst_sp]);
232d4afb5ceSopenharmony_ci
233d4afb5ceSopenharmony_ci		goto cleanup;
234d4afb5ceSopenharmony_ci	}
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	if (!ctx->pst[ctx->pst_sp].user) {
237d4afb5ceSopenharmony_ci		struct lws_dll2_owner *owner;
238d4afb5ceSopenharmony_ci		struct lws_dll2 *list;
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci		/* create list item object if none already */
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci		if (!ctx->path_match || !pmap)
243d4afb5ceSopenharmony_ci			return 0;
244d4afb5ceSopenharmony_ci
245d4afb5ceSopenharmony_ci		map = &args->map_st[ctx->pst_sp - 1][ctx->path_match - 1];
246d4afb5ceSopenharmony_ci		n = args->map_entries_st[ctx->pst_sp - 1];
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci		if (!ctx->pst_sp)
249d4afb5ceSopenharmony_ci			return 0;
250d4afb5ceSopenharmony_ci
251d4afb5ceSopenharmony_ci		if (pmap->type != LSMT_LIST && pmap->type != LSMT_CHILD_PTR)
252d4afb5ceSopenharmony_ci			return 1;
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci		/* we need to create a child or array item object */
255d4afb5ceSopenharmony_ci
256d4afb5ceSopenharmony_ci		owner = (struct lws_dll2_owner *)
257d4afb5ceSopenharmony_ci			(((char *)ctx->pst[ctx->pst_sp - 1].user) + pmap->ofs);
258d4afb5ceSopenharmony_ci
259d4afb5ceSopenharmony_ci		assert(pmap->aux);
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_ci		/* instantiate one of the child objects */
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci		ctx->pst[ctx->pst_sp].user = lwsac_use_zero(&args->ac,
264d4afb5ceSopenharmony_ci						pmap->aux, args->ac_block_size);
265d4afb5ceSopenharmony_ci		if (!ctx->pst[ctx->pst_sp].user) {
266d4afb5ceSopenharmony_ci			lwsl_err("OOM\n");
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci			return 1;
269d4afb5ceSopenharmony_ci		}
270d4afb5ceSopenharmony_ci		lwsl_info("%s: created '%s' object size %d\n", __func__,
271d4afb5ceSopenharmony_ci				pmap->colname, (int)pmap->aux);
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci		switch (pmap->type) {
274d4afb5ceSopenharmony_ci		case LSMT_LIST:
275d4afb5ceSopenharmony_ci			list = (struct lws_dll2 *)
276d4afb5ceSopenharmony_ci				 ((char *)ctx->pst[ctx->pst_sp].user +
277d4afb5ceSopenharmony_ci				 pmap->ofs_clist);
278d4afb5ceSopenharmony_ci
279d4afb5ceSopenharmony_ci			lws_dll2_add_tail(list, owner);
280d4afb5ceSopenharmony_ci			break;
281d4afb5ceSopenharmony_ci		case LSMT_CHILD_PTR:
282d4afb5ceSopenharmony_ci			*((void **)owner) = ctx->pst[ctx->pst_sp].user;
283d4afb5ceSopenharmony_ci			break;
284d4afb5ceSopenharmony_ci		default:
285d4afb5ceSopenharmony_ci			assert(0);
286d4afb5ceSopenharmony_ci			break;
287d4afb5ceSopenharmony_ci		}
288d4afb5ceSopenharmony_ci	}
289d4afb5ceSopenharmony_ci
290d4afb5ceSopenharmony_ci	if (!ctx->path_match)
291d4afb5ceSopenharmony_ci		return 0;
292d4afb5ceSopenharmony_ci
293d4afb5ceSopenharmony_ci	if (reason == LEJPCB_VAL_STR_CHUNK) {
294d4afb5ceSopenharmony_ci		lejp_collation_t *coll;
295d4afb5ceSopenharmony_ci
296d4afb5ceSopenharmony_ci		/* don't cache stuff we are going to ignore */
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_ci		if (map->type == LSMT_STRING_CHAR_ARRAY &&
299d4afb5ceSopenharmony_ci		    args->chunks_length >= map->aux)
300d4afb5ceSopenharmony_ci			return 0;
301d4afb5ceSopenharmony_ci
302d4afb5ceSopenharmony_ci		coll = lwsac_use_zero(&args->ac_chunks, sizeof(*coll),
303d4afb5ceSopenharmony_ci				      sizeof(*coll));
304d4afb5ceSopenharmony_ci		if (!coll) {
305d4afb5ceSopenharmony_ci			lwsl_err("%s: OOT\n", __func__);
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci			return 1;
308d4afb5ceSopenharmony_ci		}
309d4afb5ceSopenharmony_ci		coll->chunks.prev = NULL;
310d4afb5ceSopenharmony_ci		coll->chunks.next = NULL;
311d4afb5ceSopenharmony_ci		coll->chunks.owner = NULL;
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_ci		coll->len = ctx->npos;
314d4afb5ceSopenharmony_ci		lws_dll2_add_tail(&coll->chunks, &args->chunks_owner);
315d4afb5ceSopenharmony_ci
316d4afb5ceSopenharmony_ci		memcpy(coll->buf, ctx->buf, ctx->npos);
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci		args->chunks_length += ctx->npos;
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci		return 0;
321d4afb5ceSopenharmony_ci	}
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ci	if (reason != LEJPCB_VAL_STR_END && reason != LEJPCB_VAL_NUM_INT &&
324d4afb5ceSopenharmony_ci	    reason != LEJPCB_VAL_TRUE && reason != LEJPCB_VAL_FALSE)
325d4afb5ceSopenharmony_ci		return 0;
326d4afb5ceSopenharmony_ci
327d4afb5ceSopenharmony_ci	/* this is the end of the string */
328d4afb5ceSopenharmony_ci
329d4afb5ceSopenharmony_ci	if (ctx->pst[ctx->pst_sp].user && pmap && pmap->type == LSMT_CHILD_PTR) {
330d4afb5ceSopenharmony_ci		void **pp = (void **)
331d4afb5ceSopenharmony_ci			(((char *)ctx->pst[ctx->pst_sp - 1].user) + pmap->ofs);
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci		*pp = ctx->pst[ctx->pst_sp].user;
334d4afb5ceSopenharmony_ci	}
335d4afb5ceSopenharmony_ci
336d4afb5ceSopenharmony_ci	u = (char *)ctx->pst[ctx->pst_sp].user;
337d4afb5ceSopenharmony_ci	if (!u)
338d4afb5ceSopenharmony_ci		u = (char *)ctx->pst[ctx->pst_sp - 1].user;
339d4afb5ceSopenharmony_ci
340d4afb5ceSopenharmony_ci	{
341d4afb5ceSopenharmony_ci		char **pp, *s;
342d4afb5ceSopenharmony_ci		size_t lim, b;
343d4afb5ceSopenharmony_ci		long long li;
344d4afb5ceSopenharmony_ci
345d4afb5ceSopenharmony_ci		switch (map->type) {
346d4afb5ceSopenharmony_ci		case LSMT_SIGNED:
347d4afb5ceSopenharmony_ci			if (map->aux == sizeof(signed char)) {
348d4afb5ceSopenharmony_ci				signed char *pc;
349d4afb5ceSopenharmony_ci				pc = (signed char *)(u + map->ofs);
350d4afb5ceSopenharmony_ci				*pc = (signed char)atoi(ctx->buf);
351d4afb5ceSopenharmony_ci				break;
352d4afb5ceSopenharmony_ci			}
353d4afb5ceSopenharmony_ci			if (map->aux == sizeof(int)) {
354d4afb5ceSopenharmony_ci				int *pi;
355d4afb5ceSopenharmony_ci				pi = (int *)(u + map->ofs);
356d4afb5ceSopenharmony_ci				*pi = atoi(ctx->buf);
357d4afb5ceSopenharmony_ci				break;
358d4afb5ceSopenharmony_ci			}
359d4afb5ceSopenharmony_ci			if (map->aux == sizeof(long)) {
360d4afb5ceSopenharmony_ci				long *pl;
361d4afb5ceSopenharmony_ci				pl = (long *)(u + map->ofs);
362d4afb5ceSopenharmony_ci				*pl = atol(ctx->buf);
363d4afb5ceSopenharmony_ci			} else {
364d4afb5ceSopenharmony_ci				long long *pll;
365d4afb5ceSopenharmony_ci				pll = (long long *)(u + map->ofs);
366d4afb5ceSopenharmony_ci				*pll = atoll(ctx->buf);
367d4afb5ceSopenharmony_ci			}
368d4afb5ceSopenharmony_ci			break;
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci		case LSMT_UNSIGNED:
371d4afb5ceSopenharmony_ci			if (map->aux == sizeof(unsigned char)) {
372d4afb5ceSopenharmony_ci				unsigned char *pc;
373d4afb5ceSopenharmony_ci				pc = (unsigned char *)(u + map->ofs);
374d4afb5ceSopenharmony_ci				*pc = (unsigned char)(unsigned int)atoi(ctx->buf);
375d4afb5ceSopenharmony_ci				break;
376d4afb5ceSopenharmony_ci			}
377d4afb5ceSopenharmony_ci			if (map->aux == sizeof(unsigned int)) {
378d4afb5ceSopenharmony_ci				unsigned int *pi;
379d4afb5ceSopenharmony_ci				pi = (unsigned int *)(u + map->ofs);
380d4afb5ceSopenharmony_ci				*pi = (unsigned int)atoi(ctx->buf);
381d4afb5ceSopenharmony_ci				break;
382d4afb5ceSopenharmony_ci			}
383d4afb5ceSopenharmony_ci			if (map->aux == sizeof(unsigned long)) {
384d4afb5ceSopenharmony_ci				unsigned long *pl;
385d4afb5ceSopenharmony_ci				pl = (unsigned long *)(u + map->ofs);
386d4afb5ceSopenharmony_ci				*pl = (unsigned long)atol(ctx->buf);
387d4afb5ceSopenharmony_ci			} else {
388d4afb5ceSopenharmony_ci				unsigned long long *pll;
389d4afb5ceSopenharmony_ci				pll = (unsigned long long *)(u + map->ofs);
390d4afb5ceSopenharmony_ci				*pll = (unsigned long long)atoll(ctx->buf);
391d4afb5ceSopenharmony_ci			}
392d4afb5ceSopenharmony_ci			break;
393d4afb5ceSopenharmony_ci
394d4afb5ceSopenharmony_ci		case LSMT_BOOLEAN:
395d4afb5ceSopenharmony_ci			li = reason == LEJPCB_VAL_TRUE;
396d4afb5ceSopenharmony_ci			if (map->aux == sizeof(char)) {
397d4afb5ceSopenharmony_ci				char *pc;
398d4afb5ceSopenharmony_ci				pc = (char *)(u + map->ofs);
399d4afb5ceSopenharmony_ci				*pc = (char)li;
400d4afb5ceSopenharmony_ci				break;
401d4afb5ceSopenharmony_ci			}
402d4afb5ceSopenharmony_ci			if (map->aux == sizeof(int)) {
403d4afb5ceSopenharmony_ci				int *pi;
404d4afb5ceSopenharmony_ci				pi = (int *)(u + map->ofs);
405d4afb5ceSopenharmony_ci				*pi = (int)li;
406d4afb5ceSopenharmony_ci			} else {
407d4afb5ceSopenharmony_ci				uint64_t *p64;
408d4afb5ceSopenharmony_ci				p64 = (uint64_t *)(u + map->ofs);
409d4afb5ceSopenharmony_ci				*p64 = (uint64_t)li;
410d4afb5ceSopenharmony_ci			}
411d4afb5ceSopenharmony_ci			break;
412d4afb5ceSopenharmony_ci
413d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
414d4afb5ceSopenharmony_ci			s = (char *)(u + map->ofs);
415d4afb5ceSopenharmony_ci			lim = map->aux - 1;
416d4afb5ceSopenharmony_ci			goto chunk_copy;
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
419d4afb5ceSopenharmony_ci			pp = (char **)(u + map->ofs);
420d4afb5ceSopenharmony_ci			lim = args->chunks_length + ctx->npos;
421d4afb5ceSopenharmony_ci			s = lwsac_use(&args->ac, lim + 1, args->ac_block_size);
422d4afb5ceSopenharmony_ci			if (!s)
423d4afb5ceSopenharmony_ci				goto cleanup;
424d4afb5ceSopenharmony_ci			*pp = s;
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_cichunk_copy:
427d4afb5ceSopenharmony_ci			s[lim] = '\0';
428d4afb5ceSopenharmony_ci			/* copy up to lim from the string chunk ac first */
429d4afb5ceSopenharmony_ci			lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
430d4afb5ceSopenharmony_ci						args->chunks_owner.head) {
431d4afb5ceSopenharmony_ci				lejp_collation_t *coll = (lejp_collation_t *)p;
432d4afb5ceSopenharmony_ci
433d4afb5ceSopenharmony_ci				if (lim) {
434d4afb5ceSopenharmony_ci					b = (unsigned int)coll->len;
435d4afb5ceSopenharmony_ci					if (b > lim)
436d4afb5ceSopenharmony_ci						b = lim;
437d4afb5ceSopenharmony_ci					memcpy(s, coll->buf, b);
438d4afb5ceSopenharmony_ci					s += b;
439d4afb5ceSopenharmony_ci					lim -= b;
440d4afb5ceSopenharmony_ci				}
441d4afb5ceSopenharmony_ci			} lws_end_foreach_dll_safe(p, p1);
442d4afb5ceSopenharmony_ci
443d4afb5ceSopenharmony_ci			lwsac_free(&args->ac_chunks);
444d4afb5ceSopenharmony_ci			args->chunks_owner.count = 0;
445d4afb5ceSopenharmony_ci			args->chunks_owner.head = NULL;
446d4afb5ceSopenharmony_ci			args->chunks_owner.tail = NULL;
447d4afb5ceSopenharmony_ci
448d4afb5ceSopenharmony_ci			if (lim) {
449d4afb5ceSopenharmony_ci				b = ctx->npos;
450d4afb5ceSopenharmony_ci				if (b > lim)
451d4afb5ceSopenharmony_ci					b = lim;
452d4afb5ceSopenharmony_ci				memcpy(s, ctx->buf, b);
453d4afb5ceSopenharmony_ci				s[b] = '\0';
454d4afb5ceSopenharmony_ci			}
455d4afb5ceSopenharmony_ci			break;
456d4afb5ceSopenharmony_ci		default:
457d4afb5ceSopenharmony_ci			break;
458d4afb5ceSopenharmony_ci		}
459d4afb5ceSopenharmony_ci	}
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci	if (args->cb)
462d4afb5ceSopenharmony_ci		args->cb(args->dest, args->cb_arg);
463d4afb5ceSopenharmony_ci
464d4afb5ceSopenharmony_ci	return 0;
465d4afb5ceSopenharmony_ci
466d4afb5ceSopenharmony_cicleanup:
467d4afb5ceSopenharmony_ci	lwsl_notice("%s: cleanup\n", __func__);
468d4afb5ceSopenharmony_ci	lwsac_free(&args->ac_chunks);
469d4afb5ceSopenharmony_ci	args->chunks_owner.count = 0;
470d4afb5ceSopenharmony_ci	args->chunks_owner.head = NULL;
471d4afb5ceSopenharmony_ci	args->chunks_owner.tail = NULL;
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci	return 1;
474d4afb5ceSopenharmony_ci}
475d4afb5ceSopenharmony_ci
476d4afb5ceSopenharmony_cistatic const char * schema[] = { "schema" };
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ciint
479d4afb5ceSopenharmony_cilws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb, void *user)
480d4afb5ceSopenharmony_ci{
481d4afb5ceSopenharmony_ci	/*
482d4afb5ceSopenharmony_ci	 * By default we are looking to match on a toplevel member called
483d4afb5ceSopenharmony_ci	 * "schema", against an LSM_SCHEMA
484d4afb5ceSopenharmony_ci	 */
485d4afb5ceSopenharmony_ci	if (!cb)
486d4afb5ceSopenharmony_ci		cb = lws_struct_schema_only_lejp_cb;
487d4afb5ceSopenharmony_ci	lejp_construct(ctx, cb, user, schema, 1);
488d4afb5ceSopenharmony_ci
489d4afb5ceSopenharmony_ci	ctx->path_stride = sizeof(lws_struct_map_t);
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci	return 0;
492d4afb5ceSopenharmony_ci}
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_cilws_struct_serialize_t *
495d4afb5ceSopenharmony_cilws_struct_json_serialize_create(const lws_struct_map_t *map,
496d4afb5ceSopenharmony_ci				 size_t map_entries, int flags,
497d4afb5ceSopenharmony_ci				 const void *ptoplevel)
498d4afb5ceSopenharmony_ci{
499d4afb5ceSopenharmony_ci	lws_struct_serialize_t *js = lws_zalloc(sizeof(*js), __func__);
500d4afb5ceSopenharmony_ci	lws_struct_serialize_st_t *j;
501d4afb5ceSopenharmony_ci
502d4afb5ceSopenharmony_ci	if (!js)
503d4afb5ceSopenharmony_ci		return NULL;
504d4afb5ceSopenharmony_ci
505d4afb5ceSopenharmony_ci	js->flags = flags;
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci	j = &js->st[0];
508d4afb5ceSopenharmony_ci	j->map = map;
509d4afb5ceSopenharmony_ci	j->map_entries = map_entries;
510d4afb5ceSopenharmony_ci	j->obj = ptoplevel;
511d4afb5ceSopenharmony_ci	j->idt = 0;
512d4afb5ceSopenharmony_ci
513d4afb5ceSopenharmony_ci	return js;
514d4afb5ceSopenharmony_ci}
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_civoid
517d4afb5ceSopenharmony_cilws_struct_json_serialize_destroy(lws_struct_serialize_t **pjs)
518d4afb5ceSopenharmony_ci{
519d4afb5ceSopenharmony_ci	if (!*pjs)
520d4afb5ceSopenharmony_ci		return;
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ci	lws_free(*pjs);
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci	*pjs = NULL;
525d4afb5ceSopenharmony_ci}
526d4afb5ceSopenharmony_ci
527d4afb5ceSopenharmony_cistatic void
528d4afb5ceSopenharmony_cilws_struct_pretty(lws_struct_serialize_t *js, uint8_t **pbuf, size_t *plen)
529d4afb5ceSopenharmony_ci{
530d4afb5ceSopenharmony_ci	if (js->flags & LSSERJ_FLAG_PRETTY) {
531d4afb5ceSopenharmony_ci		int n;
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci		*(*pbuf)++ = '\n';
534d4afb5ceSopenharmony_ci		(*plen)--;
535d4afb5ceSopenharmony_ci		for (n = 0; n < js->st[js->sp].idt; n++) {
536d4afb5ceSopenharmony_ci			*(*pbuf)++ = ' ';
537d4afb5ceSopenharmony_ci			(*plen)--;
538d4afb5ceSopenharmony_ci		}
539d4afb5ceSopenharmony_ci	}
540d4afb5ceSopenharmony_ci}
541d4afb5ceSopenharmony_ci
542d4afb5ceSopenharmony_cilws_struct_json_serialize_result_t
543d4afb5ceSopenharmony_cilws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
544d4afb5ceSopenharmony_ci			  size_t len, size_t *written)
545d4afb5ceSopenharmony_ci{
546d4afb5ceSopenharmony_ci	lws_struct_serialize_st_t *j;
547d4afb5ceSopenharmony_ci	const lws_struct_map_t *map;
548d4afb5ceSopenharmony_ci	size_t budget = 0, olen = len, m;
549d4afb5ceSopenharmony_ci	struct lws_dll2_owner *o;
550d4afb5ceSopenharmony_ci	unsigned long long uli;
551d4afb5ceSopenharmony_ci	const char *q;
552d4afb5ceSopenharmony_ci	const void *p;
553d4afb5ceSopenharmony_ci	char dbuf[72];
554d4afb5ceSopenharmony_ci	long long li;
555d4afb5ceSopenharmony_ci	int n, used;
556d4afb5ceSopenharmony_ci
557d4afb5ceSopenharmony_ci	*written = 0;
558d4afb5ceSopenharmony_ci	*buf = '\0';
559d4afb5ceSopenharmony_ci
560d4afb5ceSopenharmony_ci	while (len > sizeof(dbuf) + 20) {
561d4afb5ceSopenharmony_ci		j = &js->st[js->sp];
562d4afb5ceSopenharmony_ci		map = &j->map[j->map_entry];
563d4afb5ceSopenharmony_ci		q = j->obj + map->ofs;
564d4afb5ceSopenharmony_ci
565d4afb5ceSopenharmony_ci		/* early check if the entry should be elided */
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ci		switch (map->type) {
568d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
569d4afb5ceSopenharmony_ci			if (!q)
570d4afb5ceSopenharmony_ci				goto up;
571d4afb5ceSopenharmony_ci			break;
572d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
573d4afb5ceSopenharmony_ci		case LSMT_CHILD_PTR:
574d4afb5ceSopenharmony_ci			q = (char *)*(char **)q;
575d4afb5ceSopenharmony_ci			if (!q)
576d4afb5ceSopenharmony_ci				goto up;
577d4afb5ceSopenharmony_ci			break;
578d4afb5ceSopenharmony_ci
579d4afb5ceSopenharmony_ci		case LSMT_LIST:
580d4afb5ceSopenharmony_ci			o = (struct lws_dll2_owner *)q;
581d4afb5ceSopenharmony_ci			p = j->dllpos = lws_dll2_get_head(o);
582d4afb5ceSopenharmony_ci			if (!p)
583d4afb5ceSopenharmony_ci				goto up;
584d4afb5ceSopenharmony_ci			break;
585d4afb5ceSopenharmony_ci
586d4afb5ceSopenharmony_ci		case LSMT_BLOB_PTR:
587d4afb5ceSopenharmony_ci			goto up;
588d4afb5ceSopenharmony_ci
589d4afb5ceSopenharmony_ci		default:
590d4afb5ceSopenharmony_ci			break;
591d4afb5ceSopenharmony_ci		}
592d4afb5ceSopenharmony_ci
593d4afb5ceSopenharmony_ci		if (j->subsequent) {
594d4afb5ceSopenharmony_ci			*buf++ = ',';
595d4afb5ceSopenharmony_ci			len--;
596d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
597d4afb5ceSopenharmony_ci		}
598d4afb5ceSopenharmony_ci		j->subsequent = 1;
599d4afb5ceSopenharmony_ci
600d4afb5ceSopenharmony_ci		if (map->type != LSMT_SCHEMA && !js->offset) {
601d4afb5ceSopenharmony_ci			n = lws_snprintf((char *)buf, len, "\"%s\":",
602d4afb5ceSopenharmony_ci					    map->colname);
603d4afb5ceSopenharmony_ci			buf += n;
604d4afb5ceSopenharmony_ci			len = len - (unsigned int)n;
605d4afb5ceSopenharmony_ci			if (js->flags & LSSERJ_FLAG_PRETTY) {
606d4afb5ceSopenharmony_ci				*buf++ = ' ';
607d4afb5ceSopenharmony_ci				len--;
608d4afb5ceSopenharmony_ci			}
609d4afb5ceSopenharmony_ci		}
610d4afb5ceSopenharmony_ci
611d4afb5ceSopenharmony_ci		switch (map->type) {
612d4afb5ceSopenharmony_ci		case LSMT_BOOLEAN:
613d4afb5ceSopenharmony_ci		case LSMT_UNSIGNED:
614d4afb5ceSopenharmony_ci			if (map->aux == sizeof(char)) {
615d4afb5ceSopenharmony_ci				uli = *(unsigned char *)q;
616d4afb5ceSopenharmony_ci			} else {
617d4afb5ceSopenharmony_ci				if (map->aux == sizeof(int)) {
618d4afb5ceSopenharmony_ci					uli = *(unsigned int *)q;
619d4afb5ceSopenharmony_ci				} else {
620d4afb5ceSopenharmony_ci					if (map->aux == sizeof(long))
621d4afb5ceSopenharmony_ci						uli = *(unsigned long *)q;
622d4afb5ceSopenharmony_ci					else
623d4afb5ceSopenharmony_ci						uli = *(unsigned long long *)q;
624d4afb5ceSopenharmony_ci				}
625d4afb5ceSopenharmony_ci			}
626d4afb5ceSopenharmony_ci			q = dbuf;
627d4afb5ceSopenharmony_ci
628d4afb5ceSopenharmony_ci			if (map->type == LSMT_BOOLEAN) {
629d4afb5ceSopenharmony_ci				budget = (unsigned int)lws_snprintf(dbuf, sizeof(dbuf),
630d4afb5ceSopenharmony_ci						"%s", uli ? "true" : "false");
631d4afb5ceSopenharmony_ci			} else
632d4afb5ceSopenharmony_ci				budget = (unsigned int)lws_snprintf(dbuf, sizeof(dbuf),
633d4afb5ceSopenharmony_ci						      "%llu", uli);
634d4afb5ceSopenharmony_ci			break;
635d4afb5ceSopenharmony_ci
636d4afb5ceSopenharmony_ci		case LSMT_SIGNED:
637d4afb5ceSopenharmony_ci			if (map->aux == sizeof(signed char)) {
638d4afb5ceSopenharmony_ci				li = (long long)*(signed char *)q;
639d4afb5ceSopenharmony_ci			} else {
640d4afb5ceSopenharmony_ci				if (map->aux == sizeof(int)) {
641d4afb5ceSopenharmony_ci					li = (long long)*(int *)q;
642d4afb5ceSopenharmony_ci				} else {
643d4afb5ceSopenharmony_ci					if (map->aux == sizeof(long))
644d4afb5ceSopenharmony_ci						li = (long long)*(long *)q;
645d4afb5ceSopenharmony_ci					else
646d4afb5ceSopenharmony_ci						li = *(long long *)q;
647d4afb5ceSopenharmony_ci				}
648d4afb5ceSopenharmony_ci			}
649d4afb5ceSopenharmony_ci			q = dbuf;
650d4afb5ceSopenharmony_ci			budget = (unsigned int)lws_snprintf(dbuf, sizeof(dbuf), "%lld", li);
651d4afb5ceSopenharmony_ci			break;
652d4afb5ceSopenharmony_ci
653d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
654d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
655d4afb5ceSopenharmony_ci			if (!js->offset) {
656d4afb5ceSopenharmony_ci				*buf++ = '\"';
657d4afb5ceSopenharmony_ci				len--;
658d4afb5ceSopenharmony_ci			}
659d4afb5ceSopenharmony_ci			break;
660d4afb5ceSopenharmony_ci
661d4afb5ceSopenharmony_ci		case LSMT_LIST:
662d4afb5ceSopenharmony_ci			*buf++ = '[';
663d4afb5ceSopenharmony_ci			len--;
664d4afb5ceSopenharmony_ci			if (js->sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
665d4afb5ceSopenharmony_ci				return LSJS_RESULT_ERROR;
666d4afb5ceSopenharmony_ci
667d4afb5ceSopenharmony_ci			/* add a stack level to handle parsing array members */
668d4afb5ceSopenharmony_ci
669d4afb5ceSopenharmony_ci			o = (struct lws_dll2_owner *)q;
670d4afb5ceSopenharmony_ci			p = j->dllpos = lws_dll2_get_head(o);
671d4afb5ceSopenharmony_ci
672d4afb5ceSopenharmony_ci			if (!j->dllpos) {
673d4afb5ceSopenharmony_ci				*buf++ = ']';
674d4afb5ceSopenharmony_ci				len--;
675d4afb5ceSopenharmony_ci				goto up;
676d4afb5ceSopenharmony_ci			}
677d4afb5ceSopenharmony_ci
678d4afb5ceSopenharmony_ci			n = j->idt;
679d4afb5ceSopenharmony_ci			j = &js->st[++js->sp];
680d4afb5ceSopenharmony_ci			j->idt = (char)(n + 2);
681d4afb5ceSopenharmony_ci			j->map = map->child_map;
682d4afb5ceSopenharmony_ci			j->map_entries = map->child_map_size;
683d4afb5ceSopenharmony_ci			j->size = map->aux;
684d4afb5ceSopenharmony_ci			j->subsequent = 0;
685d4afb5ceSopenharmony_ci			j->map_entry = 0;
686d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
687d4afb5ceSopenharmony_ci			*buf++ = '{';
688d4afb5ceSopenharmony_ci			len--;
689d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
690d4afb5ceSopenharmony_ci			if (p)
691d4afb5ceSopenharmony_ci				j->obj = ((char *)p) - j->map->ofs_clist;
692d4afb5ceSopenharmony_ci			else
693d4afb5ceSopenharmony_ci				j->obj = NULL;
694d4afb5ceSopenharmony_ci			continue;
695d4afb5ceSopenharmony_ci
696d4afb5ceSopenharmony_ci		case LSMT_CHILD_PTR:
697d4afb5ceSopenharmony_ci
698d4afb5ceSopenharmony_ci			if (js->sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
699d4afb5ceSopenharmony_ci				return LSJS_RESULT_ERROR;
700d4afb5ceSopenharmony_ci
701d4afb5ceSopenharmony_ci			/* add a stack level to handle parsing child members */
702d4afb5ceSopenharmony_ci
703d4afb5ceSopenharmony_ci			n = j->idt;
704d4afb5ceSopenharmony_ci			j = &js->st[++js->sp];
705d4afb5ceSopenharmony_ci			j->idt = (char)(n + 2);
706d4afb5ceSopenharmony_ci			j->map = map->child_map;
707d4afb5ceSopenharmony_ci			j->map_entries = map->child_map_size;
708d4afb5ceSopenharmony_ci			j->size = map->aux;
709d4afb5ceSopenharmony_ci			j->subsequent = 0;
710d4afb5ceSopenharmony_ci			j->map_entry = 0;
711d4afb5ceSopenharmony_ci			*buf++ = '{';
712d4afb5ceSopenharmony_ci			len--;
713d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
714d4afb5ceSopenharmony_ci			j->obj = q;
715d4afb5ceSopenharmony_ci
716d4afb5ceSopenharmony_ci			continue;
717d4afb5ceSopenharmony_ci
718d4afb5ceSopenharmony_ci		case LSMT_SCHEMA:
719d4afb5ceSopenharmony_ci			q = dbuf;
720d4afb5ceSopenharmony_ci			*buf++ = '{';
721d4afb5ceSopenharmony_ci			len--;
722d4afb5ceSopenharmony_ci			j = &js->st[++js->sp];
723d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
724d4afb5ceSopenharmony_ci			if (!(js->flags & LSSERJ_FLAG_OMIT_SCHEMA)) {
725d4afb5ceSopenharmony_ci				budget = (unsigned int)lws_snprintf(dbuf, 15, "\"schema\":");
726d4afb5ceSopenharmony_ci				if (js->flags & LSSERJ_FLAG_PRETTY)
727d4afb5ceSopenharmony_ci					dbuf[budget++] = ' ';
728d4afb5ceSopenharmony_ci
729d4afb5ceSopenharmony_ci				budget += (unsigned int)lws_snprintf(dbuf + budget,
730d4afb5ceSopenharmony_ci						       sizeof(dbuf) - budget,
731d4afb5ceSopenharmony_ci						       "\"%s\"", map->colname);
732d4afb5ceSopenharmony_ci			}
733d4afb5ceSopenharmony_ci
734d4afb5ceSopenharmony_ci
735d4afb5ceSopenharmony_ci			if (js->sp != 1)
736d4afb5ceSopenharmony_ci				return LSJS_RESULT_ERROR;
737d4afb5ceSopenharmony_ci			j->map = map->child_map;
738d4afb5ceSopenharmony_ci			j->map_entries = map->child_map_size;
739d4afb5ceSopenharmony_ci			j->size = map->aux;
740d4afb5ceSopenharmony_ci			j->subsequent = 0;
741d4afb5ceSopenharmony_ci			j->map_entry = 0;
742d4afb5ceSopenharmony_ci			j->obj = js->st[js->sp - 1].obj;
743d4afb5ceSopenharmony_ci			j->dllpos = NULL;
744d4afb5ceSopenharmony_ci			if (!(js->flags & LSSERJ_FLAG_OMIT_SCHEMA))
745d4afb5ceSopenharmony_ci				/* we're actually at the same level */
746d4afb5ceSopenharmony_ci				j->subsequent = 1;
747d4afb5ceSopenharmony_ci			j->idt = 1;
748d4afb5ceSopenharmony_ci			break;
749d4afb5ceSopenharmony_ci		default:
750d4afb5ceSopenharmony_ci			break;
751d4afb5ceSopenharmony_ci		}
752d4afb5ceSopenharmony_ci
753d4afb5ceSopenharmony_ci		switch (map->type) {
754d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
755d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
756d4afb5ceSopenharmony_ci			/*
757d4afb5ceSopenharmony_ci			 * This is a bit tricky... we have to escape the string
758d4afb5ceSopenharmony_ci			 * which may 6x its length depending on what the
759d4afb5ceSopenharmony_ci			 * contents are.
760d4afb5ceSopenharmony_ci			 *
761d4afb5ceSopenharmony_ci			 * We offset the unescaped string starting point first
762d4afb5ceSopenharmony_ci			 */
763d4afb5ceSopenharmony_ci
764d4afb5ceSopenharmony_ci			q += js->offset;
765d4afb5ceSopenharmony_ci			budget = strlen(q); /* how much unescaped is left */
766d4afb5ceSopenharmony_ci
767d4afb5ceSopenharmony_ci			/*
768d4afb5ceSopenharmony_ci			 * This is going to escape as much as it can fit, and
769d4afb5ceSopenharmony_ci			 * let us know the amount of input that was consumed
770d4afb5ceSopenharmony_ci			 * in "used".
771d4afb5ceSopenharmony_ci			 */
772d4afb5ceSopenharmony_ci
773d4afb5ceSopenharmony_ci			lws_json_purify((char *)buf, q, (int)len, &used);
774d4afb5ceSopenharmony_ci			m = strlen((const char *)buf);
775d4afb5ceSopenharmony_ci			buf += m;
776d4afb5ceSopenharmony_ci			len -= m;
777d4afb5ceSopenharmony_ci			js->remaining = budget - (unsigned int)used;
778d4afb5ceSopenharmony_ci			js->offset = (unsigned int)used;
779d4afb5ceSopenharmony_ci			if (!js->remaining)
780d4afb5ceSopenharmony_ci				js->offset = 0;
781d4afb5ceSopenharmony_ci
782d4afb5ceSopenharmony_ci			break;
783d4afb5ceSopenharmony_ci		default:
784d4afb5ceSopenharmony_ci			q += js->offset;
785d4afb5ceSopenharmony_ci			budget -= js->remaining;
786d4afb5ceSopenharmony_ci
787d4afb5ceSopenharmony_ci			if (budget > len) {
788d4afb5ceSopenharmony_ci				js->remaining = budget - len;
789d4afb5ceSopenharmony_ci				js->offset = len;
790d4afb5ceSopenharmony_ci				budget = len;
791d4afb5ceSopenharmony_ci			} else {
792d4afb5ceSopenharmony_ci				js->remaining = 0;
793d4afb5ceSopenharmony_ci				js->offset = 0;
794d4afb5ceSopenharmony_ci			}
795d4afb5ceSopenharmony_ci
796d4afb5ceSopenharmony_ci			memcpy(buf, q, budget);
797d4afb5ceSopenharmony_ci			buf += budget;
798d4afb5ceSopenharmony_ci			*buf = '\0';
799d4afb5ceSopenharmony_ci			len -= budget;
800d4afb5ceSopenharmony_ci			break;
801d4afb5ceSopenharmony_ci		}
802d4afb5ceSopenharmony_ci
803d4afb5ceSopenharmony_ci
804d4afb5ceSopenharmony_ci
805d4afb5ceSopenharmony_ci		switch (map->type) {
806d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
807d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
808d4afb5ceSopenharmony_ci			*buf++ = '\"';
809d4afb5ceSopenharmony_ci			len--;
810d4afb5ceSopenharmony_ci			break;
811d4afb5ceSopenharmony_ci		case LSMT_SCHEMA:
812d4afb5ceSopenharmony_ci			continue;
813d4afb5ceSopenharmony_ci		default:
814d4afb5ceSopenharmony_ci			break;
815d4afb5ceSopenharmony_ci		}
816d4afb5ceSopenharmony_ci
817d4afb5ceSopenharmony_ci		if (js->remaining)
818d4afb5ceSopenharmony_ci			continue;
819d4afb5ceSopenharmony_ciup:
820d4afb5ceSopenharmony_ci		if (++j->map_entry < j->map_entries)
821d4afb5ceSopenharmony_ci			continue;
822d4afb5ceSopenharmony_ci
823d4afb5ceSopenharmony_ci		if (!js->sp)
824d4afb5ceSopenharmony_ci			continue;
825d4afb5ceSopenharmony_ci		js->sp--;
826d4afb5ceSopenharmony_ci		if (!js->sp) {
827d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
828d4afb5ceSopenharmony_ci			*buf++ = '}';
829d4afb5ceSopenharmony_ci			len--;
830d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
831d4afb5ceSopenharmony_ci			break;
832d4afb5ceSopenharmony_ci		}
833d4afb5ceSopenharmony_ci		js->offset = 0;
834d4afb5ceSopenharmony_ci		j = &js->st[js->sp];
835d4afb5ceSopenharmony_ci		map = &j->map[j->map_entry];
836d4afb5ceSopenharmony_ci
837d4afb5ceSopenharmony_ci		if (map->type == LSMT_CHILD_PTR) {
838d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
839d4afb5ceSopenharmony_ci			*buf++ = '}';
840d4afb5ceSopenharmony_ci			len--;
841d4afb5ceSopenharmony_ci
842d4afb5ceSopenharmony_ci			/* we have done the singular child pointer */
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci			js->offset = 0;
845d4afb5ceSopenharmony_ci			goto up;
846d4afb5ceSopenharmony_ci		}
847d4afb5ceSopenharmony_ci
848d4afb5ceSopenharmony_ci		if (map->type != LSMT_LIST)
849d4afb5ceSopenharmony_ci			continue;
850d4afb5ceSopenharmony_ci		/*
851d4afb5ceSopenharmony_ci		 * we are coming back up to an array map, it means we should
852d4afb5ceSopenharmony_ci		 * advance to the next array member if there is one
853d4afb5ceSopenharmony_ci		 */
854d4afb5ceSopenharmony_ci
855d4afb5ceSopenharmony_ci		lws_struct_pretty(js, &buf, &len);
856d4afb5ceSopenharmony_ci		*buf++ = '}';
857d4afb5ceSopenharmony_ci		len--;
858d4afb5ceSopenharmony_ci
859d4afb5ceSopenharmony_ci		p = j->dllpos = j->dllpos->next;
860d4afb5ceSopenharmony_ci		if (j->dllpos) {
861d4afb5ceSopenharmony_ci			/*
862d4afb5ceSopenharmony_ci			 * there was another item in the array to do... let's
863d4afb5ceSopenharmony_ci			 * move on to that and do it
864d4afb5ceSopenharmony_ci			 */
865d4afb5ceSopenharmony_ci			*buf++ = ',';
866d4afb5ceSopenharmony_ci			len--;
867d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
868d4afb5ceSopenharmony_ci			js->offset = 0;
869d4afb5ceSopenharmony_ci			j = &js->st[++js->sp];
870d4afb5ceSopenharmony_ci			j->map_entry = 0;
871d4afb5ceSopenharmony_ci			map = &j->map[j->map_entry];
872d4afb5ceSopenharmony_ci
873d4afb5ceSopenharmony_ci			*buf++ = '{';
874d4afb5ceSopenharmony_ci			len--;
875d4afb5ceSopenharmony_ci			lws_struct_pretty(js, &buf, &len);
876d4afb5ceSopenharmony_ci
877d4afb5ceSopenharmony_ci			j->subsequent = 0;
878d4afb5ceSopenharmony_ci			j->obj = ((char *)p) - j->map->ofs_clist;
879d4afb5ceSopenharmony_ci			continue;
880d4afb5ceSopenharmony_ci		}
881d4afb5ceSopenharmony_ci
882d4afb5ceSopenharmony_ci		/* there are no further items in the array */
883d4afb5ceSopenharmony_ci
884d4afb5ceSopenharmony_ci		js->offset = 0;
885d4afb5ceSopenharmony_ci		lws_struct_pretty(js, &buf, &len);
886d4afb5ceSopenharmony_ci		*buf++ = ']';
887d4afb5ceSopenharmony_ci		len--;
888d4afb5ceSopenharmony_ci		goto up;
889d4afb5ceSopenharmony_ci	}
890d4afb5ceSopenharmony_ci
891d4afb5ceSopenharmony_ci	*written = olen - len;
892d4afb5ceSopenharmony_ci	*buf = '\0'; /* convenience, a NUL after the official end */
893d4afb5ceSopenharmony_ci
894d4afb5ceSopenharmony_ci	return LSJS_RESULT_FINISH;
895d4afb5ceSopenharmony_ci}
896