Skip to content

Commit 64a8cb7

Browse files
committed
refactor for readability and more specific errors
1 parent 2b939aa commit 64a8cb7

File tree

2 files changed

+94
-87
lines changed

2 files changed

+94
-87
lines changed

src/ICSharpCode.SharpZipLib/Zip/ZipConstants.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ public enum GeneralBitFlags
231231
/// </summary>
232232
ReservedPkware15 = 0x8000
233233
}
234+
235+
/// <summary>
236+
/// Helpers for <see cref="GeneralBitFlags"/>
237+
/// </summary>
238+
public static class GeneralBitFlagsExtensions
239+
{
240+
/// <summary>
241+
/// This is equivalent of <see cref="Enum.HasFlag"/> in .NET Core, but since the .NET FW
242+
/// version is really slow (due to un-/boxing and reflection) we use this wrapper.
243+
/// </summary>
244+
/// <param name="flagData"></param>
245+
/// <param name="flag"></param>
246+
/// <returns></returns>
247+
public static bool Includes(this GeneralBitFlags flagData, GeneralBitFlags flag) => (flag & flagData) != 0;
248+
}
234249

235250
#endregion Enumerations
236251

src/ICSharpCode.SharpZipLib/Zip/ZipFile.cs

Lines changed: 79 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,13 +1111,12 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
11111111

11121112
if (signature != ZipConstants.LocalHeaderSignature)
11131113
{
1114-
throw new ZipException(string.Format("Wrong local header signature at 0x{0:x}, expected 0x{1:x8}, actual 0x{2:x8}",
1115-
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}");
11161115
}
11171116

11181117
var extractVersion = (short)(ReadLEUshort() & 0x00ff);
1119-
var localFlags = (short)ReadLEUshort();
1120-
var compressionMethod = (short)ReadLEUshort();
1118+
var localFlags = (GeneralBitFlags)ReadLEUshort();
1119+
var compressionMethod = (CompressionMethod)ReadLEUshort();
11211120
var fileTime = (short)ReadLEUshort();
11221121
var fileDate = (short)ReadLEUshort();
11231122
uint crcValue = ReadLEUint();
@@ -1135,15 +1134,15 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
11351134
var localExtraData = new ZipExtraData(extraData);
11361135

11371136
// Extra data / zip64 checks
1138-
if (localExtraData.Find(1))
1137+
if (localExtraData.Find(headerID: 1))
11391138
{
11401139
// 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64
11411140
// and size or compressedSize = MaxValue, due to rogue creators.
11421141

11431142
size = localExtraData.ReadLong();
11441143
compressedSize = localExtraData.ReadLong();
11451144

1146-
if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)
1145+
if (localFlags.Includes(GeneralBitFlags.Descriptor))
11471146
{
11481147
// These may be valid if patched later
11491148
if ((size != -1) && (size != entry.Size))
@@ -1176,15 +1175,17 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
11761175
throw new ZipException("Compression method not supported");
11771176
}
11781177

1179-
if ((extractVersion > ZipConstants.VersionMadeBy)
1180-
|| ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)))
1178+
if (extractVersion > ZipConstants.VersionMadeBy
1179+
|| (extractVersion > 20 && extractVersion < ZipConstants.VersionZip64))
11811180
{
1182-
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})");
11831182
}
11841183

1185-
if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0)
1184+
const GeneralBitFlags notSupportedFlags = GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption |
1185+
GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked;
1186+
if (localFlags.Includes(notSupportedFlags))
11861187
{
1187-
throw new ZipException("The library does not support the zip version required to extract this entry");
1188+
throw new ZipException($"The library does not support the zip features required to extract this entry ({localFlags & notSupportedFlags:F})");
11881189
}
11891190
}
11901191
}
@@ -1208,53 +1209,53 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
12081209
(extractVersion != 63)
12091210
)
12101211
{
1211-
throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion));
1212+
throw new ZipException($"Version required to extract this entry is invalid ({extractVersion})");
12121213
}
12131214

12141215
var localEncoding = _stringCodec.ZipInputEncoding(localFlags);
12151216

12161217
// Local entry flags dont have reserved bit set on.
1217-
if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0)
1218+
if (localFlags.Includes(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15))
12181219
{
12191220
throw new ZipException("Reserved bit flags cannot be set.");
12201221
}
12211222

12221223
// Encryption requires extract version >= 20
1223-
if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))
1224+
if (localFlags.Includes(GeneralBitFlags.Encrypted) && extractVersion < 20)
12241225
{
1225-
throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
1226+
throw new ZipException($"Version required to extract this entry is too low for encryption ({extractVersion})");
12261227
}
12271228

12281229
// Strong encryption requires encryption flag to be set and extract version >= 50.
1229-
if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)
1230+
if (localFlags.Includes(GeneralBitFlags.StrongEncryption))
12301231
{
1231-
if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)
1232+
if (!localFlags.Includes(GeneralBitFlags.Encrypted))
12321233
{
12331234
throw new ZipException("Strong encryption flag set but encryption flag is not set");
12341235
}
12351236

12361237
if (extractVersion < 50)
12371238
{
1238-
throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
1239+
throw new ZipException($"Version required to extract this entry is too low for encryption ({extractVersion})");
12391240
}
12401241
}
12411242

12421243
// Patched entries require extract version >= 27
1243-
if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))
1244+
if (localFlags.Includes(GeneralBitFlags.Patched) && extractVersion < 27)
12441245
{
1245-
throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
1246+
throw new ZipException($"Patched data requires higher version than ({extractVersion})");
12461247
}
12471248

12481249
// Central header flags match local entry flags.
1249-
if (localFlags != entry.Flags)
1250+
if (!localFlags.Equals((GeneralBitFlags)entry.Flags))
12501251
{
1251-
throw new ZipException("Central header/local header flags mismatch");
1252+
throw new ZipException($"Central header/local header flags mismatch ({(GeneralBitFlags)entry.Flags:F} vs {localFlags:F})");
12521253
}
12531254

12541255
// Central header compression method matches local entry
1255-
if (entry.CompressionMethodForHeader != (CompressionMethod)compressionMethod)
1256+
if (entry.CompressionMethodForHeader != compressionMethod)
12561257
{
1257-
throw new ZipException("Central header/local header compression method mismatch");
1258+
throw new ZipException($"Central header/local header compression method mismatch ({entry.CompressionMethodForHeader:G} vs {compressionMethod:G})");
12581259
}
12591260

12601261
if (entry.Version != extractVersion)
@@ -1263,23 +1264,23 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
12631264
}
12641265

12651266
// Strong encryption and extract version match
1266-
if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)
1267+
if (localFlags.Includes(GeneralBitFlags.StrongEncryption))
12671268
{
12681269
if (extractVersion < 62)
12691270
{
12701271
throw new ZipException("Strong encryption flag set but version not high enough");
12711272
}
12721273
}
12731274

1274-
if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)
1275+
if (localFlags.Includes(GeneralBitFlags.HeaderMasked))
12751276
{
1276-
if ((fileTime != 0) || (fileDate != 0))
1277+
if (fileTime != 0 || fileDate != 0)
12771278
{
12781279
throw new ZipException("Header masked set but date/time values non-zero");
12791280
}
12801281
}
12811282

1282-
if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)
1283+
if (!localFlags.Includes(GeneralBitFlags.Descriptor))
12831284
{
12841285
if (crcValue != (uint)entry.Crc)
12851286
{
@@ -1288,8 +1289,8 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
12881289
}
12891290

12901291
// Crc valid for empty entry.
1291-
// This will also apply to streamed entries where size isnt known and the header cant be patched
1292-
if ((size == 0) && (compressedSize == 0))
1292+
// This will also apply to streamed entries where size isn't known and the header cant be patched
1293+
if (size == 0 && compressedSize == 0)
12931294
{
12941295
if (crcValue != 0)
12951296
{
@@ -1349,23 +1350,18 @@ private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
13491350

13501351
// Size can be verified only if it is known in the local header.
13511352
// it will always be known in the central header.
1352-
if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
1353+
if (!localFlags.Includes(GeneralBitFlags.Descriptor) ||
13531354
((size > 0 || compressedSize > 0) && entry.Size > 0))
13541355
{
1355-
if ((size != 0)
1356-
&& (size != entry.Size))
1356+
if (size != 0 && size != entry.Size)
13571357
{
1358-
throw new ZipException(
1359-
string.Format("Size mismatch between central header({0}) and local header({1})",
1360-
entry.Size, size));
1358+
throw new ZipException($"Size mismatch between central header ({entry.Size}) and local header ({size})");
13611359
}
13621360

1363-
if ((compressedSize != 0)
1361+
if (compressedSize != 0
13641362
&& (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1))
13651363
{
1366-
throw new ZipException(
1367-
string.Format("Compressed size mismatch between central header({0}) and local header({1})",
1368-
entry.CompressedSize, compressedSize));
1364+
throw new ZipException($"Compressed size mismatch between central header({entry.CompressedSize}) and local header({compressedSize})");
13691365
}
13701366
}
13711367

@@ -3503,20 +3499,16 @@ private void ReadEntries()
35033499
}
35043500

35053501
bool isZip64 = false;
3506-
bool requireZip64 = false;
3507-
3502+
35083503
// Check if zip64 header information is required.
3509-
if ((thisDiskNumber == 0xffff) ||
3510-
(startCentralDirDisk == 0xffff) ||
3511-
(entriesForThisDisk == 0xffff) ||
3512-
(entriesForWholeCentralDir == 0xffff) ||
3513-
(centralDirSize == 0xffffffff) ||
3514-
(offsetOfCentralDir == 0xffffffff))
3515-
{
3516-
requireZip64 = true;
3517-
}
3518-
3519-
// #357 - always check for the existance of the Zip64 central directory.
3504+
bool requireZip64 = thisDiskNumber == 0xffff ||
3505+
startCentralDirDisk == 0xffff ||
3506+
entriesForThisDisk == 0xffff ||
3507+
entriesForWholeCentralDir == 0xffff ||
3508+
centralDirSize == 0xffffffff ||
3509+
offsetOfCentralDir == 0xffffffff;
3510+
3511+
// #357 - always check for the existence of the Zip64 central directory.
35203512
// #403 - Take account of the fixed size of the locator when searching.
35213513
// Subtract from locatedEndOfCentralDir so that the endLocation is the location of EndOfCentralDirectorySignature,
35223514
// rather than the data following the signature.
@@ -3550,7 +3542,7 @@ private void ReadEntries()
35503542

35513543
if (sig64 != ZipConstants.Zip64CentralFileHeaderSignature)
35523544
{
3553-
throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
3545+
throw new ZipException($"Invalid Zip64 Central directory signature at {offset64:X}");
35543546
}
35553547

35563548
// NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
@@ -3605,8 +3597,11 @@ private void ReadEntries()
36053597
int extraLen = ReadLEUshort();
36063598
int commentLen = ReadLEUshort();
36073599

3608-
int diskStartNo = ReadLEUshort(); // Not currently used
3609-
int internalAttributes = ReadLEUshort(); // Not currently used
3600+
3601+
// ReSharper disable once UnusedVariable, Currently unused but needs to be read to offset the stream
3602+
int diskStartNo = ReadLEUshort();
3603+
// ReSharper disable once UnusedVariable, Currently unused but needs to be read to offset the stream
3604+
int internalAttributes = ReadLEUshort();
36103605

36113606
uint externalAttributes = ReadLEUint();
36123607
long offset = ReadLEUint();
@@ -3630,7 +3625,7 @@ private void ReadEntries()
36303625
ExternalFileAttributes = (int)externalAttributes
36313626
};
36323627

3633-
if ((bitFlags & 8) == 0)
3628+
if (!entry.HasFlag(GeneralBitFlags.Descriptor))
36343629
{
36353630
entry.CryptoCheckValue = (byte)(crc >> 24);
36363631
}
@@ -3698,15 +3693,15 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
36983693
}
36993694
int saltLen = entry.AESSaltLen;
37003695
byte[] saltBytes = new byte[saltLen];
3701-
int saltIn = StreamUtils.ReadRequestedBytes(baseStream, saltBytes, 0, saltLen);
3702-
if (saltIn != saltLen)
3703-
throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
3704-
//
3696+
int saltIn = StreamUtils.ReadRequestedBytes(baseStream, saltBytes, offset: 0, saltLen);
3697+
3698+
if (saltIn != saltLen) throw new ZipException($"AES Salt expected {saltLen} git {saltIn}");
3699+
37053700
byte[] pwdVerifyRead = new byte[2];
37063701
StreamUtils.ReadFully(baseStream, pwdVerifyRead);
37073702
int blockSize = entry.AESKeySize / 8; // bits to bytes
37083703

3709-
var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
3704+
var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, writeMode: false);
37103705
byte[] pwdVerifyCalc = decryptor.PwdVerifier;
37113706
if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
37123707
throw new ZipException("Invalid password for AES");
@@ -3719,8 +3714,7 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
37193714
}
37203715
else
37213716
{
3722-
if ((entry.Version < ZipConstants.VersionStrongEncryption)
3723-
|| (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0)
3717+
if (entry.Version < ZipConstants.VersionStrongEncryption || !entry.HasFlag(GeneralBitFlags.StrongEncryption))
37243718
{
37253719
var classicManaged = new PkzipClassicManaged();
37263720

@@ -3745,31 +3739,29 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
37453739

37463740
private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
37473741
{
3748-
CryptoStream result = null;
3749-
if ((entry.Version < ZipConstants.VersionStrongEncryption)
3750-
|| (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0)
3751-
{
3752-
var classicManaged = new PkzipClassicManaged();
3742+
if (entry.Version >= ZipConstants.VersionStrongEncryption &&
3743+
entry.HasFlag(GeneralBitFlags.StrongEncryption)) return null;
37533744

3754-
OnKeysRequired(entry.Name);
3755-
if (HaveKeys == false)
3756-
{
3757-
throw new ZipException("No password available for encrypted stream");
3758-
}
3745+
var classicManaged = new PkzipClassicManaged();
3746+
3747+
OnKeysRequired(entry.Name);
3748+
if (HaveKeys == false)
3749+
{
3750+
throw new ZipException("No password available for encrypted stream");
3751+
}
37593752

3760-
// Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
3761-
// which doesnt do this.
3762-
result = new CryptoStream(new UncompressedStream(baseStream),
3763-
classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
3753+
// Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
3754+
// which doesnt do this.
3755+
var result = new CryptoStream(new UncompressedStream(baseStream),
3756+
classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);
37643757

3765-
if ((entry.Crc < 0) || (entry.Flags & 8) != 0)
3766-
{
3767-
WriteEncryptionHeader(result, entry.DosTime << 16);
3768-
}
3769-
else
3770-
{
3771-
WriteEncryptionHeader(result, entry.Crc);
3772-
}
3758+
if (entry.Crc < 0 || entry.HasFlag(GeneralBitFlags.Descriptor))
3759+
{
3760+
WriteEncryptionHeader(result, entry.DosTime << 16);
3761+
}
3762+
else
3763+
{
3764+
WriteEncryptionHeader(result, entry.Crc);
37733765
}
37743766
return result;
37753767
}
@@ -3792,7 +3784,7 @@ private static void WriteEncryptionHeader(Stream stream, long crcValue)
37923784
rng.GetBytes(cryptBuffer);
37933785
}
37943786
cryptBuffer[11] = (byte)(crcValue >> 24);
3795-
stream.Write(cryptBuffer, 0, cryptBuffer.Length);
3787+
stream.Write(cryptBuffer, offset: 0, cryptBuffer.Length);
37963788
}
37973789

37983790
#endregion Internal routines

0 commit comments

Comments
 (0)