System.Uri.Compress C# (CSharp) Method

Compress() private static method

private static Compress ( char dest, ushort start, int &destLength, UriParser syntax ) : char[]
dest char
start ushort
destLength int
syntax UriParser
return char[]
        private static char[] Compress(char[] dest, ushort start, ref int destLength, UriParser syntax)
        {
            ushort slashCount = 0;
            ushort lastSlash = 0;
            ushort dotCount = 0;
            ushort removeSegments = 0;

            unchecked
            {
                //ushort i == -1 and start == -1 overflow is ok here
                ushort i = (ushort)((ushort)destLength - (ushort)1);
                start = (ushort)(start - 1);

                for (; i != start; --i)
                {
                    char ch = dest[i];
                    if (ch == '\\' && syntax.InFact(UriSyntaxFlags.ConvertPathSlashes))
                    {
                        dest[i] = ch = '/';
                    }

                    //
                    // compress multiple '/' for file URI
                    //
                    if (ch == '/')
                    {
                        ++slashCount;
                    }
                    else
                    {
                        if (slashCount > 1)
                        {
                            // else preserve repeated slashes
                            lastSlash = (ushort)(i + 1);
                        }
                        slashCount = 0;
                    }

                    if (ch == '.')
                    {
                        ++dotCount;
                        continue;
                    }
                    else if (dotCount != 0)
                    {
                        bool skipSegment = syntax.NotAny(UriSyntaxFlags.CanonicalizeAsFilePath)
                            && (dotCount > 2 || ch != '/' || i == start);

                        //
                        // Cases:
                        // /./                  = remove this segment 
                        // /../                 = remove this segment, mark next for removal
                        // /....x               = DO NOT TOUCH, leave as is
                        // x.../                = DO NOT TOUCH, leave as is, except for V2 legacy mode
                        //
                        if (!skipSegment && ch == '/')
                        {
                            if ((lastSlash == i + dotCount + 1 // "/..../"
                                    || (lastSlash == 0 && i + dotCount + 1 == destLength)) // "/..."
                                && (dotCount <= 2))
                            {
                                //
                                //  /./ or /.<eos> or /../ or /..<eos>
                                //
                                // just reusing a variable slot we perform //dest.Remove(i+1, dotCount + (lastSlash==0?0:1));
                                lastSlash = (ushort)(i + 1 + dotCount + (lastSlash == 0 ? 0 : 1));
                                Buffer.BlockCopy(dest, lastSlash << 1, dest, (i + 1) << 1, (destLength - lastSlash) << 1);
                                destLength -= (lastSlash - i - 1);

                                lastSlash = i;
                                if (dotCount == 2)
                                {
                                    //
                                    // We have 2 dots in between like /../ or /..<eos>,
                                    // Mark next segment for removal and remove this /../ or /..
                                    //
                                    ++removeSegments;
                                }
                                dotCount = 0;
                                continue;
                            }
                        }
                        // .NET 4.5 no longer removes trailing dots in a path segment x.../  or  x...<eos>
                        dotCount = 0;

                        //
                        // Here all other cases go such as
                        // x.[..]y or /.[..]x or (/x.[...][/] && removeSegments !=0)
                    }

                    //
                    // Now we may want to remove a segment because of previous /../
                    //
                    if (ch == '/')
                    {
                        if (removeSegments != 0)
                        {
                            --removeSegments;

                            // just reusing a variable slot we perform //dest.Remove(i+1, lastSlash - i);
                            lastSlash = (ushort)(lastSlash + 1);
                            Buffer.BlockCopy(dest, lastSlash << 1, dest, (i + 1) << 1, (destLength - lastSlash) << 1);
                            destLength -= (lastSlash - i - 1);
                        }
                        lastSlash = i;
                    }
                }

                start = (ushort)((ushort)start + (ushort)1);
            } //end of unchecked

            if ((ushort)destLength > start && syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath))
            {
                if (slashCount <= 1)
                {
                    if (removeSegments != 0 && dest[start] != '/')
                    {
                        //remove first not rooted segment
                        lastSlash = (ushort)(lastSlash + 1);
                        Buffer.BlockCopy(dest, lastSlash << 1, dest, start << 1, (destLength - lastSlash) << 1);
                        destLength -= lastSlash;
                    }
                    else if (dotCount != 0)
                    {
                        // If final string starts with a segment looking like .[...]/ or .[...]<eos>
                        // then we remove this first segment
                        if (lastSlash == dotCount + 1 || (lastSlash == 0 && dotCount + 1 == destLength))
                        {
                            dotCount = (ushort)(dotCount + (lastSlash == 0 ? 0 : 1));
                            Buffer.BlockCopy(dest, dotCount << 1, dest, start << 1, (destLength - dotCount) << 1);
                            destLength -= dotCount;
                        }
                    }
                }
            }
            return dest;
        }