Make DqnJson handle more cases
This commit is contained in:
		
							parent
							
								
									33cf476d29
								
							
						
					
					
						commit
						f1efb6f8f1
					
				
							
								
								
									
										117
									
								
								DqnJson.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								DqnJson.cpp
									
									
									
									
									
										Normal 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)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -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(); | ||||
|  | ||||
							
								
								
									
										182
									
								
								dqn.h
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								dqn.h
									
									
									
									
									
								
							| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user