Make DqnJson handle more cases

This commit is contained in:
Doyle T 2018-07-13 00:46:08 +10:00
parent 33cf476d29
commit f1efb6f8f1
3 changed files with 263 additions and 38 deletions

117
DqnJson.cpp Normal file
View File

@ -0,0 +1,117 @@
void DqnJson_Test()
{
char const json[] =
R"FOO(
{
"result": {
"cumulative_difficulty": 282912831023,
"difficulty": 18293,
"name": "Block",
"array_of_objects": [{
"hash": "83abdc3f",
"time": 102981029381,
}, {
"hash": "12acf73d",
"time": 123761239789,
}],
"time": 3498573485,
"embed_object": {
"proof": "axcbde",
"signature": "l9382kjabmznmx129aslzejs"
}
"bits": [1, 0, 1, 1, 0, 1, 0],
"hex": ["AF", "BE", "0C", "FF"],
"extra": [123],
"serialise": [],
},
}
)FOO";
DqnJson result = DqnJson_Get(DqnSlice<const char>(json, DQN_ARRAY_COUNT(json)), DQN_SLICE("result"));
DqnJson cumulativeDifficulty = DqnJson_Get(result, DQN_SLICE("cumulative_difficulty"));
DqnJson difficulty = DqnJson_Get(result, DQN_SLICE("difficulty"));
DqnJson name = DqnJson_Get(result, DQN_SLICE("name"));
DqnJson arrayOfObjects = DqnJson_Get(result, DQN_SLICE("array_of_objects"));
DqnJson time = DqnJson_Get(result, DQN_SLICE("time"));
DqnJson embedObject = DqnJson_Get(result, DQN_SLICE("embed_object"));
DqnJson bits = DqnJson_Get(result, DQN_SLICE("bits"));
DqnJson hex = DqnJson_Get(result, DQN_SLICE("hex"));
DqnJson extra = DqnJson_Get(result, DQN_SLICE("extra"));
DqnJson serialise = DqnJson_Get(result, DQN_SLICE("serialise"));
DQN_ASSERT(DQN_SLICE_CMP(cumulativeDifficulty.value, DQN_SLICE("282912831023"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(difficulty.value, DQN_SLICE("18293"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(name.value, DQN_SLICE("\"Block\""), Dqn::IgnoreCase::No));
{
DQN_ASSERT(arrayOfObjects.IsArray() && arrayOfObjects.numEntries == 2);
isize count = 0;
while(DqnJson it = DqnJson_GetNextArrayItem(&arrayOfObjects))
{
DqnJson hash = DqnJson_Get(it, DQN_SLICE("hash"));
DqnJson time2 = DqnJson_Get(it, DQN_SLICE("time"));
if (count == 0)
{
DQN_ASSERT(DQN_SLICE_CMP(hash.value, DQN_SLICE("\"83abdc3f\""), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(time2.value, DQN_SLICE("102981029381"), Dqn::IgnoreCase::No));
}
else
{
DQN_ASSERT(DQN_SLICE_CMP(hash.value, DQN_SLICE("\"12acf73d\""), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(time2.value, DQN_SLICE("123761239789"), Dqn::IgnoreCase::No));
}
++count;
}
}
{
DqnJson proof = DqnJson_Get(embedObject, DQN_SLICE("proof"));
DqnJson signature = DqnJson_Get(embedObject, DQN_SLICE("signature"));
DQN_ASSERT(DQN_SLICE_CMP(proof.value, DQN_SLICE("\"axcbde\""), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(signature.value, DQN_SLICE("\"l9382kjabmznmx129aslzejs\""), Dqn::IgnoreCase::No));
}
DQN_ASSERT(DQN_SLICE_CMP(time.value, DQN_SLICE("3498573485"), Dqn::IgnoreCase::No));
{
DQN_ASSERT(bits.IsArray() && bits.numEntries == 7);
DqnJson bitsArray[7];
isize bitsIndex = 0;
while(DqnJson it = DqnJson_GetNextArrayItem(&bits))
bitsArray[bitsIndex++] = it;
DQN_ASSERT(bitsIndex == DQN_ARRAY_COUNT(bitsArray));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[0].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[1].value, DQN_SLICE("0"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[2].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[3].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[4].value, DQN_SLICE("0"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[5].value, DQN_SLICE("1"), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(bitsArray[6].value, DQN_SLICE("0"), Dqn::IgnoreCase::No));
}
{
DQN_ASSERT(hex.IsArray() && hex.numEntries == 4);
DqnJson hexArray[4];
isize hexIndex = 0;
while(DqnJson it = DqnJson_GetNextArrayItem(&hex))
hexArray[hexIndex++] = it;
DQN_ASSERT(hexIndex == DQN_ARRAY_COUNT(hexArray));
DQN_ASSERT(DQN_SLICE_CMP(hexArray[0].value, DQN_SLICE("\"AF\""), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(hexArray[1].value, DQN_SLICE("\"BE\""), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(hexArray[2].value, DQN_SLICE("\"0C\""), Dqn::IgnoreCase::No));
DQN_ASSERT(DQN_SLICE_CMP(hexArray[3].value, DQN_SLICE("\"FF\""), Dqn::IgnoreCase::No));
}
{
DQN_ASSERT(extra.IsArray() && extra.numEntries == 1);
while(DqnJson it = DqnJson_GetNextArrayItem(&extra))
{
DQN_ASSERT(DQN_SLICE_CMP(it.value, DQN_SLICE("123"), Dqn::IgnoreCase::No));
}
}
}

View File

@ -139,6 +139,7 @@ void LogHeader(char const *funcName)
#include "DqnFixedString.cpp"
#include "DqnOS.cpp"
#include "DqnJson.cpp"
void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
{
@ -2897,6 +2898,7 @@ int main(void)
Dqn_BSearch_Test();
DqnMemSet_Test();
DqnFixedString_Test();
DqnJson_Test();
#ifdef DQN_PLATFORM_HEADER
DqnOS_Test();

150
dqn.h
View File

@ -2825,7 +2825,8 @@ struct DqnJson
enum struct Type
{
Object,
Array,
ArrayOfObjects,
ArrayOfPrimitives,
};
Type type;
@ -2833,6 +2834,7 @@ struct DqnJson
i32 numEntries;
operator bool () const { return (value.data != nullptr); }
bool IsArray() const { return (type == Type::ArrayOfObjects || type == Type::ArrayOfPrimitives); }
i64 ToI64() const { return Dqn_StrToI64(value.data, value.len); }
};
@ -6802,17 +6804,69 @@ DQN_FILE_SCOPE i64 Dqn_BSearch(i64 *array, i64 size, i64 find,
}
}
// TODO(doyle): This should maybe be a tokenizer ...
DQN_FILE_SCOPE DqnJson DqnJson_Get(char const *buf, i32 bufLen, char const *findProperty, i32 findPropertyLen)
{
DqnJson result = {};
char const *tmp = DqnChar_SkipWhitespace(buf);
bufLen = static_cast<int>((buf + bufLen) - tmp);
buf = tmp;
if (buf[0] == '{' || buf[1] == '[')
{
buf++;
bufLen--;
}
TryNext:
char *locate = DqnStr_GetFirstOccurence(buf, bufLen, findProperty, findPropertyLen);
char const *locate = nullptr;
for (i32 indexIntoBuf = 0; indexIntoBuf < bufLen; ++indexIntoBuf)
{
i32 remainingLenInSrcStr = bufLen - indexIntoBuf;
if (remainingLenInSrcStr < findPropertyLen) break;
char const *bufSubStr = buf + indexIntoBuf;
if (bufSubStr[0] == '{' || bufSubStr[0] == '[')
{
int bracketCount = 0;
int braceCount = 0;
int *searchCharCount = nullptr;
if (bufSubStr[0] == '[')
{
bracketCount++;
searchCharCount = &bracketCount;
}
else
{
braceCount++;
searchCharCount = &braceCount;
}
for (++indexIntoBuf; (*searchCharCount) != 0; ++indexIntoBuf)
{
bufSubStr = buf + indexIntoBuf;
if (!bufSubStr[0])
return result;
if (bufSubStr[0] == '{') ++braceCount;
else if (bufSubStr[0] == '}') --braceCount;
else if (bufSubStr[0] == '[') ++bracketCount;
else if (bufSubStr[0] == ']') --bracketCount;
else continue;
}
}
if (DqnStr_Cmp(bufSubStr, findProperty, findPropertyLen, Dqn::IgnoreCase::No) == 0)
{
locate = buf + indexIntoBuf;
break;
}
}
if (!locate) return result;
// NOTE: if find property is '{' we are looking for an object in array or the global scope etc
// which doesn't have a specific property name
char *startOfValue = locate;
char const *startOfValue = locate;
char const *bufPtr = startOfValue;
if (findProperty[0] != '{' && findProperty[0] != '[')
{
@ -6844,11 +6898,19 @@ TryNext:
startOfValue++;
i32 *searchCharCount = nullptr;
if (bufPtr[0] == '[')
if (*bufPtr++ == '[')
{
bracketCount++;
result.type = DqnJson::Type::Array;
searchCharCount = &bracketCount;
while(bufPtr[0] != '{' && bufPtr[0] != '[' && bufPtr[0] != '"' && !DqnChar_IsAlphaNum(bufPtr[0]) && !bufPtr[0])
bufPtr++;
if (!bufPtr[0])
return result;
const b32 arrayOfPrimitives = (DqnChar_IsAlphaNum(bufPtr[0]) || bufPtr[0] == '"');
result.type = (arrayOfPrimitives) ? DqnJson::Type::ArrayOfPrimitives : DqnJson::Type::ArrayOfObjects;
}
else
{
@ -6857,22 +6919,41 @@ TryNext:
searchCharCount = &braceCount;
}
result.numEntries = 0;
for (bufPtr++; (*searchCharCount) != 0; bufPtr++)
if (result.type == DqnJson::Type::ArrayOfPrimitives)
{
bool countsChanged = true;
for (result.numEntries = 1;;)
{
while(bufPtr[0] && (bufPtr[0] != ',' && bufPtr[0] != ']'))
bufPtr++;
if (bufPtr[0] == ',')
{
result.numEntries++;
bufPtr++;
continue;
}
if (!bufPtr[0])
return result;
if (bufPtr[0] == '{') braceCount++;
else if (bufPtr[0] == '}') braceCount--;
else if (bufPtr[0] == '[') bracketCount++;
else if (bufPtr[0] == ']') bracketCount--;
else countsChanged = false;
if (countsChanged)
if (bufPtr[0] == ']')
break;
}
}
else
{
if (result.type == DqnJson::Type::Array)
for (; (*searchCharCount) != 0; ++bufPtr)
{
if (!bufPtr[0])
return result;
if (bufPtr[0] == '{') ++braceCount;
else if (bufPtr[0] == '}') --braceCount;
else if (bufPtr[0] == '[') ++bracketCount;
else if (bufPtr[0] == ']') --bracketCount;
else continue;
if (result.type == DqnJson::Type::ArrayOfObjects)
{
if (braceCount == 0 && bracketCount == 1)
{
@ -6887,10 +6968,11 @@ TryNext:
}
}
}
}
// Don't include the open and closing braces/brackets.
bufPtr--;
}
}
else if (bufPtr[0] == '"' || DqnChar_IsAlphaNum(bufPtr[0]))
{
while(bufPtr[0] && (bufPtr[0] != '\n' && bufPtr[0] != ',' && bufPtr[0] != '}'))
@ -6906,7 +6988,7 @@ TryNext:
return result;
}
result.value.data = startOfValue;
result.value.data = (char *)startOfValue;
result.value.len = static_cast<i32>(bufPtr - result.value.data);
result.value.data = DqnChar_TrimWhitespaceAround(result.value.data, result.value.len, &result.value.len);
return result;
@ -6945,15 +7027,16 @@ DQN_FILE_SCOPE DqnJson DqnJson_Get(DqnJson const input, DqnSlice<char const> con
DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator)
{
DqnJson result = {};
if (iterator->type != DqnJson::Type::Array || iterator->numEntries <= 0)
if (!iterator->IsArray() || iterator->numEntries <= 0)
return result;
result = DqnJson_Get(iterator->value, DQN_SLICE("{"));
if (result)
if (iterator->type == DqnJson::Type::ArrayOfObjects)
{
if (result = DqnJson_Get(iterator->value, DQN_SLICE("{")))
{
char const *end = iterator->value.data + iterator->value.len;
iterator->value.data = result.value.data + result.value.len;
iterator->numEntries--;
--iterator->numEntries;
while (iterator->value.data[0] && *iterator->value.data++ != '}')
;
@ -6965,6 +7048,29 @@ DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator)
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
iterator->value.len = (iterator->value.data) ? static_cast<i32>(end - iterator->value.data) : 0;
}
}
else
{
char const *end = iterator->value.data + iterator->value.len;
result.value.data = iterator->value.data;
--iterator->numEntries;
if (iterator->numEntries == 0)
{
while (iterator->value.data[0] && iterator->value.data[0] != ']')
++iterator->value.data;
}
else
{
while (iterator->value.data[0] && iterator->value.data[0] != ',')
++iterator->value.data;
}
result.value.len = static_cast<i32>(iterator->value.data - result.value.data);
iterator->value.data = DqnChar_SkipWhitespace(++iterator->value.data);
iterator->value.len = (iterator->value.data) ? static_cast<i32>(end - iterator->value.data) : 0;
}
return result;
}