Lite³
A JSON-Compatible Zero-Copy Serialization Format
Loading...
Searching...
No Matches
json_dec.c
1/*
2 Lite³: A JSON-Compatible Zero-Copy Serialization Format
3
4 Copyright © 2025 Elias de Jong <elias@fastserial.com>
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23
24 __ __________________ ____
25 _ ___ ___/ /___(_)_/ /_______|_ /
26 _ _____/ / __/ /_ __/ _ \_/_ <
27 ___ __/ /___/ / / /_ / __/____/
28 /_____/_/ \__/ \___/
29*/
30#include "lite3.h"
31
32
33
34#ifdef LITE3_JSON
35#include <stdint.h>
36#include <errno.h>
37
38#include "yyjson/yyjson.h"
39
40
41
42// Forward declarations
43int _lite3_json_dec_obj(unsigned char *buf, size_t *restrict inout_buflen, size_t ofs, size_t bufsz, size_t nesting_depth, yyjson_doc *doc, yyjson_val *obj);
44int _lite3_json_dec_arr(unsigned char *buf, size_t *restrict inout_buflen, size_t ofs, size_t bufsz, size_t nesting_depth, yyjson_doc *doc, yyjson_val *arr);
45
46int _lite3_json_dec_obj_switch(unsigned char *buf, size_t *restrict inout_buflen, size_t ofs, size_t bufsz, size_t nesting_depth, yyjson_doc *doc, yyjson_val *yy_key, yyjson_val *yy_val)
47{
48 const char *key = yyjson_get_str(yy_key);
49 yyjson_type type = yyjson_get_type(yy_val);
50 int ret;
51 switch (type) {
52 case YYJSON_TYPE_NULL:
53 if ((ret = lite3_set_null(buf, inout_buflen, ofs, bufsz, key)) < 0)
54 return ret;
55 break;
56 case YYJSON_TYPE_BOOL:
57 switch (yyjson_get_subtype(yy_val)) {
58 case YYJSON_SUBTYPE_FALSE:
59 if ((ret = lite3_set_bool(buf, inout_buflen, ofs, bufsz, key, 0)) < 0)
60 return ret;
61 break;
62 case YYJSON_SUBTYPE_TRUE:
63 if ((ret = lite3_set_bool(buf, inout_buflen, ofs, bufsz, key, 1)) < 0)
64 return ret;
65 break;
66 default:
67 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING BOOL SUBTYPE\n");
68 errno = EINVAL;
69 return -1;
70 }
71 break;
72 case YYJSON_TYPE_NUM:
73 switch (yyjson_get_subtype(yy_val)) {
74 case YYJSON_SUBTYPE_SINT:
75 ;
76 int64_t num_i64 = yyjson_get_sint(yy_val);
77 if ((ret = lite3_set_i64(buf, inout_buflen, ofs, bufsz, key, num_i64)) < 0)
78 return ret;
79 break;
80 case YYJSON_SUBTYPE_UINT:
81 ;
82 uint64_t num_u64 = yyjson_get_uint(yy_val);
83 if (num_u64 <= INT64_MAX) {
84 if ((ret = lite3_set_i64(buf, inout_buflen, ofs, bufsz, key, (int64_t)num_u64)) < 0)
85 return ret;
86 break;
87 } else {
88 if ((ret = lite3_set_f64(buf, inout_buflen, ofs, bufsz, key, (double)num_u64)) < 0) // Number too big for (signed) int64_t, fall back to double
89 return ret;
90 break;
91 }
92 case YYJSON_SUBTYPE_REAL:
93 ;
94 double num_f64 = yyjson_get_real(yy_val);
95 if ((ret = lite3_set_f64(buf, inout_buflen, ofs, bufsz, key, num_f64)) < 0)
96 return ret;
97 break;
98 default:
99 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING NUM SUBTYPE\n");
100 errno = EINVAL;
101 return -1;
102 }
103 break;
104 case YYJSON_TYPE_STR:
105 ;
106 const char *str = yyjson_get_str(yy_val);
107 size_t len = yyjson_get_len(yy_val);
108 if ((ret = lite3_set_str_n(buf, inout_buflen, ofs, bufsz, key, str, len)) < 0)
109 return ret;
110 break;
111 case YYJSON_TYPE_OBJ:
112 ;
113 size_t obj_ofs;
114 if ((ret = lite3_set_obj(buf, inout_buflen, ofs, bufsz, key, &obj_ofs)) < 0)
115 return ret;
116 if ((ret = _lite3_json_dec_obj(buf, inout_buflen, obj_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
117 return ret;
118 break;
119 case YYJSON_TYPE_ARR:
120 ;
121 size_t arr_ofs;
122 if ((ret = lite3_set_arr(buf, inout_buflen, ofs, bufsz, key, &arr_ofs)) < 0)
123 return ret;
124 if ((ret = _lite3_json_dec_arr(buf, inout_buflen, arr_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
125 return ret;
126 break;
127 default:
128 LITE3_PRINT_ERROR("FAILED TO READ JSON: INVALID TYPE\n");
129 errno = EINVAL;
130 return -1;
131 }
132 return ret;
133}
134
135int _lite3_json_dec_arr_switch(unsigned char *buf, size_t *restrict inout_buflen, size_t ofs, size_t bufsz, size_t nesting_depth, yyjson_doc *doc, yyjson_val *yy_val)
136{
137 yyjson_type type = yyjson_get_type(yy_val);
138 int ret;
139 switch (type) {
140 case YYJSON_TYPE_NULL:
141 if ((ret = lite3_arr_append_null(buf, inout_buflen, ofs, bufsz)) < 0)
142 return ret;
143 break;
144 case YYJSON_TYPE_BOOL:
145 switch (yyjson_get_subtype(yy_val)) {
146 case YYJSON_SUBTYPE_FALSE:
147 if ((ret = lite3_arr_append_bool(buf, inout_buflen, ofs, bufsz, 0)) < 0)
148 return ret;
149 break;
150 case YYJSON_SUBTYPE_TRUE:
151 if ((ret = lite3_arr_append_bool(buf, inout_buflen, ofs, bufsz, 1)) < 0)
152 return ret;
153 break;
154 default:
155 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING BOOL SUBTYPE\n");
156 errno = EINVAL;
157 return -1;
158 }
159 break;
160 case YYJSON_TYPE_NUM:
161 switch (yyjson_get_subtype(yy_val)) {
162 case YYJSON_SUBTYPE_SINT:
163 ;
164 int64_t num_i64 = yyjson_get_sint(yy_val);
165 if ((ret = lite3_arr_append_i64(buf, inout_buflen, ofs, bufsz, num_i64)) < 0)
166 return ret;
167 break;
168 case YYJSON_SUBTYPE_UINT:
169 ;
170 uint64_t num_u64 = yyjson_get_uint(yy_val);
171 if (num_u64 <= INT64_MAX) {
172 if ((ret = lite3_arr_append_i64(buf, inout_buflen, ofs, bufsz, (int64_t)num_u64)) < 0)
173 return ret;
174 break;
175 } else {
176 if ((ret = lite3_arr_append_f64(buf, inout_buflen, ofs, bufsz, (double)num_u64)) < 0) // Number too big for (signed) int64_t, fall back to double
177 return ret;
178 break;
179 }
180 case YYJSON_SUBTYPE_REAL:
181 ;
182 double num_f64 = yyjson_get_real(yy_val);
183 if ((ret = lite3_arr_append_f64(buf, inout_buflen, ofs, bufsz, num_f64)) < 0)
184 return ret;
185 break;
186 default:
187 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING NUM SUBTYPE\n");
188 errno = EINVAL;
189 return -1;
190 }
191 break;
192 case YYJSON_TYPE_STR:
193 ;
194 const char *str = yyjson_get_str(yy_val);
195 size_t len = yyjson_get_len(yy_val);
196 if ((ret = lite3_arr_append_str_n(buf, inout_buflen, ofs, bufsz, str, len)) < 0)
197 return ret;
198 break;
199 case YYJSON_TYPE_OBJ:
200 ;
201 size_t obj_ofs;
202 if ((ret = lite3_arr_append_obj(buf, inout_buflen, ofs, bufsz, &obj_ofs)) < 0)
203 return ret;
204 if ((ret = _lite3_json_dec_obj(buf, inout_buflen, obj_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
205 return ret;
206 break;
207 case YYJSON_TYPE_ARR:
208 ;
209 size_t arr_ofs;
210 if ((ret = lite3_arr_append_arr(buf, inout_buflen, ofs, bufsz, &arr_ofs)) < 0)
211 return ret;
212 if ((ret = _lite3_json_dec_arr(buf, inout_buflen, arr_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
213 return ret;
214 break;
215 default:
216 LITE3_PRINT_ERROR("FAILED TO READ JSON: INVALID TYPE\n");
217 errno = EINVAL;
218 return -1;
219 }
220 return ret;
221}
222
223int _lite3_json_dec_obj(unsigned char *buf, size_t *restrict inout_buflen, size_t ofs, size_t bufsz, size_t nesting_depth, yyjson_doc *doc, yyjson_val *obj)
224{
225 if (++nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX) {
226 LITE3_PRINT_ERROR("FAILED TO READ JSON: nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX\n");
227 errno = EINVAL;
228 return -1;
229 }
230 yyjson_val *key, *val;
231 yyjson_obj_iter iter = yyjson_obj_iter_with(obj);
232 int ret = 0;
233 while ((key = yyjson_obj_iter_next(&iter))) {
234 val = yyjson_obj_iter_get_val(key);
235 if ((ret = _lite3_json_dec_obj_switch(buf, inout_buflen, ofs, bufsz, nesting_depth, doc, key, val)) < 0)
236 return ret;
237 }
238 return ret;
239}
240
241int _lite3_json_dec_arr(unsigned char *buf, size_t *restrict inout_buflen, size_t ofs, size_t bufsz, size_t nesting_depth, yyjson_doc *doc, yyjson_val *arr)
242{
243 if (++nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX) {
244 LITE3_PRINT_ERROR("FAILED TO READ JSON: nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX\n");
245 errno = EINVAL;
246 return -1;
247 }
248 yyjson_val *val;
249 yyjson_arr_iter iter = yyjson_arr_iter_with(arr);
250 int ret = 0;
251 while ((val = yyjson_arr_iter_next(&iter))) {
252 if ((ret = _lite3_json_dec_arr_switch(buf, inout_buflen, ofs, bufsz, nesting_depth, doc, val)) < 0)
253 return ret;
254 }
255 return ret;
256}
257
258int _lite3_json_dec_doc(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, yyjson_doc *doc)
259{
260 yyjson_val *root_val = yyjson_doc_get_root(doc);
261 int ret = 0;
262 switch (yyjson_get_type(root_val)) {
263 case YYJSON_TYPE_OBJ:
264 if ((ret = lite3_init_obj(buf, out_buflen, bufsz)) < 0)
265 goto error;
266 if ((ret = _lite3_json_dec_obj(buf, out_buflen, 0, bufsz, 0, doc, root_val)) < 0)
267 goto error;
268 break;
269 case YYJSON_TYPE_ARR:
270 if ((ret = lite3_init_arr(buf, out_buflen, bufsz)) < 0)
271 goto error;
272 if ((ret = _lite3_json_dec_arr(buf, out_buflen, 0, bufsz, 0, doc, root_val)) < 0)
273 goto error;
274 break;
275 default:
276 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING ARRAY OR OBJECT TYPE\n");
277 errno = EINVAL;
278 goto error;
279 }
280 yyjson_doc_free(doc);
281 return ret;
282error:
283 yyjson_doc_free(doc);
284 return ret;
285}
286
287int lite3_json_dec(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, const char *restrict json_str, size_t json_len)
288{
289 yyjson_read_err err;
290 yyjson_doc *doc = yyjson_read_opts((char *)json_str, json_len, YYJSON_READ_NOFLAG , NULL, &err);
291 if (!doc) {
292 LITE3_PRINT_ERROR("FAILED TO READ JSON STRING\tyyjson error code: %u\tmsg:%s\tat byte position: %lu\n", err.code, err.msg, err.pos);
293 errno = EINVAL;
294 return -1;
295 }
296 return _lite3_json_dec_doc(buf, out_buflen, bufsz, doc);
297}
298
299int lite3_json_dec_file(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, const char *restrict path)
300{
301 yyjson_read_err err;
302 yyjson_doc *doc = yyjson_read_file(path, YYJSON_READ_NOFLAG , NULL, &err);
303 if (!doc) {
304 LITE3_PRINT_ERROR("FAILED TO READ JSON FILE\tyyjson error code: %u\tmsg:%s\tat byte position: %lu\n", err.code, err.msg, err.pos);
305 errno = EINVAL;
306 return -1;
307 }
308 return _lite3_json_dec_doc(buf, out_buflen, bufsz, doc);
309}
310
311int lite3_json_dec_fp(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, FILE *fp)
312{
313 yyjson_read_err err;
314 yyjson_doc *doc = yyjson_read_fp(fp, YYJSON_READ_NOFLAG , NULL, &err);
315 if (!doc) {
316 LITE3_PRINT_ERROR("FAILED TO READ JSON FILE POINTER\tyyjson error code: %u\tmsg:%s\tat byte position: %lu\n", err.code, err.msg, err.pos);
317 errno = EINVAL;
318 return -1;
319 }
320 return _lite3_json_dec_doc(buf, out_buflen, bufsz, doc);
321}
322#endif // LITE3_JSON
static int lite3_arr_append_f64(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz, double value)
Append floating point to array.
Definition lite3.h:1259
static int lite3_arr_append_bool(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz, bool value)
Append boolean to array.
Definition lite3.h:1215
static int lite3_arr_append_str_n(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz, const char *__restrict str, size_t str_len)
Append string to array by length.
Definition lite3.h:1336
static int lite3_arr_append_null(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz)
Append null to array.
Definition lite3.h:1195
static int lite3_arr_append_arr(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz, size_t *__restrict out_ofs)
Append array to array.
Definition lite3.h:1392
static int lite3_arr_append_i64(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz, int64_t value)
Append integer to array.
Definition lite3.h:1237
static int lite3_arr_append_obj(unsigned char *buf, size_t *__restrict inout_buflen, size_t ofs, size_t bufsz, size_t *__restrict out_ofs)
Append object to array.
Definition lite3.h:1367
#define LITE3_JSON_NESTING_DEPTH_MAX
Maximum nesting limit for JSON documents being encoded or decoded.
Definition lite3.h:2873
int lite3_json_dec_file(unsigned char *buf, size_t *__restrict out_buflen, size_t bufsz, const char *__restrict path)
Convert JSON from file path to Lite³
int lite3_json_dec(unsigned char *buf, size_t *__restrict out_buflen, size_t bufsz, const char *__restrict json_str, size_t json_len)
Convert JSON string to Lite³
int lite3_json_dec_fp(unsigned char *buf, size_t *__restrict out_buflen, size_t bufsz, FILE *fp)
Convert JSON from file pointer to Lite³
#define lite3_set_null(buf, inout_buflen, ofs, bufsz, key)
Set null in object.
Definition lite3.h:816
#define lite3_set_obj(buf, inout_buflen, ofs, bufsz, key, out_ofs)
Set object in object.
Definition lite3.h:1054
#define lite3_set_arr(buf, inout_buflen, ofs, bufsz, key, out_ofs)
Set array in object.
Definition lite3.h:1096
#define lite3_set_bool(buf, inout_buflen, ofs, bufsz, key, value)
Set boolean in object.
Definition lite3.h:847
#define lite3_set_f64(buf, inout_buflen, ofs, bufsz, key, value)
Set floating point in object.
Definition lite3.h:911
#define lite3_set_str_n(buf, inout_buflen, ofs, bufsz, key, str, str_len)
Set string in object by length.
Definition lite3.h:1019
#define lite3_set_i64(buf, inout_buflen, ofs, bufsz, key, value)
Set integer in object.
Definition lite3.h:879
Lite³ Buffer API Header.