public static void Encode(this TextEncoder encoder, TextWriter output, char[] value, int startIndex, int characterCount)
        {
            if (encoder == null)
            {
                throw new ArgumentNullException("encoder");
            }
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (output == null)
            {
                throw new ArgumentNullException("output");
            }
            ValidateRanges(startIndex, characterCount, actualInputLength: value.Length);

            unsafe
            {
                fixed(char *valuePointer = value)
                {
                    char *substring          = valuePointer + startIndex;
                    int   firstIndexToEncode = encoder.FindFirstCharacterToEncode(substring, characterCount);

                    if (firstIndexToEncode == -1)                              // nothing to encode;
                    {
                        if (startIndex == 0 && characterCount == value.Length) // write whole string
                        {
                            output.Write(value);
                            return;
                        }
                        for (int i = 0; i < characterCount; i++) // write substring
                        {
                            output.Write(*substring);
                            substring++;
                        }
                        return;
                    }

                    // write prefix, then encode
                    for (int i = 0; i < firstIndexToEncode; i++)
                    {
                        output.Write(*substring);
                        substring++;
                    }

                    EncodeCore(encoder, output, substring, characterCount - firstIndexToEncode);
                }
            }
        }
Example #2
0
        public static string Encode(this TextEncoder encoder, string value)
        {
            if (value == null)
            {
                return(value);
            }

            unsafe
            {
                fixed(char *valuePointer = value)
                {
                    int firstCharacterToEncode = encoder.FindFirstCharacterToEncode(valuePointer, value.Length);

                    if (firstCharacterToEncode == -1)
                    {
                        return(value);
                    }

                    int   bufferSize   = encoder.MaxOutputCharsPerInputChar * value.Length;
                    char *wholebuffer  = stackalloc char[bufferSize];
                    char *buffer       = wholebuffer;
                    int   totalWritten = 0;

                    if (firstCharacterToEncode > 0)
                    {
                        int bytesToCopy = firstCharacterToEncode + firstCharacterToEncode;
                        Buffer.MemoryCopy(valuePointer, buffer, bytesToCopy, bytesToCopy);
                        totalWritten += firstCharacterToEncode;
                        bufferSize   -= firstCharacterToEncode;
                        buffer       += firstCharacterToEncode;
                    }

                    int valueIndex = firstCharacterToEncode;

                    char firstChar        = value[valueIndex];
                    char secondChar       = firstChar;
                    bool wasSurrogatePair = false;
                    int  charsWritten;

                    // this loop processes character pairs (in case they are surrogates).
                    // there is an if block below to process single last character.
                    for (int secondCharIndex = valueIndex + 1; secondCharIndex < value.Length; secondCharIndex++)
                    {
                        if (!wasSurrogatePair)
                        {
                            firstChar = secondChar;
                        }
                        else
                        {
                            firstChar = value[secondCharIndex - 1];
                        }
                        secondChar = value[secondCharIndex];

                        if (!encoder.Encodes(firstChar))
                        {
                            wasSurrogatePair = false;
                            *buffer = firstChar;
                            buffer++;
                            bufferSize--;
                            totalWritten++;
                        }
                        else
                        {
                            int nextScalar = UnicodeHelpers.GetScalarValueFromUtf16(firstChar, secondChar, out wasSurrogatePair);
                            if (!encoder.TryEncodeUnicodeScalar(nextScalar, buffer, bufferSize, out charsWritten))
                            {
                                throw new ArgumentException("Argument encoder does not implement MaxOutputCharsPerInputChar correctly.");
                            }

                            buffer       += charsWritten;
                            bufferSize   -= charsWritten;
                            totalWritten += charsWritten;
                            if (wasSurrogatePair)
                            {
                                secondCharIndex++;
                            }
                        }
                    }

                    if (!wasSurrogatePair)
                    {
                        firstChar = value[value.Length - 1];
                        int nextScalar = UnicodeHelpers.GetScalarValueFromUtf16(firstChar, null, out wasSurrogatePair);
                        if (!encoder.TryEncodeUnicodeScalar(nextScalar, buffer, bufferSize, out charsWritten))
                        {
                            throw new ArgumentException("Argument encoder does not implement MaxOutputCharsPerInputChar correctly.");
                        }

                        buffer       += charsWritten;
                        bufferSize   -= charsWritten;
                        totalWritten += charsWritten;
                    }

                    var result = new String(wholebuffer, 0, totalWritten);

                    return(result);
                }
            }
        }