예제 #1
0
        internal static char[]? EscapeString(
            ReadOnlySpan <char> stringToEscape,
            char[]?dest, ref int destPos,
            bool checkExistingEscaped, char forceEscape1 = '\0', char forceEscape2 = '\0')
        {
            // Get the table of characters that do not need to be escaped.
            ReadOnlySpan <bool> noEscape = stackalloc bool[0];

            if ((forceEscape1 | forceEscape2) == 0)
            {
                noEscape = UnreservedReservedTable;
            }
            else
            {
                Span <bool> tmp = stackalloc bool[0x80];
                UnreservedReservedTable.CopyTo(tmp);
                tmp[forceEscape1] = false;
                tmp[forceEscape2] = false;
                noEscape          = tmp;
            }

            // If the whole string is made up of ASCII unreserved chars, take a fast pasth.  Per the contract, if
            // dest is null, just return it.  If it's not null, copy everything to it and update destPos accordingly;
            // if that requires resizing it, do so.
            Debug.Assert(!noEscape['%'], "Need to treat % specially in case checkExistingEscaped is true");
            int  i = 0;
            char c;

            for (; i < stringToEscape.Length && (c = stringToEscape[i]) <= 0x7F && noEscape[c]; i++)
            {
                ;
            }
            if (i == stringToEscape.Length)
            {
                if (dest != null)
                {
                    EnsureCapacity(dest, destPos, stringToEscape.Length);
                    stringToEscape.CopyTo(dest.AsSpan(destPos));
                    destPos += stringToEscape.Length;
                }

                return(dest);
            }

            // Otherwise, create a ValueStringBuilder to store the escaped data into,
            // append to it all of the noEscape chars we already iterated through, and
            // escape the rest into the ValueStringBuilder.
            var vsb = new ValueStringBuilder(stackalloc char[256]);

            vsb.Append(stringToEscape.Slice(0, i));
            EscapeStringToBuilder(stringToEscape.Slice(i), ref vsb, noEscape, checkExistingEscaped);

            // Finally update dest with the result.
            EnsureCapacity(dest, destPos, vsb.Length);
            vsb.TryCopyTo(dest.AsSpan(destPos), out int charsWritten);
            destPos += charsWritten;
            return(dest);
예제 #2
0
        internal static unsafe void EscapeString(ReadOnlySpan <char> stringToEscape, ref ValueStringBuilder dest,
                                                 bool checkExistingEscaped, char forceEscape1 = '\0', char forceEscape2 = '\0')
        {
            // Get the table of characters that do not need to be escaped.
            ReadOnlySpan <bool> noEscape = stackalloc bool[0];

            if ((forceEscape1 | forceEscape2) == 0)
            {
                noEscape = UnreservedReservedTable;
            }
            else
            {
                Span <bool> tmp = stackalloc bool[0x80];
                UnreservedReservedTable.CopyTo(tmp);
                tmp[forceEscape1] = false;
                tmp[forceEscape2] = false;
                noEscape          = tmp;
            }

            // If the whole string is made up of ASCII unreserved chars, take a fast pasth.  Per the contract, if
            // dest is null, just return it.  If it's not null, copy everything to it and update destPos accordingly;
            // if that requires resizing it, do so.
            Debug.Assert(!noEscape['%'], "Need to treat % specially in case checkExistingEscaped is true");
            int  i = 0;
            char c;

            for (; i < stringToEscape.Length && (c = stringToEscape[i]) <= 0x7F && noEscape[c]; i++)
            {
                ;
            }
            if (i == stringToEscape.Length)
            {
                dest.Append(stringToEscape);
            }
            else
            {
                dest.Append(stringToEscape.Slice(0, i));

                // CS8350 & CS8352: We can't pass `noEscape` and `dest` as arguments together as that could leak the scope of the above stackalloc
                // As a workaround, re-create the Span in a way that avoids analysis
                ReadOnlySpan <bool> noEscapeCopy = MemoryMarshal.CreateReadOnlySpan(ref MemoryMarshal.GetReference(noEscape), noEscape.Length);

                EscapeStringToBuilder(stringToEscape.Slice(i), ref dest, noEscapeCopy, checkExistingEscaped);
            }
        }