JsonReader.cs 85 KB

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