Exemplo n.º 1
0
        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));
        }
Exemplo n.º 2
0
        internal bool TextEquals(int index, ReadOnlySpan <char> otherText, bool isPropertyName)
        {
            int matchIndex = isPropertyName ? index - JsonRow.Size : index;

            byte[]? otherUtf8TextArray = null;

            int         length        = checked (otherText.Length * JsonConstants.MaxExpansionFactorWhileTranscoding);
            Span <byte> otherUtf8Text = length <= JsonConstants.StackallocThreshold ?
                                        stackalloc byte[JsonConstants.StackallocThreshold] :
                                        (otherUtf8TextArray = ArrayPool <byte> .Shared.Rent(length));

            ReadOnlySpan <byte> utf16Text = MemoryMarshal.AsBytes(otherText);
            OperationStatus     status    = JsonReaderHelper.ToUtf8(utf16Text, otherUtf8Text, out int consumed, out int written);

            Debug.Assert(status != OperationStatus.DestinationTooSmall);
            bool result;

            if (status > OperationStatus.DestinationTooSmall)   // Equivalent to: (status == NeedMoreData || status == InvalidData)
            {
                result = false;
            }
            else
            {
                Debug.Assert(status == OperationStatus.Done);
                Debug.Assert(consumed == utf16Text.Length);

                result = TextEquals(index, otherUtf8Text.Slice(0, written), isPropertyName, shouldUnescape: true);
            }

            if (otherUtf8TextArray != null)
            {
                otherUtf8Text.Slice(0, written).Clear();
                ArrayPool <byte> .Shared.Return(otherUtf8TextArray);
            }

            return(result);
        }
Exemplo n.º 3
0
        internal string GetPropertyRawValueAsString(int valueIndex)
        {
            ReadOnlyMemory <byte> segment = GetPropertyRawValue(valueIndex);

            return(JsonReaderHelper.TranscodeHelper(segment.Span));
        }
Exemplo n.º 4
0
        internal string GetRawValueAsString(int index)
        {
            ReadOnlyMemory <byte> segment = GetRawValue(index, includeQuotes: true);

            return(JsonReaderHelper.TranscodeHelper(segment.Span));
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        internal bool TryGetNamedPropertyValue(ReadOnlySpan <char> propertyName, out JwtElement value)
        {
            JsonRow row;

            int maxBytes = Utf8.GetMaxByteCount(propertyName.Length);
            int endIndex = _parsedData.Length;

            if (maxBytes < JsonConstants.StackallocThreshold)
            {
                Span <byte> utf8Name = stackalloc byte[JsonConstants.StackallocThreshold];
                int         len      = JsonReaderHelper.GetUtf8FromText(propertyName, utf8Name);
                utf8Name = utf8Name.Slice(0, len);

                return(TryGetNamedPropertyValue(
                           endIndex,
                           utf8Name,
                           out value));
            }

            // Unescaping the property name will make the string shorter (or the same)
            // So the first viable candidate is one whose length in bytes matches, or
            // exceeds, our length in chars.
            //
            // The maximal escaping seems to be 6 -> 1 ("\u0030" => "0"), but just transcode
            // and switch once one viable long property is found.
            int minBytes = propertyName.Length;

            for (int candidateIndex = 0; candidateIndex <= endIndex; candidateIndex += JsonRow.Size * 2)
            {
                row = _parsedData.Get(candidateIndex);
                Debug.Assert(row.TokenType == JsonTokenType.PropertyName);

                if (row.Length >= minBytes)
                {
                    byte[] tmpUtf8 = ArrayPool <byte> .Shared.Rent(maxBytes);

                    Span <byte> utf8Name = default;

                    try
                    {
                        int len = JsonReaderHelper.GetUtf8FromText(propertyName, tmpUtf8);
                        utf8Name = tmpUtf8.AsSpan(0, len);

                        return(TryGetNamedPropertyValue(
                                   candidateIndex,
                                   utf8Name,
                                   out value));
                    }
                    finally
                    {
                        ArrayPool <byte> .Shared.Return(tmpUtf8);
                    }
                }
            }

            // None of the property names were within the range that the UTF-8 encoding would have been.
#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out value);
#else
            value = default;
#endif
            return(false);
        }