JsonReader.cs 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866
  1. /* Copyright 2010-2016 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Globalization;
  18. using System.IO;
  19. using System.Text.RegularExpressions;
  20. namespace MongoDB.Bson.IO
  21. {
  22. /// <summary>
  23. /// Represents a BSON reader for a JSON string.
  24. /// </summary>
  25. public class JsonReader : BsonReader
  26. {
  27. #region static
  28. private static readonly string[] __variableLengthIso8601Formats = new string[]
  29. {
  30. "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
  31. "yyyy-MM-ddTHH:mm:ss.FFFFFFFzz",
  32. "yyyyMMddTHHmmss.FFFFFFFK",
  33. "yyyyMMddTHHmmss.FFFFFFFzz"
  34. };
  35. private static readonly string[][] __fixedLengthIso8601Formats = new string[][]
  36. {
  37. null, // length = 0
  38. null, // length = 1
  39. null, // length = 2
  40. null, // length = 3
  41. new [] { "yyyy" }, // length = 4
  42. null, // length = 5
  43. null, // length = 6
  44. new [] { "yyyy-MM" }, // length = 7
  45. new [] { "yyyyMMdd" }, // length = 8
  46. null, // length = 9
  47. new [] { "yyyy-MM-dd" }, // length = 10
  48. new [] { "yyyyMMddTHH" }, // length = 11
  49. new [] { "yyyyMMddTHHZ" }, // length = 12
  50. new [] { "yyyy-MM-ddTHH" , "yyyyMMddTHHmm" }, // length = 13
  51. new [] { "yyyy-MM-ddTHHZ", "yyyyMMddTHHmmZ", "yyyyMMddTHHzz" }, // length = 14
  52. null, // length = 15
  53. new [] { "yyyy-MM-ddTHH:mm", "yyyy-MM-ddTHHzz", "yyyyMMddTHHmmssZ", "yyyyMMddTHHmmzz" }, // length = 16
  54. new [] { "yyyy-MM-ddTHH:mmZ", "yyyyMMddTHHzzz" }, // length = 17
  55. new [] { "yyyyMMddTHHmmsszz" }, // length = 18
  56. new [] { "yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHHzzz", "yyyy-MM-ddTHH:mmzz", "yyyyMMddTHHmmzzz" }, // length = 19
  57. null, // length = 20
  58. null, // length = 21
  59. new [] { "yyyy-MM-ddTHH:mmzzz", "yyyy-MM-ddTHH:mm:sszz" } // length = 22
  60. };
  61. #endregion
  62. // private fields
  63. private readonly JsonBuffer _buffer;
  64. private readonly JsonReaderSettings _jsonReaderSettings; // same value as in base class just declared as derived class
  65. private JsonReaderContext _context;
  66. private JsonToken _currentToken;
  67. private BsonValue _currentValue;
  68. private JsonToken _pushedToken;
  69. // constructors
  70. /// <summary>
  71. /// Initializes a new instance of the JsonReader class.
  72. /// </summary>
  73. /// <param name="json">The JSON string.</param>
  74. public JsonReader(string json)
  75. : this(json, JsonReaderSettings.Defaults)
  76. {
  77. }
  78. /// <summary>
  79. /// Initializes a new instance of the JsonReader class.
  80. /// </summary>
  81. /// <param name="json">The JSON string.</param>
  82. /// <param name="settings">The reader settings.</param>
  83. public JsonReader(string json, JsonReaderSettings settings)
  84. : this(new JsonBuffer(json), settings)
  85. {
  86. }
  87. /// <summary>
  88. /// Initializes a new instance of the JsonReader class.
  89. /// </summary>
  90. /// <param name="textReader">The TextReader.</param>
  91. public JsonReader(TextReader textReader)
  92. : this(textReader, JsonReaderSettings.Defaults)
  93. {
  94. }
  95. /// <summary>
  96. /// Initializes a new instance of the JsonReader class.
  97. /// </summary>
  98. /// <param name="textReader">The TextReader.</param>
  99. /// <param name="settings">The reader settings.</param>
  100. public JsonReader(TextReader textReader, JsonReaderSettings settings)
  101. : this(new JsonBuffer(textReader), settings)
  102. {
  103. }
  104. private JsonReader(JsonBuffer buffer, JsonReaderSettings settings)
  105. : base(settings)
  106. {
  107. _buffer = buffer;
  108. _jsonReaderSettings = settings; // already frozen by base class
  109. _context = new JsonReaderContext(null, ContextType.TopLevel);
  110. }
  111. // public methods
  112. /// <summary>
  113. /// Closes the reader.
  114. /// </summary>
  115. public override void Close()
  116. {
  117. // Close can be called on Disposed objects
  118. State = BsonReaderState.Closed;
  119. }
  120. /// <summary>
  121. /// Gets a bookmark to the reader's current position and state.
  122. /// </summary>
  123. /// <returns>A bookmark.</returns>
  124. public override BsonReaderBookmark GetBookmark()
  125. {
  126. return new JsonReaderBookmark(State, CurrentBsonType, CurrentName, _context, _currentToken, _currentValue, _pushedToken, _buffer.Position);
  127. }
  128. /// <summary>
  129. /// Determines whether this reader is at end of file.
  130. /// </summary>
  131. /// <returns>
  132. /// Whether this reader is at end of file.
  133. /// </returns>
  134. public override bool IsAtEndOfFile()
  135. {
  136. int c;
  137. while ((c = _buffer.Read()) != -1)
  138. {
  139. if (!char.IsWhiteSpace((char)c))
  140. {
  141. _buffer.UnRead(c);
  142. return false;
  143. }
  144. }
  145. return true;
  146. }
  147. /// <summary>
  148. /// Reads BSON binary data from the reader.
  149. /// </summary>
  150. /// <returns>A BsonBinaryData.</returns>
  151. public override BsonBinaryData ReadBinaryData()
  152. {
  153. if (Disposed) { ThrowObjectDisposedException(); }
  154. VerifyBsonType("ReadBinaryData", BsonType.Binary);
  155. State = GetNextState();
  156. return _currentValue.AsBsonBinaryData;
  157. }
  158. /// <summary>
  159. /// Reads a BSON boolean from the reader.
  160. /// </summary>
  161. /// <returns>A Boolean.</returns>
  162. public override bool ReadBoolean()
  163. {
  164. if (Disposed) { ThrowObjectDisposedException(); }
  165. VerifyBsonType("ReadBoolean", BsonType.Boolean);
  166. State = GetNextState();
  167. return _currentValue.AsBoolean;
  168. }
  169. /// <summary>
  170. /// Reads a BsonType from the reader.
  171. /// </summary>
  172. /// <returns>A BsonType.</returns>
  173. public override BsonType ReadBsonType()
  174. {
  175. if (Disposed) { ThrowObjectDisposedException(); }
  176. if (State == BsonReaderState.Initial || State == BsonReaderState.ScopeDocument)
  177. {
  178. if (State == BsonReaderState.Initial)
  179. {
  180. _buffer.ResetBuffer();
  181. }
  182. // in JSON the top level value can be of any type so fall through
  183. State = BsonReaderState.Type;
  184. }
  185. if (State != BsonReaderState.Type)
  186. {
  187. ThrowInvalidState("ReadBsonType", BsonReaderState.Type);
  188. }
  189. if (_context.ContextType == ContextType.Document)
  190. {
  191. var nameToken = PopToken();
  192. switch (nameToken.Type)
  193. {
  194. case JsonTokenType.String:
  195. case JsonTokenType.UnquotedString:
  196. CurrentName = nameToken.StringValue;
  197. break;
  198. case JsonTokenType.EndObject:
  199. State = BsonReaderState.EndOfDocument;
  200. return BsonType.EndOfDocument;
  201. default:
  202. var message = string.Format("JSON reader was expecting a name but found '{0}'.", nameToken.Lexeme);
  203. throw new FormatException(message);
  204. }
  205. var colonToken = PopToken();
  206. if (colonToken.Type != JsonTokenType.Colon)
  207. {
  208. var message = string.Format("JSON reader was expecting ':' but found '{0}'.", colonToken.Lexeme);
  209. throw new FormatException(message);
  210. }
  211. }
  212. var valueToken = PopToken();
  213. if (_context.ContextType == ContextType.Array && valueToken.Type == JsonTokenType.EndArray)
  214. {
  215. State = BsonReaderState.EndOfArray;
  216. return BsonType.EndOfDocument;
  217. }
  218. var noValueFound = false;
  219. switch (valueToken.Type)
  220. {
  221. case JsonTokenType.BeginArray:
  222. CurrentBsonType = BsonType.Array;
  223. break;
  224. case JsonTokenType.BeginObject:
  225. CurrentBsonType = ParseExtendedJson();
  226. break;
  227. case JsonTokenType.DateTime:
  228. CurrentBsonType = BsonType.DateTime;
  229. _currentValue = valueToken.DateTimeValue;
  230. break;
  231. case JsonTokenType.Double:
  232. CurrentBsonType = BsonType.Double;
  233. _currentValue = valueToken.DoubleValue;
  234. break;
  235. case JsonTokenType.EndOfFile:
  236. CurrentBsonType = BsonType.EndOfDocument;
  237. break;
  238. case JsonTokenType.Int32:
  239. CurrentBsonType = BsonType.Int32;
  240. _currentValue = valueToken.Int32Value;
  241. break;
  242. case JsonTokenType.Int64:
  243. CurrentBsonType = BsonType.Int64;
  244. _currentValue = valueToken.Int64Value;
  245. break;
  246. case JsonTokenType.ObjectId:
  247. CurrentBsonType = BsonType.ObjectId;
  248. _currentValue = valueToken.ObjectIdValue;
  249. break;
  250. case JsonTokenType.RegularExpression:
  251. CurrentBsonType = BsonType.RegularExpression;
  252. _currentValue = valueToken.RegularExpressionValue;
  253. break;
  254. case JsonTokenType.String:
  255. CurrentBsonType = BsonType.String;
  256. _currentValue = valueToken.StringValue;
  257. break;
  258. case JsonTokenType.UnquotedString:
  259. switch (valueToken.Lexeme)
  260. {
  261. case "false":
  262. case "true":
  263. CurrentBsonType = BsonType.Boolean;
  264. _currentValue = JsonConvert.ToBoolean(valueToken.Lexeme);
  265. break;
  266. case "Infinity":
  267. CurrentBsonType = BsonType.Double;
  268. _currentValue = double.PositiveInfinity;
  269. break;
  270. case "NaN":
  271. CurrentBsonType = BsonType.Double;
  272. _currentValue = double.NaN;
  273. break;
  274. case "null":
  275. CurrentBsonType = BsonType.Null;
  276. break;
  277. case "undefined":
  278. CurrentBsonType = BsonType.Undefined;
  279. break;
  280. case "BinData":
  281. CurrentBsonType = BsonType.Binary;
  282. _currentValue = ParseBinDataConstructor();
  283. break;
  284. case "Date":
  285. CurrentBsonType = BsonType.String;
  286. _currentValue = ParseDateTimeConstructor(false); // withNew = false
  287. break;
  288. case "HexData":
  289. CurrentBsonType = BsonType.Binary;
  290. _currentValue = ParseHexDataConstructor();
  291. break;
  292. case "ISODate":
  293. CurrentBsonType = BsonType.DateTime;
  294. _currentValue = ParseISODateTimeConstructor();
  295. break;
  296. case "MaxKey":
  297. CurrentBsonType = BsonType.MaxKey;
  298. _currentValue = BsonMaxKey.Value;
  299. break;
  300. case "MinKey":
  301. CurrentBsonType = BsonType.MinKey;
  302. _currentValue = BsonMinKey.Value;
  303. break;
  304. case "NumberDecimal":
  305. CurrentBsonType = BsonType.Decimal128;
  306. _currentValue = ParseNumberDecimalConstructor();
  307. break;
  308. case "Number":
  309. case "NumberInt":
  310. CurrentBsonType = BsonType.Int32;
  311. _currentValue = ParseNumberConstructor();
  312. break;
  313. case "NumberLong":
  314. CurrentBsonType = BsonType.Int64;
  315. _currentValue = ParseNumberLongConstructor();
  316. break;
  317. case "ObjectId":
  318. CurrentBsonType = BsonType.ObjectId;
  319. _currentValue = ParseObjectIdConstructor();
  320. break;
  321. case "RegExp":
  322. CurrentBsonType = BsonType.RegularExpression;
  323. _currentValue = ParseRegularExpressionConstructor();
  324. break;
  325. case "Timestamp":
  326. CurrentBsonType = BsonType.Timestamp;
  327. _currentValue = ParseTimestampConstructor();
  328. break;
  329. case "UUID":
  330. case "GUID":
  331. case "CSUUID":
  332. case "CSGUID":
  333. case "JUUID":
  334. case "JGUID":
  335. case "PYUUID":
  336. case "PYGUID":
  337. CurrentBsonType = BsonType.Binary;
  338. _currentValue = ParseUUIDConstructor(valueToken.Lexeme);
  339. break;
  340. case "new":
  341. CurrentBsonType = ParseNew(out _currentValue);
  342. break;
  343. default:
  344. noValueFound = true;
  345. break;
  346. }
  347. break;
  348. default:
  349. noValueFound = true;
  350. break;
  351. }
  352. if (noValueFound)
  353. {
  354. var message = string.Format("JSON reader was expecting a value but found '{0}'.", valueToken.Lexeme);
  355. throw new FormatException(message);
  356. }
  357. _currentToken = valueToken;
  358. if (_context.ContextType == ContextType.Array || _context.ContextType == ContextType.Document)
  359. {
  360. var commaToken = PopToken();
  361. if (commaToken.Type != JsonTokenType.Comma)
  362. {
  363. PushToken(commaToken);
  364. }
  365. }
  366. switch (_context.ContextType)
  367. {
  368. case ContextType.Document:
  369. case ContextType.ScopeDocument:
  370. default:
  371. State = BsonReaderState.Name;
  372. break;
  373. case ContextType.Array:
  374. case ContextType.JavaScriptWithScope:
  375. case ContextType.TopLevel:
  376. State = BsonReaderState.Value;
  377. break;
  378. }
  379. return CurrentBsonType;
  380. }
  381. /// <summary>
  382. /// Reads BSON binary data from the reader.
  383. /// </summary>
  384. /// <returns>A byte array.</returns>
  385. public override byte[] ReadBytes()
  386. {
  387. #pragma warning disable 618
  388. if (Disposed) { ThrowObjectDisposedException(); }
  389. VerifyBsonType("ReadBinaryData", BsonType.Binary);
  390. State = GetNextState();
  391. var binaryData = _currentValue.AsBsonBinaryData;
  392. var subType = binaryData.SubType;
  393. if (subType != BsonBinarySubType.Binary && subType != BsonBinarySubType.OldBinary)
  394. {
  395. var message = string.Format("ReadBytes requires the binary sub type to be Binary, not {0}.", subType);
  396. throw new FormatException(message);
  397. }
  398. return binaryData.Bytes;
  399. #pragma warning restore
  400. }
  401. /// <summary>
  402. /// Reads a BSON DateTime from the reader.
  403. /// </summary>
  404. /// <returns>The number of milliseconds since the Unix epoch.</returns>
  405. public override long ReadDateTime()
  406. {
  407. if (Disposed) { ThrowObjectDisposedException(); }
  408. VerifyBsonType("ReadDateTime", BsonType.DateTime);
  409. State = GetNextState();
  410. return _currentValue.AsBsonDateTime.MillisecondsSinceEpoch;
  411. }
  412. /// <inheritdoc />
  413. public override Decimal128 ReadDecimal128()
  414. {
  415. if (Disposed) { ThrowObjectDisposedException(); }
  416. VerifyBsonType(nameof(ReadDecimal128), BsonType.Decimal128);
  417. State = GetNextState();
  418. return _currentValue.AsDecimal128;
  419. }
  420. /// <summary>
  421. /// Reads a BSON Double from the reader.
  422. /// </summary>
  423. /// <returns>A Double.</returns>
  424. public override double ReadDouble()
  425. {
  426. if (Disposed) { ThrowObjectDisposedException(); }
  427. VerifyBsonType("ReadDouble", BsonType.Double);
  428. State = GetNextState();
  429. return _currentValue.AsDouble;
  430. }
  431. /// <summary>
  432. /// Reads the end of a BSON array from the reader.
  433. /// </summary>
  434. public override void ReadEndArray()
  435. {
  436. if (Disposed) { ThrowObjectDisposedException(); }
  437. if (_context.ContextType != ContextType.Array)
  438. {
  439. ThrowInvalidContextType("ReadEndArray", _context.ContextType, ContextType.Array);
  440. }
  441. if (State == BsonReaderState.Type)
  442. {
  443. ReadBsonType(); // will set state to EndOfArray if at end of array
  444. }
  445. if (State != BsonReaderState.EndOfArray)
  446. {
  447. ThrowInvalidState("ReadEndArray", BsonReaderState.EndOfArray);
  448. }
  449. _context = _context.PopContext();
  450. switch (_context.ContextType)
  451. {
  452. case ContextType.Array: State = BsonReaderState.Type; break;
  453. case ContextType.Document: State = BsonReaderState.Type; break;
  454. case ContextType.TopLevel: State = BsonReaderState.Initial; break;
  455. default: throw new BsonInternalException("Unexpected ContextType.");
  456. }
  457. if (_context.ContextType == ContextType.Array || _context.ContextType == ContextType.Document)
  458. {
  459. var commaToken = PopToken();
  460. if (commaToken.Type != JsonTokenType.Comma)
  461. {
  462. PushToken(commaToken);
  463. }
  464. }
  465. }
  466. /// <summary>
  467. /// Reads the end of a BSON document from the reader.
  468. /// </summary>
  469. public override void ReadEndDocument()
  470. {
  471. if (Disposed) { ThrowObjectDisposedException(); }
  472. if (_context.ContextType != ContextType.Document && _context.ContextType != ContextType.ScopeDocument)
  473. {
  474. ThrowInvalidContextType("ReadEndDocument", _context.ContextType, ContextType.Document, ContextType.ScopeDocument);
  475. }
  476. if (State == BsonReaderState.Type)
  477. {
  478. ReadBsonType(); // will set state to EndOfDocument if at end of document
  479. }
  480. if (State != BsonReaderState.EndOfDocument)
  481. {
  482. ThrowInvalidState("ReadEndDocument", BsonReaderState.EndOfDocument);
  483. }
  484. _context = _context.PopContext();
  485. if (_context != null && _context.ContextType == ContextType.JavaScriptWithScope)
  486. {
  487. _context = _context.PopContext(); // JavaScriptWithScope
  488. VerifyToken("}"); // outermost closing bracket for JavaScriptWithScope
  489. }
  490. switch (_context.ContextType)
  491. {
  492. case ContextType.Array: State = BsonReaderState.Type; break;
  493. case ContextType.Document: State = BsonReaderState.Type; break;
  494. case ContextType.TopLevel: State = BsonReaderState.Initial; break;
  495. default: throw new BsonInternalException("Unexpected ContextType");
  496. }
  497. if (_context.ContextType == ContextType.Array || _context.ContextType == ContextType.Document)
  498. {
  499. var commaToken = PopToken();
  500. if (commaToken.Type != JsonTokenType.Comma)
  501. {
  502. PushToken(commaToken);
  503. }
  504. }
  505. }
  506. /// <summary>
  507. /// Reads a BSON Int32 from the reader.
  508. /// </summary>
  509. /// <returns>An Int32.</returns>
  510. public override int ReadInt32()
  511. {
  512. if (Disposed) { ThrowObjectDisposedException(); }
  513. VerifyBsonType("ReadInt32", BsonType.Int32);
  514. State = GetNextState();
  515. return _currentValue.AsInt32;
  516. }
  517. /// <summary>
  518. /// Reads a BSON Int64 from the reader.
  519. /// </summary>
  520. /// <returns>An Int64.</returns>
  521. public override long ReadInt64()
  522. {
  523. if (Disposed) { ThrowObjectDisposedException(); }
  524. VerifyBsonType("ReadInt64", BsonType.Int64);
  525. State = GetNextState();
  526. return _currentValue.AsInt64;
  527. }
  528. /// <summary>
  529. /// Reads a BSON JavaScript from the reader.
  530. /// </summary>
  531. /// <returns>A string.</returns>
  532. public override string ReadJavaScript()
  533. {
  534. if (Disposed) { ThrowObjectDisposedException(); }
  535. VerifyBsonType("ReadJavaScript", BsonType.JavaScript);
  536. State = GetNextState();
  537. return _currentValue.AsString;
  538. }
  539. /// <summary>
  540. /// Reads a BSON JavaScript with scope from the reader (call ReadStartDocument next to read the scope).
  541. /// </summary>
  542. /// <returns>A string.</returns>
  543. public override string ReadJavaScriptWithScope()
  544. {
  545. if (Disposed) { ThrowObjectDisposedException(); }
  546. VerifyBsonType("ReadJavaScriptWithScope", BsonType.JavaScriptWithScope);
  547. _context = new JsonReaderContext(_context, ContextType.JavaScriptWithScope);
  548. State = BsonReaderState.ScopeDocument;
  549. return _currentValue.AsString;
  550. }
  551. /// <summary>
  552. /// Reads a BSON MaxKey from the reader.
  553. /// </summary>
  554. public override void ReadMaxKey()
  555. {
  556. if (Disposed) { ThrowObjectDisposedException(); }
  557. VerifyBsonType("ReadMaxKey", BsonType.MaxKey);
  558. State = GetNextState();
  559. }
  560. /// <summary>
  561. /// Reads a BSON MinKey from the reader.
  562. /// </summary>
  563. public override void ReadMinKey()
  564. {
  565. if (Disposed) { ThrowObjectDisposedException(); }
  566. VerifyBsonType("ReadMinKey", BsonType.MinKey);
  567. State = GetNextState();
  568. }
  569. /// <summary>
  570. /// Reads the name of an element from the reader.
  571. /// </summary>
  572. /// <param name="nameDecoder">The name decoder.</param>
  573. /// <returns>
  574. /// The name of the element.
  575. /// </returns>
  576. public override string ReadName(INameDecoder nameDecoder)
  577. {
  578. if (nameDecoder == null)
  579. {
  580. throw new ArgumentNullException("nameDecoder");
  581. }
  582. if (Disposed) { ThrowObjectDisposedException(); }
  583. if (State == BsonReaderState.Type)
  584. {
  585. ReadBsonType();
  586. }
  587. if (State != BsonReaderState.Name)
  588. {
  589. ThrowInvalidState("ReadName", BsonReaderState.Name);
  590. }
  591. nameDecoder.Inform(CurrentName);
  592. State = BsonReaderState.Value;
  593. return CurrentName;
  594. }
  595. /// <summary>
  596. /// Reads a BSON null from the reader.
  597. /// </summary>
  598. public override void ReadNull()
  599. {
  600. if (Disposed) { ThrowObjectDisposedException(); }
  601. VerifyBsonType("ReadNull", BsonType.Null);
  602. State = GetNextState();
  603. }
  604. /// <summary>
  605. /// Reads a BSON ObjectId from the reader.
  606. /// </summary>
  607. /// <returns>An ObjectId.</returns>
  608. public override ObjectId ReadObjectId()
  609. {
  610. if (Disposed) { ThrowObjectDisposedException(); }
  611. VerifyBsonType("ReadObjectId", BsonType.ObjectId);
  612. State = GetNextState();
  613. return _currentValue.AsObjectId;
  614. }
  615. /// <summary>
  616. /// Reads a BSON regular expression from the reader.
  617. /// </summary>
  618. /// <returns>A BsonRegularExpression.</returns>
  619. public override BsonRegularExpression ReadRegularExpression()
  620. {
  621. if (Disposed) { ThrowObjectDisposedException(); }
  622. VerifyBsonType("ReadRegularExpression", BsonType.RegularExpression);
  623. State = GetNextState();
  624. return _currentValue.AsBsonRegularExpression;
  625. }
  626. /// <summary>
  627. /// Reads the start of a BSON array.
  628. /// </summary>
  629. public override void ReadStartArray()
  630. {
  631. if (Disposed) { ThrowObjectDisposedException(); }
  632. VerifyBsonType("ReadStartArray", BsonType.Array);
  633. _context = new JsonReaderContext(_context, ContextType.Array);
  634. State = BsonReaderState.Type;
  635. }
  636. /// <summary>
  637. /// Reads the start of a BSON document.
  638. /// </summary>
  639. public override void ReadStartDocument()
  640. {
  641. if (Disposed) { ThrowObjectDisposedException(); }
  642. VerifyBsonType("ReadStartDocument", BsonType.Document);
  643. _context = new JsonReaderContext(_context, ContextType.Document);
  644. State = BsonReaderState.Type;
  645. }
  646. /// <summary>
  647. /// Reads a BSON string from the reader.
  648. /// </summary>
  649. /// <returns>A String.</returns>
  650. public override string ReadString()
  651. {
  652. if (Disposed) { ThrowObjectDisposedException(); }
  653. VerifyBsonType("ReadString", BsonType.String);
  654. State = GetNextState();
  655. return _currentValue.AsString;
  656. }
  657. /// <summary>
  658. /// Reads a BSON symbol from the reader.
  659. /// </summary>
  660. /// <returns>A string.</returns>
  661. public override string ReadSymbol()
  662. {
  663. if (Disposed) { ThrowObjectDisposedException(); }
  664. VerifyBsonType("ReadSymbol", BsonType.Symbol);
  665. State = GetNextState();
  666. return _currentValue.AsString;
  667. }
  668. /// <summary>
  669. /// Reads a BSON timestamp from the reader.
  670. /// </summary>
  671. /// <returns>The combined timestamp/increment.</returns>
  672. public override long ReadTimestamp()
  673. {
  674. if (Disposed) { ThrowObjectDisposedException(); }
  675. VerifyBsonType("ReadTimestamp", BsonType.Timestamp);
  676. State = GetNextState();
  677. var timestamp = _currentValue.AsBsonTimestamp;
  678. return timestamp.Value;
  679. }
  680. /// <summary>
  681. /// Reads a BSON undefined from the reader.
  682. /// </summary>
  683. public override void ReadUndefined()
  684. {
  685. if (Disposed) { ThrowObjectDisposedException(); }
  686. VerifyBsonType("ReadUndefined", BsonType.Undefined);
  687. State = GetNextState();
  688. }
  689. /// <summary>
  690. /// Returns the reader to previously bookmarked position and state.
  691. /// </summary>
  692. /// <param name="bookmark">The bookmark.</param>
  693. public override void ReturnToBookmark(BsonReaderBookmark bookmark)
  694. {
  695. if (Disposed) { ThrowObjectDisposedException(); }
  696. var jsonReaderBookmark = (JsonReaderBookmark)bookmark;
  697. State = jsonReaderBookmark.State;
  698. CurrentBsonType = jsonReaderBookmark.CurrentBsonType;
  699. CurrentName = jsonReaderBookmark.CurrentName;
  700. _context = jsonReaderBookmark.CloneContext();
  701. _currentToken = jsonReaderBookmark.CurrentToken;
  702. _currentValue = jsonReaderBookmark.CurrentValue;
  703. _pushedToken = jsonReaderBookmark.PushedToken;
  704. _buffer.Position = jsonReaderBookmark.Position;
  705. }
  706. /// <summary>
  707. /// Skips the name (reader must be positioned on a name).
  708. /// </summary>
  709. public override void SkipName()
  710. {
  711. if (Disposed) { ThrowObjectDisposedException(); }
  712. if (State != BsonReaderState.Name)
  713. {
  714. ThrowInvalidState("SkipName", BsonReaderState.Name);
  715. }
  716. State = BsonReaderState.Value;
  717. }
  718. /// <summary>
  719. /// Skips the value (reader must be positioned on a value).
  720. /// </summary>
  721. public override void SkipValue()
  722. {
  723. if (Disposed) { ThrowObjectDisposedException(); }
  724. if (State != BsonReaderState.Value)
  725. {
  726. ThrowInvalidState("SkipValue", BsonReaderState.Value);
  727. }
  728. switch (CurrentBsonType)
  729. {
  730. case BsonType.Array:
  731. ReadStartArray();
  732. while (ReadBsonType() != BsonType.EndOfDocument)
  733. {
  734. SkipValue();
  735. }
  736. ReadEndArray();
  737. break;
  738. case BsonType.Binary:
  739. ReadBinaryData();
  740. break;
  741. case BsonType.Boolean:
  742. ReadBoolean();
  743. break;
  744. case BsonType.DateTime:
  745. ReadDateTime();
  746. break;
  747. case BsonType.Document:
  748. ReadStartDocument();
  749. while (ReadBsonType() != BsonType.EndOfDocument)
  750. {
  751. SkipName();
  752. SkipValue();
  753. }
  754. ReadEndDocument();
  755. break;
  756. case BsonType.Double:
  757. ReadDouble();
  758. break;
  759. case BsonType.Int32:
  760. ReadInt32();
  761. break;
  762. case BsonType.Int64:
  763. ReadInt64();
  764. break;
  765. case BsonType.JavaScript:
  766. ReadJavaScript();
  767. break;
  768. case BsonType.JavaScriptWithScope:
  769. ReadJavaScriptWithScope();
  770. ReadStartDocument();
  771. while (ReadBsonType() != BsonType.EndOfDocument)
  772. {
  773. SkipName();
  774. SkipValue();
  775. }
  776. ReadEndDocument();
  777. break;
  778. case BsonType.MaxKey:
  779. ReadMaxKey();
  780. break;
  781. case BsonType.MinKey:
  782. ReadMinKey();
  783. break;
  784. case BsonType.Null:
  785. ReadNull();
  786. break;
  787. case BsonType.ObjectId:
  788. ReadObjectId();
  789. break;
  790. case BsonType.RegularExpression:
  791. ReadRegularExpression();
  792. break;
  793. case BsonType.String:
  794. ReadString();
  795. break;
  796. case BsonType.Symbol:
  797. ReadSymbol();
  798. break;
  799. case BsonType.Timestamp:
  800. ReadTimestamp();
  801. break;
  802. case BsonType.Undefined:
  803. ReadUndefined();
  804. break;
  805. default:
  806. throw new BsonInternalException("Invalid BsonType.");
  807. }
  808. }
  809. // protected methods
  810. /// <summary>
  811. /// Disposes of any resources used by the reader.
  812. /// </summary>
  813. /// <param name="disposing">True if called from Dispose.</param>
  814. protected override void Dispose(bool disposing)
  815. {
  816. if (disposing)
  817. {
  818. try
  819. {
  820. Close();
  821. }
  822. catch { } // ignore exceptions
  823. }
  824. base.Dispose(disposing);
  825. }
  826. // private methods
  827. private string FormatInvalidTokenMessage(JsonToken token)
  828. {
  829. return string.Format("Invalid JSON token: '{0}'", token.Lexeme);
  830. }
  831. private string FormatJavaScriptDateTimeString(DateTime dateTime)
  832. {
  833. var utc = BsonUtils.ToUniversalTime(dateTime);
  834. var local = BsonUtils.ToLocalTime(utc);
  835. var offset = local - utc;
  836. var offsetSign = "+";
  837. if (offset < TimeSpan.Zero)
  838. {
  839. offset = -offset;
  840. offsetSign = "-";
  841. }
  842. var timeZone = TimeZoneInfo.Local;
  843. var timeZoneName = local.IsDaylightSavingTime() ? timeZone.DaylightName : timeZone.StandardName;
  844. var dateTimeString = string.Format(
  845. "{0} GMT{1}{2:D2}{3:D2} ({4})",
  846. local.ToString("ddd MMM dd yyyy HH:mm:ss"), offsetSign, offset.Hours, offset.Minutes, timeZoneName);
  847. return dateTimeString;
  848. }
  849. private BsonReaderState GetNextState()
  850. {
  851. switch (_context.ContextType)
  852. {
  853. case ContextType.Array:
  854. case ContextType.Document:
  855. return BsonReaderState.Type;
  856. case ContextType.TopLevel:
  857. return BsonReaderState.Initial;
  858. default:
  859. throw new BsonInternalException("Unexpected ContextType.");
  860. }
  861. }
  862. private BsonValue ParseBinDataConstructor()
  863. {
  864. VerifyToken("(");
  865. var subTypeToken = PopToken();
  866. if (subTypeToken.Type != JsonTokenType.Int32)
  867. {
  868. var message = string.Format("JSON reader expected a binary subtype but found '{0}'.", subTypeToken.Lexeme);
  869. throw new FormatException(message);
  870. }
  871. VerifyToken(",");
  872. var bytesToken = PopToken();
  873. if (bytesToken.Type != JsonTokenType.String)
  874. {
  875. var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
  876. throw new FormatException(message);
  877. }
  878. VerifyToken(")");
  879. var bytes = Convert.FromBase64String(bytesToken.StringValue);
  880. var subType = (BsonBinarySubType)subTypeToken.Int32Value;
  881. GuidRepresentation guidRepresentation;
  882. switch (subType)
  883. {
  884. case BsonBinarySubType.UuidLegacy: guidRepresentation = _jsonReaderSettings.GuidRepresentation; break;
  885. case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
  886. default: guidRepresentation = GuidRepresentation.Unspecified; break;
  887. }
  888. return new BsonBinaryData(bytes, subType, guidRepresentation);
  889. }
  890. private BsonValue ParseBinDataExtendedJson()
  891. {
  892. VerifyToken(":");
  893. var bytesToken = PopToken();
  894. if (bytesToken.Type != JsonTokenType.String)
  895. {
  896. var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
  897. throw new FormatException(message);
  898. }
  899. var bytes = Convert.FromBase64String(bytesToken.StringValue);
  900. VerifyToken(",");
  901. VerifyString("$type");
  902. VerifyToken(":");
  903. BsonBinarySubType subType;
  904. var subTypeToken = PopToken();
  905. if (subTypeToken.Type == JsonTokenType.String)
  906. {
  907. subType = (BsonBinarySubType)Convert.ToInt32(subTypeToken.StringValue, 16);
  908. }
  909. else if (subTypeToken.Type == JsonTokenType.Int32 || subTypeToken.Type == JsonTokenType.Int64)
  910. {
  911. subType = (BsonBinarySubType)subTypeToken.Int32Value;
  912. }
  913. else
  914. {
  915. var message = string.Format("JSON reader expected a string or integer but found '{0}'.", subTypeToken.Lexeme);
  916. throw new FormatException(message);
  917. }
  918. VerifyToken("}");
  919. GuidRepresentation guidRepresentation;
  920. switch (subType)
  921. {
  922. case BsonBinarySubType.UuidLegacy: guidRepresentation = _jsonReaderSettings.GuidRepresentation; break;
  923. case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
  924. default: guidRepresentation = GuidRepresentation.Unspecified; break;
  925. }
  926. return new BsonBinaryData(bytes, subType, guidRepresentation);
  927. }
  928. private BsonValue ParseHexDataConstructor()
  929. {
  930. VerifyToken("(");
  931. var subTypeToken = PopToken();
  932. if (subTypeToken.Type != JsonTokenType.Int32)
  933. {
  934. var message = string.Format("JSON reader expected a binary subtype but found '{0}'.", subTypeToken.Lexeme);
  935. throw new FormatException(message);
  936. }
  937. VerifyToken(",");
  938. var bytesToken = PopToken();
  939. if (bytesToken.Type != JsonTokenType.String)
  940. {
  941. var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
  942. throw new FormatException(message);
  943. }
  944. VerifyToken(")");
  945. var bytes = BsonUtils.ParseHexString(bytesToken.StringValue);
  946. var subType = (BsonBinarySubType)subTypeToken.Int32Value;
  947. GuidRepresentation guidRepresentation;
  948. switch (subType)
  949. {
  950. case BsonBinarySubType.UuidLegacy: guidRepresentation = _jsonReaderSettings.GuidRepresentation; break;
  951. case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
  952. default: guidRepresentation = GuidRepresentation.Unspecified; break;
  953. }
  954. return new BsonBinaryData(bytes, subType, guidRepresentation);
  955. }
  956. private BsonType ParseJavaScriptExtendedJson(out BsonValue value)
  957. {
  958. VerifyToken(":");
  959. var codeToken = PopToken();
  960. if (codeToken.Type != JsonTokenType.String)
  961. {
  962. var message = string.Format("JSON reader expected a string but found '{0}'.", codeToken.Lexeme);
  963. throw new FormatException(message);
  964. }
  965. var nextToken = PopToken();
  966. switch (nextToken.Type)
  967. {
  968. case JsonTokenType.Comma:
  969. VerifyString("$scope");
  970. VerifyToken(":");
  971. State = BsonReaderState.Value;
  972. value = codeToken.StringValue;
  973. return BsonType.JavaScriptWithScope;
  974. case JsonTokenType.EndObject:
  975. value = codeToken.StringValue;
  976. return BsonType.JavaScript;
  977. default:
  978. var message = string.Format("JSON reader expected ',' or '}}' but found '{0}'.", codeToken.Lexeme);
  979. throw new FormatException(message);
  980. }
  981. }
  982. private BsonValue ParseISODateTimeConstructor()
  983. {
  984. VerifyToken("(");
  985. var valueToken = PopToken();
  986. if (valueToken.Type != JsonTokenType.String)
  987. {
  988. var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
  989. throw new FormatException(message);
  990. }
  991. VerifyToken(")");
  992. var value = valueToken.StringValue;
  993. string[] formats = null;
  994. if (!value.Contains(".") && value.Length < __fixedLengthIso8601Formats.Length)
  995. {
  996. formats = __fixedLengthIso8601Formats[value.Length];
  997. }
  998. if (formats == null)
  999. {
  1000. formats = __variableLengthIso8601Formats;
  1001. }
  1002. var utcDateTime = DateTime.ParseExact(value, formats, null, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
  1003. return new BsonDateTime(utcDateTime);
  1004. }
  1005. private BsonValue ParseDateTimeExtendedJson()
  1006. {
  1007. VerifyToken(":");
  1008. var valueToken = PopToken();
  1009. long millisecondsSinceEpoch;
  1010. if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
  1011. {
  1012. millisecondsSinceEpoch = valueToken.Int64Value;
  1013. }
  1014. else if (valueToken.Type == JsonTokenType.String)
  1015. {
  1016. DateTime dateTime;
  1017. var dateTimeStyles = DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal;
  1018. if (!DateTime.TryParse(valueToken.StringValue, CultureInfo.InvariantCulture, dateTimeStyles, out dateTime))
  1019. {
  1020. var message = string.Format("Invalid $date string: '{0}'.", valueToken.StringValue);
  1021. throw new FormatException(message);
  1022. }
  1023. millisecondsSinceEpoch = BsonUtils.ToMillisecondsSinceEpoch(dateTime);
  1024. }
  1025. else if (valueToken.Type == JsonTokenType.BeginObject)
  1026. {
  1027. VerifyToken("$numberLong");
  1028. VerifyToken(":");
  1029. var millisecondsSinceEpochToken = PopToken();
  1030. if (millisecondsSinceEpochToken.Type == JsonTokenType.String)
  1031. {
  1032. millisecondsSinceEpoch = long.Parse(millisecondsSinceEpochToken.StringValue, CultureInfo.InvariantCulture);
  1033. }
  1034. else if (millisecondsSinceEpochToken.Type == JsonTokenType.Int32 || millisecondsSinceEpochToken.Type == JsonTokenType.Int64)
  1035. {
  1036. millisecondsSinceEpoch = millisecondsSinceEpochToken.Int64Value;
  1037. }
  1038. else
  1039. {
  1040. var message = string.Format("JSON reader expected an integer or a string for {{ $date : {{ $numberLong : ... }} }} but found a '{0}'.", valueToken.Lexeme);
  1041. throw new FormatException(message);
  1042. }
  1043. VerifyToken("}");
  1044. }
  1045. else
  1046. {
  1047. var message = string.Format("JSON reader expected an ISO 8601 string, an integer, or {{ $numberLong : ... }} for $date but found a '{0}'.", valueToken.Lexeme);
  1048. throw new FormatException(message);
  1049. }
  1050. VerifyToken("}");
  1051. return new BsonDateTime(millisecondsSinceEpoch);
  1052. }
  1053. private BsonValue ParseDateTimeConstructor(bool withNew)
  1054. {
  1055. VerifyToken("(");
  1056. // Date when used without "new" behaves differently (JavaScript has some weird parts)
  1057. if (!withNew)
  1058. {
  1059. VerifyToken(")");
  1060. var dateTimeString = FormatJavaScriptDateTimeString(DateTime.UtcNow);
  1061. return new BsonString(dateTimeString);
  1062. }
  1063. var token = PopToken();
  1064. if (token.Lexeme == ")")
  1065. {
  1066. return new BsonDateTime(DateTime.UtcNow);
  1067. }
  1068. else if (token.Type == JsonTokenType.String)
  1069. {
  1070. VerifyToken(")");
  1071. var dateTimeString = token.StringValue;
  1072. var dateTime = ParseJavaScriptDateTimeString(dateTimeString);
  1073. return new BsonDateTime(dateTime);
  1074. }
  1075. else if (token.Type == JsonTokenType.Int32 || token.Type == JsonTokenType.Int64)
  1076. {
  1077. var args = new List<long>();
  1078. while (true)
  1079. {
  1080. args.Add(token.Int64Value);
  1081. token = PopToken();
  1082. if (token.Lexeme == ")")
  1083. {
  1084. break;
  1085. }
  1086. if (token.Lexeme != ",")
  1087. {
  1088. var message = string.Format("JSON reader expected a ',' or a ')' but found '{0}'.", token.Lexeme);
  1089. throw new FormatException(message);
  1090. }
  1091. token = PopToken();
  1092. if (token.Type != JsonTokenType.Int32 && token.Type != JsonTokenType.Int64)
  1093. {
  1094. var message = string.Format("JSON reader expected an integer but found '{0}'.", token.Lexeme);
  1095. throw new FormatException(message);
  1096. }
  1097. }
  1098. switch (args.Count)
  1099. {
  1100. case 1:
  1101. return new BsonDateTime(args[0]);
  1102. case 3:
  1103. case 4:
  1104. case 5:
  1105. case 6:
  1106. case 7:
  1107. var year = (int)args[0];
  1108. var month = (int)args[1] + 1; // JavaScript starts at 0 but .NET starts at 1
  1109. var day = (int)args[2];
  1110. var hours = (args.Count >= 4) ? (int)args[3] : 0;
  1111. var minutes = (args.Count >= 5) ? (int)args[4] : 0;
  1112. var seconds = (args.Count >= 6) ? (int)args[5] : 0;
  1113. var milliseconds = (args.Count == 7) ? (int)args[6] : 0;
  1114. var dateTime = new DateTime(year, month, day, hours, minutes, seconds, milliseconds, DateTimeKind.Utc);
  1115. return new BsonDateTime(dateTime);
  1116. default:
  1117. var message = string.Format("JSON reader expected 1 or 3-7 integers but found {0}.", args.Count);
  1118. throw new FormatException(message);
  1119. }
  1120. }
  1121. else
  1122. {
  1123. var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", token.Lexeme);
  1124. throw new FormatException(message);
  1125. }
  1126. }
  1127. private BsonType ParseExtendedJson()
  1128. {
  1129. var nameToken = PopToken();
  1130. if (nameToken.Type == JsonTokenType.String || nameToken.Type == JsonTokenType.UnquotedString)
  1131. {
  1132. switch (nameToken.StringValue)
  1133. {
  1134. case "$binary": _currentValue = ParseBinDataExtendedJson(); return BsonType.Binary;
  1135. case "$code": return ParseJavaScriptExtendedJson(out _currentValue);
  1136. case "$date": _currentValue = ParseDateTimeExtendedJson(); return BsonType.DateTime;
  1137. case "$maxkey": case "$maxKey": _currentValue = ParseMaxKeyExtendedJson(); return BsonType.MaxKey;
  1138. case "$minkey": case "$minKey": _currentValue = ParseMinKeyExtendedJson(); return BsonType.MinKey;
  1139. case "$numberDecimal": _currentValue = ParseNumberDecimalExtendedJson(); return BsonType.Decimal128;
  1140. case "$numberLong": _currentValue = ParseNumberLongExtendedJson(); return BsonType.Int64;
  1141. case "$oid": _currentValue = ParseObjectIdExtendedJson(); return BsonType.ObjectId;
  1142. case "$regex": _currentValue = ParseRegularExpressionExtendedJson(); return BsonType.RegularExpression;
  1143. case "$symbol": _currentValue = ParseSymbolExtendedJson(); return BsonType.Symbol;
  1144. case "$timestamp": _currentValue = ParseTimestampExtendedJson(); return BsonType.Timestamp;
  1145. case "$undefined": _currentValue = ParseUndefinedExtendedJson(); return BsonType.Undefined;
  1146. }
  1147. }
  1148. PushToken(nameToken);
  1149. return BsonType.Document;
  1150. }
  1151. private DateTime ParseJavaScriptDateTimeString(string dateTimeString)
  1152. {
  1153. // if DateTime.TryParse succeeds we're done, otherwise assume it's an RFC 822 formatted DateTime string
  1154. DateTime dateTime;
  1155. if (DateTime.TryParse(dateTimeString, out dateTime))
  1156. {
  1157. return dateTime;
  1158. }
  1159. else
  1160. {
  1161. var rfc822DateTimePattern =
  1162. @"^((?<dayOfWeek>(Mon|Tue|Wed|Thu|Fri|Sat|Sun)), )?" +
  1163. @"(?<day>\d{1,2}) +" +
  1164. @"(?<monthName>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " +
  1165. @"(?<year>\d{2}|\d{4}) " +
  1166. @"(?<hour>\d{1,2}):" +
  1167. @"(?<minutes>\d{1,2}):" +
  1168. @"(?<seconds>\d{1,2}(.\d{1,7})?) " +
  1169. @"(?<zone>UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-Z]|([+-]\d{4}))$";
  1170. var match = Regex.Match(dateTimeString, rfc822DateTimePattern);
  1171. if (match.Success)
  1172. {
  1173. var day = int.Parse(match.Groups["day"].Value);
  1174. int month;
  1175. var monthName = match.Groups["monthName"].Value;
  1176. switch (monthName)
  1177. {
  1178. case "Jan": month = 1; break;
  1179. case "Feb": month = 2; break;
  1180. case "Mar": month = 3; break;
  1181. case "Apr": month = 4; break;
  1182. case "May": month = 5; break;
  1183. case "Jun": month = 6; break;
  1184. case "Jul": month = 7; break;
  1185. case "Aug": month = 8; break;
  1186. case "Sep": month = 9; break;
  1187. case "Oct": month = 10; break;
  1188. case "Nov": month = 11; break;
  1189. case "Dec": month = 12; break;
  1190. default:
  1191. var message = string.Format("\"{0}\" is not a valid RFC 822 month name.", monthName);
  1192. throw new FormatException(message);
  1193. }
  1194. var yearString = match.Groups["year"].Value;
  1195. int year = int.Parse(yearString);
  1196. if (yearString.Length == 2)
  1197. {
  1198. year += 2000;
  1199. if (year - DateTime.UtcNow.Year >= 19) { year -= 100; }
  1200. }
  1201. var hour = int.Parse(match.Groups["hour"].Value);
  1202. var minutes = int.Parse(match.Groups["minutes"].Value);
  1203. var secondsString = match.Groups["seconds"].Value;
  1204. int seconds;
  1205. double milliseconds;
  1206. if (secondsString.IndexOf('.') != -1)
  1207. {
  1208. var timeSpan = TimeSpan.FromSeconds(double.Parse(secondsString));
  1209. seconds = timeSpan.Seconds;
  1210. milliseconds = timeSpan.TotalMilliseconds - seconds * 1000;
  1211. }
  1212. else
  1213. {
  1214. seconds = int.Parse(secondsString);
  1215. milliseconds = 0;
  1216. }
  1217. dateTime = new DateTime(year, month, day, hour, minutes, seconds, DateTimeKind.Utc).AddMilliseconds(milliseconds);
  1218. // check day of week before converting to UTC
  1219. var dayOfWeekString = match.Groups["dayOfWeek"].Value;
  1220. if (dayOfWeekString != "")
  1221. {
  1222. DayOfWeek dayOfWeek;
  1223. switch (dayOfWeekString)
  1224. {
  1225. case "Mon": dayOfWeek = DayOfWeek.Monday; break;
  1226. case "Tue": dayOfWeek = DayOfWeek.Tuesday; break;
  1227. case "Wed": dayOfWeek = DayOfWeek.Wednesday; break;
  1228. case "Thu": dayOfWeek = DayOfWeek.Thursday; break;
  1229. case "Fri": dayOfWeek = DayOfWeek.Friday; break;
  1230. case "Sat": dayOfWeek = DayOfWeek.Saturday; break;
  1231. case "Sun": dayOfWeek = DayOfWeek.Sunday; break;
  1232. default:
  1233. var message = string.Format("\"{0}\" is not a valid RFC 822 day name.", dayOfWeekString);
  1234. throw new FormatException(message);
  1235. }
  1236. if (dateTime.DayOfWeek != dayOfWeek)
  1237. {
  1238. var message = string.Format("\"{0}\" is not the right day of the week for {1}.", dayOfWeekString, dateTime.ToString("o"));
  1239. throw new FormatException(message);
  1240. }
  1241. }
  1242. TimeSpan offset;
  1243. var zone = match.Groups["zone"].Value;
  1244. switch (zone)
  1245. {
  1246. case "UT": case "GMT": case "Z": offset = TimeSpan.Zero; break;
  1247. case "EST": offset = TimeSpan.FromHours(-5); break;
  1248. case "EDT": offset = TimeSpan.FromHours(-4); break;
  1249. case "CST": offset = TimeSpan.FromHours(-6); break;
  1250. case "CDT": offset = TimeSpan.FromHours(-5); break;
  1251. case "MST": offset = TimeSpan.FromHours(-7); break;
  1252. case "MDT": offset = TimeSpan.FromHours(-6); break;
  1253. case "PST": offset = TimeSpan.FromHours(-8); break;
  1254. case "PDT": offset = TimeSpan.FromHours(-7); break;
  1255. case "A": offset = TimeSpan.FromHours(-1); break;
  1256. case "B": offset = TimeSpan.FromHours(-2); break;
  1257. case "C": offset = TimeSpan.FromHours(-3); break;
  1258. case "D": offset = TimeSpan.FromHours(-4); break;
  1259. case "E": offset = TimeSpan.FromHours(-5); break;
  1260. case "F": offset = TimeSpan.FromHours(-6); break;
  1261. case "G": offset = TimeSpan.FromHours(-7); break;
  1262. case "H": offset = TimeSpan.FromHours(-8); break;
  1263. case "I": offset = TimeSpan.FromHours(-9); break;
  1264. case "K": offset = TimeSpan.FromHours(-10); break;
  1265. case "L": offset = TimeSpan.FromHours(-11); break;
  1266. case "M": offset = TimeSpan.FromHours(-12); break;
  1267. case "N": offset = TimeSpan.FromHours(1); break;
  1268. case "O": offset = TimeSpan.FromHours(2); break;
  1269. case "P": offset = TimeSpan.FromHours(3); break;
  1270. case "Q": offset = TimeSpan.FromHours(4); break;
  1271. case "R": offset = TimeSpan.FromHours(5); break;
  1272. case "S": offset = TimeSpan.FromHours(6); break;
  1273. case "T": offset = TimeSpan.FromHours(7); break;
  1274. case "U": offset = TimeSpan.FromHours(8); break;
  1275. case "V": offset = TimeSpan.FromHours(9); break;
  1276. case "W": offset = TimeSpan.FromHours(10); break;
  1277. case "X": offset = TimeSpan.FromHours(11); break;
  1278. case "Y": offset = TimeSpan.FromHours(12); break;
  1279. default:
  1280. var offsetSign = zone.Substring(0);
  1281. var offsetHours = zone.Substring(1, 2);
  1282. var offsetMinutes = zone.Substring(3, 2);
  1283. offset = TimeSpan.FromHours(int.Parse(offsetHours)) + TimeSpan.FromMinutes(int.Parse(offsetMinutes));
  1284. if (offsetSign == "-")
  1285. {
  1286. offset = -offset;
  1287. }
  1288. break;
  1289. }
  1290. return dateTime.Add(-offset);
  1291. }
  1292. else
  1293. {
  1294. var message = string.Format("The DateTime string \"{0}\" is not a valid DateTime string for either .NET or JavaScript.", dateTimeString);
  1295. throw new FormatException(message);
  1296. }
  1297. }
  1298. }
  1299. private BsonValue ParseMaxKeyExtendedJson()
  1300. {
  1301. VerifyToken(":");
  1302. VerifyToken("1");
  1303. VerifyToken("}");
  1304. return BsonMaxKey.Value;
  1305. }
  1306. private BsonValue ParseMinKeyExtendedJson()
  1307. {
  1308. VerifyToken(":");
  1309. VerifyToken("1");
  1310. VerifyToken("}");
  1311. return BsonMinKey.Value;
  1312. }
  1313. private BsonType ParseNew(out BsonValue value)
  1314. {
  1315. var typeToken = PopToken();
  1316. if (typeToken.Type != JsonTokenType.UnquotedString)
  1317. {
  1318. var message = string.Format("JSON reader expected a type name but found '{0}'.", typeToken.Lexeme);
  1319. throw new FormatException(message);
  1320. }
  1321. switch (typeToken.Lexeme)
  1322. {
  1323. case "BinData":
  1324. value = ParseBinDataConstructor();
  1325. return BsonType.Binary;
  1326. case "Date":
  1327. value = ParseDateTimeConstructor(true); // withNew = true
  1328. return BsonType.DateTime;
  1329. case "HexData":
  1330. value = ParseHexDataConstructor();
  1331. return BsonType.Binary;
  1332. case "ISODate":
  1333. value = ParseISODateTimeConstructor();
  1334. return BsonType.DateTime;
  1335. case "NumberDecimal":
  1336. value = ParseNumberDecimalConstructor();
  1337. return BsonType.Decimal128;
  1338. case "NumberInt":
  1339. value = ParseNumberConstructor();
  1340. return BsonType.Int32;
  1341. case "NumberLong":
  1342. value = ParseNumberLongConstructor();
  1343. return BsonType.Int64;
  1344. case "ObjectId":
  1345. value = ParseObjectIdConstructor();
  1346. return BsonType.ObjectId;
  1347. case "RegExp":
  1348. value = ParseRegularExpressionConstructor();
  1349. return BsonType.RegularExpression;
  1350. case "Timestamp":
  1351. value = ParseTimestampConstructor();
  1352. return BsonType.Timestamp;
  1353. case "UUID":
  1354. case "GUID":
  1355. case "CSUUID":
  1356. case "CSGUID":
  1357. case "JUUID":
  1358. case "JGUID":
  1359. case "PYUUID":
  1360. case "PYGUID":
  1361. value = ParseUUIDConstructor(typeToken.Lexeme);
  1362. return BsonType.Binary;
  1363. default:
  1364. var message = string.Format("JSON reader expected a type name but found '{0}'.", typeToken.Lexeme);
  1365. throw new FormatException(message);
  1366. }
  1367. }
  1368. private BsonValue ParseNumberConstructor()
  1369. {
  1370. VerifyToken("(");
  1371. var valueToken = PopToken();
  1372. int value;
  1373. if (valueToken.IsNumber)
  1374. {
  1375. value = valueToken.Int32Value;
  1376. }
  1377. else if (valueToken.Type == JsonTokenType.String)
  1378. {
  1379. value = int.Parse(valueToken.StringValue);
  1380. }
  1381. else
  1382. {
  1383. var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
  1384. throw new FormatException(message);
  1385. }
  1386. VerifyToken(")");
  1387. return (BsonInt32)value;
  1388. }
  1389. private BsonValue ParseNumberDecimalConstructor()
  1390. {
  1391. VerifyToken("(");
  1392. var valueToken = PopToken();
  1393. Decimal128 value;
  1394. if (valueToken.Type == JsonTokenType.String)
  1395. {
  1396. value = Decimal128.Parse(valueToken.StringValue);
  1397. }
  1398. else if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
  1399. {
  1400. value = new Decimal128(valueToken.Int64Value);
  1401. }
  1402. else
  1403. {
  1404. var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
  1405. throw new FormatException(message);
  1406. }
  1407. VerifyToken(")");
  1408. return (BsonDecimal128)value;
  1409. }
  1410. private BsonValue ParseNumberLongConstructor()
  1411. {
  1412. VerifyToken("(");
  1413. var valueToken = PopToken();
  1414. long value;
  1415. if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
  1416. {
  1417. value = valueToken.Int64Value;
  1418. }
  1419. else if (valueToken.Type == JsonTokenType.String)
  1420. {
  1421. value = long.Parse(valueToken.StringValue);
  1422. }
  1423. else
  1424. {
  1425. var message = string.Format("JSON reader expected an integer or a string but found '{0}'.", valueToken.Lexeme);
  1426. throw new FormatException(message);
  1427. }
  1428. VerifyToken(")");
  1429. return (BsonInt64)value;
  1430. }
  1431. private BsonValue ParseNumberDecimalExtendedJson()
  1432. {
  1433. VerifyToken(":");
  1434. Decimal128 value;
  1435. var valueToken = PopToken();
  1436. if (valueToken.Type == JsonTokenType.String)
  1437. {
  1438. value = Decimal128.Parse(valueToken.StringValue);
  1439. }
  1440. else if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
  1441. {
  1442. value = new Decimal128(valueToken.Int64Value);
  1443. }
  1444. else
  1445. {
  1446. var message = string.Format("JSON reader expected a string or an integer but found '{0}'.", valueToken.Lexeme);
  1447. throw new FormatException(message);
  1448. }
  1449. VerifyToken("}");
  1450. return (BsonDecimal128)value;
  1451. }
  1452. private BsonValue ParseNumberLongExtendedJson()
  1453. {
  1454. VerifyToken(":");
  1455. long value;
  1456. var valueToken = PopToken();
  1457. if (valueToken.Type == JsonTokenType.String)
  1458. {
  1459. value = long.Parse(valueToken.StringValue, CultureInfo.InvariantCulture);
  1460. }
  1461. else if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
  1462. {
  1463. value = valueToken.Int64Value;
  1464. }
  1465. else
  1466. {
  1467. var message = string.Format("JSON reader expected a string or an integer but found '{0}'.", valueToken.Lexeme);
  1468. throw new FormatException(message);
  1469. }
  1470. VerifyToken("}");
  1471. return (BsonInt64)value;
  1472. }
  1473. private BsonValue ParseObjectIdConstructor()
  1474. {
  1475. VerifyToken("(");
  1476. var valueToken = PopToken();
  1477. if (valueToken.Type != JsonTokenType.String)
  1478. {
  1479. var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
  1480. throw new FormatException(message);
  1481. }
  1482. VerifyToken(")");
  1483. return new BsonObjectId(ObjectId.Parse(valueToken.StringValue));
  1484. }
  1485. private BsonValue ParseObjectIdExtendedJson()
  1486. {
  1487. VerifyToken(":");
  1488. var valueToken = PopToken();
  1489. if (valueToken.Type != JsonTokenType.String)
  1490. {
  1491. var message = string.Format("JSON reader expected a string but found '{0}'.", valueToken.Lexeme);
  1492. throw new FormatException(message);
  1493. }
  1494. VerifyToken("}");
  1495. return new BsonObjectId(ObjectId.Parse(valueToken.StringValue));
  1496. }
  1497. private BsonValue ParseRegularExpressionConstructor()
  1498. {
  1499. VerifyToken("(");
  1500. var patternToken = PopToken();
  1501. if (patternToken.Type != JsonTokenType.String)
  1502. {
  1503. var message = string.Format("JSON reader expected a string but found '{0}'.", patternToken.Lexeme);
  1504. throw new FormatException(message);
  1505. }
  1506. var options = "";
  1507. var commaToken = PopToken();
  1508. if (commaToken.Lexeme == ",")
  1509. {
  1510. var optionsToken = PopToken();
  1511. if (optionsToken.Type != JsonTokenType.String)
  1512. {
  1513. var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
  1514. throw new FormatException(message);
  1515. }
  1516. options = optionsToken.StringValue;
  1517. }
  1518. else
  1519. {
  1520. PushToken(commaToken);
  1521. }
  1522. VerifyToken(")");
  1523. return new BsonRegularExpression(patternToken.StringValue, options);
  1524. }
  1525. private BsonValue ParseRegularExpressionExtendedJson()
  1526. {
  1527. VerifyToken(":");
  1528. var patternToken = PopToken();
  1529. if (patternToken.Type != JsonTokenType.String)
  1530. {
  1531. var message = string.Format("JSON reader expected a string but found '{0}'.", patternToken.Lexeme);
  1532. throw new FormatException(message);
  1533. }
  1534. var options = "";
  1535. var commaToken = PopToken();
  1536. if (commaToken.Lexeme == ",")
  1537. {
  1538. VerifyString("$options");
  1539. VerifyToken(":");
  1540. var optionsToken = PopToken();
  1541. if (optionsToken.Type != JsonTokenType.String)
  1542. {
  1543. var message = string.Format("JSON reader expected a string but found '{0}'.", optionsToken.Lexeme);
  1544. throw new FormatException(message);
  1545. }
  1546. options = optionsToken.StringValue;
  1547. }
  1548. else
  1549. {
  1550. PushToken(commaToken);
  1551. }
  1552. VerifyToken("}");
  1553. return new BsonRegularExpression(patternToken.StringValue, options);
  1554. }
  1555. private BsonValue ParseSymbolExtendedJson()
  1556. {
  1557. VerifyToken(":");
  1558. var nameToken = PopToken();
  1559. if (nameToken.Type != JsonTokenType.String)
  1560. {
  1561. var message = string.Format("JSON reader expected a string but found '{0}'.", nameToken.Lexeme);
  1562. throw new FormatException(message);
  1563. }
  1564. VerifyToken("}");
  1565. return (BsonString)nameToken.StringValue; // will be converted to a BsonSymbol at a higher level
  1566. }
  1567. private BsonValue ParseTimestampConstructor()
  1568. {
  1569. VerifyToken("(");
  1570. int secondsSinceEpoch;
  1571. var secondsSinceEpochToken = PopToken();
  1572. if (secondsSinceEpochToken.IsNumber)
  1573. {
  1574. secondsSinceEpoch = secondsSinceEpochToken.Int32Value;
  1575. }
  1576. else
  1577. {
  1578. var message = string.Format("JSON reader expected a number but found '{0}'.", secondsSinceEpochToken.Lexeme);
  1579. throw new FormatException(message);
  1580. }
  1581. VerifyToken(",");
  1582. int increment;
  1583. var incrementToken = PopToken();
  1584. if (secondsSinceEpochToken.IsNumber)
  1585. {
  1586. increment = incrementToken.Int32Value;
  1587. }
  1588. else
  1589. {
  1590. var message = string.Format("JSON reader expected a number but found '{0}'.", secondsSinceEpochToken.Lexeme);
  1591. throw new FormatException(message);
  1592. }
  1593. VerifyToken(")");
  1594. return new BsonTimestamp(secondsSinceEpoch, increment);
  1595. }
  1596. private BsonValue ParseTimestampExtendedJson()
  1597. {
  1598. VerifyToken(":");
  1599. var nextToken = PopToken();
  1600. if (nextToken.Type == JsonTokenType.BeginObject)
  1601. {
  1602. return ParseTimestampExtendedJsonNewRepresentation();
  1603. }
  1604. else
  1605. {
  1606. return ParseTimestampExtendedJsonOldRepresentation(nextToken);
  1607. }
  1608. }
  1609. private BsonValue ParseTimestampExtendedJsonNewRepresentation()
  1610. {
  1611. VerifyString("t");
  1612. VerifyToken(":");
  1613. var secondsSinceEpochToken = PopToken();
  1614. int secondsSinceEpoch;
  1615. if (secondsSinceEpochToken.IsNumber)
  1616. {
  1617. secondsSinceEpoch = secondsSinceEpochToken.Int32Value;
  1618. }
  1619. else
  1620. {
  1621. var message = string.Format("JSON reader expected an integer but found '{0}'.", secondsSinceEpochToken.Lexeme);
  1622. throw new FormatException(message);
  1623. }
  1624. VerifyToken(",");
  1625. VerifyString("i");
  1626. VerifyToken(":");
  1627. var incrementToken = PopToken();
  1628. int increment;
  1629. if (incrementToken.IsNumber)
  1630. {
  1631. increment = incrementToken.Int32Value;
  1632. }
  1633. else
  1634. {
  1635. var message = string.Format("JSON reader expected an integer but found '{0}'.", incrementToken.Lexeme);
  1636. throw new FormatException(message);
  1637. }
  1638. VerifyToken("}");
  1639. VerifyToken("}");
  1640. return new BsonTimestamp(secondsSinceEpoch, increment);
  1641. }
  1642. private BsonValue ParseTimestampExtendedJsonOldRepresentation(JsonToken valueToken)
  1643. {
  1644. long value;
  1645. if (valueToken.Type == JsonTokenType.Int32 || valueToken.Type == JsonTokenType.Int64)
  1646. {
  1647. value = valueToken.Int64Value;
  1648. }
  1649. else if (valueToken.Type == JsonTokenType.UnquotedString && valueToken.Lexeme == "NumberLong")
  1650. {
  1651. value = ParseNumberLongConstructor().AsInt64;
  1652. }
  1653. else
  1654. {
  1655. var message = string.Format("JSON reader expected an integer but found '{0}'.", valueToken.Lexeme);
  1656. throw new FormatException(message);
  1657. }
  1658. VerifyToken("}");
  1659. return new BsonTimestamp(value);
  1660. }
  1661. private BsonValue ParseUndefinedExtendedJson()
  1662. {
  1663. VerifyToken(":");
  1664. VerifyToken("true");
  1665. VerifyToken("}");
  1666. return BsonMaxKey.Value;
  1667. }
  1668. private BsonValue ParseUUIDConstructor(string uuidConstructorName)
  1669. {
  1670. VerifyToken("(");
  1671. var bytesToken = PopToken();
  1672. if (bytesToken.Type != JsonTokenType.String)
  1673. {
  1674. var message = string.Format("JSON reader expected a string but found '{0}'.", bytesToken.Lexeme);
  1675. throw new FormatException(message);
  1676. }
  1677. VerifyToken(")");
  1678. var hexString = bytesToken.StringValue.Replace("{", "").Replace("}", "").Replace("-", "");
  1679. var bytes = BsonUtils.ParseHexString(hexString);
  1680. var guid = GuidConverter.FromBytes(bytes, GuidRepresentation.Standard);
  1681. GuidRepresentation guidRepresentation;
  1682. switch (uuidConstructorName)
  1683. {
  1684. case "CSUUID":
  1685. case "CSGUID":
  1686. guidRepresentation = GuidRepresentation.CSharpLegacy;
  1687. break;
  1688. case "JUUID":
  1689. case "JGUID":
  1690. guidRepresentation = GuidRepresentation.JavaLegacy;
  1691. break;
  1692. case "PYUUID":
  1693. case "PYGUID":
  1694. guidRepresentation = GuidRepresentation.PythonLegacy;
  1695. break;
  1696. case "UUID":
  1697. case "GUID":
  1698. guidRepresentation = GuidRepresentation.Standard;
  1699. break;
  1700. default:
  1701. throw new BsonInternalException("Unexpected uuidConstructorName");
  1702. }
  1703. bytes = GuidConverter.ToBytes(guid, guidRepresentation);
  1704. var subType = (guidRepresentation == GuidRepresentation.Standard) ? BsonBinarySubType.UuidStandard : BsonBinarySubType.UuidLegacy;
  1705. return new BsonBinaryData(bytes, subType, guidRepresentation);
  1706. }
  1707. private JsonToken PopToken()
  1708. {
  1709. if (_pushedToken != null)
  1710. {
  1711. var token = _pushedToken;
  1712. _pushedToken = null;
  1713. return token;
  1714. }
  1715. else
  1716. {
  1717. return JsonScanner.GetNextToken(_buffer);
  1718. }
  1719. }
  1720. private void PushToken(JsonToken token)
  1721. {
  1722. if (_pushedToken == null)
  1723. {
  1724. _pushedToken = token;
  1725. }
  1726. else
  1727. {
  1728. throw new BsonInternalException("There is already a pending token.");
  1729. }
  1730. }
  1731. private void VerifyString(string expectedString)
  1732. {
  1733. var token = PopToken();
  1734. if ((token.Type != JsonTokenType.String && token.Type != JsonTokenType.UnquotedString) || token.StringValue != expectedString)
  1735. {
  1736. var message = string.Format("JSON reader expected '{0}' but found '{1}'.", expectedString, token.StringValue);
  1737. throw new FormatException(message);
  1738. }
  1739. }
  1740. private void VerifyToken(string expectedLexeme)
  1741. {
  1742. var token = PopToken();
  1743. if (token.Lexeme != expectedLexeme)
  1744. {
  1745. var message = string.Format("JSON reader expected '{0}' but found '{1}'.", expectedLexeme, token.Lexeme);
  1746. throw new FormatException(message);
  1747. }
  1748. }
  1749. }
  1750. }