| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192 |
- /* Copyright 2010-present MongoDB Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using System.Text.RegularExpressions;
- using MongoDB.Shared;
- namespace MongoDB.Bson.IO
- {
- /// <summary>
- /// Represents a BSON reader for a JSON string.
- /// </summary>
- public class JsonReader : BsonReader
- {
- #region static
- private static readonly string[] __variableLengthIso8601Formats = new string[]
- {
- "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
- "yyyy-MM-ddTHH:mm:ss.FFFFFFFzz",
- "yyyyMMddTHHmmss.FFFFFFFK",
- "yyyyMMddTHHmmss.FFFFFFFzz"
- };
- private static readonly string[][] __fixedLengthIso8601Formats = new string[][]
- {
- null, // length = 0
- null, // length = 1
- null, // length = 2
- null, // length = 3
- new [] { "yyyy" }, // length = 4
- null, // length = 5
- null, // length = 6
- new [] { "yyyy-MM" }, // length = 7
- new [] { "yyyyMMdd" }, // length = 8
- null, // length = 9
- new [] { "yyyy-MM-dd" }, // length = 10
- new [] { "yyyyMMddTHH" }, // length = 11
- new [] { "yyyyMMddTHHZ" }, // length = 12
- new [] { "yyyy-MM-ddTHH" , "yyyyMMddTHHmm" }, // length = 13
- new [] { "yyyy-MM-ddTHHZ", "yyyyMMddTHHmmZ", "yyyyMMddTHHzz" }, // length = 14
- null, // length = 15
- new [] { "yyyy-MM-ddTHH:mm", "yyyy-MM-ddTHHzz", "yyyyMMddTHHmmssZ", "yyyyMMddTHHmmzz" }, // length = 16
- new [] { "yyyy-MM-ddTHH:mmZ", "yyyyMMddTHHzzz" }, // length = 17
- new [] { "yyyyMMddTHHmmsszz" }, // length = 18
- new [] { "yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHHzzz", "yyyy-MM-ddTHH:mmzz", "yyyyMMddTHHmmzzz" }, // length = 19
- null, // length = 20
- null, // length = 21
- new [] { "yyyy-MM-ddTHH:mmzzz", "yyyy-MM-ddTHH:mm:sszz" } // length = 22
- };
- #endregion
- // private fields
- private readonly JsonBuffer _buffer;
- private readonly JsonReaderSettings _jsonReaderSettings; // same value as in base class just declared as derived class
- private JsonReaderContext _context;
- private JsonToken _currentToken;
- private BsonValue _currentValue;
- private JsonToken _pushedToken;
- // constructors
- /// <summary>
- /// Initializes a new instance of the JsonReader class.
- /// </summary>
- /// <param name="json">The JSON string.</param>
- public JsonReader(string json)
- : this(json, JsonReaderSettings.Defaults)
- {
- }
- /// <summary>
- /// Initializes a new instance of the JsonReader class.
- /// </summary>
- /// <param name="json">The JSON string.</param>
- /// <param name="settings">The reader settings.</param>
- public JsonReader(string json, JsonReaderSettings settings)
- : this(new JsonBuffer(json), settings)
- {
- }
- /// <summary>
- /// Initializes a new instance of the JsonReader class.
- /// </summary>
- /// <param name="textReader">The TextReader.</param>
- public JsonReader(TextReader textReader)
- : this(textReader, JsonReaderSettings.Defaults)
- {
- }
- /// <summary>
- /// Initializes a new instance of the JsonReader class.
- /// </summary>
- /// <param name="textReader">The TextReader.</param>
- /// <param name="settings">The reader settings.</param>
- public JsonReader(TextReader textReader, JsonReaderSettings settings)
- : this(new JsonBuffer(textReader), settings)
- {
- }
- private JsonReader(JsonBuffer buffer, JsonReaderSettings settings)
- : base(settings)
- {
- _buffer = buffer;
- _jsonReaderSettings = settings; // already frozen by base class
- _context = new JsonReaderContext(null, ContextType.TopLevel);
- }
- // public methods
- /// <summary>
- /// Closes the reader.
- /// </summary>
- public override void Close()
- {
- // Close can be called on Disposed objects
- State = BsonReaderState.Closed;
- }
- /// <summary>
- /// Gets a bookmark to the reader's current position and state.
- /// </summary>
- /// <returns>A bookmark.</returns>
- public override BsonReaderBookmark GetBookmark()
- {
- return new JsonReaderBookmark(State, CurrentBsonType, CurrentName, _context, _currentToken, _currentValue, _pushedToken, _buffer.Position);
- }
- /// <summary>
- /// Determines whether this reader is at end of file.
- /// </summary>
- /// <returns>
- /// Whether this reader is at end of file.
- /// </returns>
- public override bool IsAtEndOfFile()
- {
- int c;
- while ((c = _buffer.Read()) != -1)
- {
- if (!char.IsWhiteSpace((char)c))
- {
- _buffer.UnRead(c);
- return false;
- }
- }
- return true;
- }
- /// <summary>
- /// Reads BSON binary data from the reader.
- /// </summary>
- /// <returns>A BsonBinaryData.</returns>
- public override BsonBinaryData ReadBinaryData()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadBinaryData", BsonType.Binary);
- State = GetNextState();
- return _currentValue.AsBsonBinaryData;
- }
- /// <summary>
- /// Reads a BSON boolean from the reader.
- /// </summary>
- /// <returns>A Boolean.</returns>
- public override bool ReadBoolean()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadBoolean", BsonType.Boolean);
- State = GetNextState();
- return _currentValue.AsBoolean;
- }
- /// <summary>
- /// Reads a BsonType from the reader.
- /// </summary>
- /// <returns>A BsonType.</returns>
- public override BsonType ReadBsonType()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- if (State == BsonReaderState.Initial || State == BsonReaderState.ScopeDocument)
- {
- if (State == BsonReaderState.Initial)
- {
- _buffer.ResetBuffer();
- }
- // in JSON the top level value can be of any type so fall through
- State = BsonReaderState.Type;
- }
- if (State != BsonReaderState.Type)
- {
- ThrowInvalidState("ReadBsonType", BsonReaderState.Type);
- }
- if (_context.ContextType == ContextType.Document)
- {
- var nameToken = PopToken();
- switch (nameToken.Type)
- {
- case JsonTokenType.String:
- case JsonTokenType.UnquotedString:
- CurrentName = nameToken.StringValue;
- break;
- case JsonTokenType.EndObject:
- State = BsonReaderState.EndOfDocument;
- return BsonType.EndOfDocument;
- default:
- var message = string.Format("JSON reader was expecting a name but found '{0}'.", nameToken.Lexeme);
- throw new FormatException(message);
- }
- var colonToken = PopToken();
- if (colonToken.Type != JsonTokenType.Colon)
- {
- var message = string.Format("JSON reader was expecting ':' but found '{0}'.", colonToken.Lexeme);
- throw new FormatException(message);
- }
- }
- var valueToken = PopToken();
- if (_context.ContextType == ContextType.Array && valueToken.Type == JsonTokenType.EndArray)
- {
- State = BsonReaderState.EndOfArray;
- return BsonType.EndOfDocument;
- }
- var noValueFound = false;
- switch (valueToken.Type)
- {
- case JsonTokenType.BeginArray:
- CurrentBsonType = BsonType.Array;
- break;
- case JsonTokenType.BeginObject:
- CurrentBsonType = ParseExtendedJson();
- break;
- case JsonTokenType.DateTime:
- CurrentBsonType = BsonType.DateTime;
- _currentValue = valueToken.DateTimeValue;
- break;
- case JsonTokenType.Double:
- CurrentBsonType = BsonType.Double;
- _currentValue = valueToken.DoubleValue;
- break;
- case JsonTokenType.EndOfFile:
- CurrentBsonType = BsonType.EndOfDocument;
- break;
- case JsonTokenType.Int32:
- CurrentBsonType = BsonType.Int32;
- _currentValue = valueToken.Int32Value;
- break;
- case JsonTokenType.Int64:
- CurrentBsonType = BsonType.Int64;
- _currentValue = valueToken.Int64Value;
- break;
- case JsonTokenType.ObjectId:
- CurrentBsonType = BsonType.ObjectId;
- _currentValue = valueToken.ObjectIdValue;
- break;
- case JsonTokenType.RegularExpression:
- CurrentBsonType = BsonType.RegularExpression;
- _currentValue = valueToken.RegularExpressionValue;
- break;
- case JsonTokenType.String:
- CurrentBsonType = BsonType.String;
- _currentValue = valueToken.StringValue;
- break;
- case JsonTokenType.UnquotedString:
- switch (valueToken.Lexeme)
- {
- case "false":
- case "true":
- CurrentBsonType = BsonType.Boolean;
- _currentValue = JsonConvert.ToBoolean(valueToken.Lexeme);
- break;
- case "Infinity":
- CurrentBsonType = BsonType.Double;
- _currentValue = double.PositiveInfinity;
- break;
- case "NaN":
- CurrentBsonType = BsonType.Double;
- _currentValue = double.NaN;
- break;
- case "null":
- CurrentBsonType = BsonType.Null;
- break;
- case "undefined":
- CurrentBsonType = BsonType.Undefined;
- break;
- case "BinData":
- CurrentBsonType = BsonType.Binary;
- _currentValue = ParseBinDataConstructor();
- break;
- case "Date":
- CurrentBsonType = BsonType.String;
- _currentValue = ParseDateTimeConstructor(false); // withNew = false
- break;
- case "HexData":
- CurrentBsonType = BsonType.Binary;
- _currentValue = ParseHexDataConstructor();
- break;
- case "ISODate":
- CurrentBsonType = BsonType.DateTime;
- _currentValue = ParseISODateTimeConstructor();
- break;
- case "MaxKey":
- CurrentBsonType = BsonType.MaxKey;
- _currentValue = BsonMaxKey.Value;
- break;
- case "MinKey":
- CurrentBsonType = BsonType.MinKey;
- _currentValue = BsonMinKey.Value;
- break;
- case "NumberDecimal":
- CurrentBsonType = BsonType.Decimal128;
- _currentValue = ParseNumberDecimalConstructor();
- break;
- case "Number":
- case "NumberInt":
- CurrentBsonType = BsonType.Int32;
- _currentValue = ParseNumberConstructor();
- break;
- case "NumberLong":
- CurrentBsonType = BsonType.Int64;
- _currentValue = ParseNumberLongConstructor();
- break;
- case "ObjectId":
- CurrentBsonType = BsonType.ObjectId;
- _currentValue = ParseObjectIdConstructor();
- break;
- case "RegExp":
- CurrentBsonType = BsonType.RegularExpression;
- _currentValue = ParseRegularExpressionConstructor();
- break;
- case "Timestamp":
- CurrentBsonType = BsonType.Timestamp;
- _currentValue = ParseTimestampConstructor();
- break;
- case "UUID":
- case "GUID":
- case "CSUUID":
- case "CSGUID":
- case "JUUID":
- case "JGUID":
- case "PYUUID":
- case "PYGUID":
- CurrentBsonType = BsonType.Binary;
- _currentValue = ParseUUIDConstructor(valueToken.Lexeme);
- break;
- case "new":
- CurrentBsonType = ParseNew(out _currentValue);
- break;
- default:
- noValueFound = true;
- break;
- }
- break;
- default:
- noValueFound = true;
- break;
- }
- if (noValueFound)
- {
- var message = string.Format("JSON reader was expecting a value but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- _currentToken = valueToken;
- if (_context.ContextType == ContextType.Array || _context.ContextType == ContextType.Document)
- {
- var commaToken = PopToken();
- if (commaToken.Type != JsonTokenType.Comma)
- {
- PushToken(commaToken);
- }
- }
- switch (_context.ContextType)
- {
- case ContextType.Document:
- case ContextType.ScopeDocument:
- default:
- State = BsonReaderState.Name;
- break;
- case ContextType.Array:
- case ContextType.JavaScriptWithScope:
- case ContextType.TopLevel:
- State = BsonReaderState.Value;
- break;
- }
- return CurrentBsonType;
- }
- /// <summary>
- /// Reads BSON binary data from the reader.
- /// </summary>
- /// <returns>A byte array.</returns>
- public override byte[] ReadBytes()
- {
- #pragma warning disable 618
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadBinaryData", BsonType.Binary);
- State = GetNextState();
- var binaryData = _currentValue.AsBsonBinaryData;
- var subType = binaryData.SubType;
- if (subType != BsonBinarySubType.Binary && subType != BsonBinarySubType.OldBinary)
- {
- var message = string.Format("ReadBytes requires the binary sub type to be Binary, not {0}.", subType);
- throw new FormatException(message);
- }
- return binaryData.Bytes;
- #pragma warning restore
- }
- /// <summary>
- /// Reads a BSON DateTime from the reader.
- /// </summary>
- /// <returns>The number of milliseconds since the Unix epoch.</returns>
- public override long ReadDateTime()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadDateTime", BsonType.DateTime);
- State = GetNextState();
- return _currentValue.AsBsonDateTime.MillisecondsSinceEpoch;
- }
- /// <inheritdoc />
- public override Decimal128 ReadDecimal128()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType(nameof(ReadDecimal128), BsonType.Decimal128);
- State = GetNextState();
- return _currentValue.AsDecimal128;
- }
- /// <summary>
- /// Reads a BSON Double from the reader.
- /// </summary>
- /// <returns>A Double.</returns>
- public override double ReadDouble()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadDouble", BsonType.Double);
- State = GetNextState();
- return _currentValue.AsDouble;
- }
- /// <summary>
- /// Reads the end of a BSON array from the reader.
- /// </summary>
- public override void ReadEndArray()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- if (_context.ContextType != ContextType.Array)
- {
- ThrowInvalidContextType("ReadEndArray", _context.ContextType, ContextType.Array);
- }
- if (State == BsonReaderState.Type)
- {
- ReadBsonType(); // will set state to EndOfArray if at end of array
- }
- if (State != BsonReaderState.EndOfArray)
- {
- ThrowInvalidState("ReadEndArray", BsonReaderState.EndOfArray);
- }
- _context = _context.PopContext();
- switch (_context.ContextType)
- {
- case ContextType.Array: State = BsonReaderState.Type; break;
- case ContextType.Document: State = BsonReaderState.Type; break;
- case ContextType.TopLevel: State = BsonReaderState.Initial; break;
- default: throw new BsonInternalException("Unexpected ContextType.");
- }
- if (_context.ContextType == ContextType.Array || _context.ContextType == ContextType.Document)
- {
- var commaToken = PopToken();
- if (commaToken.Type != JsonTokenType.Comma)
- {
- PushToken(commaToken);
- }
- }
- }
- /// <summary>
- /// Reads the end of a BSON document from the reader.
- /// </summary>
- public override void ReadEndDocument()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- if (_context.ContextType != ContextType.Document && _context.ContextType != ContextType.ScopeDocument)
- {
- ThrowInvalidContextType("ReadEndDocument", _context.ContextType, ContextType.Document, ContextType.ScopeDocument);
- }
- if (State == BsonReaderState.Type)
- {
- ReadBsonType(); // will set state to EndOfDocument if at end of document
- }
- if (State != BsonReaderState.EndOfDocument)
- {
- ThrowInvalidState("ReadEndDocument", BsonReaderState.EndOfDocument);
- }
- _context = _context.PopContext();
- if (_context != null && _context.ContextType == ContextType.JavaScriptWithScope)
- {
- _context = _context.PopContext(); // JavaScriptWithScope
- VerifyToken("}"); // outermost closing bracket for JavaScriptWithScope
- }
- switch (_context.ContextType)
- {
- case ContextType.Array: State = BsonReaderState.Type; break;
- case ContextType.Document: State = BsonReaderState.Type; break;
- case ContextType.TopLevel: State = BsonReaderState.Initial; break;
- default: throw new BsonInternalException("Unexpected ContextType");
- }
- if (_context.ContextType == ContextType.Array || _context.ContextType == ContextType.Document)
- {
- var commaToken = PopToken();
- if (commaToken.Type != JsonTokenType.Comma)
- {
- PushToken(commaToken);
- }
- }
- }
- /// <summary>
- /// Reads a BSON Int32 from the reader.
- /// </summary>
- /// <returns>An Int32.</returns>
- public override int ReadInt32()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadInt32", BsonType.Int32);
- State = GetNextState();
- return _currentValue.AsInt32;
- }
- /// <summary>
- /// Reads a BSON Int64 from the reader.
- /// </summary>
- /// <returns>An Int64.</returns>
- public override long ReadInt64()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadInt64", BsonType.Int64);
- State = GetNextState();
- return _currentValue.AsInt64;
- }
- /// <summary>
- /// Reads a BSON JavaScript from the reader.
- /// </summary>
- /// <returns>A string.</returns>
- public override string ReadJavaScript()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadJavaScript", BsonType.JavaScript);
- State = GetNextState();
- return _currentValue.AsString;
- }
- /// <summary>
- /// Reads a BSON JavaScript with scope from the reader (call ReadStartDocument next to read the scope).
- /// </summary>
- /// <returns>A string.</returns>
- public override string ReadJavaScriptWithScope()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadJavaScriptWithScope", BsonType.JavaScriptWithScope);
- _context = new JsonReaderContext(_context, ContextType.JavaScriptWithScope);
- State = BsonReaderState.ScopeDocument;
- return _currentValue.AsString;
- }
- /// <summary>
- /// Reads a BSON MaxKey from the reader.
- /// </summary>
- public override void ReadMaxKey()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadMaxKey", BsonType.MaxKey);
- State = GetNextState();
- }
- /// <summary>
- /// Reads a BSON MinKey from the reader.
- /// </summary>
- public override void ReadMinKey()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadMinKey", BsonType.MinKey);
- State = GetNextState();
- }
- /// <summary>
- /// Reads the name of an element from the reader.
- /// </summary>
- /// <param name="nameDecoder">The name decoder.</param>
- /// <returns>
- /// The name of the element.
- /// </returns>
- public override string ReadName(INameDecoder nameDecoder)
- {
- if (nameDecoder == null)
- {
- throw new ArgumentNullException("nameDecoder");
- }
- if (Disposed) { ThrowObjectDisposedException(); }
- if (State == BsonReaderState.Type)
- {
- ReadBsonType();
- }
- if (State != BsonReaderState.Name)
- {
- ThrowInvalidState("ReadName", BsonReaderState.Name);
- }
- nameDecoder.Inform(CurrentName);
- State = BsonReaderState.Value;
- return CurrentName;
- }
- /// <summary>
- /// Reads a BSON null from the reader.
- /// </summary>
- public override void ReadNull()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadNull", BsonType.Null);
- State = GetNextState();
- }
- /// <summary>
- /// Reads a BSON ObjectId from the reader.
- /// </summary>
- /// <returns>An ObjectId.</returns>
- public override ObjectId ReadObjectId()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadObjectId", BsonType.ObjectId);
- State = GetNextState();
- return _currentValue.AsObjectId;
- }
- /// <summary>
- /// Reads a BSON regular expression from the reader.
- /// </summary>
- /// <returns>A BsonRegularExpression.</returns>
- public override BsonRegularExpression ReadRegularExpression()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadRegularExpression", BsonType.RegularExpression);
- State = GetNextState();
- return _currentValue.AsBsonRegularExpression;
- }
- /// <summary>
- /// Reads the start of a BSON array.
- /// </summary>
- public override void ReadStartArray()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadStartArray", BsonType.Array);
- _context = new JsonReaderContext(_context, ContextType.Array);
- State = BsonReaderState.Type;
- }
- /// <summary>
- /// Reads the start of a BSON document.
- /// </summary>
- public override void ReadStartDocument()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadStartDocument", BsonType.Document);
- _context = new JsonReaderContext(_context, ContextType.Document);
- State = BsonReaderState.Type;
- }
- /// <summary>
- /// Reads a BSON string from the reader.
- /// </summary>
- /// <returns>A String.</returns>
- public override string ReadString()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadString", BsonType.String);
- State = GetNextState();
- return _currentValue.AsString;
- }
- /// <summary>
- /// Reads a BSON symbol from the reader.
- /// </summary>
- /// <returns>A string.</returns>
- public override string ReadSymbol()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadSymbol", BsonType.Symbol);
- State = GetNextState();
- return _currentValue.AsString;
- }
- /// <summary>
- /// Reads a BSON timestamp from the reader.
- /// </summary>
- /// <returns>The combined timestamp/increment.</returns>
- public override long ReadTimestamp()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadTimestamp", BsonType.Timestamp);
- State = GetNextState();
- var timestamp = _currentValue.AsBsonTimestamp;
- return timestamp.Value;
- }
- /// <summary>
- /// Reads a BSON undefined from the reader.
- /// </summary>
- public override void ReadUndefined()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- VerifyBsonType("ReadUndefined", BsonType.Undefined);
- State = GetNextState();
- }
- /// <summary>
- /// Returns the reader to previously bookmarked position and state.
- /// </summary>
- /// <param name="bookmark">The bookmark.</param>
- public override void ReturnToBookmark(BsonReaderBookmark bookmark)
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- var jsonReaderBookmark = (JsonReaderBookmark)bookmark;
- State = jsonReaderBookmark.State;
- CurrentBsonType = jsonReaderBookmark.CurrentBsonType;
- CurrentName = jsonReaderBookmark.CurrentName;
- _context = jsonReaderBookmark.CloneContext();
- _currentToken = jsonReaderBookmark.CurrentToken;
- _currentValue = jsonReaderBookmark.CurrentValue;
- _pushedToken = jsonReaderBookmark.PushedToken;
- _buffer.Position = jsonReaderBookmark.Position;
- }
- /// <summary>
- /// Skips the name (reader must be positioned on a name).
- /// </summary>
- public override void SkipName()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- if (State != BsonReaderState.Name)
- {
- ThrowInvalidState("SkipName", BsonReaderState.Name);
- }
- State = BsonReaderState.Value;
- }
- /// <summary>
- /// Skips the value (reader must be positioned on a value).
- /// </summary>
- public override void SkipValue()
- {
- if (Disposed) { ThrowObjectDisposedException(); }
- if (State != BsonReaderState.Value)
- {
- ThrowInvalidState("SkipValue", BsonReaderState.Value);
- }
- switch (CurrentBsonType)
- {
- case BsonType.Array:
- ReadStartArray();
- while (ReadBsonType() != BsonType.EndOfDocument)
- {
- SkipValue();
- }
- ReadEndArray();
- break;
- case BsonType.Binary:
- ReadBinaryData();
- break;
- case BsonType.Boolean:
- ReadBoolean();
- break;
- case BsonType.DateTime:
- ReadDateTime();
- break;
- case BsonType.Document:
- ReadStartDocument();
- while (ReadBsonType() != BsonType.EndOfDocument)
- {
- SkipName();
- SkipValue();
- }
- ReadEndDocument();
- break;
- case BsonType.Double:
- ReadDouble();
- break;
- case BsonType.Int32:
- ReadInt32();
- break;
- case BsonType.Int64:
- ReadInt64();
- break;
- case BsonType.JavaScript:
- ReadJavaScript();
- break;
- case BsonType.JavaScriptWithScope:
- ReadJavaScriptWithScope();
- ReadStartDocument();
- while (ReadBsonType() != BsonType.EndOfDocument)
- {
- SkipName();
- SkipValue();
- }
- ReadEndDocument();
- break;
- case BsonType.MaxKey:
- ReadMaxKey();
- break;
- case BsonType.MinKey:
- ReadMinKey();
- break;
- case BsonType.Null:
- ReadNull();
- break;
- case BsonType.ObjectId:
- ReadObjectId();
- break;
- case BsonType.RegularExpression:
- ReadRegularExpression();
- break;
- case BsonType.String:
- ReadString();
- break;
- case BsonType.Symbol:
- ReadSymbol();
- break;
- case BsonType.Timestamp:
- ReadTimestamp();
- break;
- case BsonType.Undefined:
- ReadUndefined();
- break;
- default:
- throw new BsonInternalException("Invalid BsonType.");
- }
- }
- // protected methods
- /// <summary>
- /// Disposes of any resources used by the reader.
- /// </summary>
- /// <param name="disposing">True if called from Dispose.</param>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- try
- {
- Close();
- }
- catch { } // ignore exceptions
- }
- base.Dispose(disposing);
- }
- // private methods
- private string FormatInvalidTokenMessage(JsonToken token)
- {
- return string.Format("Invalid JSON token: '{0}'", token.Lexeme);
- }
- private string FormatJavaScriptDateTimeString(DateTime dateTime)
- {
- var utc = BsonUtils.ToUniversalTime(dateTime);
- var local = BsonUtils.ToLocalTime(utc);
- var offset = local - utc;
- var offsetSign = "+";
- if (offset < TimeSpan.Zero)
- {
- offset = -offset;
- offsetSign = "-";
- }
- var timeZone = TimeZoneInfo.Local;
- var timeZoneName = local.IsDaylightSavingTime() ? timeZone.DaylightName : timeZone.StandardName;
- var dateTimeString = string.Format(
- "{0} GMT{1}{2:D2}{3:D2} ({4})",
- local.ToString("ddd MMM dd yyyy HH:mm:ss"), offsetSign, offset.Hours, offset.Minutes, timeZoneName);
- return dateTimeString;
- }
- private BsonReaderState GetNextState()
- {
- switch (_context.ContextType)
- {
- case ContextType.Array:
- case ContextType.Document:
- return BsonReaderState.Type;
- case ContextType.TopLevel:
- return BsonReaderState.Initial;
- default:
- throw new BsonInternalException("Unexpected ContextType.");
- }
- }
- private bool IsValidBinaryDataSubTypeString(string value)
- {
- return
- value.Length >= 1 &&
- value.Length <= 2 &&
- HexUtils.IsValidHexString(value);
- }
- private BsonValue ParseBinDataConstructor()
- {
- VerifyToken("(");
- var subTypeToken = PopToken();
- if (subTypeToken.Type != JsonTokenType.Int32)
- {
- var message = string.Format("JSON reader expected a binary subtype but found '{0}'.", subTypeToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(",");
- var bytesToken = PopToken();
- if (bytesToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- var bytes = Convert.FromBase64String(bytesToken.StringValue);
- var subType = (BsonBinarySubType)subTypeToken.Int32Value;
- #pragma warning disable 618
- if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
- {
- GuidRepresentation guidRepresentation;
- switch (subType)
- {
- case BsonBinarySubType.UuidLegacy: guidRepresentation = _jsonReaderSettings.GuidRepresentation; break;
- case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
- default: guidRepresentation = GuidRepresentation.Unspecified; break;
- }
- return new BsonBinaryData(bytes, subType, guidRepresentation);
- }
- else
- {
- return new BsonBinaryData(bytes, subType);
- }
- #pragma warning restore 618
- }
- private BsonValue ParseBinDataExtendedJson()
- {
- VerifyToken(":");
- byte[] bytes;
- BsonBinarySubType subType;
- var nextToken = PopToken();
- if (nextToken.Type == JsonTokenType.BeginObject)
- {
- ParseBinDataExtendedJsonCanonical(out bytes, out subType);
- }
- else
- {
- ParseBinDataExtendedJsonLegacy(nextToken, out bytes, out subType);
- }
- VerifyToken("}");
- #pragma warning disable 618
- if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
- {
- GuidRepresentation guidRepresentation;
- switch (subType)
- {
- case BsonBinarySubType.UuidLegacy: guidRepresentation = _jsonReaderSettings.GuidRepresentation; break;
- case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
- default: guidRepresentation = GuidRepresentation.Unspecified; break;
- }
- return new BsonBinaryData(bytes, subType, guidRepresentation);
- }
- else
- {
- return new BsonBinaryData(bytes, subType);
- }
- #pragma warning restore 618
- }
- private void ParseBinDataExtendedJsonCanonical(out byte[] bytes, out BsonBinarySubType subType)
- {
- string base64String = null;
- string subTypeString = null;
- var nextToken = PopToken();
- while (nextToken.Type != JsonTokenType.EndObject)
- {
- if (nextToken.Type != JsonTokenType.String && nextToken.Type != JsonTokenType.UnquotedString)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- var name = nextToken.StringValue;
- nextToken = PopToken();
- if (nextToken.Type != JsonTokenType.Colon)
- {
- var message = string.Format("JSON reader expected ':' but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- nextToken = PopToken();
- if (nextToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- var value = nextToken.StringValue;
- switch (name)
- {
- case "base64": base64String = value; break;
- case "subType": subTypeString = value; break;
- default:
- var message = string.Format("JSON reader expected 'base64' or 'subType', but found '{0}'.", name);
- throw new FormatException(message);
- }
- nextToken = PopToken();
- if (nextToken.Type != JsonTokenType.Comma && nextToken.Type != JsonTokenType.EndObject)
- {
- var message = string.Format("JSON reader expected ',' or '}}' but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- if (nextToken.Type == JsonTokenType.Comma)
- {
- nextToken = PopToken();
- }
- }
- if (base64String == null)
- {
- var message = "JSON reader expected $binary to contain a 'base64' element.";
- throw new FormatException(message);
- }
- if (subTypeString == null)
- {
- var message = "JSON reader expected $binary to contain a 'subType' element.";
- throw new FormatException(message);
- }
- if (!IsValidBinaryDataSubTypeString(subTypeString))
- {
- var message = string.Format("JSON reader expected subType to be a one or two digit hex string, but found '{0}'.", subTypeString);
- throw new FormatException(message);
- }
- bytes = Convert.FromBase64String(base64String);
- subType = (BsonBinarySubType)HexUtils.ParseInt32(subTypeString);
- }
- private void ParseBinDataExtendedJsonLegacy(JsonToken nextToken, out byte[] bytes, out BsonBinarySubType subType)
- {
- if (nextToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- bytes = Convert.FromBase64String(nextToken.StringValue);
- VerifyToken(",");
- VerifyString("$type");
- VerifyToken(":");
- var subTypeToken = PopToken();
- if (subTypeToken.Type == JsonTokenType.String)
- {
- subType = (BsonBinarySubType)Convert.ToInt32(subTypeToken.StringValue, 16);
- }
- else if (subTypeToken.Type == JsonTokenType.Int32 || subTypeToken.Type == JsonTokenType.Int64)
- {
- subType = (BsonBinarySubType)subTypeToken.Int32Value;
- }
- else
- {
- var message = string.Format("JSON reader expected a string or integer but found '{0}'.", subTypeToken.Lexeme);
- throw new FormatException(message);
- }
- }
- private BsonValue ParseHexDataConstructor()
- {
- VerifyToken("(");
- var subTypeToken = PopToken();
- if (subTypeToken.Type != JsonTokenType.Int32)
- {
- var message = string.Format("JSON reader expected a binary subtype but found '{0}'.", subTypeToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(",");
- var bytesToken = PopToken();
- if (bytesToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- var bytes = BsonUtils.ParseHexString(bytesToken.StringValue);
- var subType = (BsonBinarySubType)subTypeToken.Int32Value;
- #pragma warning disable 618
- if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
- {
- GuidRepresentation guidRepresentation;
- switch (subType)
- {
- case BsonBinarySubType.UuidLegacy: guidRepresentation = _jsonReaderSettings.GuidRepresentation; break;
- case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
- default: guidRepresentation = GuidRepresentation.Unspecified; break;
- }
- return new BsonBinaryData(bytes, subType, guidRepresentation);
- }
- else
- {
- return new BsonBinaryData(bytes, subType);
- }
- #pragma warning restore 618
- }
- private BsonType ParseJavaScriptExtendedJson(out BsonValue value)
- {
- VerifyToken(":");
- var codeToken = PopToken();
- if (codeToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", codeToken.Lexeme);
- throw new FormatException(message);
- }
- var nextToken = PopToken();
- switch (nextToken.Type)
- {
- case JsonTokenType.Comma:
- VerifyString("$scope");
- VerifyToken(":");
- State = BsonReaderState.Value;
- value = codeToken.StringValue;
- return BsonType.JavaScriptWithScope;
- case JsonTokenType.EndObject:
- value = codeToken.StringValue;
- return BsonType.JavaScript;
- default:
- var message = string.Format("JSON reader expected ',' or '}}' but found '{0}'.", codeToken.Lexeme);
- throw new FormatException(message);
- }
- }
- private BsonValue ParseISODateTimeConstructor()
- {
- VerifyToken("(");
- var valueToken = PopToken();
- if (valueToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- var value = valueToken.StringValue;
- string[] formats = null;
- if (!value.Contains(".") && value.Length < __fixedLengthIso8601Formats.Length)
- {
- formats = __fixedLengthIso8601Formats[value.Length];
- }
- if (formats == null)
- {
- formats = __variableLengthIso8601Formats;
- }
- var utcDateTime = DateTime.ParseExact(value, formats, null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
- return new BsonDateTime(utcDateTime);
- }
- private BsonValue ParseDateTimeExtendedJson()
- {
- VerifyToken(":");
- var valueToken = PopToken();
- long millisecondsSinceEpoch;
- if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
- {
- millisecondsSinceEpoch = valueToken.Int64Value;
- }
- else if (valueToken.Type == JsonTokenType.String)
- {
- DateTime dateTime;
- var dateTimeStyles = DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal;
- if (!DateTime.TryParse(valueToken.StringValue, CultureInfo.InvariantCulture, dateTimeStyles, out dateTime))
- {
- var message = string.Format("Invalid $date string: '{0}'.", valueToken.StringValue);
- throw new FormatException(message);
- }
- millisecondsSinceEpoch = BsonUtils.ToMillisecondsSinceEpoch(dateTime);
- }
- else if (valueToken.Type == JsonTokenType.BeginObject)
- {
- VerifyString("$numberLong");
- VerifyToken(":");
- var millisecondsSinceEpochToken = PopToken();
- if (millisecondsSinceEpochToken.Type == JsonTokenType.String)
- {
- millisecondsSinceEpoch = long.Parse(millisecondsSinceEpochToken.StringValue, CultureInfo.InvariantCulture);
- }
- else if (millisecondsSinceEpochToken.Type == JsonTokenType.Int32 || millisecondsSinceEpochToken.Type == JsonTokenType.Int64)
- {
- millisecondsSinceEpoch = millisecondsSinceEpochToken.Int64Value;
- }
- else
- {
- var message = string.Format("JSON reader expected an integer or a string for {{ $date : {{ $numberLong : ... }} }} but found a '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- }
- else
- {
- var message = string.Format("JSON reader expected an ISO 8601 string, an integer, or {{ $numberLong : ... }} for $date but found a '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return new BsonDateTime(millisecondsSinceEpoch);
- }
- private BsonValue ParseDateTimeConstructor(bool withNew)
- {
- VerifyToken("(");
- // Date when used without "new" behaves differently (JavaScript has some weird parts)
- if (!withNew)
- {
- VerifyToken(")");
- var dateTimeString = FormatJavaScriptDateTimeString(DateTime.UtcNow);
- return new BsonString(dateTimeString);
- }
- var token = PopToken();
- if (token.Lexeme == ")")
- {
- return new BsonDateTime(DateTime.UtcNow);
- }
- else if (token.Type == JsonTokenType.String)
- {
- VerifyToken(")");
- var dateTimeString = token.StringValue;
- var dateTime = ParseJavaScriptDateTimeString(dateTimeString);
- return new BsonDateTime(dateTime);
- }
- else if (token.Type == JsonTokenType.Int32 || token.Type == JsonTokenType.Int64)
- {
- var args = new List<long>();
- while (true)
- {
- args.Add(token.Int64Value);
- token = PopToken();
- if (token.Lexeme == ")")
- {
- break;
- }
- if (token.Lexeme != ",")
- {
- var message = string.Format("JSON reader expected a ',' or a ')' but found '{0}'.", token.Lexeme);
- throw new FormatException(message);
- }
- token = PopToken();
- if (token.Type != JsonTokenType.Int32 && token.Type != JsonTokenType.Int64)
- {
- var message = string.Format("JSON reader expected an integer but found '{0}'.", token.Lexeme);
- throw new FormatException(message);
- }
- }
- switch (args.Count)
- {
- case 1:
- return new BsonDateTime(args[0]);
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- var year = (int)args[0];
- var month = (int)args[1] + 1; // JavaScript starts at 0 but .NET starts at 1
- var day = (int)args[2];
- var hours = (args.Count >= 4) ? (int)args[3] : 0;
- var minutes = (args.Count >= 5) ? (int)args[4] : 0;
- var seconds = (args.Count >= 6) ? (int)args[5] : 0;
- var milliseconds = (args.Count == 7) ? (int)args[6] : 0;
- var dateTime = new DateTime(year, month, day, hours, minutes, seconds, milliseconds, DateTimeKind.Utc);
- return new BsonDateTime(dateTime);
- default:
- var message = string.Format("JSON reader expected 1 or 3-7 integers but found {0}.", args.Count);
- throw new FormatException(message);
- }
- }
- else
- {
- var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", token.Lexeme);
- throw new FormatException(message);
- }
- }
- private BsonType ParseExtendedJson()
- {
- var bookmark = GetBookmark();
- var nameToken = PopToken();
- if (nameToken.Type == JsonTokenType.String || nameToken.Type == JsonTokenType.UnquotedString)
- {
- switch (nameToken.StringValue)
- {
- case "$binary": _currentValue = ParseBinDataExtendedJson(); return BsonType.Binary;
- case "$code": return ParseJavaScriptExtendedJson(out _currentValue);
- case "$date": _currentValue = ParseDateTimeExtendedJson(); return BsonType.DateTime;
- case "$maxkey": case "$maxKey": _currentValue = ParseMaxKeyExtendedJson(); return BsonType.MaxKey;
- case "$minkey": case "$minKey": _currentValue = ParseMinKeyExtendedJson(); return BsonType.MinKey;
- case "$numberDecimal": _currentValue = ParseNumberDecimalExtendedJson(); return BsonType.Decimal128;
- case "$numberDouble": _currentValue = ParseNumberDoubleExtendedJson(); return BsonType.Double;
- case "$numberInt": _currentValue = ParseNumberIntExtendedJson(); return BsonType.Int32;
- case "$numberLong": _currentValue = ParseNumberLongExtendedJson(); return BsonType.Int64;
- case "$oid": _currentValue = ParseObjectIdExtendedJson(); return BsonType.ObjectId;
- case "$regex":
- if (TryParseRegularExpressionExtendedJsonLegacy(out _currentValue))
- {
- return BsonType.RegularExpression;
- }
- break;
- case "$regularExpression": _currentValue = ParseRegularExpressionExtendedJsonCanonical(); return BsonType.RegularExpression;
- case "$symbol": _currentValue = ParseSymbolExtendedJson(); return BsonType.Symbol;
- case "$timestamp": _currentValue = ParseTimestampExtendedJson(); return BsonType.Timestamp;
- case "$undefined": _currentValue = ParseUndefinedExtendedJson(); return BsonType.Undefined;
- case "$uuid": _currentValue = ParseUuidExtendedJson(); return BsonType.Binary;
- }
- }
- ReturnToBookmark(bookmark);
- return BsonType.Document;
- }
- private DateTime ParseJavaScriptDateTimeString(string dateTimeString)
- {
- // if DateTime.TryParse succeeds we're done, otherwise assume it's an RFC 822 formatted DateTime string
- DateTime dateTime;
- if (DateTime.TryParse(dateTimeString, out dateTime))
- {
- return dateTime;
- }
- else
- {
- var rfc822DateTimePattern =
- @"^((?<dayOfWeek>(Mon|Tue|Wed|Thu|Fri|Sat|Sun)), )?" +
- @"(?<day>\d{1,2}) +" +
- @"(?<monthName>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " +
- @"(?<year>\d{2}|\d{4}) " +
- @"(?<hour>\d{1,2}):" +
- @"(?<minutes>\d{1,2}):" +
- @"(?<seconds>\d{1,2}(.\d{1,7})?) " +
- @"(?<zone>UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-Z]|([+-]\d{4}))$";
- var match = Regex.Match(dateTimeString, rfc822DateTimePattern);
- if (match.Success)
- {
- var day = int.Parse(match.Groups["day"].Value);
- int month;
- var monthName = match.Groups["monthName"].Value;
- switch (monthName)
- {
- case "Jan": month = 1; break;
- case "Feb": month = 2; break;
- case "Mar": month = 3; break;
- case "Apr": month = 4; break;
- case "May": month = 5; break;
- case "Jun": month = 6; break;
- case "Jul": month = 7; break;
- case "Aug": month = 8; break;
- case "Sep": month = 9; break;
- case "Oct": month = 10; break;
- case "Nov": month = 11; break;
- case "Dec": month = 12; break;
- default:
- var message = string.Format("\"{0}\" is not a valid RFC 822 month name.", monthName);
- throw new FormatException(message);
- }
- var yearString = match.Groups["year"].Value;
- int year = int.Parse(yearString);
- if (yearString.Length == 2)
- {
- year += 2000;
- if (year - DateTime.UtcNow.Year >= 19) { year -= 100; }
- }
- var hour = int.Parse(match.Groups["hour"].Value);
- var minutes = int.Parse(match.Groups["minutes"].Value);
- var secondsString = match.Groups["seconds"].Value;
- int seconds;
- double milliseconds;
- if (secondsString.IndexOf('.') != -1)
- {
- var timeSpan = TimeSpan.FromSeconds(double.Parse(secondsString));
- seconds = timeSpan.Seconds;
- milliseconds = timeSpan.TotalMilliseconds - seconds * 1000;
- }
- else
- {
- seconds = int.Parse(secondsString);
- milliseconds = 0;
- }
- dateTime = new DateTime(year, month, day, hour, minutes, seconds, DateTimeKind.Utc).AddMilliseconds(milliseconds);
- // check day of week before converting to UTC
- var dayOfWeekString = match.Groups["dayOfWeek"].Value;
- if (dayOfWeekString != "")
- {
- DayOfWeek dayOfWeek;
- switch (dayOfWeekString)
- {
- case "Mon": dayOfWeek = DayOfWeek.Monday; break;
- case "Tue": dayOfWeek = DayOfWeek.Tuesday; break;
- case "Wed": dayOfWeek = DayOfWeek.Wednesday; break;
- case "Thu": dayOfWeek = DayOfWeek.Thursday; break;
- case "Fri": dayOfWeek = DayOfWeek.Friday; break;
- case "Sat": dayOfWeek = DayOfWeek.Saturday; break;
- case "Sun": dayOfWeek = DayOfWeek.Sunday; break;
- default:
- var message = string.Format("\"{0}\" is not a valid RFC 822 day name.", dayOfWeekString);
- throw new FormatException(message);
- }
- if (dateTime.DayOfWeek != dayOfWeek)
- {
- var message = string.Format("\"{0}\" is not the right day of the week for {1}.", dayOfWeekString, dateTime.ToString("o"));
- throw new FormatException(message);
- }
- }
- TimeSpan offset;
- var zone = match.Groups["zone"].Value;
- switch (zone)
- {
- case "UT": case "GMT": case "Z": offset = TimeSpan.Zero; break;
- case "EST": offset = TimeSpan.FromHours(-5); break;
- case "EDT": offset = TimeSpan.FromHours(-4); break;
- case "CST": offset = TimeSpan.FromHours(-6); break;
- case "CDT": offset = TimeSpan.FromHours(-5); break;
- case "MST": offset = TimeSpan.FromHours(-7); break;
- case "MDT": offset = TimeSpan.FromHours(-6); break;
- case "PST": offset = TimeSpan.FromHours(-8); break;
- case "PDT": offset = TimeSpan.FromHours(-7); break;
- case "A": offset = TimeSpan.FromHours(-1); break;
- case "B": offset = TimeSpan.FromHours(-2); break;
- case "C": offset = TimeSpan.FromHours(-3); break;
- case "D": offset = TimeSpan.FromHours(-4); break;
- case "E": offset = TimeSpan.FromHours(-5); break;
- case "F": offset = TimeSpan.FromHours(-6); break;
- case "G": offset = TimeSpan.FromHours(-7); break;
- case "H": offset = TimeSpan.FromHours(-8); break;
- case "I": offset = TimeSpan.FromHours(-9); break;
- case "K": offset = TimeSpan.FromHours(-10); break;
- case "L": offset = TimeSpan.FromHours(-11); break;
- case "M": offset = TimeSpan.FromHours(-12); break;
- case "N": offset = TimeSpan.FromHours(1); break;
- case "O": offset = TimeSpan.FromHours(2); break;
- case "P": offset = TimeSpan.FromHours(3); break;
- case "Q": offset = TimeSpan.FromHours(4); break;
- case "R": offset = TimeSpan.FromHours(5); break;
- case "S": offset = TimeSpan.FromHours(6); break;
- case "T": offset = TimeSpan.FromHours(7); break;
- case "U": offset = TimeSpan.FromHours(8); break;
- case "V": offset = TimeSpan.FromHours(9); break;
- case "W": offset = TimeSpan.FromHours(10); break;
- case "X": offset = TimeSpan.FromHours(11); break;
- case "Y": offset = TimeSpan.FromHours(12); break;
- default:
- var offsetSign = zone.Substring(0);
- var offsetHours = zone.Substring(1, 2);
- var offsetMinutes = zone.Substring(3, 2);
- offset = TimeSpan.FromHours(int.Parse(offsetHours)) + TimeSpan.FromMinutes(int.Parse(offsetMinutes));
- if (offsetSign == "-")
- {
- offset = -offset;
- }
- break;
- }
- return dateTime.Add(-offset);
- }
- else
- {
- var message = string.Format("The DateTime string \"{0}\" is not a valid DateTime string for either .NET or JavaScript.", dateTimeString);
- throw new FormatException(message);
- }
- }
- }
- private BsonValue ParseMaxKeyExtendedJson()
- {
- VerifyToken(":");
- VerifyToken("1");
- VerifyToken("}");
- return BsonMaxKey.Value;
- }
- private BsonValue ParseMinKeyExtendedJson()
- {
- VerifyToken(":");
- VerifyToken("1");
- VerifyToken("}");
- return BsonMinKey.Value;
- }
- private BsonType ParseNew(out BsonValue value)
- {
- var typeToken = PopToken();
- if (typeToken.Type != JsonTokenType.UnquotedString)
- {
- var message = string.Format("JSON reader expected a type name but found '{0}'.", typeToken.Lexeme);
- throw new FormatException(message);
- }
- switch (typeToken.Lexeme)
- {
- case "BinData":
- value = ParseBinDataConstructor();
- return BsonType.Binary;
- case "Date":
- value = ParseDateTimeConstructor(true); // withNew = true
- return BsonType.DateTime;
- case "HexData":
- value = ParseHexDataConstructor();
- return BsonType.Binary;
- case "ISODate":
- value = ParseISODateTimeConstructor();
- return BsonType.DateTime;
- case "NumberDecimal":
- value = ParseNumberDecimalConstructor();
- return BsonType.Decimal128;
- case "NumberInt":
- value = ParseNumberConstructor();
- return BsonType.Int32;
- case "NumberLong":
- value = ParseNumberLongConstructor();
- return BsonType.Int64;
- case "ObjectId":
- value = ParseObjectIdConstructor();
- return BsonType.ObjectId;
- case "RegExp":
- value = ParseRegularExpressionConstructor();
- return BsonType.RegularExpression;
- case "Timestamp":
- value = ParseTimestampConstructor();
- return BsonType.Timestamp;
- case "UUID":
- case "GUID":
- case "CSUUID":
- case "CSGUID":
- case "JUUID":
- case "JGUID":
- case "PYUUID":
- case "PYGUID":
- value = ParseUUIDConstructor(typeToken.Lexeme);
- return BsonType.Binary;
- default:
- var message = string.Format("JSON reader expected a type name but found '{0}'.", typeToken.Lexeme);
- throw new FormatException(message);
- }
- }
- private BsonValue ParseNumberConstructor()
- {
- VerifyToken("(");
- var valueToken = PopToken();
- int value;
- if (valueToken.IsNumber)
- {
- value = valueToken.Int32Value;
- }
- else if (valueToken.Type == JsonTokenType.String)
- {
- value = int.Parse(valueToken.StringValue);
- }
- else
- {
- var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- return (BsonInt32)value;
- }
- private BsonValue ParseNumberDecimalConstructor()
- {
- VerifyToken("(");
- var valueToken = PopToken();
- Decimal128 value;
- if (valueToken.Type == JsonTokenType.String)
- {
- value = Decimal128.Parse(valueToken.StringValue);
- }
- else if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
- {
- value = new Decimal128(valueToken.Int64Value);
- }
- else
- {
- var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- return (BsonDecimal128)value;
- }
- private BsonValue ParseNumberLongConstructor()
- {
- VerifyToken("(");
- var valueToken = PopToken();
- long value;
- if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
- {
- value = valueToken.Int64Value;
- }
- else if (valueToken.Type == JsonTokenType.String)
- {
- value = long.Parse(valueToken.StringValue);
- }
- else
- {
- var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- return (BsonInt64)value;
- }
- private BsonValue ParseNumberDecimalExtendedJson()
- {
- VerifyToken(":");
- Decimal128 value;
- var valueToken = PopToken();
- if (valueToken.Type == JsonTokenType.String)
- {
- value = Decimal128.Parse(valueToken.StringValue);
- }
- else if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
- {
- value = new Decimal128(valueToken.Int64Value);
- }
- else
- {
- var message = string.Format("JSON reader expected a string or an integer but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return (BsonDecimal128)value;
- }
- private BsonValue ParseNumberDoubleExtendedJson()
- {
- VerifyToken(":");
- double value;
- var valueToken = PopToken();
- if (valueToken.IsNumber)
- {
- value = valueToken.DoubleValue;
- }
- else if (valueToken.Type == JsonTokenType.String)
- {
- value = JsonConvert.ToDouble(valueToken.StringValue);
- }
- else
- {
- var message = string.Format("JSON reader expected a number or numeric string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return (BsonDouble)value;
- }
- private BsonValue ParseNumberIntExtendedJson()
- {
- VerifyToken(":");
- int value;
- var valueToken = PopToken();
- if (valueToken.Type == JsonTokenType.Int32)
- {
- value = valueToken.Int32Value;
- }
- else if (valueToken.Type == JsonTokenType.String)
- {
- value = JsonConvert.ToInt32(valueToken.StringValue);
- }
- else
- {
- var message = string.Format("JSON reader expected an integer but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return (BsonInt32)value;
- }
- private BsonValue ParseNumberLongExtendedJson()
- {
- VerifyToken(":");
- long value;
- var valueToken = PopToken();
- if (valueToken.Type == JsonTokenType.String)
- {
- value = long.Parse(valueToken.StringValue, CultureInfo.InvariantCulture);
- }
- else if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
- {
- value = valueToken.Int64Value;
- }
- else
- {
- var message = string.Format("JSON reader expected a string or an integer but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return (BsonInt64)value;
- }
- private BsonValue ParseObjectIdConstructor()
- {
- VerifyToken("(");
- var valueToken = PopToken();
- if (valueToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- return new BsonObjectId(ObjectId.Parse(valueToken.StringValue));
- }
- private BsonValue ParseObjectIdExtendedJson()
- {
- VerifyToken(":");
- var valueToken = PopToken();
- if (valueToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return new BsonObjectId(ObjectId.Parse(valueToken.StringValue));
- }
- private BsonValue ParseRegularExpressionExtendedJsonCanonical()
- {
- VerifyToken(":");
- VerifyToken("{");
- string pattern = null;
- string options = null;
- var nextToken = PopToken();
- while (nextToken.Type != JsonTokenType.EndObject)
- {
- if (nextToken.Type != JsonTokenType.String && nextToken.Type != JsonTokenType.UnquotedString)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- var name = nextToken.StringValue;
- VerifyToken(":");
- nextToken = PopToken();
- if (nextToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- var value = nextToken.StringValue;
- switch (name)
- {
- case "pattern":
- pattern = value;
- break;
- case "options":
- options = value;
- break;
- default:
- var message = string.Format("JSON reader expected 'pattern' or 'options' but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- nextToken = PopToken();
- if (nextToken.Type != JsonTokenType.Comma && nextToken.Type != JsonTokenType.EndObject)
- {
- var message = string.Format("JSON reader expected ',' or '}}' but found '{0}'.", nextToken.Lexeme);
- throw new FormatException(message);
- }
- if (nextToken.Type == JsonTokenType.Comma)
- {
- nextToken = PopToken();
- }
- }
- VerifyToken("}");
- if (pattern == null)
- {
- var message = "JSON reader expected $regularExpression to contain a 'pattern' element.";
- throw new FormatException(message);
- }
- if (options == null)
- {
- var message = "JSON reader expected $regularExpression to contain an 'options' element.";
- throw new FormatException(message);
- }
- return new BsonRegularExpression(pattern, options);
- }
- private BsonValue ParseRegularExpressionConstructor()
- {
- VerifyToken("(");
- var patternToken = PopToken();
- if (patternToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", patternToken.Lexeme);
- throw new FormatException(message);
- }
- var options = "";
- var commaToken = PopToken();
- if (commaToken.Lexeme == ",")
- {
- var optionsToken = PopToken();
- if (optionsToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
- throw new FormatException(message);
- }
- options = optionsToken.StringValue;
- }
- else
- {
- PushToken(commaToken);
- }
- VerifyToken(")");
- return new BsonRegularExpression(patternToken.StringValue, options);
- }
- private bool TryParseRegularExpressionExtendedJsonLegacy(out BsonValue value)
- {
- VerifyToken(":");
- var patternToken = PopToken();
- if (patternToken.Type == JsonTokenType.BeginObject)
- {
- value = null;
- return false;
- }
- if (patternToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", patternToken.Lexeme);
- throw new FormatException(message);
- }
- var options = "";
- var commaToken = PopToken();
- if (commaToken.Lexeme == ",")
- {
- VerifyString("$options");
- VerifyToken(":");
- var optionsToken = PopToken();
- if (optionsToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
- throw new FormatException(message);
- }
- options = optionsToken.StringValue;
- }
- else
- {
- PushToken(commaToken);
- }
- VerifyToken("}");
- value = new BsonRegularExpression(patternToken.StringValue, options);
- return true;
- }
- private BsonValue ParseSymbolExtendedJson()
- {
- VerifyToken(":");
- var nameToken = PopToken();
- if (nameToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", nameToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return (BsonString)nameToken.StringValue; // will be converted to a BsonSymbol at a higher level
- }
- private BsonValue ParseTimestampConstructor()
- {
- VerifyToken("(");
- int secondsSinceEpoch;
- var secondsSinceEpochToken = PopToken();
- if (secondsSinceEpochToken.IsNumber)
- {
- secondsSinceEpoch = secondsSinceEpochToken.Int32Value;
- }
- else
- {
- var message = string.Format("JSON reader expected a number but found '{0}'.", secondsSinceEpochToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(",");
- int increment;
- var incrementToken = PopToken();
- if (secondsSinceEpochToken.IsNumber)
- {
- increment = incrementToken.Int32Value;
- }
- else
- {
- var message = string.Format("JSON reader expected a number but found '{0}'.", secondsSinceEpochToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- return new BsonTimestamp(secondsSinceEpoch, increment);
- }
- private BsonValue ParseTimestampExtendedJson()
- {
- VerifyToken(":");
- var nextToken = PopToken();
- if (nextToken.Type == JsonTokenType.BeginObject)
- {
- return ParseTimestampExtendedJsonNewRepresentation();
- }
- else
- {
- return ParseTimestampExtendedJsonOldRepresentation(nextToken);
- }
- }
- private BsonValue ParseTimestampExtendedJsonNewRepresentation()
- {
- int? timestamp = null;
- int? increment = null;
- while (true)
- {
- var token = PopToken();
- if (token.Type != JsonTokenType.String && token.Type != JsonTokenType.UnquotedString)
- {
- throw new FormatException($"JSON reader expected an element name but found '{token.Lexeme}'.");
- }
- var name = token.StringValue;
- token = PopToken();
- if (token.Type != JsonTokenType.Colon)
- {
- throw new FormatException($"JSON reader expected ':' but found '{name}'.");
- }
- token = PopToken();
- if (token.Type != JsonTokenType.Int64 && token.Type != JsonTokenType.Int32)
- {
- throw new FormatException($"JSON reader expected an integer but found '{token.Lexeme}'.");
- }
- var value = token.Int64Value;
- switch (name)
- {
- case "t":
- timestamp = (int)value;
- break;
- case "i":
- increment = (int)value;
- break;
- default:
- throw new FormatException($"JSON reader expected 't' or 'i' element names but found '{name}'.");
- }
- token = PopToken();
- if (token.Type == JsonTokenType.Comma)
- {
- continue;
- }
- else if (token.Type == JsonTokenType.EndObject)
- {
- break;
- }
- else
- {
- throw new FormatException($"JSON reader expected ',' or '}}' but found '{token.Lexeme}'.");
- }
- }
- VerifyToken("}");
- if (!timestamp.HasValue)
- {
- throw new FormatException("JSON reader did not find the required \"t\" element.");
- }
- if (!increment.HasValue)
- {
- throw new FormatException("JSON reader did not find the required \"i\" element.");
- }
- return new BsonTimestamp(timestamp.Value, increment.Value);
- }
- private BsonValue ParseTimestampExtendedJsonOldRepresentation(JsonToken valueToken)
- {
- long value;
- if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
- {
- value = valueToken.Int64Value;
- }
- else if (valueToken.Type == JsonTokenType.UnquotedString && valueToken.Lexeme == "NumberLong")
- {
- value = ParseNumberLongConstructor().AsInt64;
- }
- else
- {
- var message = string.Format("JSON reader expected an integer but found '{0}'.", valueToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- return new BsonTimestamp(value);
- }
- private BsonValue ParseUndefinedExtendedJson()
- {
- VerifyToken(":");
- VerifyToken("true");
- VerifyToken("}");
- return BsonMaxKey.Value;
- }
- private BsonValue ParseUuidExtendedJson()
- {
- VerifyToken(":");
- var uuidToken = PopToken();
- if (uuidToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", uuidToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken("}");
- var guid = Guid.Parse(uuidToken.StringValue);
- return new BsonBinaryData(guid, GuidRepresentation.Standard);
- }
- private BsonValue ParseUUIDConstructor(string uuidConstructorName)
- {
- VerifyToken("(");
- var bytesToken = PopToken();
- if (bytesToken.Type != JsonTokenType.String)
- {
- var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
- throw new FormatException(message);
- }
- VerifyToken(")");
- var hexString = bytesToken.StringValue.Replace("{", "").Replace("}", "").Replace("-", "");
- var bytes = BsonUtils.ParseHexString(hexString);
- var guid = GuidConverter.FromBytes(bytes, GuidRepresentation.Standard);
- GuidRepresentation guidRepresentation;
- switch (uuidConstructorName)
- {
- case "CSUUID":
- case "CSGUID":
- guidRepresentation = GuidRepresentation.CSharpLegacy;
- break;
- case "JUUID":
- case "JGUID":
- guidRepresentation = GuidRepresentation.JavaLegacy;
- break;
- case "PYUUID":
- case "PYGUID":
- guidRepresentation = GuidRepresentation.PythonLegacy;
- break;
- case "UUID":
- case "GUID":
- guidRepresentation = GuidRepresentation.Standard;
- break;
- default:
- throw new BsonInternalException("Unexpected uuidConstructorName");
- }
- bytes = GuidConverter.ToBytes(guid, guidRepresentation);
- var subType = GuidConverter.GetSubType(guidRepresentation);
- #pragma warning disable 618
- if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2)
- {
- return new BsonBinaryData(bytes, subType, guidRepresentation);
- }
- else
- {
- return new BsonBinaryData(bytes, subType);
- }
- #pragma warning restore 618
- }
- private JsonToken PopToken()
- {
- if (_pushedToken != null)
- {
- var token = _pushedToken;
- _pushedToken = null;
- return token;
- }
- else
- {
- return JsonScanner.GetNextToken(_buffer);
- }
- }
- private void PushToken(JsonToken token)
- {
- if (_pushedToken == null)
- {
- _pushedToken = token;
- }
- else
- {
- throw new BsonInternalException("There is already a pending token.");
- }
- }
- private void VerifyString(string expectedString)
- {
- var token = PopToken();
- if ((token.Type != JsonTokenType.String && token.Type != JsonTokenType.UnquotedString) || token.StringValue != expectedString)
- {
- var message = string.Format("JSON reader expected string '{0}' but found '{1}'.", expectedString, token.Lexeme);
- throw new FormatException(message);
- }
- }
- private void VerifyToken(string expectedLexeme)
- {
- var token = PopToken();
- if (token.Lexeme != expectedLexeme)
- {
- var message = string.Format("JSON reader expected '{0}' but found '{1}'.", expectedLexeme, token.Lexeme);
- throw new FormatException(message);
- }
- }
- }
- }
|