/// <summary> /// Gets the next JsonToken from a JsonBuffer. /// </summary> /// <param name="buffer">The buffer.</param> /// <returns>The next token.</returns> public static JsonToken GetNextToken( JsonBuffer buffer ) { // skip leading whitespace var c = buffer.Read(); while (c != -1 && char.IsWhiteSpace((char) c)) { c = buffer.Read(); } if (c == -1) { return new JsonToken(JsonTokenType.EndOfFile, "<eof>"); } // leading character determines token type switch (c) { case '{': return new JsonToken(JsonTokenType.BeginObject, "{"); case '}': return new JsonToken(JsonTokenType.EndObject, "}"); case '[': return new JsonToken(JsonTokenType.BeginArray, "["); case ']': return new JsonToken(JsonTokenType.EndArray, "]"); case ':': return new JsonToken(JsonTokenType.Colon, ":"); case ',': return new JsonToken(JsonTokenType.Comma, ","); case '"': return GetStringToken(buffer); case '/': return GetRegularExpressionToken(buffer); default: if (c == '-' || char.IsDigit((char) c)) { return GetNumberToken(buffer, c); } else if (c == '$' || char.IsLetter((char) c)) { return GetUnquotedStringToken(buffer); } else { buffer.UnRead(c); throw new FileFormatException(FormatMessage("Invalid JSON input", buffer, buffer.Position)); } } }
private static JsonToken GetNumberToken( JsonBuffer 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.Int64; // assume integer until proved otherwise while (true) { c = buffer.Read(); switch (state) { case NumberState.SawLeadingMinus: switch (c) { case '0': state = NumberState.SawLeadingZero; break; case 'I': state = NumberState.SawMinusI; 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 ')': 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 ')': 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.Double; 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 ')': 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.Double; 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 ')': 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; case NumberState.SawMinusI: var sawMinusInfinity = true; var nfinity = new char[] { 'n', 'f', 'i', 'n', 'i', 't', 'y' }; for (var i = 0; i < nfinity.Length; i++) { if (c != nfinity[i]) { sawMinusInfinity = false; break; } c = buffer.Read(); } if (sawMinusInfinity) { type = JsonTokenType.Double; switch (c) { case ',': case '}': case ']': case ')': case -1: state = NumberState.Done; break; default: if (char.IsWhiteSpace((char) c)) { state = NumberState.Done; } else { state = NumberState.Invalid; } break; } } else { state = NumberState.Invalid; } break; } switch (state) { case NumberState.Done: buffer.UnRead(c); var lexeme = buffer.Substring(start, buffer.Position - start); if (type == JsonTokenType.Double) { var value = XmlConvert.ToDouble(lexeme); return new DoubleJsonToken(lexeme, value); } else { var value = XmlConvert.ToInt64(lexeme); if (value < int.MinValue || value > int.MaxValue) { return new Int64JsonToken(lexeme, value); } else { return new Int32JsonToken(lexeme, (int) value); } } case NumberState.Invalid: throw new FileFormatException(FormatMessage("Invalid JSON number", buffer, start)); } } }
private static JsonToken GetUnquotedStringToken( JsonBuffer buffer ) { // opening letter or $ has already been read var start = buffer.Position - 1; var c = buffer.Read(); while (c == '$' || char.IsLetterOrDigit((char) c)) { c = buffer.Read(); } buffer.UnRead(c); var lexeme = buffer.Substring(start, buffer.Position - start); return new StringJsonToken(JsonTokenType.UnquotedString, lexeme, lexeme); }
private static JsonToken GetRegularExpressionToken( JsonBuffer 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 ')': 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 lexeme = buffer.Substring(start, buffer.Position - start); var regex = BsonRegularExpression.Create(lexeme); return new RegularExpressionJsonToken(lexeme, regex); case RegularExpressionState.Invalid: throw new FileFormatException(FormatMessage("Invalid JSON regular expression", buffer, start)); } } }
private static JsonToken GetUnquotedStringToken( JsonBuffer buffer ) { // opening letter or $ has already been read var start = buffer.Position - 1; string lexeme; while (true) { var c = buffer.Read(); switch (c) { case ':': case ',': case '}': case ']': case -1: buffer.UnRead(c); lexeme = buffer.Substring(start, buffer.Position - start); return new StringJsonToken(JsonTokenType.UnquotedString, lexeme, lexeme); default: if (c == '$' || char.IsLetterOrDigit((char) c)) { // continue } else if (char.IsWhiteSpace((char) c)) { buffer.UnRead(c); lexeme = buffer.Substring(start, buffer.Position - start); return new StringJsonToken(JsonTokenType.UnquotedString, lexeme, lexeme); } else { if (c == '(') { var value = buffer.Substring(start, buffer.Position - 1 - start); switch (value) { case "Date": return GetTenGenDate(buffer, start); case "NumberLong": return GetTenGenInt64(buffer, start); case "ObjectId": return GetTenGenObjectId(buffer, start); } } throw new FileFormatException(FormatMessage("Invalid JSON unquoted string", buffer, start)); } break; } } }
private static JsonToken GetNumberToken(JsonBuffer buffer, int firstChar) { var c = firstChar; // 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.Int64; // assume integer until proved otherwise while (true) { c = buffer.Read(); switch (state) { case NumberState.SawLeadingMinus: switch (c) { case '0': state = NumberState.SawLeadingZero; break; case 'I': state = NumberState.SawMinusI; 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 ')': 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 ')': 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.Double; 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 ')': 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.Double; 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 ')': 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; case NumberState.SawMinusI: var sawMinusInfinity = true; var nfinity = new char[] { 'n', 'f', 'i', 'n', 'i', 't', 'y' }; for (var i = 0; i < nfinity.Length; i++) { if (c != nfinity[i]) { sawMinusInfinity = false; break; } c = buffer.Read(); } if (sawMinusInfinity) { type = JsonTokenType.Double; switch (c) { case ',': case '}': case ']': case ')': case -1: state = NumberState.Done; break; default: if (char.IsWhiteSpace((char)c)) { state = NumberState.Done; } else { state = NumberState.Invalid; } break; } } else { state = NumberState.Invalid; } break; } switch (state) { case NumberState.Done: buffer.UnRead(c); var lexeme = buffer.Substring(start, buffer.Position - start); if (type == JsonTokenType.Double) { var value = XmlConvert.ToDouble(lexeme); return(new DoubleJsonToken(lexeme, value)); } else { var value = XmlConvert.ToInt64(lexeme); if (value < int.MinValue || value > int.MaxValue) { return(new Int64JsonToken(lexeme, value)); } else { return(new Int32JsonToken(lexeme, (int)value)); } } case NumberState.Invalid: throw new FileFormatException(FormatMessage("Invalid JSON number", buffer, start)); } } }
private static JsonToken GetRegularExpressionToken( JsonBuffer 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 ')': 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 lexeme = buffer.Substring(start, buffer.Position - start); var regex = BsonRegularExpression.Create(lexeme); return(new RegularExpressionJsonToken(lexeme, regex)); case RegularExpressionState.Invalid: throw new FileFormatException(FormatMessage("Invalid JSON regular expression", buffer, start)); } } }
internal static IEnumerable<object> ReadDocumentsAs(Type documentType, string filePath, FileFormat format) { if (format == FileFormat.Auto) format = filePath.EndsWith(".json", StringComparison.OrdinalIgnoreCase) ? FileFormat.Json : FileFormat.Bson; var serializer = BsonSerializer.LookupSerializer(documentType); var options = DocumentSerializationOptions.Defaults; if (format == FileFormat.Json) { var jb = new JsonBuffer(File.ReadAllText(filePath)); bool array = false; for (; ; ) { // skip white int c; for (; ; ) { // end or white? if ((c = jb.Read()) <= 32) { // end? if (c < 0) goto end; // white continue; } // document if (c == '{') { jb.UnRead(c); break; } // array if (c == ',') { if (array) continue; } else if (c == ']') { if (array) { array = false; continue; } } else if (c == '[') { if (!array) { array = true; continue; } } throw new FormatException(string.Format(null, "Unexpected character '{0}' at position {1}.", (char)c, jb.Position - 1)); } using (var bsonReader = BsonReader.Create(jb)) yield return serializer.Deserialize(bsonReader, documentType, options); } end: ; } else { using (var stream = File.OpenRead(filePath)) { long length = stream.Length; while (stream.Position < length) using (var bsonReader = BsonReader.Create(stream)) yield return serializer.Deserialize(bsonReader, documentType, options); } } }