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 int64_t num_i64 = yyjson_get_sint(yy_val);
76 if ((ret = lite3_set_i64(buf, inout_buflen, ofs, bufsz, key, num_i64)) < 0)
77 return ret;
78 break;
79 case YYJSON_SUBTYPE_UINT:
80 uint64_t num_u64 = yyjson_get_uint(yy_val);
81 if (num_u64 <= INT64_MAX) {
82 if ((ret = lite3_set_i64(buf, inout_buflen, ofs, bufsz, key, (int64_t)num_u64)) < 0)
83 return ret;
84 break;
85 } else {
86 if ((ret = lite3_set_f64(buf, inout_buflen, ofs, bufsz, key, (double)num_u64)) < 0) // Number to big for (signed) int64_t, fall back to double
87 return ret;
88 break;
89 }
90 case YYJSON_SUBTYPE_REAL:
91 double num_f64 = yyjson_get_real(yy_val);
92 if ((ret = lite3_set_f64(buf, inout_buflen, ofs, bufsz, key, num_f64)) < 0)
93 return ret;
94 break;
95 default:
96 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING NUM SUBTYPE\n");
97 errno = EINVAL;
98 return -1;
99 }
100 break;
101 case YYJSON_TYPE_STR:
102 const char *str = yyjson_get_str(yy_val);
103 size_t len = yyjson_get_len(yy_val);
104 if ((ret = lite3_set_str_n(buf, inout_buflen, ofs, bufsz, key, str, len)) < 0)
105 return ret;
106 break;
107 case YYJSON_TYPE_OBJ:
108 size_t obj_ofs;
109 if ((ret = lite3_set_obj(buf, inout_buflen, ofs, bufsz, key, &obj_ofs)) < 0)
110 return ret;
111 if ((ret = _lite3_json_dec_obj(buf, inout_buflen, obj_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
112 return ret;
113 break;
114 case YYJSON_TYPE_ARR:
115 size_t arr_ofs;
116 if ((ret = lite3_set_arr(buf, inout_buflen, ofs, bufsz, key, &arr_ofs)) < 0)
117 return ret;
118 if ((ret = _lite3_json_dec_arr(buf, inout_buflen, arr_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
119 return ret;
120 break;
121 default:
122 LITE3_PRINT_ERROR("FAILED TO READ JSON: INVALID TYPE\n");
123 errno = EINVAL;
124 return -1;
125 }
126 return ret;
127}
128
129int _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)
130{
131 yyjson_type type = yyjson_get_type(yy_val);
132 int ret;
133 switch (type) {
134 case YYJSON_TYPE_NULL:
135 if ((ret = lite3_arr_append_null(buf, inout_buflen, ofs, bufsz)) < 0)
136 return ret;
137 break;
138 case YYJSON_TYPE_BOOL:
139 switch (yyjson_get_subtype(yy_val)) {
140 case YYJSON_SUBTYPE_FALSE:
141 if ((ret = lite3_arr_append_bool(buf, inout_buflen, ofs, bufsz, 0)) < 0)
142 return ret;
143 break;
144 case YYJSON_SUBTYPE_TRUE:
145 if ((ret = lite3_arr_append_bool(buf, inout_buflen, ofs, bufsz, 1)) < 0)
146 return ret;
147 break;
148 default:
149 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING BOOL SUBTYPE\n");
150 errno = EINVAL;
151 return -1;
152 }
153 break;
154 case YYJSON_TYPE_NUM:
155 switch (yyjson_get_subtype(yy_val)) {
156 case YYJSON_SUBTYPE_SINT:
157 int64_t num_i64 = yyjson_get_sint(yy_val);
158 if ((ret = lite3_arr_append_i64(buf, inout_buflen, ofs, bufsz, num_i64)) < 0)
159 return ret;
160 break;
161 case YYJSON_SUBTYPE_UINT:
162 uint64_t num_u64 = yyjson_get_uint(yy_val);
163 if (num_u64 <= INT64_MAX) {
164 if ((ret = lite3_arr_append_i64(buf, inout_buflen, ofs, bufsz, (int64_t)num_u64)) < 0)
165 return ret;
166 break;
167 } else {
168 if ((ret = lite3_arr_append_f64(buf, inout_buflen, ofs, bufsz, (double)num_u64)) < 0) // Number to big for (signed) int64_t, fall back to double
169 return ret;
170 break;
171 }
172 case YYJSON_SUBTYPE_REAL:
173 double num_f64 = yyjson_get_real(yy_val);
174 if ((ret = lite3_arr_append_f64(buf, inout_buflen, ofs, bufsz, num_f64)) < 0)
175 return ret;
176 break;
177 default:
178 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING NUM SUBTYPE\n");
179 errno = EINVAL;
180 return -1;
181 }
182 break;
183 case YYJSON_TYPE_STR:
184 const char *str = yyjson_get_str(yy_val);
185 size_t len = yyjson_get_len(yy_val);
186 if ((ret = lite3_arr_append_str_n(buf, inout_buflen, ofs, bufsz, str, len)) < 0)
187 return ret;
188 break;
189 case YYJSON_TYPE_OBJ:
190 size_t obj_ofs;
191 if ((ret = lite3_arr_append_obj(buf, inout_buflen, ofs, bufsz, &obj_ofs)) < 0)
192 return ret;
193 if ((ret = _lite3_json_dec_obj(buf, inout_buflen, obj_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
194 return ret;
195 break;
196 case YYJSON_TYPE_ARR:
197 size_t arr_ofs;
198 if ((ret = lite3_arr_append_arr(buf, inout_buflen, ofs, bufsz, &arr_ofs)) < 0)
199 return ret;
200 if ((ret = _lite3_json_dec_arr(buf, inout_buflen, arr_ofs, bufsz, nesting_depth, doc, yy_val)) < 0)
201 return ret;
202 break;
203 default:
204 LITE3_PRINT_ERROR("FAILED TO READ JSON: INVALID TYPE\n");
205 errno = EINVAL;
206 return -1;
207 }
208 return ret;
209}
210
211int _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)
212{
213 if (++nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX) {
214 LITE3_PRINT_ERROR("FAILED TO READ JSON: nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX\n");
215 errno = EINVAL;
216 return -1;
217 }
218 yyjson_val *key, *val;
219 yyjson_obj_iter iter = yyjson_obj_iter_with(obj);
220 int ret = 0;
221 while ((key = yyjson_obj_iter_next(&iter))) {
222 val = yyjson_obj_iter_get_val(key);
223 if ((ret = _lite3_json_dec_obj_switch(buf, inout_buflen, ofs, bufsz, nesting_depth, doc, key, val)) < 0)
224 return ret;
225 }
226 return ret;
227}
228
229int _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)
230{
231 if (++nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX) {
232 LITE3_PRINT_ERROR("FAILED TO READ JSON: nesting_depth > LITE3_JSON_NESTING_DEPTH_MAX\n");
233 errno = EINVAL;
234 return -1;
235 }
236 yyjson_val *val;
237 yyjson_arr_iter iter = yyjson_arr_iter_with(arr);
238 int ret = 0;
239 while ((val = yyjson_arr_iter_next(&iter))) {
240 if ((ret = _lite3_json_dec_arr_switch(buf, inout_buflen, ofs, bufsz, nesting_depth, doc, val)) < 0)
241 return ret;
242 }
243 return ret;
244}
245
246int _lite3_json_dec_doc(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, yyjson_doc *doc)
247{
248 yyjson_val *root_val = yyjson_doc_get_root(doc);
249 int ret = 0;
250 switch (yyjson_get_type(root_val)) {
251 case YYJSON_TYPE_OBJ:
252 if ((ret = lite3_init_obj(buf, out_buflen, bufsz)) < 0)
253 goto error;
254 if ((ret = _lite3_json_dec_obj(buf, out_buflen, 0, bufsz, 0, doc, root_val)) < 0)
255 goto error;
256 break;
257 case YYJSON_TYPE_ARR:
258 if ((ret = lite3_init_arr(buf, out_buflen, bufsz)) < 0)
259 goto error;
260 if ((ret = _lite3_json_dec_arr(buf, out_buflen, 0, bufsz, 0, doc, root_val)) < 0)
261 goto error;
262 break;
263 default:
264 LITE3_PRINT_ERROR("FAILED TO READ JSON: EXPECTING ARRAY OR OBJECT TYPE\n");
265 errno = EINVAL;
266 goto error;
267 }
268 yyjson_doc_free(doc);
269 return ret;
270error:
271 yyjson_doc_free(doc);
272 return ret;
273}
274
275int lite3_json_dec(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, const char *restrict json_str, size_t json_len)
276{
277 yyjson_read_err err;
278 yyjson_doc *doc = yyjson_read_opts((char *)json_str, json_len, YYJSON_READ_NOFLAG , NULL, &err);
279 if (!doc) {
280 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);
281 errno = EINVAL;
282 return -1;
283 }
284 return _lite3_json_dec_doc(buf, out_buflen, bufsz, doc);
285}
286
287int lite3_json_dec_file(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, const char *restrict path)
288{
289 yyjson_read_err err;
290 yyjson_doc *doc = yyjson_read_file(path, YYJSON_READ_NOFLAG , NULL, &err);
291 if (!doc) {
292 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);
293 errno = EINVAL;
294 return -1;
295 }
296 return _lite3_json_dec_doc(buf, out_buflen, bufsz, doc);
297}
298
299int lite3_json_dec_fp(unsigned char *buf, size_t *restrict out_buflen, size_t bufsz, FILE *fp)
300{
301 yyjson_read_err err;
302 yyjson_doc *doc = yyjson_read_fp(fp, YYJSON_READ_NOFLAG , NULL, &err);
303 if (!doc) {
304 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);
305 errno = EINVAL;
306 return -1;
307 }
308 return _lite3_json_dec_doc(buf, out_buflen, bufsz, doc);
309}
310#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:1258
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:1214
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:1335
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:1194
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:1391
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:1236
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:1366
#define LITE3_JSON_NESTING_DEPTH_MAX
Maximum nesting limit for JSON documents being encoded or decoded.
Definition lite3.h:2828
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:821
#define lite3_set_obj(buf, inout_buflen, ofs, bufsz, key, out_ofs)
Set object in object.
Definition lite3.h:1059
#define lite3_set_arr(buf, inout_buflen, ofs, bufsz, key, out_ofs)
Set array in object.
Definition lite3.h:1100
#define lite3_set_bool(buf, inout_buflen, ofs, bufsz, key, value)
Set boolean in object.
Definition lite3.h:852
#define lite3_set_f64(buf, inout_buflen, ofs, bufsz, key, value)
Set floating point in object.
Definition lite3.h:916
#define lite3_set_str_n(buf, inout_buflen, ofs, bufsz, key, str, str_len)
Set string in object by length.
Definition lite3.h:1024
#define lite3_set_i64(buf, inout_buflen, ofs, bufsz, key, value)
Set integer in object.
Definition lite3.h:884
Lite³ Buffer API Header.