protected int LookAhead(char[] json, int index) { var ias = new IndexAndSuccess(); ias.index = index; return(this.NextToken(json, ias)); }
protected object ParseValue(char[] json, IndexAndSuccess ias) { switch (this.LookAhead(json, ias.index)) { case TOKEN_STRING: return(this.ParseString(json, ias)); case TOKEN_NUMBER: return(this.ParseNumber(json, ias)); case TOKEN_CURLY_OPEN: return(this.ParseObject(json, ias)); case TOKEN_SQUARED_OPEN: return(this.ParseArray(json, ias)); case TOKEN_TRUE: this.NextToken(json, ias); return(true); case TOKEN_FALSE: this.NextToken(json, ias); return(false); case TOKEN_NULL: this.NextToken(json, ias); return(null); case TOKEN_NONE: break; } ias.success = false; return(null); }
protected Hashtable ParseObject(char[] json, IndexAndSuccess ias) { var table = new Hashtable(); int token; // { this.NextToken(json, ias); var done = false; while (!done) { token = this.LookAhead(json, ias.index); if (token == TOKEN_NONE) { ias.success = false; return(null); } if (token == TOKEN_COMMA) { this.NextToken(json, ias); } else if (token == TOKEN_CURLY_CLOSE) { this.NextToken(json, ias); return(table); } else { // name var name = this.ParseString(json, ias); if (!ias.success) { ias.success = false; return(null); } // : token = this.NextToken(json, ias); if (token != TOKEN_COLON) { ias.success = false; return(null); } // value var value = this.ParseValue(json, ias); if (!ias.success) { ias.success = false; return(null); } table[name] = value; } } return(table); }
/// <summary> /// Parses the string json into a value /// </summary> /// <param name="json">A JSON string.</param> /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns> public object JsonDecode(string json) { var ias = new IndexAndSuccess(); ias.success = true; return(this.JsonDecode(json, ias)); }
protected void EatWhitespace(char[] json, IndexAndSuccess ias) { for (; ias.index < json.Length; ias.index++) { if (" \t\n\r".IndexOf(json[ias.index]) == -1) { break; } } }
/// <summary> /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. /// </summary> /// <param name="json">A JSON string.</param> /// <param name="success">Successful parse?</param> /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns> public object JsonDecode(string json, IndexAndSuccess ias) { ias.success = true; if (json != null) { var charArray = json.ToCharArray(); ias.index = 0; var value = this.ParseValue(charArray, ias); return(value); } return(null); }
protected double ParseNumber(char[] json, IndexAndSuccess ias) { this.EatWhitespace(json, ias); var lastIndex = this.GetLastIndexOfNumber(json, ias.index); var charLength = (lastIndex - ias.index) + 1; double number; ias.success = Double.TryParse(new string(json, ias.index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number); ias.index = lastIndex + 1; return(number); }
protected ArrayList ParseArray(char[] json, IndexAndSuccess ias) { var array = new ArrayList(); // [ this.NextToken(json, ias); var done = false; while (!done) { var token = this.LookAhead(json, ias.index); if (token == TOKEN_NONE) { ias.success = false; return(null); } if (token == TOKEN_COMMA) { this.NextToken(json, ias); } else if (token == TOKEN_SQUARED_CLOSE) { this.NextToken(json, ias); break; } else { var value = this.ParseValue(json, ias); if (!ias.success) { return(null); } array.Add(value); } } return(array); }
protected int NextToken(char[] json, IndexAndSuccess ias) { this.EatWhitespace(json, ias); if (ias.index == json.Length) { return(TOKEN_NONE); } var c = json[ias.index]; ias.index++; switch (c) { case '{': return(TOKEN_CURLY_OPEN); case '}': return(TOKEN_CURLY_CLOSE); case '[': return(TOKEN_SQUARED_OPEN); case ']': return(TOKEN_SQUARED_CLOSE); case ',': return(TOKEN_COMMA); case '"': return(TOKEN_STRING); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': return(TOKEN_NUMBER); case ':': return(TOKEN_COLON); } ias.index--; var remainingLength = json.Length - ias.index; // false if (remainingLength >= 5) { if (json[ias.index] == 'f' && json[ias.index + 1] == 'a' && json[ias.index + 2] == 'l' && json[ias.index + 3] == 's' && json[ias.index + 4] == 'e') { ias.index += 5; return(TOKEN_FALSE); } } // true if (remainingLength >= 4) { if (json[ias.index] == 't' && json[ias.index + 1] == 'r' && json[ias.index + 2] == 'u' && json[ias.index + 3] == 'e') { ias.index += 4; return(TOKEN_TRUE); } } // null if (remainingLength >= 4) { if (json[ias.index] == 'n' && json[ias.index + 1] == 'u' && json[ias.index + 2] == 'l' && json[ias.index + 3] == 'l') { ias.index += 4; return(TOKEN_NULL); } } return(TOKEN_NONE); }
protected string ParseString(char[] json, IndexAndSuccess ias) { var s = new StringBuilder(BUILDER_CAPACITY); char c; this.EatWhitespace(json, ias); // " c = json[ias.index++]; var complete = false; while (!complete) { if (ias.index == json.Length) { break; } c = json[ias.index++]; if (c == '"') { complete = true; break; } if (c == '\\') { if (ias.index == json.Length) { break; } c = json[ias.index++]; if (c == '"') { s.Append('"'); } else if (c == '\\') { s.Append('\\'); } else if (c == '/') { s.Append('/'); } else if (c == 'b') { s.Append('\b'); } else if (c == 'f') { s.Append('\f'); } else if (c == 'n') { s.Append('\n'); } else if (c == 'r') { s.Append('\r'); } else if (c == 't') { s.Append('\t'); } else if (c == 'u') { var remainingLength = json.Length - ias.index; if (remainingLength >= 4) { // parse the 32 bit hex into an integer codepoint uint codePoint; if ( !(ias.success = UInt32.TryParse(new string(json, ias.index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) { return(""); } // convert the integer codepoint to a unicode char and add to string s.Append(Char.ConvertFromUtf32((int)codePoint)); // skip 4 chars ias.index += 4; } else { break; } } } else { s.Append(c); } } if (!complete) { ias.success = false; return(null); } return(s.ToString()); }