@@ -1084,6 +1084,7 @@ public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandl
1084
1084
[ Flags ]
1085
1085
private enum HeaderTest
1086
1086
{
1087
+ None = 0x0 ,
1087
1088
Extract = 0x01 , // Check that this header represents an entry whose data can be extracted
1088
1089
Header = 0x02 , // Check that this header contents are valid
1089
1090
}
@@ -1110,13 +1111,12 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1110
1111
1111
1112
if ( signature != ZipConstants . LocalHeaderSignature )
1112
1113
{
1113
- throw new ZipException ( string . Format ( "Wrong local header signature at 0x{0:x}, expected 0x{1:x8}, actual 0x{2:x8}" ,
1114
- entryAbsOffset , ZipConstants . LocalHeaderSignature , signature ) ) ;
1114
+ throw new ZipException ( $ "Wrong local header signature at 0x{ entryAbsOffset : x} , expected 0x{ ZipConstants . LocalHeaderSignature : x8} , actual 0x{ signature : x8} ") ;
1115
1115
}
1116
1116
1117
1117
var extractVersion = ( short ) ( ReadLEUshort ( ) & 0x00ff ) ;
1118
1118
var localFlags = ( GeneralBitFlags ) ReadLEUshort ( ) ;
1119
- var compressionMethod = ( short ) ReadLEUshort ( ) ;
1119
+ var compressionMethod = ( CompressionMethod ) ReadLEUshort ( ) ;
1120
1120
var fileTime = ( short ) ReadLEUshort ( ) ;
1121
1121
var fileDate = ( short ) ReadLEUshort ( ) ;
1122
1122
uint crcValue = ReadLEUint ( ) ;
@@ -1134,7 +1134,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1134
1134
var localExtraData = new ZipExtraData ( extraData ) ;
1135
1135
1136
1136
// Extra data / zip64 checks
1137
- if ( localExtraData . Find ( 1 ) )
1137
+ if ( localExtraData . Find ( headerID : 1 ) )
1138
1138
{
1139
1139
// 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
1140
1140
// and size or compressedSize = MaxValue, due to rogue creators.
@@ -1175,15 +1175,19 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1175
1175
throw new ZipException ( "Compression method not supported" ) ;
1176
1176
}
1177
1177
1178
- if ( ( extractVersion > ZipConstants . VersionMadeBy )
1179
- || ( ( extractVersion > 20 ) && ( extractVersion < ZipConstants . VersionZip64 ) ) )
1178
+ if ( extractVersion > ZipConstants . VersionMadeBy
1179
+ || ( extractVersion > 20 && extractVersion < ZipConstants . VersionZip64 ) )
1180
1180
{
1181
- throw new ZipException ( string . Format ( "Version required to extract this entry not supported ({0 })" , extractVersion ) ) ;
1181
+ throw new ZipException ( $ "Version required to extract this entry not supported ({ extractVersion } )") ;
1182
1182
}
1183
1183
1184
- if ( localFlags . HasAny ( GeneralBitFlags . Patched | GeneralBitFlags . StrongEncryption | GeneralBitFlags . EnhancedCompress | GeneralBitFlags . HeaderMasked ) )
1184
+ const GeneralBitFlags notSupportedFlags = GeneralBitFlags . Patched
1185
+ | GeneralBitFlags . StrongEncryption
1186
+ | GeneralBitFlags . EnhancedCompress
1187
+ | GeneralBitFlags . HeaderMasked ;
1188
+ if ( localFlags . HasAny ( notSupportedFlags ) )
1185
1189
{
1186
- throw new ZipException ( "The library does not support the zip version required to extract this entry" ) ;
1190
+ throw new ZipException ( $ "The library does not support the zip features required to extract this entry ( { localFlags & notSupportedFlags : F } ) ") ;
1187
1191
}
1188
1192
}
1189
1193
}
@@ -1207,7 +1211,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1207
1211
( extractVersion != 63 )
1208
1212
)
1209
1213
{
1210
- throw new ZipException ( string . Format ( "Version required to extract this entry is invalid ({0 })" , extractVersion ) ) ;
1214
+ throw new ZipException ( $ "Version required to extract this entry is invalid ({ extractVersion } )") ;
1211
1215
}
1212
1216
1213
1217
var localEncoding = _stringCodec . ZipInputEncoding ( localFlags ) ;
@@ -1221,7 +1225,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1221
1225
// Encryption requires extract version >= 20
1222
1226
if ( localFlags . HasAny ( GeneralBitFlags . Encrypted ) && extractVersion < 20 )
1223
1227
{
1224
- throw new ZipException ( string . Format ( "Version required to extract this entry is too low for encryption ({0 })" , extractVersion ) ) ;
1228
+ throw new ZipException ( $ "Version required to extract this entry is too low for encryption ({ extractVersion } )") ;
1225
1229
}
1226
1230
1227
1231
// Strong encryption requires encryption flag to be set and extract version >= 50.
@@ -1234,26 +1238,26 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1234
1238
1235
1239
if ( extractVersion < 50 )
1236
1240
{
1237
- throw new ZipException ( string . Format ( "Version required to extract this entry is too low for encryption ({0 })" , extractVersion ) ) ;
1241
+ throw new ZipException ( $ "Version required to extract this entry is too low for encryption ({ extractVersion } )") ;
1238
1242
}
1239
1243
}
1240
1244
1241
1245
// Patched entries require extract version >= 27
1242
1246
if ( localFlags . HasAny ( GeneralBitFlags . Patched ) && extractVersion < 27 )
1243
1247
{
1244
- throw new ZipException ( string . Format ( "Patched data requires higher version than ({0 })" , extractVersion ) ) ;
1248
+ throw new ZipException ( $ "Patched data requires higher version than ({ extractVersion } )") ;
1245
1249
}
1246
1250
1247
1251
// Central header flags match local entry flags.
1248
1252
if ( ( int ) localFlags != entry . Flags )
1249
1253
{
1250
- throw new ZipException ( "Central header/local header flags mismatch" ) ;
1254
+ throw new ZipException ( $ "Central header/local header flags mismatch ( { ( GeneralBitFlags ) entry . Flags : F } vs { localFlags : F } ) ") ;
1251
1255
}
1252
1256
1253
1257
// Central header compression method matches local entry
1254
- if ( entry . CompressionMethodForHeader != ( CompressionMethod ) compressionMethod )
1258
+ if ( entry . CompressionMethodForHeader != compressionMethod )
1255
1259
{
1256
- throw new ZipException ( "Central header/local header compression method mismatch" ) ;
1260
+ throw new ZipException ( $ "Central header/local header compression method mismatch ( { entry . CompressionMethodForHeader : G } vs { compressionMethod : G } ) ") ;
1257
1261
}
1258
1262
1259
1263
if ( entry . Version != extractVersion )
@@ -1272,7 +1276,7 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1272
1276
1273
1277
if ( localFlags . HasAny ( GeneralBitFlags . HeaderMasked ) )
1274
1278
{
1275
- if ( ( fileTime != 0 ) || ( fileDate != 0 ) )
1279
+ if ( fileTime != 0 || fileDate != 0 )
1276
1280
{
1277
1281
throw new ZipException ( "Header masked set but date/time values non-zero" ) ;
1278
1282
}
@@ -1287,8 +1291,8 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1287
1291
}
1288
1292
1289
1293
// Crc valid for empty entry.
1290
- // This will also apply to streamed entries where size isnt known and the header cant be patched
1291
- if ( ( size == 0 ) && ( compressedSize == 0 ) )
1294
+ // This will also apply to streamed entries where size isn't known and the header cant be patched
1295
+ if ( size == 0 && compressedSize == 0 )
1292
1296
{
1293
1297
if ( crcValue != 0 )
1294
1298
{
@@ -1351,20 +1355,15 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
1351
1355
if ( ! localFlags . HasAny ( GeneralBitFlags . Descriptor ) ||
1352
1356
( ( size > 0 || compressedSize > 0 ) && entry . Size > 0 ) )
1353
1357
{
1354
- if ( ( size != 0 )
1355
- && ( size != entry . Size ) )
1358
+ if ( size != 0 && size != entry . Size )
1356
1359
{
1357
- throw new ZipException (
1358
- string . Format ( "Size mismatch between central header({0}) and local header({1})" ,
1359
- entry . Size , size ) ) ;
1360
+ throw new ZipException ( $ "Size mismatch between central header ({ entry . Size } ) and local header ({ size } )") ;
1360
1361
}
1361
1362
1362
- if ( ( compressedSize != 0 )
1363
+ if ( compressedSize != 0
1363
1364
&& ( compressedSize != entry . CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != - 1 ) )
1364
1365
{
1365
- throw new ZipException (
1366
- string . Format ( "Compressed size mismatch between central header({0}) and local header({1})" ,
1367
- entry . CompressedSize , compressedSize ) ) ;
1366
+ throw new ZipException ( $ "Compressed size mismatch between central header({ entry . CompressedSize } ) and local header({ compressedSize } )") ;
1368
1367
}
1369
1368
}
1370
1369
@@ -3502,20 +3501,16 @@ private void ReadEntries()
3502
3501
}
3503
3502
3504
3503
bool isZip64 = false ;
3505
- bool requireZip64 = false ;
3506
-
3504
+
3507
3505
// Check if zip64 header information is required.
3508
- if ( ( thisDiskNumber == 0xffff ) ||
3509
- ( startCentralDirDisk == 0xffff ) ||
3510
- ( entriesForThisDisk == 0xffff ) ||
3511
- ( entriesForWholeCentralDir == 0xffff ) ||
3512
- ( centralDirSize == 0xffffffff ) ||
3513
- ( offsetOfCentralDir == 0xffffffff ) )
3514
- {
3515
- requireZip64 = true ;
3516
- }
3517
-
3518
- // #357 - always check for the existance of the Zip64 central directory.
3506
+ bool requireZip64 = thisDiskNumber == 0xffff ||
3507
+ startCentralDirDisk == 0xffff ||
3508
+ entriesForThisDisk == 0xffff ||
3509
+ entriesForWholeCentralDir == 0xffff ||
3510
+ centralDirSize == 0xffffffff ||
3511
+ offsetOfCentralDir == 0xffffffff ;
3512
+
3513
+ // #357 - always check for the existence of the Zip64 central directory.
3519
3514
// #403 - Take account of the fixed size of the locator when searching.
3520
3515
// Subtract from locatedEndOfCentralDir so that the endLocation is the location of EndOfCentralDirectorySignature,
3521
3516
// rather than the data following the signature.
@@ -3549,7 +3544,7 @@ private void ReadEntries()
3549
3544
3550
3545
if ( sig64 != ZipConstants . Zip64CentralFileHeaderSignature )
3551
3546
{
3552
- throw new ZipException ( string . Format ( "Invalid Zip64 Central directory signature at {0 :X}" , offset64 ) ) ;
3547
+ throw new ZipException ( $ "Invalid Zip64 Central directory signature at { offset64 : X} ") ;
3553
3548
}
3554
3549
3555
3550
// NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
@@ -3604,8 +3599,11 @@ private void ReadEntries()
3604
3599
int extraLen = ReadLEUshort ( ) ;
3605
3600
int commentLen = ReadLEUshort ( ) ;
3606
3601
3607
- int diskStartNo = ReadLEUshort ( ) ; // Not currently used
3608
- int internalAttributes = ReadLEUshort ( ) ; // Not currently used
3602
+
3603
+ // ReSharper disable once UnusedVariable, Currently unused but needs to be read to offset the stream
3604
+ int diskStartNo = ReadLEUshort ( ) ;
3605
+ // ReSharper disable once UnusedVariable, Currently unused but needs to be read to offset the stream
3606
+ int internalAttributes = ReadLEUshort ( ) ;
3609
3607
3610
3608
uint externalAttributes = ReadLEUint ( ) ;
3611
3609
long offset = ReadLEUint ( ) ;
@@ -3629,7 +3627,7 @@ private void ReadEntries()
3629
3627
ExternalFileAttributes = ( int ) externalAttributes
3630
3628
} ;
3631
3629
3632
- if ( ( bitFlags & 8 ) == 0 )
3630
+ if ( ! entry . HasFlag ( GeneralBitFlags . Descriptor ) )
3633
3631
{
3634
3632
entry . CryptoCheckValue = ( byte ) ( crc >> 24 ) ;
3635
3633
}
@@ -3672,9 +3670,15 @@ private void ReadEntries()
3672
3670
/// </exception>
3673
3671
private long LocateEntry ( ZipEntry entry )
3674
3672
{
3675
- return TestLocalHeader ( entry , HeaderTest . Extract ) ;
3673
+ return TestLocalHeader ( entry , SkipLocalEntryTestsOnLocate ? HeaderTest . None : HeaderTest . Extract ) ;
3676
3674
}
3677
3675
3676
+ /// <summary>
3677
+ /// Skip the verification of the local header when reading an archive entry. Set this to attempt to read the
3678
+ /// entries even if the headers should indicate that doing so would fail or produce an unexpected output.
3679
+ /// </summary>
3680
+ public bool SkipLocalEntryTestsOnLocate { get ; set ; } = false ;
3681
+
3678
3682
private Stream CreateAndInitDecryptionStream ( Stream baseStream , ZipEntry entry )
3679
3683
{
3680
3684
CryptoStream result = null ;
@@ -3691,15 +3695,15 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
3691
3695
}
3692
3696
int saltLen = entry . AESSaltLen ;
3693
3697
byte [ ] saltBytes = new byte [ saltLen ] ;
3694
- int saltIn = StreamUtils . ReadRequestedBytes ( baseStream , saltBytes , 0 , saltLen ) ;
3695
- if ( saltIn != saltLen )
3696
- throw new ZipException ( "AES Salt expected " + saltLen + " got " + saltIn ) ;
3697
- //
3698
+ int saltIn = StreamUtils . ReadRequestedBytes ( baseStream , saltBytes , offset : 0 , saltLen ) ;
3699
+
3700
+ if ( saltIn != saltLen ) throw new ZipException ( $ "AES Salt expected { saltLen } git { saltIn } " ) ;
3701
+
3698
3702
byte [ ] pwdVerifyRead = new byte [ 2 ] ;
3699
3703
StreamUtils . ReadFully ( baseStream , pwdVerifyRead ) ;
3700
3704
int blockSize = entry . AESKeySize / 8 ; // bits to bytes
3701
3705
3702
- var decryptor = new ZipAESTransform ( rawPassword_ , saltBytes , blockSize , false ) ;
3706
+ var decryptor = new ZipAESTransform ( rawPassword_ , saltBytes , blockSize , writeMode : false ) ;
3703
3707
byte [ ] pwdVerifyCalc = decryptor . PwdVerifier ;
3704
3708
if ( pwdVerifyCalc [ 0 ] != pwdVerifyRead [ 0 ] || pwdVerifyCalc [ 1 ] != pwdVerifyRead [ 1 ] )
3705
3709
throw new ZipException ( "Invalid password for AES" ) ;
@@ -3712,8 +3716,7 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
3712
3716
}
3713
3717
else
3714
3718
{
3715
- if ( ( entry . Version < ZipConstants . VersionStrongEncryption )
3716
- || ( entry . Flags & ( int ) GeneralBitFlags . StrongEncryption ) == 0 )
3719
+ if ( entry . Version < ZipConstants . VersionStrongEncryption || ! entry . HasFlag ( GeneralBitFlags . StrongEncryption ) )
3717
3720
{
3718
3721
var classicManaged = new PkzipClassicManaged ( ) ;
3719
3722
@@ -3738,31 +3741,29 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
3738
3741
3739
3742
private Stream CreateAndInitEncryptionStream ( Stream baseStream , ZipEntry entry )
3740
3743
{
3741
- CryptoStream result = null ;
3742
- if ( ( entry . Version < ZipConstants . VersionStrongEncryption )
3743
- || ( entry . Flags & ( int ) GeneralBitFlags . StrongEncryption ) == 0 )
3744
- {
3745
- var classicManaged = new PkzipClassicManaged ( ) ;
3744
+ if ( entry . Version >= ZipConstants . VersionStrongEncryption &&
3745
+ entry . HasFlag ( GeneralBitFlags . StrongEncryption ) ) return null ;
3746
3746
3747
- OnKeysRequired ( entry . Name ) ;
3748
- if ( HaveKeys == false )
3749
- {
3750
- throw new ZipException ( "No password available for encrypted stream" ) ;
3751
- }
3747
+ var classicManaged = new PkzipClassicManaged ( ) ;
3752
3748
3753
- // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
3754
- // which doesnt do this.
3755
- result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3756
- classicManaged . CreateEncryptor ( key , null ) , CryptoStreamMode . Write ) ;
3749
+ OnKeysRequired ( entry . Name ) ;
3750
+ if ( HaveKeys == false )
3751
+ {
3752
+ throw new ZipException ( "No password available for encrypted stream" ) ;
3753
+ }
3757
3754
3758
- if ( ( entry . Crc < 0 ) || ( entry . Flags & 8 ) != 0 )
3759
- {
3760
- WriteEncryptionHeader ( result , entry . DosTime << 16 ) ;
3761
- }
3762
- else
3763
- {
3764
- WriteEncryptionHeader ( result , entry . Crc ) ;
3765
- }
3755
+ // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
3756
+ // which doesnt do this.
3757
+ var result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3758
+ classicManaged . CreateEncryptor ( key , null ) , CryptoStreamMode . Write ) ;
3759
+
3760
+ if ( entry . Crc < 0 || entry . HasFlag ( GeneralBitFlags . Descriptor ) )
3761
+ {
3762
+ WriteEncryptionHeader ( result , entry . DosTime << 16 ) ;
3763
+ }
3764
+ else
3765
+ {
3766
+ WriteEncryptionHeader ( result , entry . Crc ) ;
3766
3767
}
3767
3768
return result ;
3768
3769
}
@@ -3785,7 +3786,7 @@ private static void WriteEncryptionHeader(Stream stream, long crcValue)
3785
3786
rng . GetBytes ( cryptBuffer ) ;
3786
3787
}
3787
3788
cryptBuffer [ 11 ] = ( byte ) ( crcValue >> 24 ) ;
3788
- stream . Write ( cryptBuffer , 0 , cryptBuffer . Length ) ;
3789
+ stream . Write ( cryptBuffer , offset : 0 , cryptBuffer . Length ) ;
3789
3790
}
3790
3791
3791
3792
#endregion Internal routines
0 commit comments