Make DqnJson handle more cases

This commit is contained in:
2018-07-13 00:46:08 +10:00
parent 33cf476d29
commit f1efb6f8f1
3 changed files with 263 additions and 38 deletions
+144 -38
View File
@@ -2825,15 +2825,17 @@ struct DqnJson
enum struct Type
{
Object,
Array,
ArrayOfObjects,
ArrayOfPrimitives,
};
Type type;
DqnSlice<char> value;
i32 numEntries;
operator bool () const { return (value.data != nullptr); }
i64 ToI64() const { return Dqn_StrToI64(value.data, value.len); }
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); }
};
// Zero allocation json finder. Returns the data of the value.
@@ -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,24 +6919,43 @@ TryNext:
searchCharCount = &braceCount;
}
result.numEntries = 0;
for (bufPtr++; (*searchCharCount) != 0; bufPtr++)
if (result.type == DqnJson::Type::ArrayOfPrimitives)
{
bool countsChanged = true;
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)
for (result.numEntries = 1;;)
{
if (result.type == DqnJson::Type::Array)
while(bufPtr[0] && (bufPtr[0] != ',' && bufPtr[0] != ']'))
bufPtr++;
if (bufPtr[0] == ',')
{
if (braceCount == 0 && bracketCount == 1)
result.numEntries++;
bufPtr++;
continue;
}
if (!bufPtr[0])
return result;
if (bufPtr[0] == ']')
break;
}
}
else
{
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)
{
result.numEntries++;
}
@@ -6887,9 +6968,10 @@ TryNext:
}
}
}
// Don't include the open and closing braces/brackets.
bufPtr--;
}
// Don't include the open and closing braces/brackets.
bufPtr--;
}
else if (bufPtr[0] == '"' || DqnChar_IsAlphaNum(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,25 +7027,49 @@ 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)
{
char const *end = iterator->value.data + iterator->value.len;
iterator->value.data = result.value.data + result.value.len;
iterator->numEntries--;
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;
while (iterator->value.data[0] && *iterator->value.data++ != '}')
;
while (iterator->value.data[0] && *iterator->value.data++ != '}')
;
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
if (iterator->value.data[0] && iterator->value.data[0] == ',')
iterator->value.data++;
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
if (iterator->value.data[0] && iterator->value.data[0] == ',')
iterator->value.data++;
iterator->value.data = DqnChar_SkipWhitespace(iterator->value.data);
iterator->value.len = (iterator->value.data) ? static_cast<i32>(end - iterator->value.data) : 0;
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;