5#include "sw/device/lib/ujson/ujson.h"
11#include "sw/device/lib/base/crc32.h"
13#include "sw/device/lib/base/status.h"
15#include "sw/device/lib/ujson/private_status.h"
17static bool is_space(
int c) {
return c ==
' ' || (c >=
'\t' && c <
'\t' + 5); }
19ujson_t ujson_init(
void *context, status_t (*getc)(
void *),
20 status_t (*putbuf)(
void *,
const char *,
size_t)) {
21 ujson_t u = UJSON_INIT(context, getc, putbuf);
25void ujson_crc32_reset(ujson_t *uj) { crc32_init(&uj->
crc32); }
27uint32_t ujson_crc32_finish(ujson_t *uj) {
return crc32_finish(&uj->
crc32); }
29status_t ujson_putbuf(ujson_t *uj,
const char *buf,
size_t len) {
30 crc32_add(&uj->
crc32, buf, len);
34status_t ujson_getc(ujson_t *uj) {
35 int16_t buffer = uj->
buffer;
38 return OK_STATUS(buffer);
42 crc32_add8(&uj->
crc32, (uint8_t)s.value);
48status_t ujson_ungetc(ujson_t *uj,
char ch) {
50 return FAILED_PRECONDITION();
56bool ujson_streq(
const char *a,
const char *b) {
57 while (*a && *b && *a == *b) {
65static status_t consume_whitespace(ujson_t *uj) {
68 ch = TRY(ujson_getc(uj));
69 }
while (is_space(ch));
73static status_t consume_hexdigit(ujson_t *uj) {
74 int ch = TRY(ujson_getc(uj));
75 if (ch >=
'0' && ch <=
'9') {
76 return OK_STATUS(ch -
'0');
77 }
else if (ch >=
'A' && ch <=
'F') {
78 return OK_STATUS(ch -
'A' + 10);
79 }
else if (ch >=
'a' && ch <=
'f') {
80 return OK_STATUS(ch -
'a' + 10);
82 return OUT_OF_RANGE();
86static status_t consume_hex(ujson_t *uj) {
87 int a = TRY(consume_hexdigit(uj));
88 int b = TRY(consume_hexdigit(uj));
89 int c = TRY(consume_hexdigit(uj));
90 int d = TRY(consume_hexdigit(uj));
91 return OK_STATUS((a << 12) | (b << 8) | (c << 4) | d);
94status_t ujson_consume(ujson_t *uj,
char ch) {
95 if (ch != TRY(consume_whitespace(uj))) {
101status_t ujson_consume_maybe(ujson_t *uj,
char ch) {
102 char got = (char)TRY(consume_whitespace(uj));
104 ujson_ungetc(uj, got);
110status_t ujson_parse_qs(ujson_t *uj,
char *str,
size_t len) {
114 TRY(ujson_consume(uj,
'"'));
116 ch = (char)TRY(ujson_getc(uj));
120 ch = (char)TRY(ujson_getc(uj));
142 ch = (char)TRY(consume_hex(uj));
145 return OUT_OF_RANGE();
158status_t ujson_parse_integer(ujson_t *uj,
void *result,
size_t rsz) {
159 char ch = (char)TRY(consume_whitespace(uj));
164 ch = (char)TRY(ujson_getc(uj));
168 if (!(ch >=
'0' && ch <=
'9')) {
172 while (ch >=
'0' && ch <=
'9') {
173 if (value > UINT64_MAX / 10) {
174 return OUT_OF_RANGE();
177 if (value > UINT64_MAX - (ch -
'0')) {
178 return OUT_OF_RANGE();
187 TRY(ujson_ungetc(uj, ch));
190 if (value > (uint64_t)INT64_MAX + 1) {
191 return OUT_OF_RANGE();
194 int64_t neg_value = -1 * (int64_t)value;
195 memcpy(result, &neg_value, rsz);
199 memcpy(result, &value, rsz);
203status_t ujson_deserialize_bool(ujson_t *uj,
bool *value) {
204 char got = (char)TRY(consume_whitespace(uj));
206 TRY(ujson_consume(uj,
'r'));
207 TRY(ujson_consume(uj,
'u'));
208 TRY(ujson_consume(uj,
'e'));
210 }
else if (got ==
'f') {
211 TRY(ujson_consume(uj,
'a'));
212 TRY(ujson_consume(uj,
'l'));
213 TRY(ujson_consume(uj,
's'));
214 TRY(ujson_consume(uj,
'e'));
217 ujson_ungetc(uj, got);
223status_t ujson_deserialize_uint64_t(ujson_t *uj, uint64_t *value) {
224 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
226status_t ujson_deserialize_uint32_t(ujson_t *uj, uint32_t *value) {
227 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
229status_t ujson_deserialize_uint16_t(ujson_t *uj, uint16_t *value) {
230 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
232status_t ujson_deserialize_uint8_t(ujson_t *uj, uint8_t *value) {
233 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
235status_t ujson_deserialize_size_t(ujson_t *uj,
size_t *value) {
236 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
238status_t ujson_deserialize_int64_t(ujson_t *uj, int64_t *value) {
239 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
241status_t ujson_deserialize_int32_t(ujson_t *uj, int32_t *value) {
242 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
244status_t ujson_deserialize_int16_t(ujson_t *uj, int16_t *value) {
245 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
247status_t ujson_deserialize_int8_t(ujson_t *uj, int8_t *value) {
248 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
251static const char hex[] =
"0123456789abcdef";
253status_t ujson_serialize_string(ujson_t *uj,
const char *buf) {
255 TRY(ujson_putbuf(uj,
"\"", 1));
256 while ((ch = (uint8_t)*buf) !=
'\0') {
257 if (ch < 0x20 || ch ==
'"' || ch ==
'\\' || ch >= 0x7f) {
260 TRY(ujson_putbuf(uj,
"\\\"", 2));
263 TRY(ujson_putbuf(uj,
"\\\\", 2));
266 TRY(ujson_putbuf(uj,
"\\b", 2));
269 TRY(ujson_putbuf(uj,
"\\f", 2));
272 TRY(ujson_putbuf(uj,
"\\n", 2));
275 TRY(ujson_putbuf(uj,
"\\r", 2));
278 TRY(ujson_putbuf(uj,
"\\t", 2));
281 char esc[] = {
'\\',
'u',
'0',
'0', hex[ch >> 4], hex[ch & 0xF]};
282 TRY(ujson_putbuf(uj, esc,
sizeof(esc)));
286 TRY(ujson_putbuf(uj, buf, 1));
290 TRY(ujson_putbuf(uj,
"\"", 1));
294static status_t ujson_serialize_integer64(ujson_t *uj, uint64_t value,
297 char *end = buf +
sizeof(buf);
307 value = udiv64_slow(value, 10, &remainder);
308 *--end =
'0' + (char)remainder;
315 TRY(ujson_putbuf(uj, end, len));
319static status_t ujson_serialize_integer32(ujson_t *uj, uint32_t value,
322 char *end = buf +
sizeof(buf);
330 *--end =
'0' + value % 10;
338 TRY(ujson_putbuf(uj, end, len));
342status_t ujson_serialize_bool(ujson_t *uj,
const bool *value) {
344 TRY(ujson_putbuf(uj,
"true", 4));
346 TRY(ujson_putbuf(uj,
"false", 5));
351status_t ujson_serialize_uint64_t(ujson_t *uj,
const uint64_t *value) {
352 return ujson_serialize_integer64(uj, *value,
false);
354status_t ujson_serialize_uint32_t(ujson_t *uj,
const uint32_t *value) {
355 return ujson_serialize_integer32(uj, *value,
false);
358status_t ujson_serialize_uint16_t(ujson_t *uj,
const uint16_t *value) {
359 return ujson_serialize_integer32(uj, *value,
false);
362status_t ujson_serialize_uint8_t(ujson_t *uj,
const uint8_t *value) {
363 return ujson_serialize_integer32(uj, *value,
false);
366status_t ujson_serialize_size_t(ujson_t *uj,
const size_t *value) {
367 if (
sizeof(
size_t) ==
sizeof(uint64_t)) {
368 return ujson_serialize_integer64(uj, *value,
false);
370 return ujson_serialize_integer32(uj, *value,
false);
374status_t ujson_serialize_int64_t(ujson_t *uj,
const int64_t *value) {
375 return ujson_serialize_integer64(uj, (uint64_t)*value, *value < 0);
378status_t ujson_serialize_int32_t(ujson_t *uj,
const int32_t *value) {
379 return ujson_serialize_integer32(uj, (uint32_t)*value, *value < 0);
382status_t ujson_serialize_int16_t(ujson_t *uj,
const int16_t *value) {
383 return ujson_serialize_integer32(uj, (uint32_t)*value, *value < 0);
386status_t ujson_serialize_int8_t(ujson_t *uj,
const int8_t *value) {
387 return ujson_serialize_integer32(uj, (uint32_t)*value, *value < 0);
390status_t ujson_deserialize_status_t(ujson_t *uj, status_t *value) {
391 private_status_t code;
392 uint32_t module_id = 0;
394 TRY(ujson_consume(uj,
'{'));
395 TRY(ujson_deserialize_private_status_t(uj, &code));
396 TRY(ujson_consume(uj,
':'));
397 if (TRY(ujson_consume_maybe(uj,
'['))) {
399 TRY(ujson_parse_qs(uj, module,
sizeof(module)));
400 module_id = MAKE_MODULE_ID(module[0], module[1], module[2]);
401 TRY(ujson_consume(uj,
','));
402 TRY(ujson_deserialize_uint32_t(uj, &arg));
403 TRY(ujson_consume(uj,
']'));
405 TRY(ujson_deserialize_uint32_t(uj, &arg));
407 TRY(ujson_consume(uj,
'}'));
409 status_create((absl_status_t)code, module_id, __FILE__, (int32_t)arg);
413status_t ujson_serialize_status_t(ujson_t *uj,
const status_t *value) {
416 .sink = (size_t(*)(
void *,
const char *, size_t))ujson_putbuf,
418 base_fprintf(out,
"%!r", *value);