internal string?[]? GetStringArray(int index) { JsonRow row = _parsedData.Get(index); JsonTokenType tokenType = row.TokenType; if (tokenType == JsonTokenType.Null) { return(null); } CheckExpectedType(JsonTokenType.StartArray, tokenType); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); string?[] array = new string[row.NumberOfItems]; var reader = new Utf8JsonReader(segment); reader.Read(); for (int i = 0; i < row.NumberOfItems; i++) { if (reader.Read()) { CheckExpectedType(JsonTokenType.String, reader.TokenType); array[i] = reader.GetString(); } } return(array); }
internal JsonMetadata CopySegment(int startIndex, int endIndex) { Debug.Assert( endIndex > startIndex, $"endIndex={endIndex} was at or before startIndex={startIndex}"); AssertValidIndex(startIndex); Debug.Assert(endIndex <= Length); JsonRow start = Get(startIndex); int length = endIndex - startIndex; byte[] newDatabase = new byte[length]; _data.AsSpan(startIndex, length).CopyTo(newDatabase); Span <int> newDbInts = MemoryMarshal.Cast <byte, int>(newDatabase); int locationOffset = newDbInts[0]; // Need to nudge one forward to account for the hidden quote on the string. if (start.TokenType == JsonTokenType.String) { locationOffset--; } for (int i = (length - JsonRow.Size) / sizeof(int); i >= 0; i -= JsonRow.Size / sizeof(int)) { Debug.Assert(newDbInts[i] >= locationOffset); newDbInts[i] -= locationOffset; } return(new JsonMetadata(newDatabase)); }
internal string?GetString(int index, JsonTokenType expectedType) { JsonRow row = _parsedData.Get(index); JsonTokenType tokenType = row.TokenType; if (tokenType == JsonTokenType.Null) { return(null); } CheckExpectedType(expectedType, tokenType); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); string value; int backslash = segment.IndexOf(JsonConstants.BackSlash); if (backslash < 0) { value = JsonReaderHelper.TranscodeHelper(segment); } else { value = JsonReaderHelper.GetUnescapedString(segment, backslash); } Debug.Assert(value != null); return(value); }
private ReadOnlyMemory <byte> GetPropertyRawValue(int valueIndex) { // The property name is stored one row before the value JsonRow row = _parsedData.Get(valueIndex - JsonRow.Size); Debug.Assert(row.TokenType == JsonTokenType.PropertyName); // Subtract one for the open quote. int start = row.Location - 1; int end; row = _parsedData.Get(valueIndex); if (row.IsSimpleValue) { end = row.Location + row.Length; // If the value was a string, pick up the terminating quote. if (row.TokenType == JsonTokenType.String) { end++; } return(_utf8Json.Slice(start, end - start)); } int endElementIdx = GetEndIndex(valueIndex, includeEndElement: false); row = _parsedData.Get(endElementIdx); end = row.Location + row.Length; return(_utf8Json.Slice(start, end - start)); }
internal int GetMemberCount(int index) { JsonRow row = _parsedData.Get(index); CheckExpectedType(JsonTokenType.StartObject, row.TokenType); return(row.NumberOfItems); }
internal int GetArrayLength(int index) { JsonRow row = _parsedData.Get(index); CheckExpectedType(JsonTokenType.StartArray, row.TokenType); return(row.Length); }
internal TValue?Deserialize <TValue>(int index, JsonSerializerOptions?options = null) where TValue : class { JsonRow row = _parsedData.Get(index); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); return(JsonSerializer.Deserialize <TValue>(segment, options)); }
internal void Append(JsonTokenType tokenType, int startLocation, int length) { if (Length >= _data.Length - JsonRow.Size) { Enlarge(); } JsonRow row = new JsonRow(tokenType, startLocation, length); MemoryMarshal.Write(_data.AsSpan(Length), ref row); Length += JsonRow.Size; }
internal bool TryGetValue(int index, [NotNullWhen(true)] out JsonDocument?value) { JsonRow row = _parsedData.Get(index); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); var reader = new Utf8JsonReader(segment); if (JsonDocument.TryParseValue(ref reader, out var doc)) { _disposableRegistry.Add(doc); value = doc; return(true); } value = null; return(false); }
private ReadOnlyMemory <byte> GetRawValue(int index, bool includeQuotes) { JsonRow row = _parsedData.Get(index); if (row.IsSimpleValue) { if (includeQuotes && row.TokenType == JsonTokenType.String) { // Start one character earlier than the value (the open quote) // End one character after the value (the close quote) return(_utf8Json.Slice(row.Location - 1, row.Length + 2)); } return(_utf8Json.Slice(row.Location, row.Length)); } return(_utf8Json.Slice(row.Location, row.Length)); }
internal int GetEndIndex(int index, bool includeEndElement) { JsonRow row = _parsedData.Get(index); if (row.IsSimpleValue) { return(index + JsonRow.Size); } int endIndex = index + JsonRow.Size * row.NumberOfItems; if (includeEndElement) { endIndex += JsonRow.Size; } return(endIndex); }
internal bool TryGetValue(int index, out double value) { JsonRow row = _parsedData.Get(index); CheckExpectedType(JsonTokenType.Number, row.TokenType); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); if (Utf8Parser.TryParse(segment, out double tmp, out int bytesConsumed) && segment.Length == bytesConsumed) { value = tmp; return(true); } value = 0; return(false); }
internal JwtElement GetArrayIndexElement(int currentIndex, int arrayIndex) { JsonRow row = _parsedData.Get(currentIndex); CheckExpectedType(JsonTokenType.StartArray, row.TokenType); int arrayLength = row.Length; if ((uint)arrayIndex >= (uint)arrayLength) { throw new IndexOutOfRangeException(); } if (!row.NeedUnescaping) { return(new JwtElement(this, currentIndex + ((arrayIndex + 1) * JsonRow.Size))); } int elementCount = 0; int objectOffset = currentIndex + JsonRow.Size; for (; objectOffset < _parsedData.Length; objectOffset += JsonRow.Size) { if (arrayIndex == elementCount) { return(new JwtElement(this, objectOffset)); } row = _parsedData.Get(objectOffset); if (!row.IsSimpleValue) { objectOffset += JsonRow.Size * row.NumberOfItems; } elementCount++; } Debug.Fail( $"Ran out of database searching for array index {arrayIndex} from {currentIndex} when length was {arrayLength}"); throw new IndexOutOfRangeException(); }
internal bool TextEquals(int index, ReadOnlySpan <byte> otherUtf8Text, bool isPropertyName, bool shouldUnescape) { int matchIndex = isPropertyName ? index - JsonRow.Size : index; JsonRow row = _parsedData.Get(matchIndex); CheckExpectedType( isPropertyName ? JsonTokenType.PropertyName : JsonTokenType.String, row.TokenType); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); if (otherUtf8Text.Length > segment.Length || (!shouldUnescape && otherUtf8Text.Length != segment.Length)) { return(false); } if (row.NeedUnescaping && shouldUnescape) { if (otherUtf8Text.Length < segment.Length / JsonConstants.MaxExpansionFactorWhileEscaping) { return(false); } int idx = segment.IndexOf(JsonConstants.BackSlash); Debug.Assert(idx != -1); if (!otherUtf8Text.StartsWith(segment.Slice(0, idx))) { return(false); } return(JsonReaderHelper.UnescapeAndCompare(segment.Slice(idx), otherUtf8Text.Slice(idx))); } return(segment.SequenceEqual(otherUtf8Text)); }
internal bool TryGetValue(int index, out double value) { JsonRow row = _parsedData.Get(index); CheckExpectedType(JsonTokenType.Number, row.TokenType); ReadOnlySpan <byte> data = _utf8Json.Span; ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length); if (Utf8Parser.TryParse(segment, out double tmp, out int bytesConsumed) && segment.Length == bytesConsumed) { value = tmp; return(true); } #if NET5_0_OR_GREATER Unsafe.SkipInit(out value); #else value = default; #endif return(false); }
private bool TryGetNamedPropertyValue( int endIndex, ReadOnlySpan <byte> propertyName, out JwtElement value) { ReadOnlySpan <byte> documentSpan = _utf8Json.Span; Span <byte> utf8UnescapedStack = stackalloc byte[JsonConstants.StackallocThreshold]; // Move to the row before the EndObject int index = 0; while (index < endIndex) { JsonRow row = _parsedData.Get(index); Debug.Assert(row.TokenType == JsonTokenType.PropertyName); ReadOnlySpan <byte> currentPropertyName = documentSpan.Slice(row.Location, row.Length); if (row.NeedUnescaping) { // An escaped property name will be longer than an unescaped candidate, so only unescape // when the lengths are compatible. if (currentPropertyName.Length > propertyName.Length) { int idx = currentPropertyName.IndexOf(JsonConstants.BackSlash); Debug.Assert(idx >= 0); // If everything up to where the property name has a backslash matches, keep going. if (propertyName.Length > idx && currentPropertyName.Slice(0, idx).SequenceEqual(propertyName.Slice(0, idx))) { int remaining = currentPropertyName.Length - idx; int written = 0; byte[]? rented = null; try { Span <byte> utf8Unescaped = remaining <= utf8UnescapedStack.Length ? utf8UnescapedStack : (rented = ArrayPool <byte> .Shared.Rent(remaining)); // Only unescape the part we haven't processed. JsonReaderHelper.Unescape(currentPropertyName.Slice(idx), utf8Unescaped, 0, out written); // If the unescaped remainder matches the input remainder, it's a match. if (utf8Unescaped.Slice(0, written).SequenceEqual(propertyName.Slice(idx))) { // If the property name is a match, the answer is the next element. value = new JwtElement(this, index + JsonRow.Size); return(true); } } finally { if (rented != null) { rented.AsSpan(0, written).Clear(); ArrayPool <byte> .Shared.Return(rented); } } } } } else if (currentPropertyName.SequenceEqual(propertyName)) { // If the property name is a match, the answer is the next element. value = new JwtElement(this, index + JsonRow.Size); return(true); } // Move to the previous value index += JsonRow.Size * 2; } value = default; return(false); }