public static JsonValue Parse(string json) { JsonValue root = null; JsonValue top = null; string name = null; var escapedNewlines = 0; char[] jsonArray = null; var i = 0; for (; i < json.Length; i++) { var ch = json[i]; // skip white space if (ch == '\x20' || ch == '\x9' || ch == '\xD' || ch == '\xA') { continue; } switch (ch) { case '{': case '[': { // create new value var value = new JsonValue { Name = name }; // name name = null; // type value.Type = ch == '{' ? JsonType.Object : JsonType.Array; // set top and root if (top != null) { top.Append(value); } else if (root == null) { root = value; } else { throw new JsonParserException(i, "Second root. Only one root allowed"); } top = value; } break; case '}': case ']': { if (top == null || top.Type != ((ch == '}') ? JsonType.Object : JsonType.Array)) { throw new JsonParserException(i, "Mismatch closing brace/bracket"); } // set top top = top.Parent; } break; case ':': if (top == null || top.Type != JsonType.Object) { throw new JsonParserException(i, "Unexpected character"); } break; case ',': CheckTop(top, i); break; case '"': { CheckTop(top, i); // skip '"' character i++; ch = json[i]; var first = i; var last = i; var chLast = ch; while (i < json.Length) { if (ch < '\x20') { throw new JsonParserException(first, "Control characters not allowed in strings"); } if (ch == '\\') { switch (json[i + 1]) { case '"': chLast = '"'; break; case '\\': chLast = '\\'; break; case '/': chLast = '/'; break; case 'b': chLast = '\b'; break; case 'f': chLast = '\f'; break; case 'n': chLast = '\n'; ++escapedNewlines; break; case 'r': chLast = '\r'; break; case 't': chLast = '\t'; break; case 'u': { if (jsonArray == null) { jsonArray = json.ToCharArray(); } uint codepoint; if (HexToInteger(json.Substring(i + 2, 4), out codepoint) != 4) { throw new JsonParserException(i, "Bad unicode codepoint"); } if (codepoint <= 0x7F) { chLast = (char)codepoint; } else if (codepoint <= 0x7FF) { last++; jsonArray[last] = (char)(0xC0 | (codepoint >> 6)); last++; jsonArray[last] = (char)(0x80 | (codepoint & 0x3F)); } else if (codepoint <= 0xFFFF) { last++; jsonArray[last] = (char)(0xE0 | (codepoint >> 12)); last++; jsonArray[last] = (char)(0x80 | ((codepoint >> 6) & 0x3F)); last++; jsonArray[last] = (char)(0x80 | (codepoint & 0x3F)); } } i += 4; break; default: throw new JsonParserException(first, "Unrecognized escape sequence"); } last++; i++; } else if (ch == '"') { break; } else { last++; i++; ch = json[i]; } } if (top != null && (name == null && top.Type == JsonType.Object)) { // field name in object name = json.Substring(first, i - first); } else { // new string value var value = new JsonValue { Name = name }; name = null; value.Type = JsonType.String; string s; if (jsonArray != null) { var slice = new char[i - first]; Array.Copy(jsonArray, first, slice, 0, i - first); s = new string(slice); } else { s = json.Substring(first, i - first); } value.Value = s; if (top != null) { top.Append(value); } } } break; case 'n': case 't': case 'f': { CheckTop(top, i); // new null/bool value var value = new JsonValue { Name = name }; name = null; // null if (ch == 'n' && json[i + 1] == 'u' && json[i + 2] == 'l' && json[i + 3] == 'l') { value.Type = JsonType.Null; i += 3; } // true else if (ch == 't' && json[i + 1] == 'r' && json[i + 2] == 'u' && json[i + 3] == 'e') { value.Type = JsonType.Boolean; value.Value = true; i += 3; } // false else if (ch == 'f' && json[i + 1] == 'a' && json[i + 2] == 'l' && json[i + 3] == 's' && json[i + 4] == 'e') { value.Type = JsonType.Boolean; value.Value = false; i += 4; } else { throw new JsonParserException(i, "Unknown identifier"); } if (top != null) { top.Append(value); } } break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { CheckTop(top, i); // new number value var value = new JsonValue { Name = name }; name = null; value.Type = JsonType.Integer; int first = i; while (ch != '\x20' && ch != '\x9' && ch != '\xD' && ch != '\xA' && ch != ',' && ch != ']' && ch != '}') { if (ch == '.' || ch == 'e' || ch == 'E') { value.Type = JsonType.Decimal; } i++; ch = json[i]; } if (value.Type == JsonType.Integer) { if (TextToInteger(json.Substring(first, i - first), out var n) != i - first) { throw new JsonParserException(first, "Bad integer number"); } else { value.Value = n; } i--; } if (value.Type == JsonType.Decimal) { if (TextToDecimal(json.Substring(first, i - first), out var d) != i - first) { throw new JsonParserException(first, "Bad decimal number"); } value.Value = d; i--; } if (top != null) { top.Append(value); } } break; default: throw new JsonParserException(i, "Unexpected character"); } } if (top != null) { throw new JsonParserException(i, "Not all objects/arrays have been properly closed"); } return(root); }