Пример #1
0
        // Licensed to the .NET Foundation under one or more agreements.
        // The .NET Foundation licenses this file to you under the MIT license.
        // See the LICENSE file in the project root for more information.
        public static string NormalizeInternal(string inPath)
        {
            // Relative paths aren't a thing for IFileSystem, so assume all paths are absolute
            // and add a '/' to the beginning of the path if it doesn't already begin with one
            if (inPath.Length == 0 || !IsDirectorySeparator(inPath[0]))
            {
                inPath = DirectorySeparator + inPath;
            }

            ReadOnlySpan <char> path = inPath.AsSpan();

            if (path.Length == 0)
            {
                return(DirectorySeparator.ToString());
            }

            Span <char> initialBuffer = stackalloc char[0x200];
            var         sb            = new ValueStringBuilder(initialBuffer);

            for (int i = 0; i < path.Length; i++)
            {
                char c = path[i];

                if (IsDirectorySeparator(c) && i + 1 < path.Length)
                {
                    // Skip this character if it's a directory separator and if the next character is, too,
                    // e.g. "parent//child" => "parent/child"
                    if (IsDirectorySeparator(path[i + 1]))
                    {
                        continue;
                    }

                    // Skip this character and the next if it's referring to the current directory,
                    // e.g. "parent/./child" => "parent/child"
                    if (IsCurrentDirectory(path, i))
                    {
                        i++;
                        continue;
                    }

                    // Skip this character and the next two if it's referring to the parent directory,
                    // e.g. "parent/child/../grandchild" => "parent/grandchild"
                    if (IsParentDirectory(path, i))
                    {
                        // Unwind back to the last slash (and if there isn't one, clear out everything).
                        for (int s = sb.Length - 1; s >= 0; s--)
                        {
                            if (IsDirectorySeparator(sb[s]))
                            {
                                sb.Length = s;
                                break;
                            }
                        }

                        i += 2;
                        continue;
                    }
                }
                sb.Append(c);
            }

            // If we haven't changed the source path, return the original
            if (sb.Length == inPath.Length)
            {
                return(inPath);
            }

            if (sb.Length == 0)
            {
                sb.Append(DirectorySeparator);
            }

            return(sb.ToString());
        }
Пример #2
0
        // Licensed to the .NET Foundation under one or more agreements.
        // The .NET Foundation licenses this file to you under the MIT license.
        // See the LICENSE file in the project root for more information.
        internal static bool NormalizeInternal(ReadOnlySpan <char> path, int rootLength, ref ValueStringBuilder sb)
        {
            if (rootLength > 0)
            {
                sb.Append(path.Slice(0, rootLength));
            }

            bool isNormalized = true;

            var state = NormalizeState.Initial;

            for (int i = rootLength; i < path.Length; i++)
            {
                char c = path[i];

                switch (state)
                {
                case NormalizeState.Initial when IsDirectorySeparator(c):
                    state = NormalizeState.Delimiter;

                    sb.Append(c);
                    break;

                case NormalizeState.Initial when c == '.':
                    isNormalized = false;
                    state        = NormalizeState.Dot;

                    sb.Append(DirectorySeparator);
                    sb.Append(c);
                    break;

                case NormalizeState.Initial:
                    isNormalized = false;
                    state        = NormalizeState.Normal;

                    sb.Append(DirectorySeparator);
                    sb.Append(c);
                    break;

                case NormalizeState.Normal when IsDirectorySeparator(c):
                    state = NormalizeState.Delimiter;

                    sb.Append(c);
                    break;

                case NormalizeState.Normal:
                    sb.Append(c);
                    break;

                case NormalizeState.Delimiter when IsDirectorySeparator(c):
                    isNormalized = false;

                    break;

                case NormalizeState.Delimiter when c == '.':
                    state = NormalizeState.Dot;
                    sb.Append(c);
                    break;

                case NormalizeState.Delimiter:
                    state = NormalizeState.Normal;
                    sb.Append(c);
                    break;

                case NormalizeState.Dot when IsDirectorySeparator(c):
                    isNormalized = false;

                    state      = NormalizeState.Delimiter;
                    sb.Length -= 1;
                    break;

                case NormalizeState.Dot when c == '.':
                    state = NormalizeState.DoubleDot;
                    sb.Append(c);
                    break;

                case NormalizeState.Dot:
                    state = NormalizeState.Normal;
                    sb.Append(c);
                    break;

                case NormalizeState.DoubleDot when IsDirectorySeparator(c):
                    isNormalized = false;

                    state = NormalizeState.Delimiter;

                    int s          = sb.Length - 1;
                    int separators = 0;

                    for (; s > rootLength; s--)
                    {
                        if (IsDirectorySeparator(sb[s]))
                        {
                            separators++;

                            if (separators == 2)
                            {
                                break;
                            }
                        }
                    }

                    sb.Length = s + 1;

                    break;

                case NormalizeState.DoubleDot:
                    state = NormalizeState.Normal;
                    break;
                }
            }

            switch (state)
            {
            case NormalizeState.Dot:
                isNormalized = false;
                sb.Length   -= 2;
                break;

            case NormalizeState.DoubleDot:
                isNormalized = false;

                int s          = sb.Length - 1;
                int separators = 0;

                for (; s > rootLength; s--)
                {
                    if (IsDirectorySeparator(sb[s]))
                    {
                        separators++;

                        if (separators == 2)
                        {
                            break;
                        }
                    }
                }

                sb.Length = s;

                break;
            }

            if (sb.Length == rootLength)
            {
                sb.Append(DirectorySeparator);

                return(false);
            }

            return(isNormalized);
        }