/// <summary> /// Path for loading a JSON array /// </summary> /// <param name="json"></param> private void LoadArrayString(List <object> list, string json) { if (string.IsNullOrEmpty(json) || !ValueIsArray(json)) { return; } int startBracketPos = json.IndexOf("["); int endBracketPos = json.LastIndexOf("]"); json = json.Substring(startBracketPos + 1, endBracketPos - startBracketPos - 1); //walk the string JsonTracePos tracePos = new JsonTracePos(); for (tracePos.CurrentPos = 0; tracePos.CurrentPos < json.Length; tracePos.CurrentPos++) { AppendCurrentCharToTrace(json, tracePos, false, null, list); } //look to flush final unquoted value if (tracePos.InValue && tracePos.InUnQuotedValue) { string val = tracePos.FlushBuffer(); list.Add(GetResolvedValue(val)); } else if (tracePos.InKey || tracePos.InValue) { throw new Exception("Malformed JSON data"); } }
/// <summary> /// Path for loading a JSON object /// </summary> /// <param name="dictionary"></param> /// <param name="json"></param> private void LoadObjectString(Dictionary <string, object> dictionary, string json) { if (string.IsNullOrEmpty(json) || !ValueIsObject(json)) { return; } int startBracketPos = json.IndexOf("{"); int endBracketPos = json.LastIndexOf("}"); json = json.Substring(startBracketPos + 1, endBracketPos - startBracketPos - 1); //walk the string JsonTracePos tracePos = new JsonTracePos(); for (tracePos.CurrentPos = 0; tracePos.CurrentPos < json.Length; tracePos.CurrentPos++) { AppendCurrentCharToTrace(json, tracePos, true, dictionary, null); } //look to flush final unquoted value if (tracePos.InValue && tracePos.InUnQuotedValue && tracePos.PreviousKey != null) { string val = tracePos.FlushBuffer(); dictionary[tracePos.PreviousKey] = GetResolvedValue(val); } else if (tracePos.InKey || tracePos.InValue) { throw new Exception("Malformed JSON data"); } }
/// <summary> /// Appends the next character to the trace /// </summary> /// <param name="json"></param> /// <param name="tracePos"></param> /// <param name="isObject"></param> private void AppendCurrentCharToTrace(string json, JsonTracePos tracePos, bool isObject, Dictionary <string, object> dictionaryForObject, List <object> listForArray) { char curChar = json[tracePos.CurrentPos]; if ((!isObject && !tracePos.InValue) || (isObject && !tracePos.InKey && !tracePos.InValue)) { if ((isObject && curChar == ':') || curChar == ',' || curChar == '\t' || curChar == '\n' || curChar == '\r' || curChar == ' ') { return; } if (isObject) { if (tracePos.PreviousKey != null) { if (IsCurrentCharObjectStart(curChar)) { //recurse and add object result //char matchChar = '\0'; //if (curChar == '{') matchChar = '}'; //else if (curChar == '[') matchChar = ']'; int embeddedObjectEndPos = FindMatchedCloseCharPosition(json, tracePos.CurrentPos); if (embeddedObjectEndPos == -1) { throw new Exception("Malformed JSON data"); } //todo - walk backwards to identify correct delimiter string embeddedJson = json.Substring(tracePos.CurrentPos, (embeddedObjectEndPos - tracePos.CurrentPos) + 1); dictionaryForObject[tracePos.PreviousKey] = GetResolvedValue(embeddedJson); tracePos.CurrentPos = embeddedObjectEndPos + 1; tracePos.PreviousKey = null; tracePos.ClearContext(); return; } else if (!IsCurrentCharQuote(curChar, '\0')) { tracePos.InValue = true; tracePos.InUnQuotedValue = true; tracePos.AppendChar(curChar); return; } } else if (!IsCurrentCharQuote(curChar, tracePos.QuoteChar)) { //in unquoted key tracePos.InKey = true; tracePos.InUnQuotedKey = true; tracePos.AppendChar(curChar); return; } } //array branch else { if (IsCurrentCharObjectStart(curChar)) { //recurse and add object result //char matchChar = '\0'; //if (curChar == '{') matchChar = '}'; //else if (curChar == '[') matchChar = ']'; int embeddedObjectEndPos = FindMatchedCloseCharPosition(json, tracePos.CurrentPos); if (embeddedObjectEndPos == -1) { throw new Exception("Malformed JSON data"); } string embeddedJson = json.Substring(tracePos.CurrentPos, (embeddedObjectEndPos - tracePos.CurrentPos) + 1); listForArray.Add(GetResolvedValue(embeddedJson)); tracePos.CurrentPos = embeddedObjectEndPos + 1; tracePos.ClearContext(); return; } else if (!IsCurrentCharQuote(curChar, '\0')) { tracePos.InValue = true; tracePos.InUnQuotedValue = true; tracePos.AppendChar(curChar); return; } } } if (curChar == '\\' && !tracePos.AfterEscapeChar) { tracePos.AfterEscapeChar = true; return; } if (!tracePos.AfterEscapeChar && IsCurrentCharQuote(curChar, tracePos.QuoteChar)) { if ((!isObject && !tracePos.InValue) || (isObject && !tracePos.InKey && !tracePos.InValue)) { tracePos.QuoteChar = curChar; if (isObject) { if (tracePos.PreviousKey == null) { tracePos.InKey = true; } else { tracePos.InValue = true; } } else { tracePos.InValue = true; } } else { tracePos.QuoteChar = '\0'; if (isObject) { if (tracePos.InKey) { tracePos.PreviousKey = tracePos.FlushBuffer(); tracePos.InKey = false; } else { string val = tracePos.FlushBuffer(); //resolve if array or object dictionaryForObject[tracePos.PreviousKey] = GetResolvedValue(val); tracePos.ClearContext(); tracePos.PreviousKey = null; } } else { tracePos.QuoteChar = '\0'; string val = tracePos.FlushBuffer(); //resolve if array or object listForArray.Add(GetResolvedValue(val)); tracePos.ClearContext(); } } return; } else { if (tracePos.InValue && tracePos.InUnQuotedValue && curChar == ',') { string val = tracePos.FlushBuffer(); //resolve if array or object if (isObject) { dictionaryForObject[tracePos.PreviousKey] = GetResolvedValue(val); } else { listForArray.Add(GetResolvedValue(val)); } tracePos.InValue = false; tracePos.InUnQuotedValue = false; tracePos.PreviousKey = null; return; } else if (isObject && (tracePos.InKey && tracePos.InUnQuotedKey && (curChar == ' ' || curChar == ':' || curChar == '\t' || curChar == '\n' || curChar == '\r'))) { string val = tracePos.FlushBuffer(); tracePos.PreviousKey = val; tracePos.InUnQuotedKey = false; tracePos.InKey = false; return; } else { if (tracePos.AfterEscapeChar) { switch (curChar) { case '\'': case '"': tracePos.AppendChar(curChar); break; case 'n': tracePos.AppendChar('\n'); break; case 'r': tracePos.AppendChar('\r'); break; case 't': tracePos.AppendChar('\t'); break; case 'f': tracePos.AppendChar('\f'); break; case '\r': //check for windows \r\n combo by peeking ahead if (json.Length > tracePos.CurrentPos + 1 && '\n' == json[tracePos.CurrentPos + 1]) { //advance past linefeed tracePos.CurrentPos++; } break; case '\n': break; default: tracePos.AppendChar(curChar); break; } } else { tracePos.AppendChar(curChar); } } if (tracePos.AfterEscapeChar) { tracePos.AfterEscapeChar = false; } } }