Exemple #1
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;

            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++;
                    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;
                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;
            }
        }