Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 7b9331e

Browse files
committed
Use slash instead of backslash when creating ZipFiles
Per the .ZIP File Format Specification 4.4.17.1 all slashes should be forward slashes, not back slashes. https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT This change needs to also be made to desktop and quirked, which is being tracked as a separate bug. [tfs-changeset: 1493255]
1 parent cfbc76d commit 7b9331e

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

src/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.cs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ namespace System.IO.Compression
88
{
99
public static class ZipFile
1010
{
11+
// Per the .ZIP File Format Specification 4.4.17.1 all slashes should be forward slashes
12+
private const char c_pathSeparator = '/';
13+
1114
/// <summary>
1215
/// Opens a <code>ZipArchive</code> on the specified path for reading. The specified file is opened with <code>FileMode.Open</code>.
1316
/// </summary>
@@ -503,10 +506,7 @@ private static void DoCreateFromDirectory(String sourceDirectoryName, String des
503506
Int32 entryNameLength = file.FullName.Length - basePath.Length;
504507
Debug.Assert(entryNameLength > 0);
505508

506-
String entryName = file.FullName.Substring(basePath.Length, entryNameLength);
507-
508-
// Remove any leading slashes from the entry name:
509-
entryName = entryName.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
509+
String entryName = EntryFromPath(file.FullName, basePath.Length, entryNameLength);
510510

511511
if (file is FileInfo)
512512
{
@@ -520,18 +520,52 @@ private static void DoCreateFromDirectory(String sourceDirectoryName, String des
520520
if (possiblyEmpty != null && IsDirEmpty(possiblyEmpty))
521521
{
522522
// FullName never returns a directory separator character on the end,
523-
// but Zip archives require it to specify an explicit directory:
524-
archive.CreateEntry(entryName + Path.DirectorySeparatorChar);
523+
// but Zip archives require it to specify an explicit directory:
524+
archive.CreateEntry(entryName + c_pathSeparator);
525525
}
526526
}
527527
} // foreach
528528

529529
// If no entries create an empty root directory entry:
530530
if (includeBaseDirectory && directoryIsEmpty)
531-
archive.CreateEntry(di.Name + Path.DirectorySeparatorChar);
531+
archive.CreateEntry(EntryFromPath(di.Name, 0, di.Name.Length) + c_pathSeparator);
532+
532533
} // using
533534
} // DoCreateFromDirectory
534535

536+
private static string EntryFromPath(string entry, int offset, int length)
537+
{
538+
Debug.Assert(length <= entry.Length - offset);
539+
540+
// Remove any leading slashes from the entry name:
541+
while (length > 0)
542+
{
543+
if (entry[offset] != Path.DirectorySeparatorChar &&
544+
entry[offset] != Path.AltDirectorySeparatorChar)
545+
break;
546+
547+
offset++;
548+
length--;
549+
}
550+
551+
if (length == 0)
552+
return String.Empty;
553+
554+
// create a mutable copy
555+
char[] chars = entry.ToCharArray(offset, length);
556+
557+
// '/' is a more broadly recognized directory separator on all platforms (eg: mac, linux)
558+
// We don't use Path.DirectorySeparatorChar or AltDirectorySeparatorChar because this is
559+
// explicitly trying to standardize to '/'
560+
for(int i = 0; i < chars.Length; i++)
561+
{
562+
if (chars[i] == Path.DirectorySeparatorChar || chars[i] == Path.AltDirectorySeparatorChar)
563+
chars[i] = c_pathSeparator;
564+
}
565+
566+
return new string(chars);
567+
}
568+
535569

536570
private static Boolean IsDirEmpty(DirectoryInfo possiblyEmptyDir)
537571
{

src/System.IO.Compression.ZipFile/tests/ZipFileConvenienceMethods.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ private static void SameExceptForBaseDir(string zipNoBaseDir, string zipBaseDir,
4949
{
5050
ZipArchiveEntry bEntry = b.Entries[bIdx++];
5151

52-
Assert.Equal(Path.Combine(Path.GetFileName(baseDir), aEntry.FullName), bEntry.FullName);
52+
Assert.Equal(Path.GetFileName(baseDir) + "/" + aEntry.FullName, bEntry.FullName);
5353
Assert.Equal(aEntry.Name, bEntry.Name);
5454
Assert.Equal(aEntry.Length, bEntry.Length);
5555
Assert.Equal(aEntry.CompressedLength, bEntry.CompressedLength);

0 commit comments

Comments
 (0)