You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

825 lines
30 KiB

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Globalization;
  28. using System.Text;
  29. using System.IO;
  30. using Newtonsoft.Json.Serialization;
  31. using Newtonsoft.Json.Utilities;
  32. using Newtonsoft.Json.Linq;
  33. namespace Newtonsoft.Json.Bson
  34. {
  35. /// <summary>
  36. /// Represents a reader that provides fast, non-cached, forward-only access to serialized BSON data.
  37. /// </summary>
  38. [Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/Newtonsoft.Json.Bson for more details.")]
  39. internal class BsonReader : JsonReader
  40. {
  41. private const int MaxCharBytesSize = 128;
  42. private static readonly byte[] SeqRange1 = new byte[] { 0, 127 }; // range of 1-byte sequence
  43. private static readonly byte[] SeqRange2 = new byte[] { 194, 223 }; // range of 2-byte sequence
  44. private static readonly byte[] SeqRange3 = new byte[] { 224, 239 }; // range of 3-byte sequence
  45. private static readonly byte[] SeqRange4 = new byte[] { 240, 244 }; // range of 4-byte sequence
  46. private readonly BinaryReader _reader;
  47. private readonly List<ContainerContext> _stack;
  48. private byte[] _byteBuffer;
  49. private char[] _charBuffer;
  50. private BsonType _currentElementType;
  51. private BsonReaderState _bsonReaderState;
  52. private ContainerContext _currentContext;
  53. private bool _readRootValueAsArray;
  54. private bool _jsonNet35BinaryCompatibility;
  55. private DateTimeKind _dateTimeKindHandling;
  56. private enum BsonReaderState
  57. {
  58. Normal = 0,
  59. ReferenceStart = 1,
  60. ReferenceRef = 2,
  61. ReferenceId = 3,
  62. CodeWScopeStart = 4,
  63. CodeWScopeCode = 5,
  64. CodeWScopeScope = 6,
  65. CodeWScopeScopeObject = 7,
  66. CodeWScopeScopeEnd = 8
  67. }
  68. private class ContainerContext
  69. {
  70. public readonly BsonType Type;
  71. public int Length;
  72. public int Position;
  73. public ContainerContext(BsonType type)
  74. {
  75. Type = type;
  76. }
  77. }
  78. /// <summary>
  79. /// Gets or sets a value indicating whether binary data reading should be compatible with incorrect Json.NET 3.5 written binary.
  80. /// </summary>
  81. /// <value>
  82. /// <c>true</c> if binary data reading will be compatible with incorrect Json.NET 3.5 written binary; otherwise, <c>false</c>.
  83. /// </value>
  84. [Obsolete("JsonNet35BinaryCompatibility will be removed in a future version of Json.NET.")]
  85. public bool JsonNet35BinaryCompatibility
  86. {
  87. get => _jsonNet35BinaryCompatibility;
  88. set => _jsonNet35BinaryCompatibility = value;
  89. }
  90. /// <summary>
  91. /// Gets or sets a value indicating whether the root object will be read as a JSON array.
  92. /// </summary>
  93. /// <value>
  94. /// <c>true</c> if the root object will be read as a JSON array; otherwise, <c>false</c>.
  95. /// </value>
  96. public bool ReadRootValueAsArray
  97. {
  98. get => _readRootValueAsArray;
  99. set => _readRootValueAsArray = value;
  100. }
  101. /// <summary>
  102. /// Gets or sets the <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.
  103. /// </summary>
  104. /// <value>The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</value>
  105. public DateTimeKind DateTimeKindHandling
  106. {
  107. get => _dateTimeKindHandling;
  108. set => _dateTimeKindHandling = value;
  109. }
  110. /// <summary>
  111. /// Initializes a new instance of the <see cref="BsonReader"/> class.
  112. /// </summary>
  113. /// <param name="stream">The <see cref="Stream"/> containing the BSON data to read.</param>
  114. public BsonReader(Stream stream)
  115. : this(stream, false, DateTimeKind.Local)
  116. {
  117. }
  118. /// <summary>
  119. /// Initializes a new instance of the <see cref="BsonReader"/> class.
  120. /// </summary>
  121. /// <param name="reader">The <see cref="BinaryReader"/> containing the BSON data to read.</param>
  122. public BsonReader(BinaryReader reader)
  123. : this(reader, false, DateTimeKind.Local)
  124. {
  125. }
  126. /// <summary>
  127. /// Initializes a new instance of the <see cref="BsonReader"/> class.
  128. /// </summary>
  129. /// <param name="stream">The <see cref="Stream"/> containing the BSON data to read.</param>
  130. /// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
  131. /// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
  132. public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
  133. {
  134. ValidationUtils.ArgumentNotNull(stream, nameof(stream));
  135. _reader = new BinaryReader(stream);
  136. _stack = new List<ContainerContext>();
  137. _readRootValueAsArray = readRootValueAsArray;
  138. _dateTimeKindHandling = dateTimeKindHandling;
  139. }
  140. /// <summary>
  141. /// Initializes a new instance of the <see cref="BsonReader"/> class.
  142. /// </summary>
  143. /// <param name="reader">The <see cref="BinaryReader"/> containing the BSON data to read.</param>
  144. /// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
  145. /// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
  146. public BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
  147. {
  148. ValidationUtils.ArgumentNotNull(reader, nameof(reader));
  149. _reader = reader;
  150. _stack = new List<ContainerContext>();
  151. _readRootValueAsArray = readRootValueAsArray;
  152. _dateTimeKindHandling = dateTimeKindHandling;
  153. }
  154. private string ReadElement()
  155. {
  156. _currentElementType = ReadType();
  157. string elementName = ReadString();
  158. return elementName;
  159. }
  160. /// <summary>
  161. /// Reads the next JSON token from the underlying <see cref="Stream"/>.
  162. /// </summary>
  163. /// <returns>
  164. /// <c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.
  165. /// </returns>
  166. public override bool Read()
  167. {
  168. try
  169. {
  170. bool success;
  171. switch (_bsonReaderState)
  172. {
  173. case BsonReaderState.Normal:
  174. success = ReadNormal();
  175. break;
  176. case BsonReaderState.ReferenceStart:
  177. case BsonReaderState.ReferenceRef:
  178. case BsonReaderState.ReferenceId:
  179. success = ReadReference();
  180. break;
  181. case BsonReaderState.CodeWScopeStart:
  182. case BsonReaderState.CodeWScopeCode:
  183. case BsonReaderState.CodeWScopeScope:
  184. case BsonReaderState.CodeWScopeScopeObject:
  185. case BsonReaderState.CodeWScopeScopeEnd:
  186. success = ReadCodeWScope();
  187. break;
  188. default:
  189. throw JsonReaderException.Create(this, "Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState));
  190. }
  191. if (!success)
  192. {
  193. SetToken(JsonToken.None);
  194. return false;
  195. }
  196. return true;
  197. }
  198. catch (EndOfStreamException)
  199. {
  200. SetToken(JsonToken.None);
  201. return false;
  202. }
  203. }
  204. /// <summary>
  205. /// Changes the reader's state to <see cref="JsonReader.State.Closed"/>.
  206. /// If <see cref="JsonReader.CloseInput"/> is set to <c>true</c>, the underlying <see cref="Stream"/> is also closed.
  207. /// </summary>
  208. public override void Close()
  209. {
  210. base.Close();
  211. if (CloseInput)
  212. {
  213. _reader?.Close();
  214. //_reader?.Dispose();
  215. }
  216. }
  217. private bool ReadCodeWScope()
  218. {
  219. switch (_bsonReaderState)
  220. {
  221. case BsonReaderState.CodeWScopeStart:
  222. SetToken(JsonToken.PropertyName, "$code");
  223. _bsonReaderState = BsonReaderState.CodeWScopeCode;
  224. return true;
  225. case BsonReaderState.CodeWScopeCode:
  226. // total CodeWScope size - not used
  227. ReadInt32();
  228. SetToken(JsonToken.String, ReadLengthString());
  229. _bsonReaderState = BsonReaderState.CodeWScopeScope;
  230. return true;
  231. case BsonReaderState.CodeWScopeScope:
  232. if (CurrentState == State.PostValue)
  233. {
  234. SetToken(JsonToken.PropertyName, "$scope");
  235. return true;
  236. }
  237. else
  238. {
  239. SetToken(JsonToken.StartObject);
  240. _bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
  241. ContainerContext newContext = new ContainerContext(BsonType.Object);
  242. PushContext(newContext);
  243. newContext.Length = ReadInt32();
  244. return true;
  245. }
  246. case BsonReaderState.CodeWScopeScopeObject:
  247. bool result = ReadNormal();
  248. if (result && TokenType == JsonToken.EndObject)
  249. {
  250. _bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
  251. }
  252. return result;
  253. case BsonReaderState.CodeWScopeScopeEnd:
  254. SetToken(JsonToken.EndObject);
  255. _bsonReaderState = BsonReaderState.Normal;
  256. return true;
  257. default:
  258. throw new ArgumentOutOfRangeException();
  259. }
  260. }
  261. private bool ReadReference()
  262. {
  263. switch (CurrentState)
  264. {
  265. case State.ObjectStart:
  266. {
  267. SetToken(JsonToken.PropertyName, JsonTypeReflector.RefPropertyName);
  268. _bsonReaderState = BsonReaderState.ReferenceRef;
  269. return true;
  270. }
  271. case State.Property:
  272. {
  273. if (_bsonReaderState == BsonReaderState.ReferenceRef)
  274. {
  275. SetToken(JsonToken.String, ReadLengthString());
  276. return true;
  277. }
  278. else if (_bsonReaderState == BsonReaderState.ReferenceId)
  279. {
  280. SetToken(JsonToken.Bytes, ReadBytes(12));
  281. return true;
  282. }
  283. else
  284. {
  285. throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState);
  286. }
  287. }
  288. case State.PostValue:
  289. {
  290. if (_bsonReaderState == BsonReaderState.ReferenceRef)
  291. {
  292. SetToken(JsonToken.PropertyName, JsonTypeReflector.IdPropertyName);
  293. _bsonReaderState = BsonReaderState.ReferenceId;
  294. return true;
  295. }
  296. else if (_bsonReaderState == BsonReaderState.ReferenceId)
  297. {
  298. SetToken(JsonToken.EndObject);
  299. _bsonReaderState = BsonReaderState.Normal;
  300. return true;
  301. }
  302. else
  303. {
  304. throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState);
  305. }
  306. }
  307. default:
  308. throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + CurrentState);
  309. }
  310. }
  311. private bool ReadNormal()
  312. {
  313. switch (CurrentState)
  314. {
  315. case State.Start:
  316. {
  317. JsonToken token = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
  318. BsonType type = (!_readRootValueAsArray) ? BsonType.Object : BsonType.Array;
  319. SetToken(token);
  320. ContainerContext newContext = new ContainerContext(type);
  321. PushContext(newContext);
  322. newContext.Length = ReadInt32();
  323. return true;
  324. }
  325. case State.Complete:
  326. case State.Closed:
  327. return false;
  328. case State.Property:
  329. {
  330. ReadType(_currentElementType);
  331. return true;
  332. }
  333. case State.ObjectStart:
  334. case State.ArrayStart:
  335. case State.PostValue:
  336. ContainerContext context = _currentContext;
  337. if (context == null)
  338. {
  339. return false;
  340. }
  341. int lengthMinusEnd = context.Length - 1;
  342. if (context.Position < lengthMinusEnd)
  343. {
  344. if (context.Type == BsonType.Array)
  345. {
  346. ReadElement();
  347. ReadType(_currentElementType);
  348. return true;
  349. }
  350. else
  351. {
  352. SetToken(JsonToken.PropertyName, ReadElement());
  353. return true;
  354. }
  355. }
  356. else if (context.Position == lengthMinusEnd)
  357. {
  358. if (ReadByte() != 0)
  359. {
  360. throw JsonReaderException.Create(this, "Unexpected end of object byte value.");
  361. }
  362. PopContext();
  363. if (_currentContext != null)
  364. {
  365. MovePosition(context.Length);
  366. }
  367. JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
  368. SetToken(endToken);
  369. return true;
  370. }
  371. else
  372. {
  373. throw JsonReaderException.Create(this, "Read past end of current container context.");
  374. }
  375. case State.ConstructorStart:
  376. break;
  377. case State.Constructor:
  378. break;
  379. case State.Error:
  380. break;
  381. case State.Finished:
  382. break;
  383. default:
  384. throw new ArgumentOutOfRangeException();
  385. }
  386. return false;
  387. }
  388. private void PopContext()
  389. {
  390. _stack.RemoveAt(_stack.Count - 1);
  391. if (_stack.Count == 0)
  392. {
  393. _currentContext = null;
  394. }
  395. else
  396. {
  397. _currentContext = _stack[_stack.Count - 1];
  398. }
  399. }
  400. private void PushContext(ContainerContext newContext)
  401. {
  402. _stack.Add(newContext);
  403. _currentContext = newContext;
  404. }
  405. private byte ReadByte()
  406. {
  407. MovePosition(1);
  408. return _reader.ReadByte();
  409. }
  410. private void ReadType(BsonType type)
  411. {
  412. switch (type)
  413. {
  414. case BsonType.Number:
  415. double d = ReadDouble();
  416. if (_floatParseHandling == FloatParseHandling.Decimal)
  417. {
  418. SetToken(JsonToken.Float, Convert.ToDecimal(d, CultureInfo.InvariantCulture));
  419. }
  420. else
  421. {
  422. SetToken(JsonToken.Float, d);
  423. }
  424. break;
  425. case BsonType.String:
  426. case BsonType.Symbol:
  427. SetToken(JsonToken.String, ReadLengthString());
  428. break;
  429. case BsonType.Object:
  430. {
  431. SetToken(JsonToken.StartObject);
  432. ContainerContext newContext = new ContainerContext(BsonType.Object);
  433. PushContext(newContext);
  434. newContext.Length = ReadInt32();
  435. break;
  436. }
  437. case BsonType.Array:
  438. {
  439. SetToken(JsonToken.StartArray);
  440. ContainerContext newContext = new ContainerContext(BsonType.Array);
  441. PushContext(newContext);
  442. newContext.Length = ReadInt32();
  443. break;
  444. }
  445. case BsonType.Binary:
  446. BsonBinaryType binaryType;
  447. byte[] data = ReadBinary(out binaryType);
  448. object value = (binaryType != BsonBinaryType.Uuid)
  449. ? data
  450. : (object)new Guid(data);
  451. SetToken(JsonToken.Bytes, value);
  452. break;
  453. case BsonType.Undefined:
  454. SetToken(JsonToken.Undefined);
  455. break;
  456. case BsonType.Oid:
  457. byte[] oid = ReadBytes(12);
  458. SetToken(JsonToken.Bytes, oid);
  459. break;
  460. case BsonType.Boolean:
  461. bool b = Convert.ToBoolean(ReadByte());
  462. SetToken(JsonToken.Boolean, b);
  463. break;
  464. case BsonType.Date:
  465. long ticks = ReadInt64();
  466. DateTime utcDateTime = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks);
  467. DateTime dateTime;
  468. switch (DateTimeKindHandling)
  469. {
  470. case DateTimeKind.Unspecified:
  471. dateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified);
  472. break;
  473. case DateTimeKind.Local:
  474. dateTime = utcDateTime.ToLocalTime();
  475. break;
  476. default:
  477. dateTime = utcDateTime;
  478. break;
  479. }
  480. SetToken(JsonToken.Date, dateTime);
  481. break;
  482. case BsonType.Null:
  483. SetToken(JsonToken.Null);
  484. break;
  485. case BsonType.Regex:
  486. string expression = ReadString();
  487. string modifiers = ReadString();
  488. string regex = @"/" + expression + @"/" + modifiers;
  489. SetToken(JsonToken.String, regex);
  490. break;
  491. case BsonType.Reference:
  492. SetToken(JsonToken.StartObject);
  493. _bsonReaderState = BsonReaderState.ReferenceStart;
  494. break;
  495. case BsonType.Code:
  496. SetToken(JsonToken.String, ReadLengthString());
  497. break;
  498. case BsonType.CodeWScope:
  499. SetToken(JsonToken.StartObject);
  500. _bsonReaderState = BsonReaderState.CodeWScopeStart;
  501. break;
  502. case BsonType.Integer:
  503. SetToken(JsonToken.Integer, (long)ReadInt32());
  504. break;
  505. case BsonType.TimeStamp:
  506. case BsonType.Long:
  507. SetToken(JsonToken.Integer, ReadInt64());
  508. break;
  509. default:
  510. throw new ArgumentOutOfRangeException(nameof(type), "Unexpected BsonType value: " + type);
  511. }
  512. }
  513. private byte[] ReadBinary(out BsonBinaryType binaryType)
  514. {
  515. int dataLength = ReadInt32();
  516. binaryType = (BsonBinaryType)ReadByte();
  517. #pragma warning disable 612,618
  518. // the old binary type has the data length repeated in the data for some reason
  519. if (binaryType == BsonBinaryType.BinaryOld && !_jsonNet35BinaryCompatibility)
  520. {
  521. dataLength = ReadInt32();
  522. }
  523. #pragma warning restore 612,618
  524. return ReadBytes(dataLength);
  525. }
  526. private string ReadString()
  527. {
  528. EnsureBuffers();
  529. StringBuilder builder = null;
  530. int totalBytesRead = 0;
  531. // used in case of left over multibyte characters in the buffer
  532. int offset = 0;
  533. while (true)
  534. {
  535. int count = offset;
  536. byte b;
  537. while (count < MaxCharBytesSize && (b = _reader.ReadByte()) > 0)
  538. {
  539. _byteBuffer[count++] = b;
  540. }
  541. int byteCount = count - offset;
  542. totalBytesRead += byteCount;
  543. if (count < MaxCharBytesSize && builder == null)
  544. {
  545. // pref optimization to avoid reading into a string builder
  546. // if string is smaller than the buffer then return it directly
  547. int length = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
  548. MovePosition(totalBytesRead + 1);
  549. return new string(_charBuffer, 0, length);
  550. }
  551. else
  552. {
  553. // calculate the index of the end of the last full character in the buffer
  554. int lastFullCharStop = GetLastFullCharStop(count - 1);
  555. int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
  556. if (builder == null)
  557. {
  558. builder = new StringBuilder(MaxCharBytesSize * 2);
  559. }
  560. builder.Append(_charBuffer, 0, charCount);
  561. if (lastFullCharStop < byteCount - 1)
  562. {
  563. offset = byteCount - lastFullCharStop - 1;
  564. // copy left over multi byte characters to beginning of buffer for next iteration
  565. Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
  566. }
  567. else
  568. {
  569. // reached end of string
  570. if (count < MaxCharBytesSize)
  571. {
  572. MovePosition(totalBytesRead + 1);
  573. return builder.ToString();
  574. }
  575. offset = 0;
  576. }
  577. }
  578. }
  579. }
  580. private string ReadLengthString()
  581. {
  582. int length = ReadInt32();
  583. MovePosition(length);
  584. string s = GetString(length - 1);
  585. _reader.ReadByte();
  586. return s;
  587. }
  588. private string GetString(int length)
  589. {
  590. if (length == 0)
  591. {
  592. return string.Empty;
  593. }
  594. EnsureBuffers();
  595. StringBuilder builder = null;
  596. int totalBytesRead = 0;
  597. // used in case of left over multibyte characters in the buffer
  598. int offset = 0;
  599. do
  600. {
  601. int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
  602. ? MaxCharBytesSize - offset
  603. : length - totalBytesRead;
  604. int byteCount = _reader.Read(_byteBuffer, offset, count);
  605. if (byteCount == 0)
  606. {
  607. throw new EndOfStreamException("Unable to read beyond the end of the stream.");
  608. }
  609. totalBytesRead += byteCount;
  610. // Above, byteCount is how many bytes we read this time.
  611. // Below, byteCount is how many bytes are in the _byteBuffer.
  612. byteCount += offset;
  613. if (byteCount == length)
  614. {
  615. // pref optimization to avoid reading into a string builder
  616. // first iteration and all bytes read then return string directly
  617. int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
  618. return new string(_charBuffer, 0, charCount);
  619. }
  620. else
  621. {
  622. int lastFullCharStop = GetLastFullCharStop(byteCount - 1);
  623. if (builder == null)
  624. {
  625. builder = new StringBuilder(length);
  626. }
  627. int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
  628. builder.Append(_charBuffer, 0, charCount);
  629. if (lastFullCharStop < byteCount - 1)
  630. {
  631. offset = byteCount - lastFullCharStop - 1;
  632. // copy left over multi byte characters to beginning of buffer for next iteration
  633. Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
  634. }
  635. else
  636. {
  637. offset = 0;
  638. }
  639. }
  640. } while (totalBytesRead < length);
  641. return builder.ToString();
  642. }
  643. private int GetLastFullCharStop(int start)
  644. {
  645. int lookbackPos = start;
  646. int bis = 0;
  647. while (lookbackPos >= 0)
  648. {
  649. bis = BytesInSequence(_byteBuffer[lookbackPos]);
  650. if (bis == 0)
  651. {
  652. lookbackPos--;
  653. continue;
  654. }
  655. else if (bis == 1)
  656. {
  657. break;
  658. }
  659. else
  660. {
  661. lookbackPos--;
  662. break;
  663. }
  664. }
  665. if (bis == start - lookbackPos)
  666. {
  667. //Full character.
  668. return start;
  669. }
  670. else
  671. {
  672. return lookbackPos;
  673. }
  674. }
  675. private int BytesInSequence(byte b)
  676. {
  677. if (b <= SeqRange1[1])
  678. {
  679. return 1;
  680. }
  681. if (b >= SeqRange2[0] && b <= SeqRange2[1])
  682. {
  683. return 2;
  684. }
  685. if (b >= SeqRange3[0] && b <= SeqRange3[1])
  686. {
  687. return 3;
  688. }
  689. if (b >= SeqRange4[0] && b <= SeqRange4[1])
  690. {
  691. return 4;
  692. }
  693. return 0;
  694. }
  695. private void EnsureBuffers()
  696. {
  697. if (_byteBuffer == null)
  698. {
  699. _byteBuffer = new byte[MaxCharBytesSize];
  700. }
  701. if (_charBuffer == null)
  702. {
  703. int charBufferSize = Encoding.UTF8.GetMaxCharCount(MaxCharBytesSize);
  704. _charBuffer = new char[charBufferSize];
  705. }
  706. }
  707. private double ReadDouble()
  708. {
  709. MovePosition(8);
  710. return _reader.ReadDouble();
  711. }
  712. private int ReadInt32()
  713. {
  714. MovePosition(4);
  715. return _reader.ReadInt32();
  716. }
  717. private long ReadInt64()
  718. {
  719. MovePosition(8);
  720. return _reader.ReadInt64();
  721. }
  722. private BsonType ReadType()
  723. {
  724. MovePosition(1);
  725. return (BsonType)_reader.ReadSByte();
  726. }
  727. private void MovePosition(int count)
  728. {
  729. _currentContext.Position += count;
  730. }
  731. private byte[] ReadBytes(int count)
  732. {
  733. MovePosition(count);
  734. return _reader.ReadBytes(count);
  735. }
  736. }
  737. }