private static Utf8String UnescapeJson()

in Microsoft.Azure.Cosmos/src/Json/JsonTextParser.cs [225:362]


        private static Utf8String UnescapeJson(Utf8Memory escapedString, bool checkIfNeedsEscaping = true)
        {
            if (escapedString.IsEmpty)
            {
                return Utf8String.Empty;
            }

            if (checkIfNeedsEscaping && (escapedString.Span.Span.IndexOf(JsonTextParser.ReverseSolidusBytes.Span) < 0))
            {
                // String doesn't need unescaping
                return Utf8String.UnsafeFromUtf8BytesNoValidation(escapedString.Memory);
            }

            Memory<byte> stringBuffer = new byte[escapedString.Length];
            escapedString.Memory.CopyTo(stringBuffer);

            Span<byte> stringBufferSpan = stringBuffer.Span;

            int readOffset = 0;
            int writeOffset = 0;
            while (readOffset != stringBuffer.Length)
            {
                if (stringBufferSpan[readOffset] == '\\')
                {
                    // Consume the '\' character
                    readOffset++;

                    // Figure out how to escape.
                    switch (stringBufferSpan[readOffset++])
                    {
                        case (byte)'b':
                            stringBufferSpan[writeOffset++] = (byte)'\b';
                            break;
                        case (byte)'f':
                            stringBufferSpan[writeOffset++] = (byte)'\f';
                            break;
                        case (byte)'n':
                            stringBufferSpan[writeOffset++] = (byte)'\n';
                            break;
                        case (byte)'r':
                            stringBufferSpan[writeOffset++] = (byte)'\r';
                            break;
                        case (byte)'t':
                            stringBufferSpan[writeOffset++] = (byte)'\t';
                            break;
                        case (byte)'\\':
                            stringBufferSpan[writeOffset++] = (byte)'\\';
                            break;
                        case (byte)'"':
                            stringBufferSpan[writeOffset++] = (byte)'"';
                            break;
                        case (byte)'/':
                            stringBufferSpan[writeOffset++] = (byte)'/';
                            break;
                        case (byte)'u':
                            // parse JSON unicode code point: \uXXXX(\uYYYY)
                            // Start by reading XXXX, since \u is already read.
                            char escapeSequence = (char)0;
                            for (int escapeSequenceIndex = 0; escapeSequenceIndex < 4; escapeSequenceIndex++)
                            {
                                escapeSequence <<= 4;

                                byte currentCharacter = stringBufferSpan[readOffset++];
                                if (currentCharacter >= '0' && currentCharacter <= '9')
                                {
                                    escapeSequence += (char)(currentCharacter - '0');
                                }
                                else if (currentCharacter >= 'A' && currentCharacter <= 'F')
                                {
                                    escapeSequence += (char)(10 + currentCharacter - 'A');
                                }
                                else if (currentCharacter >= 'a' && currentCharacter <= 'f')
                                {
                                    escapeSequence += (char)(10 + currentCharacter - 'a');
                                }
                                else
                                {
                                    throw new JsonInvalidEscapedCharacterException();
                                }
                            }

                            if ((escapeSequence >= Utf16Surrogate.High.Min) && (escapeSequence <= Utf16Surrogate.High.Max))
                            {
                                // We have a high surrogate + low surrogate pair
                                if (stringBufferSpan[readOffset++] != '\\')
                                {
                                    throw new JsonInvalidEscapedCharacterException();
                                }

                                if (stringBufferSpan[readOffset++] != 'u')
                                {
                                    throw new JsonInvalidEscapedCharacterException();
                                }

                                char highSurrogate = escapeSequence;

                                char lowSurrogate = (char)0;
                                for (int escapeSequenceIndex = 0; escapeSequenceIndex < 4; escapeSequenceIndex++)
                                {
                                    lowSurrogate <<= 4;

                                    byte currentCharacter = stringBufferSpan[readOffset++];
                                    if (currentCharacter >= '0' && currentCharacter <= '9')
                                    {
                                        lowSurrogate += (char)(currentCharacter - '0');
                                    }
                                    else if (currentCharacter >= 'A' && currentCharacter <= 'F')
                                    {
                                        lowSurrogate += (char)(10 + currentCharacter - 'A');
                                    }
                                    else if (currentCharacter >= 'a' && currentCharacter <= 'f')
                                    {
                                        lowSurrogate += (char)(10 + currentCharacter - 'a');
                                    }
                                    else
                                    {
                                        throw new JsonInvalidEscapedCharacterException();
                                    }
                                }

                                writeOffset += WideCharToMultiByte(highSurrogate, lowSurrogate, stringBufferSpan.Slice(start: writeOffset));
                            }
                            else
                            {
                                writeOffset += WideCharToMultiByte(escapeSequence, stringBufferSpan.Slice(start: writeOffset));
                            }

                            break;
                    }
                }
                else
                {
                    stringBufferSpan[writeOffset++] = stringBufferSpan[readOffset++];
                }
            }

            return Utf8String.UnsafeFromUtf8BytesNoValidation(stringBuffer.Slice(start: 0, writeOffset));
        }