BsonReader
Represents a reader that provides fast, non-cached, forward-only access to serialized BSON data.
            
                using Newtonsoft.Json.Utilities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace Newtonsoft.Json.Bson
{
    [Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/Newtonsoft.Json.Bson for more details.")]
    public class BsonReader : JsonReader
    {
        private enum BsonReaderState
        {
            Normal,
            ReferenceStart,
            ReferenceRef,
            ReferenceId,
            CodeWScopeStart,
            CodeWScopeCode,
            CodeWScopeScope,
            CodeWScopeScopeObject,
            CodeWScopeScopeEnd
        }
        private class ContainerContext
        {
            public readonly BsonType Type;
            public int Length;
            public int Position;
            public ContainerContext(BsonType type)
            {
                Type = type;
            }
        }
        private const int MaxCharBytesSize = 128;
        private static readonly byte[] SeqRange1 = new byte[2] {
            0,
            127
        };
        private static readonly byte[] SeqRange2 = new byte[2] {
            194,
            223
        };
        private static readonly byte[] SeqRange3 = new byte[2] {
            224,
            239
        };
        private static readonly byte[] SeqRange4 = new byte[2] {
            240,
            244
        };
        private readonly BinaryReader _reader;
        private readonly List<ContainerContext> _stack;
        private byte[] _byteBuffer;
        private char[] _charBuffer;
        private BsonType _currentElementType;
        private BsonReaderState _bsonReaderState;
        private ContainerContext _currentContext;
        private bool _readRootValueAsArray;
        private bool _jsonNet35BinaryCompatibility;
        private DateTimeKind _dateTimeKindHandling;
        [Obsolete("JsonNet35BinaryCompatibility will be removed in a future version of Json.NET.")]
        public bool JsonNet35BinaryCompatibility {
            get {
                return _jsonNet35BinaryCompatibility;
            }
            set {
                _jsonNet35BinaryCompatibility = value;
            }
        }
        public bool ReadRootValueAsArray {
            get {
                return _readRootValueAsArray;
            }
            set {
                _readRootValueAsArray = value;
            }
        }
        public DateTimeKind DateTimeKindHandling {
            get {
                return _dateTimeKindHandling;
            }
            set {
                _dateTimeKindHandling = value;
            }
        }
        public BsonReader(Stream stream)
            : this(stream, false, DateTimeKind.Local)
        {
        }
        public BsonReader(BinaryReader reader)
            : this(reader, false, DateTimeKind.Local)
        {
        }
        public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
        {
            ValidationUtils.ArgumentNotNull(stream, "stream");
            _reader = new BinaryReader(stream);
            _stack = new List<ContainerContext>();
            _readRootValueAsArray = readRootValueAsArray;
            _dateTimeKindHandling = dateTimeKindHandling;
        }
        public BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
        {
            ValidationUtils.ArgumentNotNull(reader, "reader");
            _reader = reader;
            _stack = new List<ContainerContext>();
            _readRootValueAsArray = readRootValueAsArray;
            _dateTimeKindHandling = dateTimeKindHandling;
        }
        private string ReadElement()
        {
            _currentElementType = ReadType();
            return ReadString();
        }
        public override bool Read()
        {
            try {
                bool flag;
                switch (_bsonReaderState) {
                case BsonReaderState.Normal:
                    flag = ReadNormal();
                    break;
                case BsonReaderState.ReferenceStart:
                case BsonReaderState.ReferenceRef:
                case BsonReaderState.ReferenceId:
                    flag = ReadReference();
                    break;
                case BsonReaderState.CodeWScopeStart:
                case BsonReaderState.CodeWScopeCode:
                case BsonReaderState.CodeWScopeScope:
                case BsonReaderState.CodeWScopeScopeObject:
                case BsonReaderState.CodeWScopeScopeEnd:
                    flag = ReadCodeWScope();
                    break;
                default:
                    throw JsonReaderException.Create(this, "Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState));
                }
                if (flag)
                    return true;
                SetToken(JsonToken.None);
                return false;
            } catch (EndOfStreamException) {
                SetToken(JsonToken.None);
                return false;
            }
        }
        public override void Close()
        {
            base.Close();
            if (base.CloseInput)
                _reader?.Close();
        }
        private bool ReadCodeWScope()
        {
            switch (_bsonReaderState) {
            case BsonReaderState.CodeWScopeStart:
                SetToken(JsonToken.PropertyName, "$code");
                _bsonReaderState = BsonReaderState.CodeWScopeCode;
                return true;
            case BsonReaderState.CodeWScopeCode:
                ReadInt32();
                SetToken(JsonToken.String, ReadLengthString());
                _bsonReaderState = BsonReaderState.CodeWScopeScope;
                return true;
            case BsonReaderState.CodeWScopeScope: {
                if (base.CurrentState == State.PostValue) {
                    SetToken(JsonToken.PropertyName, "$scope");
                    return true;
                }
                SetToken(JsonToken.StartObject);
                _bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
                ContainerContext containerContext = new ContainerContext(BsonType.Object);
                PushContext(containerContext);
                containerContext.Length = ReadInt32();
                return true;
            }
            case BsonReaderState.CodeWScopeScopeObject: {
                bool num = ReadNormal();
                if (num && TokenType == JsonToken.EndObject)
                    _bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
                return num;
            }
            case BsonReaderState.CodeWScopeScopeEnd:
                SetToken(JsonToken.EndObject);
                _bsonReaderState = BsonReaderState.Normal;
                return true;
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        private bool ReadReference()
        {
            switch (base.CurrentState) {
            case State.ObjectStart:
                SetToken(JsonToken.PropertyName, "$ref");
                _bsonReaderState = BsonReaderState.ReferenceRef;
                return true;
            case State.Property:
                if (_bsonReaderState == BsonReaderState.ReferenceRef) {
                    SetToken(JsonToken.String, ReadLengthString());
                    return true;
                }
                if (_bsonReaderState == BsonReaderState.ReferenceId) {
                    SetToken(JsonToken.Bytes, ReadBytes(12));
                    return true;
                }
                throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState.ToString());
            case State.PostValue:
                if (_bsonReaderState == BsonReaderState.ReferenceRef) {
                    SetToken(JsonToken.PropertyName, "$id");
                    _bsonReaderState = BsonReaderState.ReferenceId;
                    return true;
                }
                if (_bsonReaderState == BsonReaderState.ReferenceId) {
                    SetToken(JsonToken.EndObject);
                    _bsonReaderState = BsonReaderState.Normal;
                    return true;
                }
                throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState.ToString());
            default:
                throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + base.CurrentState.ToString());
            }
        }
        private bool ReadNormal()
        {
            switch (base.CurrentState) {
            case State.Start: {
                JsonToken token2 = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
                int type = (!_readRootValueAsArray) ? 3 : 4;
                SetToken(token2);
                ContainerContext containerContext = new ContainerContext((BsonType)type);
                PushContext(containerContext);
                containerContext.Length = ReadInt32();
                return true;
            }
            case State.Complete:
            case State.Closed:
                return false;
            case State.Property:
                ReadType(_currentElementType);
                return true;
            case State.ObjectStart:
            case State.ArrayStart:
            case State.PostValue: {
                ContainerContext currentContext = _currentContext;
                if (currentContext != null) {
                    int num = currentContext.Length - 1;
                    if (currentContext.Position < num) {
                        if (currentContext.Type == BsonType.Array) {
                            ReadElement();
                            ReadType(_currentElementType);
                            return true;
                        }
                        SetToken(JsonToken.PropertyName, ReadElement());
                        return true;
                    }
                    if (currentContext.Position == num) {
                        if (ReadByte() != 0)
                            throw JsonReaderException.Create(this, "Unexpected end of object byte value.");
                        PopContext();
                        if (_currentContext != null)
                            MovePosition(currentContext.Length);
                        JsonToken token = (currentContext.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
                        SetToken(token);
                        return true;
                    }
                    throw JsonReaderException.Create(this, "Read past end of current container context.");
                }
                if (!base.SupportMultipleContent)
                    return false;
                goto case State.Start;
            }
            default:
                throw new ArgumentOutOfRangeException();
            case State.ConstructorStart:
            case State.Constructor:
            case State.Error:
            case State.Finished:
                return false;
            }
        }
        private void PopContext()
        {
            _stack.RemoveAt(_stack.Count - 1);
            if (_stack.Count == 0)
                _currentContext = null;
            else
                _currentContext = _stack[_stack.Count - 1];
        }
        private void PushContext(ContainerContext newContext)
        {
            _stack.Add(newContext);
            _currentContext = newContext;
        }
        private byte ReadByte()
        {
            MovePosition(1);
            return _reader.ReadByte();
        }
        private void ReadType(BsonType type)
        {
            switch (type) {
            case BsonType.Number: {
                double num = ReadDouble();
                if (_floatParseHandling == FloatParseHandling.Decimal)
                    SetToken(JsonToken.Float, Convert.ToDecimal(num, CultureInfo.InvariantCulture));
                else
                    SetToken(JsonToken.Float, num);
                break;
            }
            case BsonType.String:
            case BsonType.Symbol:
                SetToken(JsonToken.String, ReadLengthString());
                break;
            case BsonType.Object: {
                SetToken(JsonToken.StartObject);
                ContainerContext containerContext2 = new ContainerContext(BsonType.Object);
                PushContext(containerContext2);
                containerContext2.Length = ReadInt32();
                break;
            }
            case BsonType.Array: {
                SetToken(JsonToken.StartArray);
                ContainerContext containerContext = new ContainerContext(BsonType.Array);
                PushContext(containerContext);
                containerContext.Length = ReadInt32();
                break;
            }
            case BsonType.Binary: {
                BsonBinaryType binaryType;
                byte[] array = ReadBinary(out binaryType);
                object value3 = (binaryType != BsonBinaryType.Uuid) ? array : ((object)new Guid(array));
                SetToken(JsonToken.Bytes, value3);
                break;
            }
            case BsonType.Undefined:
                SetToken(JsonToken.Undefined);
                break;
            case BsonType.Oid: {
                byte[] value2 = ReadBytes(12);
                SetToken(JsonToken.Bytes, value2);
                break;
            }
            case BsonType.Boolean: {
                bool flag = Convert.ToBoolean(ReadByte());
                SetToken(JsonToken.Boolean, flag);
                break;
            }
            case BsonType.Date: {
                DateTime dateTime = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ReadInt64());
                DateTime dateTime2;
                switch (DateTimeKindHandling) {
                case DateTimeKind.Unspecified:
                    dateTime2 = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
                    break;
                case DateTimeKind.Local:
                    dateTime2 = dateTime.ToLocalTime();
                    break;
                default:
                    dateTime2 = dateTime;
                    break;
                }
                SetToken(JsonToken.Date, dateTime2);
                break;
            }
            case BsonType.Null:
                SetToken(JsonToken.Null);
                break;
            case BsonType.Regex: {
                string str = ReadString();
                string str2 = ReadString();
                string value = "/" + str + "/" + str2;
                SetToken(JsonToken.String, value);
                break;
            }
            case BsonType.Reference:
                SetToken(JsonToken.StartObject);
                _bsonReaderState = BsonReaderState.ReferenceStart;
                break;
            case BsonType.Code:
                SetToken(JsonToken.String, ReadLengthString());
                break;
            case BsonType.CodeWScope:
                SetToken(JsonToken.StartObject);
                _bsonReaderState = BsonReaderState.CodeWScopeStart;
                break;
            case BsonType.Integer:
                SetToken(JsonToken.Integer, (long)ReadInt32());
                break;
            case BsonType.TimeStamp:
            case BsonType.Long:
                SetToken(JsonToken.Integer, ReadInt64());
                break;
            default:
                throw new ArgumentOutOfRangeException("type", "Unexpected BsonType value: " + type.ToString());
            }
        }
        private byte[] ReadBinary(out BsonBinaryType binaryType)
        {
            int count = ReadInt32();
            binaryType = (BsonBinaryType)ReadByte();
            if (binaryType == BsonBinaryType.BinaryOld && !_jsonNet35BinaryCompatibility)
                count = ReadInt32();
            return ReadBytes(count);
        }
        private string ReadString()
        {
            EnsureBuffers();
            StringBuilder stringBuilder = null;
            int num = 0;
            int num2 = 0;
            while (true) {
                int num3 = num2;
                byte b;
                while (num3 < 128 && (b = _reader.ReadByte()) > 0) {
                    _byteBuffer[num3++] = b;
                }
                int num5 = num3 - num2;
                num += num5;
                if (num3 < 128 && stringBuilder == null) {
                    int chars = Encoding.UTF8.GetChars(_byteBuffer, 0, num5, _charBuffer, 0);
                    MovePosition(num + 1);
                    return new string(_charBuffer, 0, chars);
                }
                int lastFullCharStop = GetLastFullCharStop(num3 - 1);
                int chars2 = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
                if (stringBuilder == null)
                    stringBuilder = new StringBuilder(256);
                stringBuilder.Append(_charBuffer, 0, chars2);
                if (lastFullCharStop < num5 - 1) {
                    num2 = num5 - lastFullCharStop - 1;
                    Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, num2);
                } else {
                    if (num3 < 128)
                        break;
                    num2 = 0;
                }
            }
            MovePosition(num + 1);
            return stringBuilder.ToString();
        }
        private string ReadLengthString()
        {
            int num = ReadInt32();
            MovePosition(num);
            string string = GetString(num - 1);
            _reader.ReadByte();
            return string;
        }
        private string GetString(int length)
        {
            if (length == 0)
                return string.Empty;
            EnsureBuffers();
            StringBuilder stringBuilder = null;
            int num = 0;
            int num2 = 0;
            do {
                int count = (length - num > 128 - num2) ? (128 - num2) : (length - num);
                int num3 = _reader.Read(_byteBuffer, num2, count);
                if (num3 == 0)
                    throw new EndOfStreamException("Unable to read beyond the end of the stream.");
                num += num3;
                num3 += num2;
                if (num3 == length) {
                    int chars = Encoding.UTF8.GetChars(_byteBuffer, 0, num3, _charBuffer, 0);
                    return new string(_charBuffer, 0, chars);
                }
                int lastFullCharStop = GetLastFullCharStop(num3 - 1);
                if (stringBuilder == null)
                    stringBuilder = new StringBuilder(length);
                int chars2 = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
                stringBuilder.Append(_charBuffer, 0, chars2);
                if (lastFullCharStop < num3 - 1) {
                    num2 = num3 - lastFullCharStop - 1;
                    Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, num2);
                } else
                    num2 = 0;
            } while (num < length);
            return stringBuilder.ToString();
        }
        private int GetLastFullCharStop(int start)
        {
            int num = start;
            int num2 = 0;
            while (num >= 0) {
                num2 = BytesInSequence(_byteBuffer[num]);
                switch (num2) {
                case 0:
                    break;
                default:
                    num--;
                    goto end_IL_0028;
                case 1:
                    goto end_IL_0028;
                }
                num--;
                continue;
                continue;
                end_IL_0028:
                break;
            }
            if (num2 == start - num)
                return start;
            return num;
        }
        private int BytesInSequence(byte b)
        {
            if (b <= SeqRange1[1])
                return 1;
            if (b >= SeqRange2[0] && b <= SeqRange2[1])
                return 2;
            if (b >= SeqRange3[0] && b <= SeqRange3[1])
                return 3;
            if (b >= SeqRange4[0] && b <= SeqRange4[1])
                return 4;
            return 0;
        }
        private void EnsureBuffers()
        {
            if (_byteBuffer == null)
                _byteBuffer = new byte[128];
            if (_charBuffer == null) {
                int maxCharCount = Encoding.UTF8.GetMaxCharCount(128);
                _charBuffer = new char[maxCharCount];
            }
        }
        private double ReadDouble()
        {
            MovePosition(8);
            return _reader.ReadDouble();
        }
        private int ReadInt32()
        {
            MovePosition(4);
            return _reader.ReadInt32();
        }
        private long ReadInt64()
        {
            MovePosition(8);
            return _reader.ReadInt64();
        }
        private BsonType ReadType()
        {
            MovePosition(1);
            return (BsonType)_reader.ReadSByte();
        }
        private void MovePosition(int count)
        {
            _currentContext.Position += count;
        }
        private byte[] ReadBytes(int count)
        {
            MovePosition(count);
            return _reader.ReadBytes(count);
        }
    }
}