// return JObject, JArray, jendarray indicating end array if inarray is set, string, long, ulong, bigint, true, false, JNull // null if unhappy static private JToken DecodeValue(IStringParserQuick parser, char[] textbuffer, bool inarray) { //System.Diagnostics.Debug.WriteLine("Decode at " + p.LineLeft); char next = parser.GetChar(); switch (next) { case '{': parser.SkipSpace(); return(new JObject()); case '[': parser.SkipSpace(); return(new JArray()); case '"': int textlen = parser.NextQuotedString(next, textbuffer, true); return(textlen >= 0 ? new JToken(TType.String, new string(textbuffer, 0, textlen)) : null); case ']': if (inarray) { parser.SkipSpace(); return(jendarray); } else { return(null); } case '0': // all positive. JSON does not allow a + at the start (integer fraction exponent) case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': parser.BackUp(); return(parser.JNextNumber(false)); case '-': return(parser.JNextNumber(true)); case 't': return(parser.IsStringMoveOn("rue") ? new JToken(TType.Boolean, true) : null); case 'f': return(parser.IsStringMoveOn("alse") ? new JToken(TType.Boolean, false) : null); case 'n': return(parser.IsStringMoveOn("ull") ? new JToken(TType.Null) : null); default: return(null); } }
private static IEnumerable <JToken> ParseTokenInt(IStringParserQuick parser, JToken.ParseOptions flags = JToken.ParseOptions.None, int maxstringlen = 16384) { char[] textbuffer = new char[maxstringlen]; JToken[] stack = new JToken[256]; int sptr = 0; bool comma = false; JArray curarray = null; JObject curobject = null; { parser.SkipSpace(); JToken o = DecodeValue(parser, textbuffer, false); // grab new value, not array end if (o == null) { throw new TokenException(GenErrorString(parser, "No Obj/Array")); } else if (o.TokenType == JToken.TType.Array) { stack[++sptr] = o; // push this one onto stack curarray = o as JArray; // this is now the current array yield return(o); } else if (o.TokenType == JToken.TType.Object) { stack[++sptr] = o; // push this one onto stack curobject = o as JObject; // this is now the current object yield return(o); } else { yield return(o); // value only yield break; } } while (true) { if (curobject != null) // if object.. { while (true) { char next = parser.GetChar(); if (next == '}') // end object { parser.SkipSpace(); if (comma == true && (flags & JToken.ParseOptions.AllowTrailingCommas) == 0) { throw new TokenException(GenErrorString(parser, "Comma")); } else { yield return(new JToken(JToken.TType.EndObject)); JToken prevtoken = stack[--sptr]; if (prevtoken == null) // if popped stack is null, we are back to beginning, return this { yield break; } else { comma = parser.IsCharMoveOn(','); curobject = prevtoken as JObject; if (curobject == null) { curarray = prevtoken as JArray; break; } } } } else if (next == '"') // property name { int textlen = parser.NextQuotedString(next, textbuffer, true); if (textlen < 1 || (comma == false && curobject.Count > 0) || !parser.IsCharMoveOn(':')) { throw new TokenException(GenErrorString(parser, "Object missing property name")); } else { string name = new string(textbuffer, 0, textlen); JToken o = DecodeValue(parser, textbuffer, false); // get value if (o == null) { throw new TokenException(GenErrorString(parser, "Object bad value")); } o.Name = name; yield return(o); if (o.TokenType == JToken.TType.Array) // if array, we need to change to this as controlling object on top of stack { if (sptr == stack.Length - 1) { throw new TokenException(GenErrorString(parser, "Stack overflow")); } stack[++sptr] = o; // push this one onto stack curarray = o as JArray; // this is now the current object curobject = null; comma = false; break; } else if (o.TokenType == JToken.TType.Object) // if object, this is the controlling object { if (sptr == stack.Length - 1) { throw new TokenException(GenErrorString(parser, "Stack overflow")); } stack[++sptr] = o; // push this one onto stack curobject = o as JObject; // this is now the current object comma = false; } else { comma = parser.IsCharMoveOn(','); } } } else { throw new TokenException(GenErrorString(parser, "Bad format in object")); } } } else { while (true) { JToken o = DecodeValue(parser, textbuffer, true); // grab new value if (o == null) { throw new TokenException(GenErrorString(parser, "Bad array value")); } else if (o.TokenType == JToken.TType.EndArray) // if end marker, jump back { if (comma == true && (flags & JToken.ParseOptions.AllowTrailingCommas) == 0) { throw new TokenException(GenErrorString(parser, "Comma")); } else { yield return(new JToken(JToken.TType.EndArray)); JToken prevtoken = stack[--sptr]; if (prevtoken == null) // if popped stack is null, we are back to beginning, return this { yield break; } else { comma = parser.IsCharMoveOn(','); curobject = prevtoken as JObject; if (curobject == null) { curarray = prevtoken as JArray; } else { break; } } } } else if ((comma == false && curarray.Count > 0)) // missing comma { throw new TokenException(GenErrorString(parser, "Comma")); } else { yield return(o); if (o.TokenType == JToken.TType.Array) // if array, we need to change to this as controlling object on top of stack { if (sptr == stack.Length - 1) { throw new TokenException(GenErrorString(parser, "Stack overflow")); } stack[++sptr] = o; // push this one onto stack curarray = o as JArray; // this is now the current array comma = false; } else if (o.TokenType == JToken.TType.Object) // if object, this is the controlling object { if (sptr == stack.Length - 1) { throw new TokenException(GenErrorString(parser, "Stack overflow")); } stack[++sptr] = o; // push this one onto stack curobject = o as JObject; // this is now the current object curarray = null; comma = false; break; } else { comma = parser.IsCharMoveOn(','); } } } } } }
// internal parse, does not check EOL private static JToken IntParse(IStringParserQuick parser, out string error, ParseOptions flags, char[] textbuffer) { error = null; JToken[] stack = new JToken[256]; int sptr = 0; bool comma = false; JArray curarray = null; JObject curobject = null; // first decode the first value/object/array { JToken o = DecodeValue(parser, textbuffer, false); // grab new value, not array end if (o == null) { return(ParseError(parser, "No Obj/Array", flags, out error)); } else if (o.TokenType == TType.Array) { stack[++sptr] = o; // push this one onto stack curarray = o as JArray; // this is now the current array } else if (o.TokenType == TType.Object) { stack[++sptr] = o; // push this one onto stack curobject = o as JObject; // this is now the current object } else { return(o); // value only } } while (true) { if (curobject != null) // if object.. { while (true) { char next = parser.GetChar(); if (next == '}') // end object { parser.SkipSpace(); if (comma == true && (flags & ParseOptions.AllowTrailingCommas) == 0) { return(ParseError(parser, "Comma", flags, out error)); } else { JToken prevtoken = stack[--sptr]; if (prevtoken == null) // if popped stack is null, we are back to beginning, return this { return(stack[sptr + 1]); } else { comma = parser.IsCharMoveOn(','); curobject = prevtoken as JObject; if (curobject == null) { curarray = prevtoken as JArray; break; } } } } else if (next == '"') // property name { int textlen = parser.NextQuotedString(next, textbuffer, true); if (textlen < 1 || (comma == false && curobject.Count > 0)) { return(ParseError(parser, "Object missing property name", flags, out error)); } else if (!parser.IsCharMoveOn(':')) { return(ParseError(parser, "Object missing : after property name", flags, out error)); } else { string name = new string(textbuffer, 0, textlen); JToken o = DecodeValue(parser, textbuffer, false); // get value if (o == null) { return(ParseError(parser, "Object bad value", flags, out error)); } o.Name = name; // object gets the name, indicating its a property curobject[name] = o; // assign to dictionary if (o.TokenType == TType.Array) // if array, we need to change to this as controlling object on top of stack { if (sptr == stack.Length - 1) { return(ParseError(parser, "Stack overflow", flags, out error)); } stack[++sptr] = o; // push this one onto stack curarray = o as JArray; // this is now the current object curobject = null; comma = false; break; } else if (o.TokenType == TType.Object) // if object, this is the controlling object { if (sptr == stack.Length - 1) { return(ParseError(parser, "Stack overflow", flags, out error)); } stack[++sptr] = o; // push this one onto stack curobject = o as JObject; // this is now the current object comma = false; } else { comma = parser.IsCharMoveOn(','); } } } else { return(ParseError(parser, "Bad format in object", flags, out error)); } } } else { while (true) { JToken o = DecodeValue(parser, textbuffer, true); // grab new value if (o == null) { return(ParseError(parser, "Bad array value", flags, out error)); } else if (o.TokenType == TType.EndArray) // if end marker, jump back { if (comma == true && (flags & ParseOptions.AllowTrailingCommas) == 0) { return(ParseError(parser, "Comma", flags, out error)); } else { JToken prevtoken = stack[--sptr]; if (prevtoken == null) // if popped stack is null, we are back to beginning, return this { return(stack[sptr + 1]); } else { comma = parser.IsCharMoveOn(','); curobject = prevtoken as JObject; if (curobject == null) { curarray = prevtoken as JArray; } else { break; } } } } else if ((comma == false && curarray.Count > 0)) // missing comma { return(ParseError(parser, "Comma", flags, out error)); } else { curarray.Add(o); if (o.TokenType == TType.Array) // if array, we need to change to this as controlling object on top of stack { if (sptr == stack.Length - 1) { return(ParseError(parser, "Stack overflow", flags, out error)); } stack[++sptr] = o; // push this one onto stack curarray = o as JArray; // this is now the current array comma = false; } else if (o.TokenType == TType.Object) // if object, this is the controlling object { if (sptr == stack.Length - 1) { return(ParseError(parser, "Stack overflow", flags, out error)); } stack[++sptr] = o; // push this one onto stack curobject = o as JObject; // this is now the current object curarray = null; comma = false; break; } else { comma = parser.IsCharMoveOn(','); } } } } } }