示例#1
0
 private static void EncodeHexString(byte[] sArray, ref ValueStringBuilder stringBuilder)
 {
     for (int i = 0; i < sArray.Length; i++)
     {
         HexConverter.ToCharsBuffer(sArray[i], stringBuilder.AppendSpan(2), 0, HexConverter.Casing.Upper);
     }
 }
示例#2
0
        public void AppendSpan_DataAppendedCorrectly()
        {
            var sb  = new StringBuilder();
            var vsb = new ValueStringBuilder();

            for (int i = 1; i <= 1000; i++)
            {
                string s = i.ToString();

                sb.Append(s);

                Span <char> span = vsb.AppendSpan(s.Length);
                Assert.Equal(sb.Length, vsb.Length);

                s.AsSpan().CopyTo(span);
            }

            Assert.Equal(sb.Length, vsb.Length);
            Assert.Equal(sb.ToString(), vsb.ToString());
        }
示例#3
0
        private static void HtmlEncode(ReadOnlySpan <char> input, ref ValueStringBuilder output)
        {
            for (int i = 0; i < input.Length; i++)
            {
                char ch = input[i];
                if (ch <= '>')
                {
                    switch (ch)
                    {
                    case '<':
                        output.Append("&lt;");
                        break;

                    case '>':
                        output.Append("&gt;");
                        break;

                    case '"':
                        output.Append("&quot;");
                        break;

                    case '\'':
                        output.Append("&#39;");
                        break;

                    case '&':
                        output.Append("&amp;");
                        break;

                    default:
                        output.Append(ch);
                        break;
                    }
                }
                else
                {
                    int valueToEncode = -1; // set to >= 0 if needs to be encoded

#if ENTITY_ENCODE_HIGH_ASCII_CHARS
                    if (ch >= 160 && ch < 256)
                    {
                        // The seemingly arbitrary 160 comes from RFC
                        valueToEncode = ch;
                    }
                    else
#endif // ENTITY_ENCODE_HIGH_ASCII_CHARS
                    if (char.IsSurrogate(ch))
                    {
                        int scalarValue = GetNextUnicodeScalarValueFromUtf16Surrogate(input, ref i);
                        if (scalarValue >= UNICODE_PLANE01_START)
                        {
                            valueToEncode = scalarValue;
                        }
                        else
                        {
                            // Don't encode BMP characters (like U+FFFD) since they wouldn't have
                            // been encoded if explicitly present in the string anyway.
                            ch = (char)scalarValue;
                        }
                    }

                    if (valueToEncode >= 0)
                    {
                        // value needs to be encoded
                        output.Append("&#");

                        // Use the buffer directly and reserve a conservative estimate of 10 chars.
                        Span <char> encodingBuffer = output.AppendSpan(MaxInt32Digits);
                        valueToEncode.TryFormat(encodingBuffer, out int charsWritten); // Invariant
                        output.Length -= (MaxInt32Digits - charsWritten);

                        output.Append(';');
                    }
                    else
                    {
                        // write out the character directly
                        output.Append(ch);
                    }
                }
            }
        }
示例#4
0
        private static string FormatBigIntegerToHex(bool targetSpan, BigInteger value, char format, int digits, NumberFormatInfo info, Span <char> destination, out int charsWritten, out bool spanSuccess)
        {
            Debug.Assert(format == 'x' || format == 'X');

            // Get the bytes that make up the BigInteger.
            byte[]      arrayToReturnToPool = null;
            Span <byte> bits = stackalloc byte[64]; // arbitrary threshold

            if (!value.TryWriteOrCountBytes(bits, out int bytesWrittenOrNeeded))
            {
                bits = arrayToReturnToPool = ArrayPool <byte> .Shared.Rent(bytesWrittenOrNeeded);

                bool success = value.TryWriteBytes(bits, out bytesWrittenOrNeeded);
                Debug.Assert(success);
            }
            bits = bits.Slice(0, bytesWrittenOrNeeded);

            Span <char> stackSpace = stackalloc char[128]; // each byte is typically two chars
            var         sb         = new ValueStringBuilder(stackSpace);

            int cur = bits.Length - 1;

            if (cur > -1)
            {
                // [FF..F8] drop the high F as the two's complement negative number remains clear
                // [F7..08] retain the high bits as the two's complement number is wrong without it
                // [07..00] drop the high 0 as the two's complement positive number remains clear
                bool clearHighF = false;
                byte head       = bits[cur];

                if (head > 0xF7)
                {
                    head      -= 0xF0;
                    clearHighF = true;
                }

                if (head < 0x08 || clearHighF)
                {
                    // {0xF8-0xFF} print as {8-F}
                    // {0x00-0x07} print as {0-7}
                    sb.Append(head < 10 ?
                              (char)(head + '0') :
                              format == 'X' ? (char)((head & 0xF) - 10 + 'A') : (char)((head & 0xF) - 10 + 'a'));
                    cur--;
                }
            }

            if (cur > -1)
            {
                Span <char> chars     = sb.AppendSpan((cur + 1) * 2);
                int         charsPos  = 0;
                string      hexValues = format == 'x' ? "0123456789abcdef" : "0123456789ABCDEF";
                while (cur > -1)
                {
                    byte b = bits[cur--];
                    chars[charsPos++] = hexValues[b >> 4];
                    chars[charsPos++] = hexValues[b & 0xF];
                }
            }

            if (digits > sb.Length)
            {
                // Insert leading zeros, e.g. user specified "X5" so we create "0ABCD" instead of "ABCD"
                sb.Insert(
                    0,
                    value._sign >= 0 ? '0' : (format == 'x') ? 'f' : 'F',
                    digits - sb.Length);
            }

            if (arrayToReturnToPool != null)
            {
                ArrayPool <byte> .Shared.Return(arrayToReturnToPool);
            }

            if (targetSpan)
            {
                spanSuccess = sb.TryCopyTo(destination, out charsWritten);
                return(null);
            }
            else
            {
                charsWritten = 0;
                spanSuccess  = false;
                return(sb.ToString());
            }
        }
示例#5
0
 internal static void EscapeAsciiChar(byte b, ref ValueStringBuilder to)
 {
     to.Append('%');
     HexConverter.ToCharsBuffer(b, to.AppendSpan(2), 0, HexConverter.Casing.Upper);
 }
示例#6
0
        private static void EscapeStringToBuilder(
            ReadOnlySpan <char> stringToEscape, ref ValueStringBuilder vsb,
            ReadOnlySpan <bool> noEscape, bool checkExistingEscaped)
        {
            // Allocate enough stack space to hold any Rune's UTF8 encoding.
            Span <byte> utf8Bytes = stackalloc byte[4];

            // Then enumerate every rune in the input.
            SpanRuneEnumerator e = stringToEscape.EnumerateRunes();

            while (e.MoveNext())
            {
                Rune r = e.Current;

                if (!r.IsAscii)
                {
                    // The rune is non-ASCII, so encode it as UTF8, and escape each UTF8 byte.
                    r.TryEncodeToUtf8(utf8Bytes, out int bytesWritten);
                    foreach (byte b in utf8Bytes.Slice(0, bytesWritten))
                    {
                        vsb.Append('%');
                        HexConverter.ToCharsBuffer(b, vsb.AppendSpan(2), 0, HexConverter.Casing.Upper);
                    }
                    continue;
                }

                // If the value doesn't need to be escaped, append it and continue.
                byte value = (byte)r.Value;
                if (noEscape[value])
                {
                    vsb.Append((char)value);
                    continue;
                }

                // If we're checking for existing escape sequences, then if this is the beginning of
                // one, check the next two characters in the sequence.  This is a little tricky to do
                // as we're using an enumerator, but luckily it's a ref struct-based enumerator: we can
                // make a copy and iterate through the copy without impacting the original, and then only
                // push the original ahead if we find what we're looking for in the copy.
                if (checkExistingEscaped && value == '%')
                {
                    // If the next two characters are valid escaped ASCII, then just output them as-is.
                    SpanRuneEnumerator tmpEnumerator = e;
                    if (tmpEnumerator.MoveNext())
                    {
                        Rune r1 = tmpEnumerator.Current;
                        if (r1.IsAscii && IsHexDigit((char)r1.Value) && tmpEnumerator.MoveNext())
                        {
                            Rune r2 = tmpEnumerator.Current;
                            if (r2.IsAscii && IsHexDigit((char)r2.Value))
                            {
                                vsb.Append('%');
                                vsb.Append((char)r1.Value);
                                vsb.Append((char)r2.Value);
                                e = tmpEnumerator;
                                continue;
                            }
                        }
                    }
                }

                // Otherwise, append the escaped character.
                vsb.Append('%');
                HexConverter.ToCharsBuffer(value, vsb.AppendSpan(2), 0, HexConverter.Casing.Upper);
            }
        }
示例#7
0
        internal static bool TryGetUnicodeEquivalent(string hostname, ref ValueStringBuilder dest)
        {
            Debug.Assert(ReferenceEquals(hostname, UriHelper.StripBidiControlCharacters(hostname, hostname)));

            int curPos = 0;

            // We run a loop where for every label
            // a) if label is ascii and no ace then we lowercase it
            // b) if label is ascii and ace and not valid idn then just lowercase it
            // c) if label is ascii and ace and is valid idn then get its unicode eqvl
            // d) if label is unicode then clean it by running it through idnmapping
            do
            {
                if (curPos != 0)
                {
                    dest.Append('.');
                }

                bool asciiLabel = true;

                //find the dot or hit the end
                int newPos;
                for (newPos = curPos; (uint)newPos < (uint)hostname.Length; newPos++)
                {
                    char c = hostname[newPos];

                    if (c == '.')
                    {
                        break;
                    }

                    if (c > '\x7F')
                    {
                        asciiLabel = false;

                        if ((c == '\u3002') || // IDEOGRAPHIC FULL STOP
                            (c == '\uFF0E') || // FULLWIDTH FULL STOP
                            (c == '\uFF61'))   // HALFWIDTH IDEOGRAPHIC FULL STOP
                        {
                            break;
                        }
                    }
                }

                if (!asciiLabel)
                {
                    try
                    {
                        string asciiForm = s_idnMapping.GetAscii(hostname, curPos, newPos - curPos);

                        dest.Append(s_idnMapping.GetUnicode(asciiForm));
                    }
                    catch (ArgumentException)
                    {
                        return(false);
                    }
                }
                else
                {
                    bool aceValid = false;

                    if ((uint)(curPos + 3) < (uint)hostname.Length &&
                        hostname[curPos] == 'x' &&
                        hostname[curPos + 1] == 'n' &&
                        hostname[curPos + 2] == '-' &&
                        hostname[curPos + 3] == '-')
                    {
                        // check ace validity
                        try
                        {
                            dest.Append(s_idnMapping.GetUnicode(hostname, curPos, newPos - curPos));
                            aceValid = true;
                        }
                        catch (ArgumentException)
                        {
                            // not valid ace so treat it as a normal ascii label
                        }
                    }

                    if (!aceValid)
                    {
                        // for invalid aces we just lowercase the label
                        ReadOnlySpan <char> slice = hostname.AsSpan(curPos, newPos - curPos);
                        int charsWritten          = slice.ToLowerInvariant(dest.AppendSpan(slice.Length));
                        Debug.Assert(charsWritten == slice.Length);
                    }
                }

                curPos = newPos + 1;
            } while (curPos < hostname.Length);

            return(true);
        }
示例#8
0
        private static void AppendByteArrayAsHexString(ref ValueStringBuilder builder, byte[] byteArray)
        {
            Debug.Assert(byteArray != null);

            HexConverter.EncodeToUtf16(byteArray, builder.AppendSpan(byteArray.Length * 2));
        }
示例#9
0
        private static string FormatBigIntegerToHex(BigInteger value, char format, int digits, NumberFormatInfo info)
        {
            Debug.Assert(format == 'x' || format == 'X');

            // Get the bytes that make up the BigInteger.
            Span <byte> bits = stackalloc byte[64]; // arbitrary limit to switch from stack to heap

            bits = value.TryWriteBytes(bits, out int bytesWritten) ?
                   bits.Slice(0, bytesWritten) :
                   value.ToByteArray();

            Span <char> stackSpace = stackalloc char[128]; // each byte is typically two chars
            var         sb         = new ValueStringBuilder(stackSpace);
            int         cur        = bits.Length - 1;

            if (cur > -1)
            {
                // [FF..F8] drop the high F as the two's complement negative number remains clear
                // [F7..08] retain the high bits as the two's complement number is wrong without it
                // [07..00] drop the high 0 as the two's complement positive number remains clear
                bool clearHighF = false;
                byte head       = bits[cur];

                if (head > 0xF7)
                {
                    head      -= 0xF0;
                    clearHighF = true;
                }

                if (head < 0x08 || clearHighF)
                {
                    // {0xF8-0xFF} print as {8-F}
                    // {0x00-0x07} print as {0-7}
                    sb.Append(head < 10 ?
                              (char)(head + '0') :
                              format == 'X' ? (char)((head & 0xF) - 10 + 'A') : (char)((head & 0xF) - 10 + 'a'));
                    cur--;
                }
            }

            if (cur > -1)
            {
                Span <char> chars     = sb.AppendSpan((cur + 1) * 2);
                int         charsPos  = 0;
                string      hexValues = format == 'x' ? "0123456789abcdef" : "0123456789ABCDEF";
                while (cur > -1)
                {
                    byte b = bits[cur--];
                    chars[charsPos++] = hexValues[b >> 4];
                    chars[charsPos++] = hexValues[b & 0xF];
                }
            }

            if (digits > sb.Length)
            {
                // Insert leading zeros, e.g. user specified "X5" so we create "0ABCD" instead of "ABCD"
                sb.Insert(
                    0,
                    value._sign >= 0 ? '0' : (format == 'x') ? 'f' : 'F',
                    digits - sb.Length);
            }

            return(sb.ToString());
        }