Avoid unnecessary allocations in SanitizeEntryFilePath (#71034)
authorStephen Toub <stoub@microsoft.com>
Tue, 21 Jun 2022 04:39:55 +0000 (00:39 -0400)
committerGitHub <noreply@github.com>
Tue, 21 Jun 2022 04:39:55 +0000 (22:39 -0600)
src/libraries/Common/src/System/IO/Archiving.Utils.Windows.cs

index d8ee462..88f7ffb 100644 (file)
@@ -9,19 +9,38 @@ namespace System.IO
     {
         internal static string SanitizeEntryFilePath(string entryPath)
         {
-            StringBuilder builder = new StringBuilder(entryPath);
+            // Find the first illegal character in the entry path.
             for (int i = 0; i < entryPath.Length; i++)
             {
-                if (((int)builder[i] >= 0 && (int)builder[i] < 32) ||
-                   builder[i] == '?' || builder[i] == ':' ||
-                   builder[i] == '*' || builder[i] == '"' ||
-                   builder[i] == '<' || builder[i] == '>' ||
-                   builder[i] == '|')
+                switch (entryPath[i])
                 {
-                    builder[i] = '_';
+                    // We found at least one character that needs to be replaced.
+                    case < (char)32 or '?' or ':' or '*' or '"' or '<' or '>' or '|':
+                        return string.Create(entryPath.Length, (i, entryPath), (dest, state) =>
+                        {
+                            string entryPath = state.entryPath;
+
+                            // Copy over to the new string everything until the character, then
+                            // substitute for the found character.
+                            entryPath.AsSpan(0, state.i).CopyTo(dest);
+                            dest[state.i] = '_';
+
+                            // Continue looking for and replacing any more illegal characters.
+                            for (int i = state.i + 1; i < entryPath.Length; i++)
+                            {
+                                char c = entryPath[i];
+                                dest[i] = c switch
+                                {
+                                    < (char)32 or '?' or ':' or '*' or '"' or '<' or '>' or '|' => '_',
+                                    _ => c,
+                                };
+                            }
+                        });
                 }
             }
-            return builder.ToString();
+
+            // There weren't any characters to sanitize.  Just return the original string.
+            return entryPath;
         }
     }
 }