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 status_t (*flushbuf)(
void *)) {
22 ujson_t u = UJSON_INIT(context, getc, putbuf, flushbuf);
26void ujson_crc32_reset(ujson_t *uj) { crc32_init(&uj->
crc32); }
28uint32_t ujson_crc32_finish(ujson_t *uj) {
return crc32_finish(&uj->
crc32); }
30status_t ujson_putbuf(ujson_t *uj,
const char *buf,
size_t len) {
31 crc32_add(&uj->
crc32, buf, len);
35static size_t ujson_putbuf_sink(ujson_t *uj,
const char *buf,
size_t len) {
36 status_t result = ujson_putbuf(uj, buf, len);
37 if (!status_ok(result)) {
40 return (
size_t)result.value;
45status_t ujson_getc(ujson_t *uj) {
46 int16_t buffer = uj->
buffer;
49 return OK_STATUS(buffer);
53 crc32_add8(&uj->
crc32, (uint8_t)s.value);
59status_t ujson_ungetc(ujson_t *uj,
char ch) {
61 return FAILED_PRECONDITION();
67bool ujson_streq(
const char *a,
const char *b) {
68 while (*a && *b && *a == *b) {
76static status_t consume_whitespace(ujson_t *uj) {
79 ch = TRY(ujson_getc(uj));
80 }
while (is_space(ch));
84static status_t consume_hexdigit(ujson_t *uj) {
85 int ch = TRY(ujson_getc(uj));
86 if (ch >=
'0' && ch <=
'9') {
87 return OK_STATUS(ch -
'0');
88 }
else if (ch >=
'A' && ch <=
'F') {
89 return OK_STATUS(ch -
'A' + 10);
90 }
else if (ch >=
'a' && ch <=
'f') {
91 return OK_STATUS(ch -
'a' + 10);
93 return OUT_OF_RANGE();
97static status_t consume_hex(ujson_t *uj) {
98 int a = TRY(consume_hexdigit(uj));
99 int b = TRY(consume_hexdigit(uj));
100 int c = TRY(consume_hexdigit(uj));
101 int d = TRY(consume_hexdigit(uj));
102 return OK_STATUS((a << 12) | (b << 8) | (c << 4) | d);
105status_t ujson_consume(ujson_t *uj,
char ch) {
106 if (ch != TRY(consume_whitespace(uj))) {
112status_t ujson_consume_maybe(ujson_t *uj,
char ch) {
113 char got = (char)TRY(consume_whitespace(uj));
115 ujson_ungetc(uj, got);
121status_t ujson_parse_qs(ujson_t *uj,
char *str,
size_t len) {
125 TRY(ujson_consume(uj,
'"'));
127 ch = (char)TRY(ujson_getc(uj));
131 ch = (char)TRY(ujson_getc(uj));
153 ch = (char)TRY(consume_hex(uj));
156 return OUT_OF_RANGE();
169status_t ujson_parse_integer(ujson_t *uj,
void *result,
size_t rsz) {
170 char ch = (char)TRY(consume_whitespace(uj));
175 ch = (char)TRY(ujson_getc(uj));
179 if (!(ch >=
'0' && ch <=
'9')) {
183 while (ch >=
'0' && ch <=
'9') {
184 if (value > UINT64_MAX / 10) {
185 return OUT_OF_RANGE();
188 if (value > UINT64_MAX - (ch -
'0')) {
189 return OUT_OF_RANGE();
198 TRY(ujson_ungetc(uj, ch));
201 if (value > (uint64_t)INT64_MAX + 1) {
202 return OUT_OF_RANGE();
205 int64_t neg_value = -1 * (int64_t)value;
206 memcpy(result, &neg_value, rsz);
210 memcpy(result, &value, rsz);
214status_t ujson_deserialize_bool(ujson_t *uj,
bool *value) {
215 char got = (char)TRY(consume_whitespace(uj));
217 TRY(ujson_consume(uj,
'r'));
218 TRY(ujson_consume(uj,
'u'));
219 TRY(ujson_consume(uj,
'e'));
221 }
else if (got ==
'f') {
222 TRY(ujson_consume(uj,
'a'));
223 TRY(ujson_consume(uj,
'l'));
224 TRY(ujson_consume(uj,
's'));
225 TRY(ujson_consume(uj,
'e'));
228 ujson_ungetc(uj, got);
234status_t ujson_deserialize_uint64_t(ujson_t *uj, uint64_t *value) {
235 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
237status_t ujson_deserialize_uint32_t(ujson_t *uj, uint32_t *value) {
238 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
240status_t ujson_deserialize_uint16_t(ujson_t *uj, uint16_t *value) {
241 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
243status_t ujson_deserialize_uint8_t(ujson_t *uj, uint8_t *value) {
244 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
246status_t ujson_deserialize_size_t(ujson_t *uj,
size_t *value) {
247 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
249status_t ujson_deserialize_int64_t(ujson_t *uj, int64_t *value) {
250 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
252status_t ujson_deserialize_int32_t(ujson_t *uj, int32_t *value) {
253 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
255status_t ujson_deserialize_int16_t(ujson_t *uj, int16_t *value) {
256 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
258status_t ujson_deserialize_int8_t(ujson_t *uj, int8_t *value) {
259 return ujson_parse_integer(uj, (
void *)value,
sizeof(*value));
262static const char hex[] =
"0123456789abcdef";
264status_t ujson_serialize_string(ujson_t *uj,
const char *buf) {
266 TRY(ujson_putbuf(uj,
"\"", 1));
267 while ((ch = (uint8_t)*buf) !=
'\0') {
268 if (ch < 0x20 || ch ==
'"' || ch ==
'\\' || ch >= 0x7f) {
271 TRY(ujson_putbuf(uj,
"\\\"", 2));
274 TRY(ujson_putbuf(uj,
"\\\\", 2));
277 TRY(ujson_putbuf(uj,
"\\b", 2));
280 TRY(ujson_putbuf(uj,
"\\f", 2));
283 TRY(ujson_putbuf(uj,
"\\n", 2));
286 TRY(ujson_putbuf(uj,
"\\r", 2));
289 TRY(ujson_putbuf(uj,
"\\t", 2));
292 char esc[] = {
'\\',
'u',
'0',
'0', hex[ch >> 4], hex[ch & 0xF]};
293 TRY(ujson_putbuf(uj, esc,
sizeof(esc)));
297 TRY(ujson_putbuf(uj, buf, 1));
301 TRY(ujson_putbuf(uj,
"\"", 1));
305static status_t ujson_serialize_integer64(ujson_t *uj, uint64_t value,
308 char *end = buf +
sizeof(buf);
318 value = udiv64_slow(value, 10, &remainder);
319 *--end =
'0' + (char)remainder;
326 TRY(ujson_putbuf(uj, end, len));
330static status_t ujson_serialize_integer32(ujson_t *uj, uint32_t value,
333 char *end = buf +
sizeof(buf);
341 *--end =
'0' + value % 10;
349 TRY(ujson_putbuf(uj, end, len));
353status_t ujson_serialize_bool(ujson_t *uj,
const bool *value) {
355 TRY(ujson_putbuf(uj,
"true", 4));
357 TRY(ujson_putbuf(uj,
"false", 5));
362status_t ujson_serialize_uint64_t(ujson_t *uj,
const uint64_t *value) {
363 return ujson_serialize_integer64(uj, *value,
false);
365status_t ujson_serialize_uint32_t(ujson_t *uj,
const uint32_t *value) {
366 return ujson_serialize_integer32(uj, *value,
false);
369status_t ujson_serialize_uint16_t(ujson_t *uj,
const uint16_t *value) {
370 return ujson_serialize_integer32(uj, *value,
false);
373status_t ujson_serialize_uint8_t(ujson_t *uj,
const uint8_t *value) {
374 return ujson_serialize_integer32(uj, *value,
false);
377status_t ujson_serialize_size_t(ujson_t *uj,
const size_t *value) {
378 if (
sizeof(
size_t) ==
sizeof(uint64_t)) {
379 return ujson_serialize_integer64(uj, *value,
false);
381 return ujson_serialize_integer32(uj, *value,
false);
385status_t ujson_serialize_int64_t(ujson_t *uj,
const int64_t *value) {
386 return ujson_serialize_integer64(uj, (uint64_t)*value, *value < 0);
389status_t ujson_serialize_int32_t(ujson_t *uj,
const int32_t *value) {
390 return ujson_serialize_integer32(uj, (uint32_t)*value, *value < 0);
393status_t ujson_serialize_int16_t(ujson_t *uj,
const int16_t *value) {
394 return ujson_serialize_integer32(uj, (uint32_t)*value, *value < 0);
397status_t ujson_serialize_int8_t(ujson_t *uj,
const int8_t *value) {
398 return ujson_serialize_integer32(uj, (uint32_t)*value, *value < 0);
401status_t ujson_deserialize_status_t(ujson_t *uj, status_t *value) {
402 private_status_t code;
403 uint32_t module_id = 0;
405 TRY(ujson_consume(uj,
'{'));
406 TRY(ujson_deserialize_private_status_t(uj, &code));
407 TRY(ujson_consume(uj,
':'));
408 if (TRY(ujson_consume_maybe(uj,
'['))) {
410 TRY(ujson_parse_qs(uj, module,
sizeof(module)));
411 module_id = MAKE_MODULE_ID(module[0], module[1], module[2]);
412 TRY(ujson_consume(uj,
','));
413 TRY(ujson_deserialize_uint32_t(uj, &arg));
414 TRY(ujson_consume(uj,
']'));
416 TRY(ujson_deserialize_uint32_t(uj, &arg));
418 TRY(ujson_consume(uj,
'}'));
420 status_create((absl_status_t)code, module_id, __FILE__, (int32_t)arg);
424status_t ujson_serialize_status_t(ujson_t *uj,
const status_t *value) {
429 base_fprintf(out,
"%!r", *value);