private static JsonToken GetUnquotedStringToken( BsonJsonBuffer buffer ) { // opening letter or $ has already been read var start = buffer.Position - 1; while (true) { var c = buffer.Read(); switch (c) { case ':': case ',': case '}': case ']': case -1: buffer.UnRead(c); return new JsonToken(JsonTokenType.UnquotedString, buffer.Substring(start, buffer.Position - start)); default: if (c == '$' || char.IsLetterOrDigit((char) c)) { // continue } else if (char.IsWhiteSpace((char) c)) { buffer.UnRead(c); return new JsonToken(JsonTokenType.UnquotedString, buffer.Substring(start, buffer.Position - start)); } else { throw new FileFormatException(FormatMessage("Invalid JSON unquoted string", buffer, start)); } break; } } }
private static JsonToken GetNumberToken( BsonJsonBuffer buffer, int c // first character ) { // leading digit or '-' has already been read var start = buffer.Position - 1; NumberState state; switch (c) { case '-': state = NumberState.SawLeadingMinus; break; case '0': state = NumberState.SawLeadingZero; break; default: state = NumberState.SawIntegerDigits; break; } var type = JsonTokenType.Integer; // assume integer until proved otherwise while (true) { c = buffer.Read(); switch (state) { case NumberState.SawLeadingMinus: switch (c) { case '0': state = NumberState.SawLeadingZero; break; default: if (char.IsDigit((char) c)) { state = NumberState.SawIntegerDigits; } else { state = NumberState.Invalid; } break; } break; case NumberState.SawLeadingZero: switch (c) { case '.': state = NumberState.SawDecimalPoint; break; case 'e': case 'E': state = NumberState.SawExponentLetter; break; case ',': case '}': case ']': case -1: state = NumberState.Done; break; default: if (char.IsWhiteSpace((char) c)) { state = NumberState.Done; } else { state = NumberState.Invalid; } break; } break; case NumberState.SawIntegerDigits: switch (c) { case '.': state = NumberState.SawDecimalPoint; break; case 'e': case 'E': state = NumberState.SawExponentLetter; break; case ',': case '}': case ']': case -1: state = NumberState.Done; break; default: if (char.IsDigit((char) c)) { state = NumberState.SawIntegerDigits; } else if (char.IsWhiteSpace((char) c)) { state = NumberState.Done; } else { state = NumberState.Invalid; } break; } break; case NumberState.SawDecimalPoint: type = JsonTokenType.FloatingPoint; if (char.IsDigit((char) c)) { state = NumberState.SawFractionDigits; } else { state = NumberState.Invalid; } break; case NumberState.SawFractionDigits: switch (c) { case 'e': case 'E': state = NumberState.SawExponentLetter; break; case ',': case '}': case ']': case -1: state = NumberState.Done; break; default: if (char.IsDigit((char) c)) { state = NumberState.SawFractionDigits; } else if (char.IsWhiteSpace((char) c)) { state = NumberState.Done; } else { state = NumberState.Invalid; } break; } break; case NumberState.SawExponentLetter: type = JsonTokenType.FloatingPoint; switch (c) { case '+': case '-': state = NumberState.SawExponentSign; break; default: if (char.IsDigit((char) c)) { state = NumberState.SawExponentDigits; } else { state = NumberState.Invalid; } break; } break; case NumberState.SawExponentSign: if (char.IsDigit((char) c)) { state = NumberState.SawExponentDigits; } else { state = NumberState.Invalid; } break; case NumberState.SawExponentDigits: switch (c) { case ',': case '}': case ']': case -1: state = NumberState.Done; break; default: if (char.IsDigit((char) c)) { state = NumberState.SawExponentDigits; } else if (char.IsWhiteSpace((char) c)) { state = NumberState.Done; } else { state = NumberState.Invalid; } break; } break; } switch (state) { case NumberState.Done: buffer.UnRead(c); return new JsonToken(type, buffer.Substring(start, buffer.Position - start)); case NumberState.Invalid: throw new FileFormatException(FormatMessage("Invalid JSON number", buffer, start)); } } }
private static JsonToken GetRegularExpressionToken( BsonJsonBuffer buffer ) { // opening slash has already been read var start = buffer.Position - 1; var state = RegularExpressionState.InPattern; while (true) { var c = buffer.Read(); switch (state) { case RegularExpressionState.InPattern: switch (c) { case '/': state = RegularExpressionState.InOptions; break; case '\\': state = RegularExpressionState.InEscapeSequence; break; default: state = RegularExpressionState.InPattern; break; } break; case RegularExpressionState.InEscapeSequence: state = RegularExpressionState.InPattern; break; case RegularExpressionState.InOptions: switch (c) { case 'g': case 'i': case 'm': state = RegularExpressionState.InOptions; break; case ',': case '}': case ']': case -1: state = RegularExpressionState.Done; break; default: if (char.IsWhiteSpace((char) c)) { state = RegularExpressionState.Done; } else { state = RegularExpressionState.Invalid; } break; } break; } switch (state) { case RegularExpressionState.Done: buffer.UnRead(c); var count = buffer.Position - start; return new JsonToken(JsonTokenType.RegularExpression, buffer.Substring(start, count)); case RegularExpressionState.Invalid: throw new FileFormatException(FormatMessage("Invalid JSON regular expression", buffer, start)); } } }
private static string FormatMessage( string message, BsonJsonBuffer buffer, int start ) { var length = 20; string snippet; if (buffer.Position + length >= buffer.Length) { snippet = buffer.Substring(start); } else { snippet = buffer.Substring(start, length) + "..."; } return string.Format("{0}: '{1}'", message, snippet); }