예제 #1
0
        private DateOnly ReadCore(ref Utf8JsonReader reader)
        {
            bool isEscaped             = reader._stringHasEscaping;
            ReadOnlySpan <byte> source = stackalloc byte[0];

            if (reader.HasValueSequence)
            {
                ReadOnlySequence <byte> valueSequence = reader.ValueSequence;
                long sequenceLength = valueSequence.Length;

                if (!JsonHelpers.IsInRangeInclusive(sequenceLength, FormatLength, MaxEscapedFormatLength))
                {
                    ThrowHelper.ThrowFormatException(DataType.DateOnly);
                }

                Span <byte> stackSpan = stackalloc byte[isEscaped ? FormatLength : MaxEscapedFormatLength];
                valueSequence.CopyTo(stackSpan);
                source = stackSpan.Slice(0, (int)sequenceLength);
            }
            else
            {
                source = reader.ValueSpan;

                if (!JsonHelpers.IsInRangeInclusive(source.Length, FormatLength, MaxEscapedFormatLength))
                {
                    ThrowHelper.ThrowFormatException(DataType.DateOnly);
                }
            }

            if (isEscaped)
            {
                int backslash = source.IndexOf(JsonConstants.BackSlash);
                Debug.Assert(backslash != -1);

                Span <byte> sourceUnescaped = stackalloc byte[MaxEscapedFormatLength];

                JsonReaderHelper.Unescape(source, sourceUnescaped, backslash, out int written);
                Debug.Assert(written > 0);

                source = sourceUnescaped.Slice(0, written);
                Debug.Assert(!source.IsEmpty);
            }

            if (!JsonHelpers.TryParseAsIso(source, out DateOnly value))
            {
                ThrowHelper.ThrowFormatException(DataType.DateOnly);
            }

            return(value);
        }
예제 #2
0
        public override Version Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.String)
            {
                ThrowHelper.ThrowInvalidOperationException_ExpectedString(reader.TokenType);
            }

#if BUILDING_INBOX_LIBRARY
            bool isEscaped = reader._stringHasEscaping;

            int maxLength = isEscaped ? MaximumEscapedVersionLength : MaximumVersionLength;
            ReadOnlySpan <byte> source = stackalloc byte[0];
            if (reader.HasValueSequence)
            {
                if (!JsonHelpers.IsInRangeInclusive(reader.ValueSequence.Length, MinimumVersionLength, maxLength))
                {
                    ThrowHelper.ThrowFormatException(DataType.Version);
                }

                Span <byte> stackSpan = stackalloc byte[isEscaped ? MaximumEscapedVersionLength : MaximumVersionLength];
                reader.ValueSequence.CopyTo(stackSpan);
                source = stackSpan.Slice(0, (int)reader.ValueSequence.Length);
            }
            else
            {
                source = reader.ValueSpan;

                if (!JsonHelpers.IsInRangeInclusive(source.Length, MinimumVersionLength, maxLength))
                {
                    ThrowHelper.ThrowFormatException(DataType.Version);
                }
            }

            if (isEscaped)
            {
                int backslash = source.IndexOf(JsonConstants.BackSlash);
                Debug.Assert(backslash != -1);

                Span <byte> sourceUnescaped = stackalloc byte[MaximumEscapedVersionLength];

                JsonReaderHelper.Unescape(source, sourceUnescaped, backslash, out int written);
                Debug.Assert(written > 0);

                source = sourceUnescaped.Slice(0, written);
                Debug.Assert(!source.IsEmpty);
            }

            byte firstChar = source[0];
            byte lastChar  = source[source.Length - 1];
            if (!JsonHelpers.IsDigit(firstChar) || !JsonHelpers.IsDigit(lastChar))
            {
                // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters
                // we need to make sure that our input doesn't have them,
                // and if it has - we need to throw, to match behaviour of other converters
                // since Version.TryParse allows them and silently parses input to Version
                ThrowHelper.ThrowFormatException(DataType.Version);
            }

            Span <char> charBuffer   = stackalloc char[MaximumVersionLength];
            int         writtenChars = JsonReaderHelper.s_utf8Encoding.GetChars(source, charBuffer);
            if (Version.TryParse(charBuffer.Slice(0, writtenChars), out Version? result))
            {
                return(result);
            }
#else
            string?versionString = reader.GetString();
            if (!string.IsNullOrEmpty(versionString) && (!char.IsDigit(versionString[0]) || !char.IsDigit(versionString[versionString.Length - 1])))
            {
                // Since leading and trailing whitespaces are forbidden throughout System.Text.Json converters
                // we need to make sure that our input doesn't have them,
                // and if it has - we need to throw, to match behaviour of other converters
                // since Version.TryParse allows them and silently parses input to Version
                ThrowHelper.ThrowFormatException(DataType.Version);
            }
            if (Version.TryParse(versionString, out Version? result))
            {
                return(result);
            }
#endif
            ThrowHelper.ThrowJsonException();
            return(null);
        }
예제 #3
0
        public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.String)
            {
                throw ThrowHelper.GetInvalidOperationException_ExpectedString(reader.TokenType);
            }

            bool isEscaped     = reader._stringHasEscaping;
            int  maximumLength = isEscaped ? MaximumEscapedTimeSpanFormatLength : MaximumTimeSpanFormatLength;

            ReadOnlySpan <byte> source = stackalloc byte[0];

            if (reader.HasValueSequence)
            {
                ReadOnlySequence <byte> valueSequence = reader.ValueSequence;
                long sequenceLength = valueSequence.Length;

                if (!JsonHelpers.IsInRangeInclusive(sequenceLength, MinimumTimeSpanFormatLength, maximumLength))
                {
                    throw ThrowHelper.GetFormatException(DataType.TimeSpan);
                }

                Span <byte> stackSpan = stackalloc byte[isEscaped ? MaximumEscapedTimeSpanFormatLength : MaximumTimeSpanFormatLength];
                valueSequence.CopyTo(stackSpan);
                source = stackSpan.Slice(0, (int)sequenceLength);
            }
            else
            {
                source = reader.ValueSpan;

                if (!JsonHelpers.IsInRangeInclusive(source.Length, MinimumTimeSpanFormatLength, maximumLength))
                {
                    throw ThrowHelper.GetFormatException(DataType.TimeSpan);
                }
            }

            if (isEscaped)
            {
                int backslash = source.IndexOf(JsonConstants.BackSlash);
                Debug.Assert(backslash != -1);

                Span <byte> sourceUnescaped = stackalloc byte[MaximumEscapedTimeSpanFormatLength];

                JsonReaderHelper.Unescape(source, sourceUnescaped, backslash, out int written);
                Debug.Assert(written > 0);

                source = sourceUnescaped.Slice(0, written);
                Debug.Assert(!source.IsEmpty);
            }

            byte firstChar = source[0];

            if (!JsonHelpers.IsDigit(firstChar) && firstChar != '-')
            {
                // Note: Utf8Parser.TryParse allows for leading whitespace so we
                // need to exclude that case here.
                throw ThrowHelper.GetFormatException(DataType.TimeSpan);
            }

            bool result = Utf8Parser.TryParse(source, out TimeSpan tmpValue, out int bytesConsumed, 'c');

            // Note: Utf8Parser.TryParse will return true for invalid input so
            // long as it starts with an integer. Example: "2021-06-18" or
            // "1$$$$$$$$$$". We need to check bytesConsumed to know if the
            // entire source was actually valid.

            if (result && source.Length == bytesConsumed)
            {
                return(tmpValue);
            }

            throw ThrowHelper.GetFormatException(DataType.TimeSpan);
        }