@@ -8,6 +8,9 @@ namespace System.IO.Compression
8
8
{
9
9
public static class ZipFile
10
10
{
11
+ // Per the .ZIP File Format Specification 4.4.17.1 all slashes should be forward slashes
12
+ private const char c_pathSeparator = '/' ;
13
+
11
14
/// <summary>
12
15
/// Opens a <code>ZipArchive</code> on the specified path for reading. The specified file is opened with <code>FileMode.Open</code>.
13
16
/// </summary>
@@ -503,10 +506,7 @@ private static void DoCreateFromDirectory(String sourceDirectoryName, String des
503
506
Int32 entryNameLength = file . FullName . Length - basePath . Length ;
504
507
Debug . Assert ( entryNameLength > 0 ) ;
505
508
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 ) ;
510
510
511
511
if ( file is FileInfo )
512
512
{
@@ -520,18 +520,52 @@ private static void DoCreateFromDirectory(String sourceDirectoryName, String des
520
520
if ( possiblyEmpty != null && IsDirEmpty ( possiblyEmpty ) )
521
521
{
522
522
// 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 ) ;
525
525
}
526
526
}
527
527
} // foreach
528
528
529
529
// If no entries create an empty root directory entry:
530
530
if ( includeBaseDirectory && directoryIsEmpty )
531
- archive . CreateEntry ( di . Name + Path . DirectorySeparatorChar ) ;
531
+ archive . CreateEntry ( EntryFromPath ( di . Name , 0 , di . Name . Length ) + c_pathSeparator ) ;
532
+
532
533
} // using
533
534
} // DoCreateFromDirectory
534
535
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
+
535
569
536
570
private static Boolean IsDirEmpty ( DirectoryInfo possiblyEmptyDir )
537
571
{
0 commit comments