Example #1
0
#pragma warning disable IDE0060 // 'this' taken explicitly to avoid argument shuffling by caller
                static int TryEncodeScalarAsHex(object @this, uint scalarValue, Span <char> destination)
#pragma warning restore IDE0060
                {
                    UnicodeDebug.AssertIsValidScalar(scalarValue);

                    // For inputs 0x0000..0x10FFFF, log2 will return 0..20.
                    // (It counts the number of bits following the highest set bit.)
                    //
                    // We divide by 4 to get the number of nibbles (this rounds down),
                    // then +1 to account for rounding effects. This also accounts for
                    // that when log2 results in an exact multiple of 4, no rounding has
                    // taken place, but we need to include a char for the preceding '0x1'.
                    // Finally, we +4 to account for the "&#x" prefix and the ";" suffix,
                    // then -1 to get the index of the last legal location we want to write to.
                    // >> +1 +4 -1 = +4

                    int idxOfSemicolon = (int)((uint)BitOperations.Log2(scalarValue) / 4) + 4;

                    Debug.Assert(4 <= idxOfSemicolon && idxOfSemicolon <= 9, "Expected '&#x0;'..'&#x10FFFF;'.");

                    if (!SpanUtility.IsValidIndex(destination, idxOfSemicolon))
                    {
                        goto OutOfSpaceInner;
                    }
                    destination[idxOfSemicolon] = ';';

                    // It's more efficient to write 4 chars at a time instead of 1 char.
                    // The '0' at the end will be overwritten.
                    if (!SpanUtility.TryWriteChars(destination, '&', '#', 'x', '0'))
                    {
                        Debug.Fail("We should've had enough room to write 4 chars.");
                    }

                    destination = destination.Slice(3, idxOfSemicolon - 3);
                    for (int i = destination.Length - 1; SpanUtility.IsValidIndex(destination, i); i--)
                    {
                        char asUpperHex = HexConverter.ToCharUpper((int)scalarValue);
                        destination[i] = asUpperHex;
                        scalarValue  >>= 4; // write a nibble - not a byte - at a time
                    }

                    return(destination.Length + 4);

OutOfSpaceInner:

                    return(-1);
                }
Example #2
0
        private bool TryEncodeUnicodeScalarUtf8(uint unicodeScalar, Span <char> utf16ScratchBuffer, Span <byte> utf8Destination, out int bytesWritten)
        {
            if (!TryEncodeUnicodeScalar(unicodeScalar, utf16ScratchBuffer, out int charsWritten))
            {
                // We really don't expect any encoder to exceed 24 escaped chars per input scalar.
                // If this happens, throw an exception and we can figure out if we want to support it
                // in the future.
                ThrowArgumentException_MaxOutputCharsPerInputChar();
            }

            // Transcode chars -> bytes one at a time.

            utf16ScratchBuffer = utf16ScratchBuffer.Slice(0, charsWritten);
            int dstIdx = 0;

            while (!utf16ScratchBuffer.IsEmpty)
            {
                if (Rune.DecodeFromUtf16(utf16ScratchBuffer, out Rune nextScalarValue, out int scalarUtf16CodeUnitCount) != OperationStatus.Done)
                {
                    // Wrote bad UTF-16 data, we cannot transcode to UTF-8.
                    ThrowArgumentException_MaxOutputCharsPerInputChar();
                }

                uint utf8lsb = (uint)UnicodeHelpers.GetUtf8RepresentationForScalarValue((uint)nextScalarValue.Value);
                do
                {
                    if (SpanUtility.IsValidIndex(utf8Destination, dstIdx))
                    {
                        utf8Destination[dstIdx++] = (byte)utf8lsb;
                    }
                    else
                    {
                        bytesWritten = 0; // ran out of space in the destination
                        return(false);
                    }
                } while ((utf8lsb >>= 8) != 0);

                utf16ScratchBuffer = utf16ScratchBuffer.Slice(scalarUtf16CodeUnitCount);
            }

            bytesWritten = dstIdx;
            return(true);
        }
Example #3
0
            internal override int EncodeUtf8(Rune value, Span <byte> destination)
            {
                if (value.Value == '<')
                {
                    if (!SpanUtility.TryWriteBytes(destination, (byte)'&', (byte)'l', (byte)'t', (byte)';'))
                    {
                        goto OutOfSpace;
                    }
                    return(4);
                }
                else if (value.Value == '>')
                {
                    if (!SpanUtility.TryWriteBytes(destination, (byte)'&', (byte)'g', (byte)'t', (byte)';'))
                    {
                        goto OutOfSpace;
                    }
                    return(4);
                }
                else if (value.Value == '&')
                {
                    if (!SpanUtility.TryWriteBytes(destination, (byte)'&', (byte)'a', (byte)'m', (byte)'p', (byte)';'))
                    {
                        goto OutOfSpace;
                    }
                    return(5);
                }
                else if (value.Value == '\"')
                {
                    if (!SpanUtility.TryWriteBytes(destination, (byte)'&', (byte)'q', (byte)'u', (byte)'o', (byte)'t', (byte)';'))
                    {
                        goto OutOfSpace;
                    }
                    return(6);
                }
                else
                {
                    return(TryEncodeScalarAsHex(this, (uint)value.Value, destination));
                }

OutOfSpace:

                return(-1);
Example #4
0
            internal override int EncodeUtf16(Rune value, Span <char> destination)
            {
                if (value.Value == '<')
                {
                    if (!SpanUtility.TryWriteChars(destination, '&', 'l', 't', ';'))
                    {
                        goto OutOfSpace;
                    }
                    return(4);
                }
                else if (value.Value == '>')
                {
                    if (!SpanUtility.TryWriteChars(destination, '&', 'g', 't', ';'))
                    {
                        goto OutOfSpace;
                    }
                    return(4);
                }
                else if (value.Value == '&')
                {
                    if (!SpanUtility.TryWriteChars(destination, '&', 'a', 'm', 'p', ';'))
                    {
                        goto OutOfSpace;
                    }
                    return(5);
                }
                else if (value.Value == '\"')
                {
                    if (!SpanUtility.TryWriteChars(destination, '&', 'q', 'u', 'o', 't', ';'))
                    {
                        goto OutOfSpace;
                    }
                    return(6);
                }
                else
                {
                    return(TryEncodeScalarAsHex(this, (uint)value.Value, destination));
                }

OutOfSpace:

                return(-1);
Example #5
0
#pragma warning disable IDE0060 // 'this' taken explicitly to avoid argument shuffling by caller
                static int TryEncodeScalarAsHex(object @this, uint scalarValue, Span <byte> destination)
#pragma warning restore IDE0060
                {
                    UnicodeDebug.AssertIsValidScalar(scalarValue);

                    // See comments in the UTF-16 equivalent method later in this file.

                    int idxOfSemicolon = (int)((uint)BitOperations.Log2(scalarValue) / 4) + 4;

                    Debug.Assert(4 <= idxOfSemicolon && idxOfSemicolon <= 9, "Expected '&#x0;'..'&#x10FFFF;'.");

                    if (!SpanUtility.IsValidIndex(destination, idxOfSemicolon))
                    {
                        goto OutOfSpaceInner;
                    }
                    destination[idxOfSemicolon] = (byte)';';

                    if (!SpanUtility.TryWriteBytes(destination, (byte)'&', (byte)'#', (byte)'x', (byte)'0'))
                    {
                        Debug.Fail("We should've had enough room to write 4 bytes.");
                    }

                    destination = destination.Slice(3, idxOfSemicolon - 3);
                    for (int i = destination.Length - 1; SpanUtility.IsValidIndex(destination, i); i--)
                    {
                        char asUpperHex = HexConverter.ToCharUpper((int)scalarValue);
                        destination[i] = (byte)asUpperHex;
                        scalarValue  >>= 4; // write a nibble - not a byte - at a time
                    }

                    return(destination.Length + 4);

OutOfSpaceInner:

                    return(-1);
                }