Пример #1
0
        public DateTimeOffset Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
        {
            var str   = reader.ReadStringSegmentUnsafe();
            var array = str.Array;
            var i     = str.Offset;
            var len   = str.Count;
            var to    = str.Offset + str.Count;

            // YYYY
            if (len == 4)
            {
                var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                return(new DateTimeOffset(y, 1, 1, 0, 0, 0, TimeSpan.Zero));
            }

            // YYYY-MM
            if (len == 7)
            {
                var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                if (array[i++] != (byte)'-')
                {
                    goto ERROR;
                }
                var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                return(new DateTimeOffset(y, m, 1, 0, 0, 0, TimeSpan.Zero));
            }

            // YYYY-MM-DD
            if (len == 10)
            {
                var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                if (array[i++] != (byte)'-')
                {
                    goto ERROR;
                }
                var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                if (array[i++] != (byte)'-')
                {
                    goto ERROR;
                }
                var d = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                return(new DateTimeOffset(y, m, d, 0, 0, 0, TimeSpan.Zero));
            }

            // range-first section requires 19
            if (array.Length < 19)
            {
                goto ERROR;
            }

            var year = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)'-')
            {
                goto ERROR;
            }
            var month = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)'-')
            {
                goto ERROR;
            }
            var day = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)'T')
            {
                goto ERROR;
            }

            var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }
            var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }
            var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            int ticks = 0;

            if (i < to && array[i] == '.')
            {
                i++;

                // *7.
                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 1000000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 100000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 10000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 1000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 100;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 10;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 1;
                i++;

                // others, lack of precision
                while (i < to && NumberConverter.IsNumber(array[i]))
                {
                    i++;
                }
            }

END_TICKS:

            if (i < to && array[i] == '-' || array[i] == '+')
            {
                if (!(i + 5 < to))
                {
                    goto ERROR;
                }

                var minus = array[i++] == '-';

                var h = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                i++;
                var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

                var offset = new TimeSpan(h, m, 0);
                if (minus)
                {
                    offset = offset.Negate();
                }

                return(new DateTimeOffset(year, month, day, hour, minute, second, offset).AddTicks(ticks));
            }

            return(new DateTimeOffset(year, month, day, hour, minute, second, TimeSpan.Zero).AddTicks(ticks));

ERROR:
            throw new InvalidOperationException("invalid datetime format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count));
        }
Пример #2
0
        public TimeSpan Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
        {
            var str   = reader.ReadStringSegmentUnsafe();
            var array = str.Array;
            var i     = str.Offset;
            var len   = str.Count;
            var to    = str.Offset + str.Count;

            // check day exists
            bool hasDay = false;
            {
                bool foundDot   = false;
                bool foundColon = false;
                for (int j = i; j < str.Count; j++)
                {
                    if (array[j] == '.')
                    {
                        if (foundColon)
                        {
                            break;
                        }
                        foundDot = true;
                    }
                    else if (array[j] == ':')
                    {
                        if (foundDot)
                        {
                            hasDay = true;
                        }
                        foundColon = true;
                    }
                }
            }

            // check sign
            var minus = false;

            if (array[i] == '-')
            {
                minus = true;
                i++;
            }

            var day = 0;

            if (hasDay)
            {
                var poolArray = BufferPool.Default.Rent();
                try
                {
                    for (; array[i] != '.'; i++)
                    {
                        poolArray[day++] = array[i];
                    }
                    day = new JsonReader(poolArray).ReadInt32();
                    i++; // skip '.'
                }
                finally
                {
                    BufferPool.Default.Return(poolArray);
                }
            }

            var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }
            var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }
            var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            int ticks = 0;

            if (i < to && array[i] == '.')
            {
                i++;

                // *7.
                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 1000000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 100000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 10000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 1000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 100;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 10;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }
                ticks += (array[i] - (byte)'0') * 1;
                i++;

                // others, lack of precision
                while (i < to && NumberConverter.IsNumber(array[i]))
                {
                    i++;
                }
            }

END_TICKS:

            // be careful to overflow
            var ts = new TimeSpan(day, hour, minute, second);
            var tk = TimeSpan.FromTicks(ticks);

            return((minus)
                ? ts.Negate().Subtract(tk)
                : ts.Add(tk));

ERROR:
            throw new InvalidOperationException("invalid datetime format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count));
        }
        public TimeSpan Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
        {
            var str   = reader.ReadStringSegmentUnsafe();
            var array = str.Array;
            var i     = str.Offset;
            var len   = str.Count;
            var to    = str.Offset + len;

            // check day exists
            var hasDay = false;
            {
                var foundDot   = false;
                var foundColon = false;
                for (var j = i; j < to; j++)
                {
                    if (array[j] == '.')
                    {
                        if (foundColon)
                        {
                            break;
                        }

                        foundDot = true;
                    }
                    else if (array[j] == ':')
                    {
                        if (foundDot)
                        {
                            hasDay = true;
                        }

                        foundColon = true;
                    }
                }
            }

            // check sign
            var minus = false;

            if (array[i] == '-')
            {
                minus = true;
                i++;
            }

            var day = 0;

            if (hasDay)
            {
                const int maxDayLength  = 8 + 1;                // {Day}.
                var       dayCharacters = new byte[maxDayLength];
                for (; array[i] != '.'; i++)
                {
                    dayCharacters[day++] = array[i];
                }

                day = new JsonReader(dayCharacters).ReadInt32();
                i++;                 // skip '.'
            }

            var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }

            var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }

            var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            var ticks = 0;

            if (i < to && array[i] == '.')
            {
                i++;

                // *7.
                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 1000000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 100000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 10000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 1000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 100;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 10;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 1;
                i++;

                // others, lack of precision
                while (i < to && NumberConverter.IsNumber(array[i]))
                {
                    i++;
                }
            }

END_TICKS:

            // be careful to overflow
            var ts = new TimeSpan(day, hour, minute, second);
            var tk = TimeSpan.FromTicks(ticks);

            return(minus
                                ? ts.Negate().Subtract(tk)
                                : ts.Add(tk));

ERROR:
            throw new InvalidOperationException("invalid TimeSpan format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count));
        }
        public DateTime Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
        {
            var str   = reader.ReadStringSegmentUnsafe();
            var array = str.Array;
            var i     = str.Offset;
            var len   = str.Count;
            var to    = str.Offset + str.Count;

            // YYYY
            if (len == 4)
            {
                var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                return(new DateTime(y, 1, 1));
            }

            // YYYY-MM
            if (len == 7)
            {
                var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                if (array[i++] != (byte)'-')
                {
                    goto ERROR;
                }

                var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                return(new DateTime(y, m, 1));
            }

            // YYYY-MM-DD
            if (len == 10)
            {
                var y = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                if (array[i++] != (byte)'-')
                {
                    goto ERROR;
                }

                var m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                if (array[i++] != (byte)'-')
                {
                    goto ERROR;
                }

                var d = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                return(new DateTime(y, m, d));
            }

            // range-first section requires 19
            if (len < 19)
            {
                goto ERROR;
            }

            var year = (array[i++] - (byte)'0') * 1000 + (array[i++] - (byte)'0') * 100 + (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)'-')
            {
                goto ERROR;
            }

            var month = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)'-')
            {
                goto ERROR;
            }

            var day = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)'T')
            {
                goto ERROR;
            }

            var hour = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }

            var minute = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            if (array[i++] != (byte)':')
            {
                goto ERROR;
            }

            var second = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');

            var ticks = 0;

            if (i < to && array[i] == '.')
            {
                i++;

                // *7.
                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 1000000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 100000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 10000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 1000;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 100;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 10;
                i++;

                if (!(i < to) || !NumberConverter.IsNumber(array[i]))
                {
                    goto END_TICKS;
                }

                ticks += (array[i] - (byte)'0') * 1;
                i++;

                // others, lack of precision
                while (i < to && NumberConverter.IsNumber(array[i]))
                {
                    i++;
                }
            }

END_TICKS:
            var kind = DateTimeKind.Unspecified;

            if (i < to && array[i] == 'Z')
            {
                kind = DateTimeKind.Utc;
            }
            else if (i < to && array[i] == '-' || array[i] == '+')
            {
                var offLen = to - i;
                if (offLen != 3 && offLen != 5 && offLen != 6)
                {
                    goto ERROR;
                }

                var minus = array[i++] == '-';
                var h     = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                var m     = 0;
                if (i < to)
                {
                    if (offLen == 6)
                    {
                        if (array[i] != ':')
                        {
                            goto ERROR;
                        }

                        i++;
                    }
                    m = (array[i++] - (byte)'0') * 10 + (array[i++] - (byte)'0');
                }

                var offset = new TimeSpan(h, m, 0);
                if (minus)
                {
                    offset = offset.Negate();
                }

                return(new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(ticks).Subtract(offset).ToLocalTime());
            }

            return(new DateTime(year, month, day, hour, minute, second, kind).AddTicks(ticks));

ERROR:
            throw new InvalidOperationException("invalid datetime format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count));
        }
Пример #5
0
        void ReadStringSegmentCore(out byte[] resultBytes, out int resultOffset, out int resultLength)
        {
            // SkipWhiteSpace is already called from IsNull

            byte[] builder       = null;
            var    builderOffset = 0;

            char[] codePointStringBuffer = null;
            var    codePointStringOffet  = 0;
            var    isNumberAsString      = false;

            if (NumberConverter.IsNumber(bytes[offset]) ||
                (bytes[offset] == '-' && NumberConverter.IsNumber(bytes[offset + 1])))
            {
                isNumberAsString = true;
            }
            if (!isNumberAsString)
            {
                if (bytes[offset] != '\"')
                {
                    throw CreateParsingException("String Begin Token");
                }
                offset++;
            }


            var from = offset;

            // eliminate array-bound check
            for (int i = offset; i < bytes.Length; i++)
            {
                byte escapeCharacter = 0;
                switch (bytes[i])
                {
                case (byte)'\\':     // escape character
                    switch ((char)bytes[i + 1])
                    {
                    case '"':
                    case '\\':
                    case '/':
                        escapeCharacter = bytes[i + 1];
                        goto COPY;

                    case 'b':
                        escapeCharacter = (byte)'\b';
                        goto COPY;

                    case 'f':
                        escapeCharacter = (byte)'\f';
                        goto COPY;

                    case 'n':
                        escapeCharacter = (byte)'\n';
                        goto COPY;

                    case 'r':
                        escapeCharacter = (byte)'\r';
                        goto COPY;

                    case 't':
                        escapeCharacter = (byte)'\t';
                        goto COPY;

                    case 'u':
                        if (codePointStringBuffer == null)
                        {
                            codePointStringBuffer = StringBuilderCache.GetCodePointStringBuffer();
                        }

                        if (codePointStringOffet == 0)
                        {
                            if (builder == null)
                            {
                                builder = StringBuilderCache.GetBuffer();
                            }

                            var copyCount = i - from;
                            BinaryUtil.EnsureCapacity(ref builder, builderOffset, copyCount + 1);         // require + 1
                            Buffer.BlockCopy(bytes, from, builder, builderOffset, copyCount);
                            builderOffset += copyCount;
                        }

                        if (codePointStringBuffer.Length == codePointStringOffet)
                        {
                            Array.Resize(ref codePointStringBuffer, codePointStringBuffer.Length * 2);
                        }

                        var a         = (char)bytes[i + 2];
                        var b         = (char)bytes[i + 3];
                        var c         = (char)bytes[i + 4];
                        var d         = (char)bytes[i + 5];
                        var codepoint = GetCodePoint(a, b, c, d);
                        codePointStringBuffer[codePointStringOffet++] = (char)codepoint;
                        i      += 5;
                        offset += 6;
                        from    = offset;
                        continue;

                    default:
                        throw CreateParsingExceptionMessage("Bad JSON escape.");
                    }

                case (byte)'"':     // endtoken
                    offset++;
                    goto END;

                default:     // string
                    if (codePointStringOffet != 0)
                    {
                        if (builder == null)
                        {
                            builder = StringBuilderCache.GetBuffer();
                        }
                        BinaryUtil.EnsureCapacity(ref builder, builderOffset, StringEncoding.UTF8.GetMaxByteCount(codePointStringOffet));
                        builderOffset       += StringEncoding.UTF8.GetBytes(codePointStringBuffer, 0, codePointStringOffet, builder, builderOffset);
                        codePointStringOffet = 0;
                    }

                    offset++;
                    if (isNumberAsString && !NumberConverter.IsNumber(bytes[i]) && bytes[i] != '.')
                    {
                        offset--;
                        goto END;
                    }
                    continue;
                }

COPY:
                {
                    if (builder == null)
                    {
                        builder = StringBuilderCache.GetBuffer();
                    }
                    if (codePointStringOffet != 0)
                    {
                        BinaryUtil.EnsureCapacity(ref builder, builderOffset, StringEncoding.UTF8.GetMaxByteCount(codePointStringOffet));
                        builderOffset       += StringEncoding.UTF8.GetBytes(codePointStringBuffer, 0, codePointStringOffet, builder, builderOffset);
                        codePointStringOffet = 0;
                    }

                    var copyCount = i - from;
                    BinaryUtil.EnsureCapacity(ref builder, builderOffset, copyCount + 1); // require + 1!
                    Buffer.BlockCopy(bytes, from, builder, builderOffset, copyCount);
                    builderOffset           += copyCount;
                    builder[builderOffset++] = escapeCharacter;
                    i      += 1;
                    offset += 2;
                    from    = offset;
                }
            }

            resultLength = 0;
            resultBytes  = null;
            resultOffset = 0;
            throw CreateParsingException("String End Token");

END:
            if (builderOffset == 0 && codePointStringOffet == 0) // no escape
            {
                resultBytes  = bytes;
                resultOffset = from;
                if (isNumberAsString)
                {
                    resultLength = offset - from;
                }
                else
                {
                    resultLength = offset - 1 - from; // skip last quote
                }
            }
            else
            {
                if (builder == null)
                {
                    builder = StringBuilderCache.GetBuffer();
                }
                if (codePointStringOffet != 0)
                {
                    BinaryUtil.EnsureCapacity(ref builder, builderOffset, StringEncoding.UTF8.GetMaxByteCount(codePointStringOffet));
                    builderOffset       += StringEncoding.UTF8.GetBytes(codePointStringBuffer, 0, codePointStringOffet, builder, builderOffset);
                    codePointStringOffet = 0;
                }

                var copyCount = offset - from - 1;
                BinaryUtil.EnsureCapacity(ref builder, builderOffset, copyCount);
                Buffer.BlockCopy(bytes, from, builder, builderOffset, copyCount);
                builderOffset += copyCount;

                resultBytes  = builder;
                resultOffset = 0;
                resultLength = builderOffset;
            }
        }