JsonDocument
Provides a mechanism for examining the structural content of a JSON value without automatically instantiating data values.
using System.Buffers;
using System.Buffers.Text;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace System.Text.Json
{
public sealed class JsonDocument : IDisposable
{
internal readonly struct DbRow
{
internal const int Size = 12;
private readonly int _location;
private readonly int _sizeOrLengthUnion;
private readonly int _numberOfRowsAndTypeUnion;
internal const int UnknownSize = -1;
internal int Location => _location;
internal int SizeOrLength => _sizeOrLengthUnion & 2147483647;
internal bool IsUnknownSize => _sizeOrLengthUnion == -1;
internal bool HasComplexChildren => _sizeOrLengthUnion < 0;
internal int NumberOfRows => _numberOfRowsAndTypeUnion & 268435455;
internal JsonTokenType TokenType => (JsonTokenType)((uint)_numberOfRowsAndTypeUnion >> 28);
internal bool IsSimpleValue => (int)TokenType >= 5;
internal DbRow(JsonTokenType jsonTokenType, int location, int sizeOrLength)
{
_location = location;
_sizeOrLengthUnion = sizeOrLength;
_numberOfRowsAndTypeUnion = (int)((uint)jsonTokenType << 28);
}
}
private struct MetadataDb : IDisposable
{
private const int SizeOrLengthOffset = 4;
private const int NumberOfRowsOffset = 8;
private byte[] _data;
private bool _convertToAlloc;
private bool _isLocked;
internal int Length {
[System.Runtime.CompilerServices.IsReadOnly]
get;
private set;
}
private MetadataDb(byte[] initialDb, bool isLocked, bool convertToAlloc)
{
_data = initialDb;
_isLocked = isLocked;
_convertToAlloc = convertToAlloc;
Length = 0;
}
internal MetadataDb(byte[] completeDb)
{
_data = completeDb;
_isLocked = true;
_convertToAlloc = false;
Length = completeDb.Length;
}
internal static MetadataDb CreateRented(int payloadLength, bool convertToAlloc)
{
int num = payloadLength + 12;
if (num > 1048576 && num <= 4194304)
num = 1048576;
return new MetadataDb(ArrayPool<byte>.Shared.Rent(num), false, convertToAlloc);
}
internal static MetadataDb CreateLocked(int payloadLength)
{
return new MetadataDb(new byte[payloadLength + 12], true, false);
}
public void Dispose()
{
byte[] array = Interlocked.Exchange(ref _data, null);
if (array != null) {
ArrayPool<byte>.Shared.Return(array, false);
Length = 0;
}
}
internal void CompleteAllocations()
{
if (!_isLocked) {
if (_convertToAlloc) {
byte[] data = _data;
_data = _data.AsSpan(0, Length).ToArray();
_isLocked = true;
_convertToAlloc = false;
ArrayPool<byte>.Shared.Return(data, false);
} else if (Length <= _data.Length / 2) {
byte[] array = ArrayPool<byte>.Shared.Rent(Length);
byte[] array2 = array;
if (array.Length < _data.Length) {
Buffer.BlockCopy(_data, 0, array, 0, Length);
array2 = _data;
_data = array;
}
ArrayPool<byte>.Shared.Return(array2, false);
}
}
}
internal void Append(JsonTokenType tokenType, int startLocation, int length)
{
if (Length >= _data.Length - 12)
Enlarge();
DbRow value = new DbRow(tokenType, startLocation, length);
MemoryMarshal.Write(_data.AsSpan(Length), ref value);
Length += 12;
}
private void Enlarge()
{
byte[] data = _data;
int num = data.Length * 2;
if ((uint)num > 2147483591)
num = 2147483591;
if (num == data.Length)
num = 2147483647;
_data = ArrayPool<byte>.Shared.Rent(num);
Buffer.BlockCopy(data, 0, _data, 0, data.Length);
ArrayPool<byte>.Shared.Return(data, false);
}
[Conditional("DEBUG")]
private void AssertValidIndex(int index)
{
}
internal void SetLength(int index, int length)
{
MemoryMarshal.Write(_data.AsSpan(index + 4), ref length);
}
internal void SetNumberOfRows(int index, int numberOfRows)
{
Span<byte> span = _data.AsSpan(index + 8);
int value = (MemoryMarshal.Read<int>(span) & -268435456) | numberOfRows;
MemoryMarshal.Write(span, ref value);
}
internal void SetHasComplexChildren(int index)
{
Span<byte> span = _data.AsSpan(index + 4);
int value = MemoryMarshal.Read<int>(span) | -2147483648;
MemoryMarshal.Write(span, ref value);
}
internal int FindIndexOfFirstUnsetSizeOrLength(JsonTokenType lookupType)
{
return FindOpenElement(lookupType);
}
private int FindOpenElement(JsonTokenType lookupType)
{
Span<byte> span = _data.AsSpan(0, Length);
for (int num = Length - 12; num >= 0; num -= 12) {
DbRow dbRow = MemoryMarshal.Read<DbRow>(span.Slice(num));
if (dbRow.IsUnknownSize && dbRow.TokenType == lookupType)
return num;
}
return -1;
}
internal DbRow Get(int index)
{
return MemoryMarshal.Read<DbRow>(_data.AsSpan(index));
}
internal JsonTokenType GetJsonTokenType(int index)
{
return (JsonTokenType)(MemoryMarshal.Read<uint>(_data.AsSpan(index + 8)) >> 28);
}
internal MetadataDb CopySegment(int startIndex, int endIndex)
{
DbRow dbRow = Get(startIndex);
int num = endIndex - startIndex;
byte[] array = new byte[num];
_data.AsSpan(startIndex, num).CopyTo(array);
Span<int> span = MemoryMarshal.Cast<byte, int>(array);
int num2 = span[0];
if (dbRow.TokenType == JsonTokenType.String)
num2--;
for (int num3 = (num - 12) / 4; num3 >= 0; num3 -= 3) {
span[num3] -= num2;
}
return new MetadataDb(array);
}
}
private readonly struct StackRow
{
internal const int Size = 8;
internal readonly int SizeOrLength;
internal readonly int NumberOfRows;
internal StackRow(int sizeOrLength = 0, int numberOfRows = -1)
{
SizeOrLength = sizeOrLength;
NumberOfRows = numberOfRows;
}
}
private struct StackRowStack : IDisposable
{
private byte[] _rentedBuffer;
private int _topOfStack;
public StackRowStack(int initialSize)
{
_rentedBuffer = ArrayPool<byte>.Shared.Rent(initialSize);
_topOfStack = _rentedBuffer.Length;
}
public void Dispose()
{
byte[] rentedBuffer = _rentedBuffer;
_rentedBuffer = null;
_topOfStack = 0;
if (rentedBuffer != null)
ArrayPool<byte>.Shared.Return(rentedBuffer, false);
}
internal void Push(StackRow row)
{
if (_topOfStack < 8)
Enlarge();
_topOfStack -= 8;
MemoryMarshal.Write(_rentedBuffer.AsSpan(_topOfStack), ref row);
}
internal StackRow Pop()
{
StackRow result = MemoryMarshal.Read<StackRow>(_rentedBuffer.AsSpan(_topOfStack));
_topOfStack += 8;
return result;
}
private void Enlarge()
{
byte[] rentedBuffer = _rentedBuffer;
_rentedBuffer = ArrayPool<byte>.Shared.Rent(rentedBuffer.Length * 2);
Buffer.BlockCopy(rentedBuffer, _topOfStack, _rentedBuffer, _rentedBuffer.Length - rentedBuffer.Length + _topOfStack, rentedBuffer.Length - _topOfStack);
_topOfStack += _rentedBuffer.Length - rentedBuffer.Length;
ArrayPool<byte>.Shared.Return(rentedBuffer, false);
}
}
private ReadOnlyMemory<byte> _utf8Json;
private MetadataDb _parsedData;
private byte[] _extraRentedArrayPoolBytes;
private PooledByteBufferWriter _extraPooledByteBufferWriter;
private static JsonDocument s_nullLiteral;
private static JsonDocument s_trueLiteral;
private static JsonDocument s_falseLiteral;
private const int UnseekableStreamInitialRentSize = 4096;
internal bool IsDisposable { get; }
public JsonElement RootElement => new JsonElement(this, 0);
private JsonDocument(ReadOnlyMemory<byte> utf8Json, MetadataDb parsedData, byte[] extraRentedArrayPoolBytes = null, PooledByteBufferWriter extraPooledByteBufferWriter = null, bool isDisposable = true)
{
_utf8Json = utf8Json;
_parsedData = parsedData;
_extraRentedArrayPoolBytes = extraRentedArrayPoolBytes;
_extraPooledByteBufferWriter = extraPooledByteBufferWriter;
IsDisposable = isDisposable;
}
public void Dispose()
{
int length = _utf8Json.Length;
if (length != 0 && IsDisposable) {
_parsedData.Dispose();
_utf8Json = ReadOnlyMemory<byte>.Empty;
if (_extraRentedArrayPoolBytes != null) {
byte[] array = Interlocked.Exchange(ref _extraRentedArrayPoolBytes, null);
if (array != null) {
array.AsSpan(0, length).Clear();
ArrayPool<byte>.Shared.Return(array, false);
}
} else if (_extraPooledByteBufferWriter != null) {
Interlocked.Exchange(ref _extraPooledByteBufferWriter, null)?.Dispose();
}
}
}
[System.Runtime.CompilerServices.NullableContext(1)]
public void WriteTo(Utf8JsonWriter writer)
{
if (writer == null)
ThrowHelper.ThrowArgumentNullException("writer");
RootElement.WriteTo(writer);
}
internal JsonTokenType GetJsonTokenType(int index)
{
CheckNotDisposed();
return _parsedData.GetJsonTokenType(index);
}
internal bool ValueIsEscaped(int index, bool isPropertyName)
{
CheckNotDisposed();
int index2 = isPropertyName ? (index - 12) : index;
return _parsedData.Get(index2).HasComplexChildren;
}
internal int GetArrayLength(int index)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.StartArray, dbRow.TokenType);
return dbRow.SizeOrLength;
}
internal int GetPropertyCount(int index)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.StartObject, dbRow.TokenType);
return dbRow.SizeOrLength;
}
internal JsonElement GetArrayIndexElement(int currentIndex, int arrayIndex)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(currentIndex);
CheckExpectedType(JsonTokenType.StartArray, dbRow.TokenType);
int sizeOrLength = dbRow.SizeOrLength;
if ((uint)arrayIndex >= (uint)sizeOrLength)
throw new IndexOutOfRangeException();
if (!dbRow.HasComplexChildren)
return new JsonElement(this, currentIndex + (arrayIndex + 1) * 12);
int num = 0;
for (int i = currentIndex + 12; i < _parsedData.Length; i += 12) {
if (arrayIndex == num)
return new JsonElement(this, i);
dbRow = _parsedData.Get(i);
if (!dbRow.IsSimpleValue)
i += 12 * dbRow.NumberOfRows;
num++;
}
throw new IndexOutOfRangeException();
}
internal int GetEndIndex(int index, bool includeEndElement)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
if (dbRow.IsSimpleValue)
return index + 12;
int num = index + 12 * dbRow.NumberOfRows;
if (includeEndElement)
num += 12;
return num;
}
internal ReadOnlyMemory<byte> GetRootRawValue()
{
return GetRawValue(0, true);
}
internal ReadOnlyMemory<byte> GetRawValue(int index, bool includeQuotes)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
if (dbRow.IsSimpleValue) {
if (includeQuotes && dbRow.TokenType == JsonTokenType.String)
return _utf8Json.Slice(dbRow.Location - 1, dbRow.SizeOrLength + 2);
return _utf8Json.Slice(dbRow.Location, dbRow.SizeOrLength);
}
int endIndex = GetEndIndex(index, false);
int location = dbRow.Location;
dbRow = _parsedData.Get(endIndex);
return _utf8Json.Slice(location, dbRow.Location - location + dbRow.SizeOrLength);
}
private ReadOnlyMemory<byte> GetPropertyRawValue(int valueIndex)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(valueIndex - 12);
int num = dbRow.Location - 1;
dbRow = _parsedData.Get(valueIndex);
int num2;
if (dbRow.IsSimpleValue) {
num2 = dbRow.Location + dbRow.SizeOrLength;
if (dbRow.TokenType == JsonTokenType.String)
num2++;
return _utf8Json.Slice(num, num2 - num);
}
int endIndex = GetEndIndex(valueIndex, false);
dbRow = _parsedData.Get(endIndex);
num2 = dbRow.Location + dbRow.SizeOrLength;
return _utf8Json.Slice(num, num2 - num);
}
internal string GetString(int index, JsonTokenType expectedType)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
JsonTokenType tokenType = dbRow.TokenType;
if (tokenType == JsonTokenType.Null)
return null;
CheckExpectedType(expectedType, tokenType);
ReadOnlySpan<byte> readOnlySpan = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (!dbRow.HasComplexChildren)
return JsonReaderHelper.TranscodeHelper(readOnlySpan);
return JsonReaderHelper.GetUnescapedString(readOnlySpan);
}
internal unsafe bool TextEquals(int index, ReadOnlySpan<char> otherText, bool isPropertyName)
{
CheckNotDisposed();
byte[] array = null;
int num = checked(otherText.Length * 3);
Span<byte> span = (num > 256) ? ((Span<byte>)(array = ArrayPool<byte>.Shared.Rent(num))) : new Span<byte>(stackalloc byte[256], 256);
Span<byte> destination = span;
int written;
bool result = JsonWriterHelper.ToUtf8(otherText, destination, out written) != OperationStatus.InvalidData && TextEquals(index, destination.Slice(0, written), isPropertyName, true);
if (array != null) {
span = destination.Slice(0, written);
span.Clear();
ArrayPool<byte>.Shared.Return(array, false);
}
return result;
}
internal bool TextEquals(int index, ReadOnlySpan<byte> otherUtf8Text, bool isPropertyName, bool shouldUnescape)
{
CheckNotDisposed();
int index2 = isPropertyName ? (index - 12) : index;
DbRow dbRow = _parsedData.Get(index2);
CheckExpectedType(isPropertyName ? JsonTokenType.PropertyName : JsonTokenType.String, dbRow.TokenType);
ReadOnlySpan<byte> span = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (otherUtf8Text.Length > span.Length || (!shouldUnescape && otherUtf8Text.Length != span.Length))
return false;
if (dbRow.HasComplexChildren & shouldUnescape) {
if (otherUtf8Text.Length < span.Length / 6)
return false;
int num = span.IndexOf<byte>(92);
if (!otherUtf8Text.StartsWith(span.Slice(0, num)))
return false;
return JsonReaderHelper.UnescapeAndCompare(span.Slice(num), otherUtf8Text.Slice(num));
}
return span.SequenceEqual(otherUtf8Text);
}
internal string GetNameOfPropertyValue(int index)
{
return GetString(index - 12, JsonTokenType.PropertyName);
}
internal ReadOnlySpan<byte> GetPropertyNameRaw(int index)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index - 12);
return _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
}
internal bool TryGetValue(int index, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out byte[] value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.String, dbRow.TokenType);
ReadOnlySpan<byte> readOnlySpan = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (dbRow.HasComplexChildren)
return JsonReaderHelper.TryGetUnescapedBase64Bytes(readOnlySpan, out value);
return JsonReaderHelper.TryDecodeBase64(readOnlySpan, out value);
}
internal bool TryGetValue(int index, out sbyte value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out sbyte value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out byte value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out byte value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out short value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out short value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out ushort value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out ushort value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out int value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out int value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out uint value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out uint value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out long value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out long value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out ulong value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out ulong value2, out int bytesConsumed, ' ') && bytesConsumed == source.Length) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out double value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out double value2, out int bytesConsumed, ' ') && source.Length == bytesConsumed) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out float value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out float value2, out int bytesConsumed, ' ') && source.Length == bytesConsumed) {
value = value2;
return true;
}
value = 0;
return false;
}
internal bool TryGetValue(int index, out decimal value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.Number, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (Utf8Parser.TryParse(source, out decimal value2, out int bytesConsumed, ' ') && source.Length == bytesConsumed) {
value = value2;
return true;
}
value = default(decimal);
return false;
}
internal bool TryGetValue(int index, out DateTime value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.String, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (!JsonHelpers.IsValidDateTimeOffsetParseLength(source.Length)) {
value = default(DateTime);
return false;
}
if (dbRow.HasComplexChildren)
return JsonReaderHelper.TryGetEscapedDateTime(source, out value);
if (JsonHelpers.TryParseAsISO(source, out DateTime value2)) {
value = value2;
return true;
}
value = default(DateTime);
return false;
}
internal bool TryGetValue(int index, out DateTimeOffset value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.String, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (!JsonHelpers.IsValidDateTimeOffsetParseLength(source.Length)) {
value = default(DateTimeOffset);
return false;
}
if (dbRow.HasComplexChildren)
return JsonReaderHelper.TryGetEscapedDateTimeOffset(source, out value);
if (JsonHelpers.TryParseAsISO(source, out DateTimeOffset value2)) {
value = value2;
return true;
}
value = default(DateTimeOffset);
return false;
}
internal bool TryGetValue(int index, out Guid value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.String, dbRow.TokenType);
ReadOnlySpan<byte> source = _utf8Json.Span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (source.Length > 216) {
value = default(Guid);
return false;
}
if (dbRow.HasComplexChildren)
return JsonReaderHelper.TryGetEscapedGuid(source, out value);
if (source.Length == 36 && Utf8Parser.TryParse(source, out Guid value2, out int _, 'D')) {
value = value2;
return true;
}
value = default(Guid);
return false;
}
internal string GetRawValueAsString(int index)
{
return JsonReaderHelper.TranscodeHelper(GetRawValue(index, true).Span);
}
internal string GetPropertyRawValueAsString(int valueIndex)
{
return JsonReaderHelper.TranscodeHelper(GetPropertyRawValue(valueIndex).Span);
}
internal JsonElement CloneElement(int index)
{
int endIndex = GetEndIndex(index, true);
MetadataDb parsedData = _parsedData.CopySegment(index, endIndex);
return new JsonDocument(GetRawValue(index, true).ToArray(), parsedData, null, null, false).RootElement;
}
internal void WriteElementTo(int index, Utf8JsonWriter writer)
{
CheckNotDisposed();
DbRow row = _parsedData.Get(index);
switch (row.TokenType) {
case JsonTokenType.EndObject:
case JsonTokenType.EndArray:
case JsonTokenType.PropertyName:
case JsonTokenType.Comment:
break;
case JsonTokenType.StartObject:
writer.WriteStartObject();
WriteComplexElement(index, writer);
break;
case JsonTokenType.StartArray:
writer.WriteStartArray();
WriteComplexElement(index, writer);
break;
case JsonTokenType.String:
WriteString(ref row, writer);
break;
case JsonTokenType.Number:
writer.WriteNumberValue(_utf8Json.Slice(row.Location, row.SizeOrLength).Span);
break;
case JsonTokenType.True:
writer.WriteBooleanValue(true);
break;
case JsonTokenType.False:
writer.WriteBooleanValue(false);
break;
case JsonTokenType.Null:
writer.WriteNullValue();
break;
}
}
private void WriteComplexElement(int index, Utf8JsonWriter writer)
{
int endIndex = GetEndIndex(index, true);
for (int i = index + 12; i < endIndex; i += 12) {
DbRow row = _parsedData.Get(i);
switch (row.TokenType) {
case JsonTokenType.String:
WriteString(ref row, writer);
break;
case JsonTokenType.Number:
writer.WriteNumberValue(_utf8Json.Slice(row.Location, row.SizeOrLength).Span);
break;
case JsonTokenType.True:
writer.WriteBooleanValue(true);
break;
case JsonTokenType.False:
writer.WriteBooleanValue(false);
break;
case JsonTokenType.Null:
writer.WriteNullValue();
break;
case JsonTokenType.StartObject:
writer.WriteStartObject();
break;
case JsonTokenType.EndObject:
writer.WriteEndObject();
break;
case JsonTokenType.StartArray:
writer.WriteStartArray();
break;
case JsonTokenType.EndArray:
writer.WriteEndArray();
break;
case JsonTokenType.PropertyName:
WritePropertyName(ref row, writer);
break;
}
}
}
private ReadOnlySpan<byte> UnescapeString([In] [System.Runtime.CompilerServices.IsReadOnly] ref DbRow row, out ArraySegment<byte> rented)
{
int location = row.Location;
int sizeOrLength = row.SizeOrLength;
ReadOnlySpan<byte> span = _utf8Json.Slice(location, sizeOrLength).Span;
if (!row.HasComplexChildren) {
rented = default(ArraySegment<byte>);
return span;
}
byte[] array = ArrayPool<byte>.Shared.Rent(sizeOrLength);
JsonReaderHelper.Unescape(span, array, out int written);
rented = new ArraySegment<byte>(array, 0, written);
return rented.AsSpan();
}
private static void ClearAndReturn(ArraySegment<byte> rented)
{
if (rented.Array != null) {
rented.AsSpan().Clear();
ArrayPool<byte>.Shared.Return(rented.Array, false);
}
}
internal void WritePropertyName(int index, Utf8JsonWriter writer)
{
CheckNotDisposed();
DbRow row = _parsedData.Get(index - 12);
WritePropertyName(ref row, writer);
}
private void WritePropertyName([In] [System.Runtime.CompilerServices.IsReadOnly] ref DbRow row, Utf8JsonWriter writer)
{
ArraySegment<byte> rented = default(ArraySegment<byte>);
try {
writer.WritePropertyName(UnescapeString(ref row, out rented));
} finally {
ClearAndReturn(rented);
}
}
private void WriteString([In] [System.Runtime.CompilerServices.IsReadOnly] ref DbRow row, Utf8JsonWriter writer)
{
ArraySegment<byte> rented = default(ArraySegment<byte>);
try {
writer.WriteStringValue(UnescapeString(ref row, out rented));
} finally {
ClearAndReturn(rented);
}
}
private static void Parse(ReadOnlySpan<byte> utf8JsonSpan, JsonReaderOptions readerOptions, ref MetadataDb database, ref StackRowStack stack)
{
bool flag = false;
int num = 0;
int num2 = 0;
int num3 = 0;
Utf8JsonReader utf8JsonReader = new Utf8JsonReader(utf8JsonSpan, true, new JsonReaderState(readerOptions));
while (utf8JsonReader.Read()) {
JsonTokenType tokenType = utf8JsonReader.TokenType;
int num4 = (int)utf8JsonReader.TokenStartIndex;
ReadOnlySpan<byte> valueSpan;
switch (tokenType) {
case JsonTokenType.StartObject: {
if (flag)
num++;
num3++;
database.Append(tokenType, num4, -1);
StackRow row2 = new StackRow(num, num2 + 1);
stack.Push(row2);
num = 0;
num2 = 0;
break;
}
case JsonTokenType.EndObject: {
int index = database.FindIndexOfFirstUnsetSizeOrLength(JsonTokenType.StartObject);
num3++;
num2++;
database.SetLength(index, num);
int length2 = database.Length;
JsonTokenType tokenType6 = tokenType;
int startLocation5 = num4;
valueSpan = utf8JsonReader.ValueSpan;
database.Append(tokenType6, startLocation5, valueSpan.Length);
database.SetNumberOfRows(index, num2);
database.SetNumberOfRows(length2, num2);
StackRow stackRow2 = stack.Pop();
num = stackRow2.SizeOrLength;
num2 += stackRow2.NumberOfRows;
break;
}
case JsonTokenType.StartArray: {
if (flag)
num++;
num2++;
database.Append(tokenType, num4, -1);
StackRow row = new StackRow(num, num3 + 1);
stack.Push(row);
num = 0;
num3 = 0;
break;
}
case JsonTokenType.EndArray: {
int num5 = database.FindIndexOfFirstUnsetSizeOrLength(JsonTokenType.StartArray);
num3++;
num2++;
database.SetLength(num5, num);
database.SetNumberOfRows(num5, num3);
if (num + 1 != num3)
database.SetHasComplexChildren(num5);
int length = database.Length;
JsonTokenType tokenType5 = tokenType;
int startLocation4 = num4;
valueSpan = utf8JsonReader.ValueSpan;
database.Append(tokenType5, startLocation4, valueSpan.Length);
database.SetNumberOfRows(length, num3);
StackRow stackRow = stack.Pop();
num = stackRow.SizeOrLength;
num3 += stackRow.NumberOfRows;
break;
}
case JsonTokenType.PropertyName: {
num3++;
num2++;
num++;
JsonTokenType tokenType4 = tokenType;
int startLocation3 = num4 + 1;
valueSpan = utf8JsonReader.ValueSpan;
database.Append(tokenType4, startLocation3, valueSpan.Length);
if (utf8JsonReader.ValueIsEscaped)
database.SetHasComplexChildren(database.Length - 12);
break;
}
default:
num3++;
num2++;
if (flag)
num++;
if (tokenType == JsonTokenType.String) {
JsonTokenType tokenType2 = tokenType;
int startLocation = num4 + 1;
valueSpan = utf8JsonReader.ValueSpan;
database.Append(tokenType2, startLocation, valueSpan.Length);
if (utf8JsonReader.ValueIsEscaped)
database.SetHasComplexChildren(database.Length - 12);
} else {
JsonTokenType tokenType3 = tokenType;
int startLocation2 = num4;
valueSpan = utf8JsonReader.ValueSpan;
database.Append(tokenType3, startLocation2, valueSpan.Length);
}
break;
}
flag = utf8JsonReader.IsInArray;
}
database.CompleteAllocations();
}
private void CheckNotDisposed()
{
if (_utf8Json.IsEmpty)
ThrowHelper.ThrowObjectDisposedException_JsonDocument();
}
private static void CheckExpectedType(JsonTokenType expected, JsonTokenType actual)
{
if (expected != actual)
ThrowHelper.ThrowJsonElementWrongTypeException(expected, actual);
}
private static void CheckSupportedOptions(JsonReaderOptions readerOptions, string paramName)
{
if (readerOptions.CommentHandling == JsonCommentHandling.Allow)
throw new ArgumentException(System.SR.JsonDocumentDoesNotSupportComments, paramName);
}
[return: System.Runtime.CompilerServices.Nullable(1)]
public static JsonDocument Parse(ReadOnlyMemory<byte> utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions))
{
return Parse(utf8Json, options.GetReaderOptions(), null, null);
}
[return: System.Runtime.CompilerServices.Nullable(1)]
public static JsonDocument Parse(ReadOnlySequence<byte> utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions))
{
JsonReaderOptions readerOptions = options.GetReaderOptions();
if (!utf8Json.IsSingleSegment) {
int num = checked((int)utf8Json.Length);
byte[] array = ArrayPool<byte>.Shared.Rent(num);
try {
ref utf8Json.CopyTo(array.AsSpan());
return Parse(array.AsMemory(0, num), readerOptions, array, null);
} catch {
array.AsSpan(0, num).Clear();
ArrayPool<byte>.Shared.Return(array, false);
throw;
}
}
return Parse(utf8Json.First, readerOptions, null, null);
}
[System.Runtime.CompilerServices.NullableContext(1)]
public static JsonDocument Parse(Stream utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions))
{
if (utf8Json == null)
ThrowHelper.ThrowArgumentNullException("utf8Json");
ArraySegment<byte> segment = ReadToEnd(utf8Json);
try {
return Parse(segment.AsMemory(), options.GetReaderOptions(), segment.Array, null);
} catch {
segment.AsSpan().Clear();
ArrayPool<byte>.Shared.Return(segment.Array, false);
throw;
}
}
internal static JsonDocument ParseRented(PooledByteBufferWriter utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions))
{
return Parse(utf8Json.WrittenMemory, options.GetReaderOptions(), null, utf8Json);
}
internal static JsonDocument ParseValue(Stream utf8Json, JsonDocumentOptions options)
{
ArraySegment<byte> segment = ReadToEnd(utf8Json);
byte[] array = new byte[segment.Count];
Buffer.BlockCopy(segment.Array, 0, array, 0, segment.Count);
segment.AsSpan().Clear();
ArrayPool<byte>.Shared.Return(segment.Array, false);
return ParseUnrented(array.AsMemory(), options.GetReaderOptions(), JsonTokenType.None);
}
internal static JsonDocument ParseValue(ReadOnlySpan<byte> utf8Json, JsonDocumentOptions options)
{
byte[] array = new byte[utf8Json.Length];
utf8Json.CopyTo(array);
return ParseUnrented(array.AsMemory(), options.GetReaderOptions(), JsonTokenType.None);
}
internal static JsonDocument ParseValue(string json, JsonDocumentOptions options)
{
return ParseValue(json.AsMemory(), options);
}
[System.Runtime.CompilerServices.NullableContext(1)]
public static Task<JsonDocument> ParseAsync(Stream utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions), CancellationToken cancellationToken = default(CancellationToken))
{
if (utf8Json == null)
ThrowHelper.ThrowArgumentNullException("utf8Json");
return ParseAsyncCore(utf8Json, options, cancellationToken);
}
[AsyncStateMachine(typeof(<ParseAsyncCore>d__69))]
private static Task<JsonDocument> ParseAsyncCore(Stream utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions), CancellationToken cancellationToken = default(CancellationToken))
{
<ParseAsyncCore>d__69 stateMachine = default(<ParseAsyncCore>d__69);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<JsonDocument>.Create();
stateMachine.utf8Json = utf8Json;
stateMachine.options = options;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[AsyncStateMachine(typeof(<ParseAsyncCoreUnrented>d__70))]
internal static Task<JsonDocument> ParseAsyncCoreUnrented(Stream utf8Json, JsonDocumentOptions options = default(JsonDocumentOptions), CancellationToken cancellationToken = default(CancellationToken))
{
<ParseAsyncCoreUnrented>d__70 stateMachine = default(<ParseAsyncCoreUnrented>d__70);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<JsonDocument>.Create();
stateMachine.utf8Json = utf8Json;
stateMachine.options = options;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[return: System.Runtime.CompilerServices.Nullable(1)]
public static JsonDocument Parse([System.Diagnostics.CodeAnalysis.StringSyntax("Json")] ReadOnlyMemory<char> json, JsonDocumentOptions options = default(JsonDocumentOptions))
{
ReadOnlySpan<char> span = json.Span;
int utf8ByteCount = JsonReaderHelper.GetUtf8ByteCount(span);
byte[] array = ArrayPool<byte>.Shared.Rent(utf8ByteCount);
try {
int utf8FromText = JsonReaderHelper.GetUtf8FromText(span, array);
return Parse(array.AsMemory(0, utf8FromText), options.GetReaderOptions(), array, null);
} catch {
array.AsSpan(0, utf8ByteCount).Clear();
ArrayPool<byte>.Shared.Return(array, false);
throw;
}
}
internal static JsonDocument ParseValue(ReadOnlyMemory<char> json, JsonDocumentOptions options)
{
ReadOnlySpan<char> span = json.Span;
int utf8ByteCount = JsonReaderHelper.GetUtf8ByteCount(span);
byte[] array = ArrayPool<byte>.Shared.Rent(utf8ByteCount);
byte[] array2 = default(byte[]);
try {
int utf8FromText = JsonReaderHelper.GetUtf8FromText(span, array);
array2 = new byte[utf8FromText];
Buffer.BlockCopy(array, 0, array2, 0, utf8FromText);
} finally {
array.AsSpan(0, utf8ByteCount).Clear();
ArrayPool<byte>.Shared.Return(array, false);
}
return ParseUnrented(array2.AsMemory(), options.GetReaderOptions(), JsonTokenType.None);
}
[System.Runtime.CompilerServices.NullableContext(1)]
public static JsonDocument Parse([System.Diagnostics.CodeAnalysis.StringSyntax("Json")] string json, JsonDocumentOptions options = default(JsonDocumentOptions))
{
if (json == null)
ThrowHelper.ThrowArgumentNullException("json");
return Parse(json.AsMemory(), options);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public static bool TryParseValue(ref Utf8JsonReader reader, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out JsonDocument document)
{
return TryParseValue(ref reader, out document, false, true);
}
[System.Runtime.CompilerServices.NullableContext(1)]
public static JsonDocument ParseValue(ref Utf8JsonReader reader)
{
TryParseValue(ref reader, out JsonDocument document, true, true);
return document;
}
internal static bool TryParseValue(ref Utf8JsonReader reader, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out JsonDocument document, bool shouldThrow, bool useArrayPools)
{
JsonReaderState currentState = reader.CurrentState;
CheckSupportedOptions(currentState.Options, "reader");
Utf8JsonReader utf8JsonReader = reader;
ReadOnlySpan<byte> readOnlySpan = default(ReadOnlySpan<byte>);
ReadOnlySequence<byte> source = default(ReadOnlySequence<byte>);
try {
JsonTokenType tokenType = reader.TokenType;
ReadOnlySpan<byte> bytes;
if ((tokenType == JsonTokenType.None || tokenType == JsonTokenType.PropertyName) && !reader.Read()) {
if (shouldThrow) {
bytes = default(ReadOnlySpan<byte>);
ThrowHelper.ThrowJsonReaderException(ref reader, ExceptionResource.ExpectedJsonTokens, 0, bytes);
}
reader = utf8JsonReader;
document = null;
return false;
}
switch (reader.TokenType) {
case JsonTokenType.StartObject:
case JsonTokenType.StartArray: {
long tokenStartIndex = reader.TokenStartIndex;
if (!reader.TrySkip()) {
if (shouldThrow) {
bytes = default(ReadOnlySpan<byte>);
ThrowHelper.ThrowJsonReaderException(ref reader, ExceptionResource.ExpectedJsonTokens, 0, bytes);
}
reader = utf8JsonReader;
document = null;
return false;
}
long num3 = reader.BytesConsumed - tokenStartIndex;
ReadOnlySequence<byte> originalSequence2 = reader.OriginalSequence;
if (originalSequence2.IsEmpty) {
bytes = reader.OriginalSpan;
readOnlySpan = checked(bytes.Slice((int)tokenStartIndex, (int)num3));
} else
source = originalSequence2.Slice(tokenStartIndex, num3);
break;
}
case JsonTokenType.True:
case JsonTokenType.False:
case JsonTokenType.Null:
if (!useArrayPools) {
document = CreateForLiteral(reader.TokenType);
return true;
}
if (reader.HasValueSequence)
source = reader.ValueSequence;
else
readOnlySpan = reader.ValueSpan;
break;
case JsonTokenType.Number:
if (reader.HasValueSequence)
source = reader.ValueSequence;
else
readOnlySpan = reader.ValueSpan;
break;
case JsonTokenType.String: {
ReadOnlySequence<byte> originalSequence = reader.OriginalSequence;
if (originalSequence.IsEmpty) {
bytes = reader.ValueSpan;
int length = bytes.Length + 2;
readOnlySpan = reader.OriginalSpan.Slice((int)reader.TokenStartIndex, length);
} else {
long num = 2;
if (reader.HasValueSequence)
num += reader.ValueSequence.Length;
else {
long num2 = num;
bytes = reader.ValueSpan;
num = num2 + bytes.Length;
}
source = originalSequence.Slice(reader.TokenStartIndex, num);
}
break;
}
default:
if (shouldThrow) {
bytes = reader.ValueSpan;
byte b = bytes[0];
byte nextByte = b;
bytes = default(ReadOnlySpan<byte>);
ThrowHelper.ThrowJsonReaderException(ref reader, ExceptionResource.ExpectedStartOfValueNotFound, nextByte, bytes);
}
reader = utf8JsonReader;
document = null;
return false;
}
} catch {
reader = utf8JsonReader;
throw;
}
int num4 = readOnlySpan.IsEmpty ? checked((int)source.Length) : readOnlySpan.Length;
if (useArrayPools) {
byte[] array = ArrayPool<byte>.Shared.Rent(num4);
Span<byte> destination = array.AsSpan(0, num4);
try {
if (readOnlySpan.IsEmpty)
ref source.CopyTo(destination);
else
readOnlySpan.CopyTo(destination);
document = Parse(array.AsMemory(0, num4), currentState.Options, array, null);
} catch {
destination.Clear();
ArrayPool<byte>.Shared.Return(array, false);
throw;
}
} else {
byte[] array2 = (!readOnlySpan.IsEmpty) ? readOnlySpan.ToArray() : ref source.ToArray();
document = ParseUnrented(array2, currentState.Options, reader.TokenType);
}
return true;
}
private static JsonDocument CreateForLiteral(JsonTokenType tokenType)
{
<>c__DisplayClass77_0 <>c__DisplayClass77_ = default(<>c__DisplayClass77_0);
<>c__DisplayClass77_.tokenType = tokenType;
ReadOnlySpan<byte> readOnlySpan;
switch (<>c__DisplayClass77_.tokenType) {
case JsonTokenType.False:
if (s_falseLiteral == null) {
readOnlySpan = JsonConstants.FalseValue;
s_falseLiteral = <CreateForLiteral>g__Create|77_0(readOnlySpan.ToArray(), ref <>c__DisplayClass77_);
}
return s_falseLiteral;
case JsonTokenType.True:
if (s_trueLiteral == null) {
readOnlySpan = JsonConstants.TrueValue;
s_trueLiteral = <CreateForLiteral>g__Create|77_0(readOnlySpan.ToArray(), ref <>c__DisplayClass77_);
}
return s_trueLiteral;
default:
if (s_nullLiteral == null) {
readOnlySpan = JsonConstants.NullValue;
s_nullLiteral = <CreateForLiteral>g__Create|77_0(readOnlySpan.ToArray(), ref <>c__DisplayClass77_);
}
return s_nullLiteral;
}
}
private static JsonDocument Parse(ReadOnlyMemory<byte> utf8Json, JsonReaderOptions readerOptions, byte[] extraRentedArrayPoolBytes = null, PooledByteBufferWriter extraPooledByteBufferWriter = null)
{
ReadOnlySpan<byte> span = utf8Json.Span;
MetadataDb database = MetadataDb.CreateRented(utf8Json.Length, false);
StackRowStack stack = new StackRowStack(512);
try {
Parse(span, readerOptions, ref database, ref stack);
} catch {
database.Dispose();
throw;
} finally {
stack.Dispose();
}
return new JsonDocument(utf8Json, database, extraRentedArrayPoolBytes, extraPooledByteBufferWriter, true);
}
private static JsonDocument ParseUnrented(ReadOnlyMemory<byte> utf8Json, JsonReaderOptions readerOptions, JsonTokenType tokenType = JsonTokenType.None)
{
ReadOnlySpan<byte> span = utf8Json.Span;
MetadataDb database;
if (tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number) {
database = MetadataDb.CreateLocked(utf8Json.Length);
StackRowStack stack = default(StackRowStack);
Parse(span, readerOptions, ref database, ref stack);
} else {
database = MetadataDb.CreateRented(utf8Json.Length, true);
StackRowStack stack2 = new StackRowStack(512);
try {
Parse(span, readerOptions, ref database, ref stack2);
} finally {
stack2.Dispose();
}
}
return new JsonDocument(utf8Json, database, null, null, false);
}
private static ArraySegment<byte> ReadToEnd(Stream stream)
{
int num = 0;
byte[] array = null;
ReadOnlySpan<byte> utf8Bom = JsonConstants.Utf8Bom;
try {
if (stream.CanSeek) {
long num2 = Math.Max(utf8Bom.Length, stream.Length - stream.Position) + 1;
array = ArrayPool<byte>.Shared.Rent(checked((int)num2));
} else
array = ArrayPool<byte>.Shared.Rent(4096);
int num3;
do {
num3 = stream.Read(array, num, utf8Bom.Length - num);
num += num3;
} while (num3 > 0 && num < utf8Bom.Length);
if (num == utf8Bom.Length && utf8Bom.SequenceEqual(array.AsSpan(0, utf8Bom.Length)))
num = 0;
do {
if (array.Length == num) {
byte[] array2 = array;
array = ArrayPool<byte>.Shared.Rent(checked(array2.Length * 2));
Buffer.BlockCopy(array2, 0, array, 0, array2.Length);
ArrayPool<byte>.Shared.Return(array2, true);
}
num3 = stream.Read(array, num, array.Length - num);
num += num3;
} while (num3 > 0);
return new ArraySegment<byte>(array, 0, num);
} catch {
if (array != null) {
array.AsSpan(0, num).Clear();
ArrayPool<byte>.Shared.Return(array, false);
}
throw;
}
}
[AsyncStateMachine(typeof(<ReadToEndAsync>d__81))]
private static Task<ArraySegment<byte>> ReadToEndAsync(Stream stream, CancellationToken cancellationToken)
{
<ReadToEndAsync>d__81 stateMachine = default(<ReadToEndAsync>d__81);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<ArraySegment<byte>>.Create();
stateMachine.stream = stream;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
internal unsafe bool TryGetNamedPropertyValue(int index, ReadOnlySpan<char> propertyName, out JsonElement value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.StartObject, dbRow.TokenType);
if (dbRow.NumberOfRows == 1) {
value = default(JsonElement);
return false;
}
int maxByteCount = JsonReaderHelper.s_utf8Encoding.GetMaxByteCount(propertyName.Length);
int startIndex = index + 12;
int num = checked(dbRow.NumberOfRows * 12 + index);
if (maxByteCount < 256) {
Span<byte> span = new Span<byte>(stackalloc byte[256], 256);
int utf8FromText = JsonReaderHelper.GetUtf8FromText(propertyName, span);
span = span.Slice(0, utf8FromText);
return TryGetNamedPropertyValue(startIndex, num, span, out value);
}
int length = propertyName.Length;
int num2;
for (num2 = num - 12; num2 > index; num2 -= 12) {
int num3 = num2;
dbRow = _parsedData.Get(num2);
num2 = ((!dbRow.IsSimpleValue) ? (num2 - 12 * (dbRow.NumberOfRows + 1)) : (num2 - 12));
dbRow = _parsedData.Get(num2);
if (dbRow.SizeOrLength >= length) {
byte[] array = ArrayPool<byte>.Shared.Rent(maxByteCount);
Span<byte> span2 = default(Span<byte>);
try {
int utf8FromText2 = JsonReaderHelper.GetUtf8FromText(propertyName, array);
span2 = array.AsSpan(0, utf8FromText2);
return TryGetNamedPropertyValue(startIndex, num3 + 12, span2, out value);
} finally {
span2.Clear();
ArrayPool<byte>.Shared.Return(array, false);
}
}
}
value = default(JsonElement);
return false;
}
internal bool TryGetNamedPropertyValue(int index, ReadOnlySpan<byte> propertyName, out JsonElement value)
{
CheckNotDisposed();
DbRow dbRow = _parsedData.Get(index);
CheckExpectedType(JsonTokenType.StartObject, dbRow.TokenType);
if (dbRow.NumberOfRows == 1) {
value = default(JsonElement);
return false;
}
int endIndex = checked(dbRow.NumberOfRows * 12 + index);
return TryGetNamedPropertyValue(index + 12, endIndex, propertyName, out value);
}
private unsafe bool TryGetNamedPropertyValue(int startIndex, int endIndex, ReadOnlySpan<byte> propertyName, out JsonElement value)
{
ReadOnlySpan<byte> span = _utf8Json.Span;
Span<byte> span2 = new Span<byte>(stackalloc byte[256], 256);
int num;
for (num = endIndex - 12; num > startIndex; num -= 12) {
DbRow dbRow = _parsedData.Get(num);
num = ((!dbRow.IsSimpleValue) ? (num - 12 * (dbRow.NumberOfRows + 1)) : (num - 12));
dbRow = _parsedData.Get(num);
ReadOnlySpan<byte> span3 = span.Slice(dbRow.Location, dbRow.SizeOrLength);
if (dbRow.HasComplexChildren) {
if (span3.Length > propertyName.Length) {
int num2 = span3.IndexOf<byte>(92);
if (propertyName.Length > num2 && span3.Slice(0, num2).SequenceEqual(propertyName.Slice(0, num2))) {
int num3 = span3.Length - num2;
int written = 0;
byte[] array = null;
try {
Span<byte> destination = (num3 <= span2.Length) ? span2 : ((Span<byte>)(array = ArrayPool<byte>.Shared.Rent(num3)));
JsonReaderHelper.Unescape(span3.Slice(num2), destination, 0, out written);
if (destination.Slice(0, written).SequenceEqual(propertyName.Slice(num2))) {
value = new JsonElement(this, num + 12);
return true;
}
} finally {
if (array != null) {
array.AsSpan(0, written).Clear();
ArrayPool<byte>.Shared.Return(array, false);
}
}
}
}
} else if (span3.SequenceEqual(propertyName)) {
value = new JsonElement(this, num + 12);
return true;
}
}
value = default(JsonElement);
return false;
}
}
}