#include <stdarg.h>
#include <stdio.h>
#include <bee2/core/hex.h>
#include <bee2/core/json.h>
#include <bee2/core/mem.h>
#include <bee2/core/str.h>
#include <bee2/core/util.h>
static const size_t _max_depth = 256;
static size_t jsonElemParse(json_elem_t* elem, const char json[], size_t count,
size_t depth);
static size_t jsonWsDec(const char json[], size_t count)
{
size_t c;
ASSERT(memIsValid(json, count));
for (c = 0; c < count && strContains(" \n\r\t", json[c]); ++c);
return c;
}
static size_t jsonDelimDec(const char json[], size_t count, char delim)
{
size_t c;
ASSERT(strContains(",:{}[]", delim));
c = jsonWsDec(json, count);
if (c == count || json[c] != delim)
return SIZE_MAX;
return c + 1 + jsonWsDec(json + c + 1, count - c - 1);
}
static size_t jsonLexDec(json_elem_t* elem, const char json[], size_t count)
{
const char* lex[] = { "true", "false", "null" };
size_t c;
size_t c1;
size_t i;
ASSERT(memIsValid(json, count));
ASSERT(memIsNullOrValid(elem, sizeof(json_elem_t)));
c = jsonWsDec(json, count);
json += c, count -= c;
for (i = 0; i < COUNT_OF(lex); ++i)
if ((c1 = strLen(lex[i])) <= count && strStartsWith(json, lex[i]))
break;
if (i == COUNT_OF(lex))
return SIZE_MAX;
if (elem)
elem->json = json, elem->count = c1;
return c + c1 + jsonWsDec(json + c + c1, count - c - c1);
}
static size_t jsonSizeParse(json_elem_t* elem, const char json[], size_t count)
{
size_t c;
size_t c1;
ASSERT(memIsValid(json, count));
ASSERT(memIsNullOrValid(elem, sizeof(json_elem_t)));
c = c1 = jsonWsDec(json, count);
for (; c < count && '0' <= json[c] && json[c] <= '9'; ++c);
if (c == c1 || json[c1] == '0' && c - c1 > 1)
return SIZE_MAX;
if (elem)
elem->json = json + c1, elem->count = c - c1;
return c + jsonWsDec(json + c, count - c);
}
size_t jsonSizeDec(size_t* size, const char json[], size_t count)
{
register size_t s;
json_elem_t e;
size_t c;
ASSERT(memIsNullOrValid(size, O_PER_S));
c = jsonSizeParse(&e, json, count);
if (c == SIZE_MAX)
return SIZE_MAX;
ASSERT(e.count > 0 && memIsValid(e.json, e.count));
for (s = 0; e.count--; ++e.json)
{
ASSERT('0' <= e.json[0] && e.json[0] <= '9');
if (s > SIZE_MAX / 10)
return SIZE_MAX;
s *= 10;
if (s + (size_t)(e.json[0] - '0') < s)
return SIZE_MAX;
s += (size_t)(e.json[0] - '0');
}
if (size)
*size = s;
CLEAN(s);
return c;
}
static size_t jsonStrParse(json_elem_t* elem, const char json[], size_t count)
{
size_t c;
size_t c1;
ASSERT(memIsValid(json, count));
ASSERT(memIsNullOrValid(elem, sizeof(json_elem_t)));
c = jsonWsDec(json, count);
if (c == count || json[c] != '"')
return SIZE_MAX;
c1 = c++;
while (c < count && json[c] != '"')
{
if (json[c++] == '\\')
{
if (c == count || !strContains("\"\\/bfnrtu", json[c]))
return SIZE_MAX;
if (json[c++] == 'u')
{
if (c + 4 >= count || !hexIsValid2(json + c, 4))
return SIZE_MAX;
c += 4;
}
}
}
if (c == count || json[c++] != '"')
return SIZE_MAX;
if (elem)
elem->json = json + c1, elem->count = c - c1;
return c + jsonWsDec(json + c, count - c);
}
size_t jsonStrDec(const char** str, size_t* len, const char json[],
size_t count)
{
json_elem_t e;
size_t c;
ASSERT(memIsNullOrValid(str, sizeof(const char*)));
ASSERT(memIsNullOrValid(len, O_PER_S));
c = jsonStrParse(&e, json, count);
if (c == SIZE_MAX)
return SIZE_MAX;
ASSERT(e.count >= 2 && memIsValid(e.json, e.count));
ASSERT(e.json[0] == '"' && e.json[e.count - 1] == '"');
if (str)
*str = e.json + 1;
if (len)
*len = e.count - 2;
return c;
}
static size_t jsonObjParse(json_elem_t* elem, const char json[], size_t count,
size_t depth)
{
size_t c;
size_t c1;
ASSERT(memIsValid(json, count));
ASSERT(memIsNullOrValid(elem, sizeof(json_elem_t)));
if (depth > _max_depth)
return SIZE_MAX;
if ((c = jsonWsDec(json, count)) == SIZE_MAX)
return SIZE_MAX;
json += c, count -= c;
if (json[0] != '{')
return SIZE_MAX;
if (elem)
elem->json = json, elem->count = c;
++c, ++json, --count;
while (count && json[0] != '}')
{
if ((c1 = jsonStrParse(0, json, count)) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
if ((c1 = jsonDelimDec(json, count, ':')) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
if ((c1 = jsonElemParse(0, json, count, depth + 1)) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
if (count && json[0] == ',')
{
c1 = 1 + jsonWsDec(json + 1, count - 1);
c += c1, json += c1, count -= c1;
if (count && json[0] == '}')
return SIZE_MAX;
}
}
if (count == 0 || json[0] != '}')
return SIZE_MAX;
++c, ++json, --count;
if (elem)
elem->count = c - elem->count;
return c + jsonWsDec(json, count);
}
size_t jsonObjDec(json_elem_t elems[], const char json[], size_t count,
const char* const names[], size_t names_count)
{
size_t c;
size_t c1;
size_t i;
ASSERT(memIsValid(json, count));
ASSERT(memIsValid(names, names_count * sizeof(char*)));
ASSERT(memIsValid(elems, names_count * sizeof(json_elem_t)));
memSetZero(elems, names_count * sizeof(json_elem_t));
if ((c = jsonDelimDec(json, count, '{')) == SIZE_MAX)
return SIZE_MAX;
json += c, count -= c;
for (i = 0; i < names_count; ++i)
{
const char* str;
size_t len;
size_t j;
if ((c1 = jsonStrDec(&str, &len, json, count)) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
for (j = 0; j < names_count; ++j)
{
ASSERT(strIsValid(names[j]));
if (len == strLen(names[j]) && memEq(str, names[j], len))
{
if (elems[j].json != 0)
return SIZE_MAX;
break;
}
}
if (j == names_count)
return SIZE_MAX;
if ((c1 = jsonDelimDec(json, count, ':')) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
if ((c1 = jsonElemParse(elems + j, json, count, 0)) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
if (i + 1 < names_count)
{
if ((c1 = jsonDelimDec(json, count, ',')) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
}
}
if ((c1 = jsonDelimDec(json, count, '}')) == SIZE_MAX)
return SIZE_MAX;
return c + c1;
}
static size_t jsonArrParse(json_elem_t* elem, json_elem_t elems[],
size_t* elems_count, const char json[], size_t count, size_t depth)
{
size_t c;
size_t c1;
size_t ec;
ASSERT(memIsValid(json, count));
ASSERT(memIsNullOrValid(elem, sizeof(json_elem_t)));
ASSERT(memIsNullOrValid(elems_count, O_PER_S));
if (depth > _max_depth)
return SIZE_MAX;
if ((c = jsonWsDec(json, count)) == SIZE_MAX)
return SIZE_MAX;
json += c, count -= c;
if (json[0] != '[')
return SIZE_MAX;
if (elem)
elem->json = json, elem->count = c;
++c, ++json, --count;
for (ec = 0; count && json[0] != ']'; ++ec)
{
json_elem_t e;
if ((c1 = jsonElemParse(&e, json, count, depth + 1)) == SIZE_MAX)
return SIZE_MAX;
c += c1, json += c1, count -= c1;
if (elems)
{
ASSERT(memIsValid(elems, (ec + 1) * sizeof(json_elem_t)));
memCopy(elems + ec, &e, sizeof(json_elem_t));
}
if (count && json[0] == ',')
{
c1 = 1 + jsonWsDec(json + 1, count - 1);
c += c1, json += c1, count -= c1;
if (count && json[0] == ']')
return SIZE_MAX;
}
}
if (count == 0 || json[0] != ']')
return SIZE_MAX;
++c, ++json, --count;
if (elem)
elem->count = c - elem->count;
if (elems_count)
*elems_count = ec;
return c + jsonWsDec(json, count);
}
size_t jsonArrDec(json_elem_t elems[], size_t* elems_count, const char json[],
size_t count)
{
return jsonArrParse(0, elems, elems_count, json, count, 0);
}
static size_t jsonElemParse(json_elem_t* elem, const char json[], size_t count,
size_t depth)
{
size_t c;
size_t c1;
ASSERT(memIsValid(json, count));
ASSERT(memIsNullOrValid(elem, sizeof(json_elem_t)));
c = jsonWsDec(json, count);
if (c == count)
return SIZE_MAX;
json += c, count -= c;
if (json[0] == '{')
c1 = jsonObjParse(elem, json, count, depth + 1);
else if (json[0] == '[')
c1 = jsonArrParse(elem, 0, 0, json, count, depth + 1);
else if (json[0] == '"')
c1 = jsonStrParse(elem, json, count);
else if ('0' <= json[0] && json[0] <= '9')
c1 = jsonSizeParse(elem, json, count);
else if (strContains("tfn", json[0]))
c1 = jsonLexDec(elem, json, count);
else
return SIZE_MAX;
if (c1 == SIZE_MAX)
return SIZE_MAX;
return c + c1;
}
bool_t jsonIsValid(const char json[], size_t count)
{
return jsonElemParse(0, json, count, 0) == count;
}
size_t jsonFmtEnc(char json[], size_t size, const char* fmt, ...)
{
va_list args;
int c;
ASSERT(strIsValid(fmt));
ASSERT(memIsNullOrValid(json, size));
if (!json || !size)
json = 0, size = 0;
va_start(args, fmt);
c = vsnprintf(json, size, fmt, args);
va_end(args);
if (c < 0 || json && (size_t)c >= size)
return SIZE_MAX;
return (size_t)c;
}