public void Get_Success() { //Arrange var itemCount = 1000000; Mapper.Load <MapperResolverTest>(); var header = new HeaderTest() { Id = Guid.NewGuid(), StringField = "String value" }; var items = new List <ItemTest>(); for (var i = 0; i < itemCount; i++) { items.Add(new ItemTest() { Id = Guid.NewGuid(), Header = header, StringField = string.Format("Item {0} String value", i) }); } header.Items = items; //Act var moment = Stopwatch.StartNew(); var headerMirror = Mapper.Map <HeaderTestMirror>(header); moment.Stop(); //Assert Assert.Equal(header.Id, headerMirror.Id); Assert.Equal(header.StringField, headerMirror.StringField); Assert.Equal(itemCount, headerMirror.Items.Count); var itemsMirror = headerMirror.Items.ToList(); for (var i = 0; i < itemCount; i++) { AssertItem(items[i], headerMirror, itemsMirror[i]); } //This test is subjective. In my machine I expect that the average elapsed time per converted //entity to be less than 15 ticks, but it can fail depending on the host machine or in what //is running at the moment Assert.True(15 > moment.ElapsedTicks / (itemCount + 1)); }
/// <summary> /// Test a local header against that provided from the central directory /// </summary> /// <param name="entry"> /// The entry to test against /// </param> /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param> /// <returns>The offset of the entries data in the file</returns> long TestLocalHeader(ZipEntry entry, HeaderTest tests) { lock(baseStream_) { bool testHeader = (tests & HeaderTest.Header) != 0; bool testData = (tests & HeaderTest.Extract) != 0; baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) { throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)); } short extractVersion = ( short ) (ReadLEUshort() & 0x00ff); short localFlags = ( short )ReadLEUshort(); short compressionMethod = ( short )ReadLEUshort(); short fileTime = ( short )ReadLEUshort(); short fileDate = ( short )ReadLEUshort(); uint crcValue = ReadLEUint(); long compressedSize = ReadLEUint(); long size = ReadLEUint(); int storedNameLength = ReadLEUshort(); int extraDataLength = ReadLEUshort(); byte[] nameData = new byte[storedNameLength]; StreamUtils.ReadFully(baseStream_, nameData); byte[] extraData = new byte[extraDataLength]; StreamUtils.ReadFully(baseStream_, extraData); ZipExtraData localExtraData = new ZipExtraData(extraData); // Extra data / zip64 checks if (localExtraData.Find(1)) { // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64 // and size or compressedSize = MaxValue, due to rogue creators. size = localExtraData.ReadLong(); compressedSize = localExtraData.ReadLong(); if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) { // These may be valid if patched later if ( (size != -1) && (size != entry.Size)) { throw new ZipException("Size invalid for descriptor"); } if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) { throw new ZipException("Compressed size invalid for descriptor"); } } } else { // No zip64 extra data but entry requires it. if ((extractVersion >= ZipConstants.VersionZip64) && (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) { throw new ZipException("Required Zip64 extended information missing"); } } if ( testData ) { if ( entry.IsFile ) { if ( !entry.IsCompressionMethodSupported() ) { throw new ZipException("Compression method not supported"); } if ( (extractVersion > ZipConstants.VersionMadeBy) || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) { throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion)); } if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0 ) { throw new ZipException("The library does not support the zip version required to extract this entry"); } } } if (testHeader) { if ((extractVersion <= 63) && // Ignore later versions as we dont know about them.. (extractVersion != 10) && (extractVersion != 11) && (extractVersion != 20) && (extractVersion != 21) && (extractVersion != 25) && (extractVersion != 27) && (extractVersion != 45) && (extractVersion != 46) && (extractVersion != 50) && (extractVersion != 51) && (extractVersion != 52) && (extractVersion != 61) && (extractVersion != 62) && (extractVersion != 63) ) { throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion)); } // Local entry flags dont have reserved bit set on. if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0) { throw new ZipException("Reserved bit flags cannot be set."); } // Encryption requires extract version >= 20 if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion)); } // Strong encryption requires encryption flag to be set and extract version >= 50. if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) { if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) { throw new ZipException("Strong encryption flag set but encryption flag is not set"); } if (extractVersion < 50) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion)); } } // Patched entries require extract version >= 27 if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) { throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion)); } // Central header flags match local entry flags. if (localFlags != entry.Flags) { throw new ZipException("Central header/local header flags mismatch"); } // Central header compression method matches local entry if (entry.CompressionMethod != (CompressionMethod)compressionMethod) { throw new ZipException("Central header/local header compression method mismatch"); } if (entry.Version != extractVersion) { throw new ZipException("Extract version mismatch"); } // Strong encryption and extract version match if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) { if (extractVersion < 62) { throw new ZipException("Strong encryption flag set but version not high enough"); } } if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) { if ((fileTime != 0) || (fileDate != 0)) { throw new ZipException("Header masked set but date/time values non-zero"); } } if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) { if (crcValue != (uint)entry.Crc) { throw new ZipException("Central header/local header crc mismatch"); } } // Crc valid for empty entry. // This will also apply to streamed entries where size isnt known and the header cant be patched if ((size == 0) && (compressedSize == 0)) { if (crcValue != 0) { throw new ZipException("Invalid CRC for empty entry"); } } // TODO: make test more correct... can't compare lengths as was done originally as this can fail for MBCS strings // Assuming a code page at this point is not valid? Best is to store the name length in the ZipEntry probably if (entry.Name.Length > storedNameLength) { throw new ZipException("File name length mismatch"); } // Name data has already been read convert it and compare. string localName = ZipConstants.ConvertToStringExt(localFlags, nameData); // Central directory and local entry name match if (localName != entry.Name) { throw new ZipException("Central header and local header file name mismatch"); } // Directories have zero actual size but can have compressed size if (entry.IsDirectory) { if (size > 0) { throw new ZipException("Directory cannot have size"); } // There may be other cases where the compressed size can be greater than this? // If so until details are known we will be strict. if (entry.IsCrypted) { if (compressedSize > ZipConstants.CryptoHeaderSize + 2) { throw new ZipException("Directory compressed size invalid"); } } else if (compressedSize > 2) { // When not compressed the directory size can validly be 2 bytes // if the true size wasnt known when data was originally being written. // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes throw new ZipException("Directory compressed size invalid"); } } if (!ZipNameTransform.IsValidName(localName, true)) { throw new ZipException("Name is invalid"); } } // Tests that apply to both data and header. // Size can be verified only if it is known in the local header. // it will always be known in the central header. if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) || ((size > 0 || compressedSize > 0) && entry.Size > 0)) { if ((size != 0) && (size != entry.Size)) { throw new ZipException( string.Format("Size mismatch between central header({0}) and local header({1})", entry.Size, size)); } if ((compressedSize != 0) && (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) { throw new ZipException( string.Format("Compressed size mismatch between central header({0}) and local header({1})", entry.CompressedSize, compressedSize)); } } int extraLength = storedNameLength + extraDataLength; return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength; } }
/// <summary> /// Test the local header against that provided from the central directory /// </summary> /// <param name="entry"> /// The entry to test against /// </param> /// <param name="tests">The type of test to carry out.</param> /// <returns>The offset of the entries data in the file</returns> long TestLocalHeader(ZipEntry entry, HeaderTest tests) { lock(baseStream_) { bool testHeader = (tests & HeaderTest.Header) != 0; bool testData = (tests & HeaderTest.Extract) != 0; baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) { throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)); } short extractVersion = ( short )ReadLEUshort(); short localFlags = ( short )ReadLEUshort(); short compressionMethod = ( short )ReadLEUshort(); short fileTime = ( short )ReadLEUshort(); short fileDate = ( short )ReadLEUshort(); uint crcValue = ReadLEUint(); long size = ReadLEUint(); long compressedSize = ReadLEUint(); int storedNameLength = ReadLEUshort(); int extraDataLength = ReadLEUshort(); if ( testData ) { if ( entry.IsFile ) { if ( !entry.IsCompressionMethodSupported() ) { throw new ZipException("Compression method not supported"); } if ( (extractVersion > ZipConstants.VersionMadeBy) || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) { throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion)); } if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0 ) { throw new ZipException("The library does not support the zip version required to extract this entry"); } } } if ( testHeader ) { if ((extractVersion < 63) && // Ignore later versions as we dont know about them.. (extractVersion != 10) && (extractVersion != 20) && (extractVersion != 21) && (extractVersion != 25) && (extractVersion != 27) && (extractVersion != 45) && (extractVersion != 46) && (extractVersion != 50) && (extractVersion != 51) && (extractVersion != 61) && (extractVersion != 62) ) { throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion)); } // Local entry flags dont have reserved bit set on. if ( (localFlags & ( int )GeneralBitFlags.Reserved) != 0 ) { throw new ZipException("Reserved bit flag cannot bet set."); } // Encryption requires extract version >= 20 if ( ((localFlags & ( int )GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20) ) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion)); } // Strong encryption requires encryption flag to be set and extract version >= 50. if ( (localFlags & (int)GeneralBitFlags.StrongEncryption) != 0 ) { if ( (localFlags & (int)GeneralBitFlags.Encrypted) == 0 ) { throw new ZipException("Strong encryption flag set but encryption flag is not set"); } if ( extractVersion < 50 ) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion)); } } // Patched entries require extract version >= 27 if ( ((localFlags & ( int )GeneralBitFlags.Patched) != 0) && (extractVersion < 27) ) { throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion)); } // Central header flags match local entry flags. if ( localFlags != entry.Flags ) { throw new ZipException("Central header/local header flags mismatch"); } // Central header compression method matches local entry if ( entry.CompressionMethod != ( CompressionMethod )compressionMethod ) { throw new ZipException("Central header/local header compression method mismatch"); } // Strong encryption and extract version match if ( (localFlags & ( int )GeneralBitFlags.StrongEncryption) != 0 ) { if ( extractVersion < 62 ) { throw new ZipException("Strong encryption flag set but version not high enough"); } } if ( (localFlags & ( int )GeneralBitFlags.HeaderMasked) != 0 ) { if ( (fileTime != 0) || (fileDate != 0) ) { throw new ZipException("Header masked set but date/time values non-zero"); } } if ( (localFlags & ( int )GeneralBitFlags.Descriptor) == 0 ) { if ( crcValue != (uint)entry.Crc ) { throw new ZipException("Central header/local header crc mismatch"); } } // Crc valid for empty entry. if ( (size == 0) && (compressedSize == 0) ) { if ( crcValue != 0 ) { throw new ZipException("Invalid CRC for empty entry"); } } // TODO: make test more correct... can't compare lengths as was done originally as this can fail for MBCS strings // Assuming a code page at this point is not valid? Best is to store the name length in the ZipEntry probably if ( entry.Name.Length > storedNameLength ) { throw new ZipException("File name length mismatch"); } byte[] nameData = new byte[storedNameLength]; StreamUtils.ReadFully(baseStream_, nameData); string localName = ZipConstants.ConvertToString(nameData); // Central directory and local entry name match if ( localName != entry.Name ) { throw new ZipException("Central header and local header file name mismatch"); } // Directories have zero size. if ( entry.IsDirectory ) { if ( (compressedSize != 0) || (size != 0) ) { throw new ZipException("Directory cannot have size"); } } if ( !ZipNameTransform.IsValidName(localName, true) ) { throw new ZipException("Name is invalid"); } byte[] data = new byte[extraDataLength]; StreamUtils.ReadFully(baseStream_, data); ZipExtraData ed = new ZipExtraData(data); // Extra data / zip64 checks if ( ed.Find(1) ) { // Zip64 extra data but extract version too low if ( extractVersion < ZipConstants.VersionZip64 ) { throw new ZipException( string.Format("Extra data contains Zip64 information but version {0}.{1} is not high enough", extractVersion / 10, extractVersion % 10)); } // Zip64 extra data but size fields dont indicate its required. if ( (( uint )size != uint.MaxValue) && (( uint )compressedSize != uint.MaxValue) ) { throw new ZipException("Entry sizes not correct for Zip64"); } size = ed.ReadLong(); compressedSize = ed.ReadLong(); } else { // No zip64 extra data but entry requires it. if ( (extractVersion >= ZipConstants.VersionZip64) && ((( uint )size == uint.MaxValue) || (( uint )compressedSize == uint.MaxValue)) ) { throw new ZipException("Required Zip64 extended information missing"); } } } int extraLength = storedNameLength + extraDataLength; return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength; } }
private long TestLocalHeader(ZipEntry entry, HeaderTest tests) { lock (baseStream_) { bool flag = (tests & HeaderTest.Header) != 0; bool flag2 = (tests & HeaderTest.Extract) != 0; baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if (ReadLEUint() != 0x4034b50) { throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)); } short num = (short)ReadLEUshort(); short flags = (short)ReadLEUshort(); short num3 = (short)ReadLEUshort(); short num4 = (short)ReadLEUshort(); short num5 = (short)ReadLEUshort(); uint num6 = ReadLEUint(); long num7 = ReadLEUint(); long num8 = ReadLEUint(); int num9 = ReadLEUshort(); int num10 = ReadLEUshort(); byte[] buffer = new byte[num9]; StreamUtils.ReadFully(baseStream_, buffer); byte[] buffer2 = new byte[num10]; StreamUtils.ReadFully(baseStream_, buffer2); ZipExtraData data = new ZipExtraData(buffer2); if (data.Find(1)) { num8 = data.ReadLong(); num7 = data.ReadLong(); if ((flags & 8) != 0) { if ((num8 != -1L) && (num8 != entry.Size)) { throw new ZipException("Size invalid for descriptor"); } if ((num7 != -1L) && (num7 != entry.CompressedSize)) { throw new ZipException("Compressed size invalid for descriptor"); } } } else if ((num >= 0x2d) && ((((uint)num8) == uint.MaxValue) || (((uint)num7) == uint.MaxValue))) { throw new ZipException("Required Zip64 extended information missing"); } if (flag2 && entry.IsFile) { if (!entry.IsCompressionMethodSupported()) { throw new ZipException("Compression method not supported"); } if ((num > 0x33) || ((num > 20) && (num < 0x2d))) { throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", num)); } if ((flags & 0x3060) != 0) { throw new ZipException("The library does not support the zip version required to extract this entry"); } } if (flag) { if (((((num <= 0x3f) && (num != 10)) && ((num != 11) && (num != 20))) && (((num != 0x15) && (num != 0x19)) && ((num != 0x1b) && (num != 0x2d)))) && ((((num != 0x2e) && (num != 50)) && ((num != 0x33) && (num != 0x34))) && (((num != 0x3d) && (num != 0x3e)) && (num != 0x3f)))) { throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", num)); } if ((flags & 0xc010) != 0) { throw new ZipException("Reserved bit flags cannot be set."); } if (((flags & 1) != 0) && (num < 20)) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", num)); } if ((flags & 0x40) != 0) { if ((flags & 1) == 0) { throw new ZipException("Strong encryption flag set but encryption flag is not set"); } if (num < 50) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", num)); } } if (((flags & 0x20) != 0) && (num < 0x1b)) { throw new ZipException(string.Format("Patched data requires higher version than ({0})", num)); } if (flags != entry.Flags) { throw new ZipException("Central header/local header flags mismatch"); } if (entry.CompressionMethod != ((CompressionMethod)num3)) { throw new ZipException("Central header/local header compression method mismatch"); } if (entry.Version != num) { throw new ZipException("Extract version mismatch"); } if (((flags & 0x40) != 0) && (num < 0x3e)) { throw new ZipException("Strong encryption flag set but version not high enough"); } if (((flags & 0x2000) != 0) && ((num4 != 0) || (num5 != 0))) { throw new ZipException("Header masked set but date/time values non-zero"); } if (((flags & 8) == 0) && (num6 != ((uint)entry.Crc))) { throw new ZipException("Central header/local header crc mismatch"); } if (((num8 == 0L) && (num7 == 0L)) && (num6 != 0)) { throw new ZipException("Invalid CRC for empty entry"); } if (entry.Name.Length > num9) { throw new ZipException("File name length mismatch"); } string name = ZipConstants.ConvertToStringExt(flags, buffer); if (name != entry.Name) { throw new ZipException("Central header and local header file name mismatch"); } if (entry.IsDirectory) { if (num8 > 0L) { throw new ZipException("Directory cannot have size"); } if (entry.IsCrypted) { if (num7 > 14L) { throw new ZipException("Directory compressed size invalid"); } } else if (num7 > 2L) { throw new ZipException("Directory compressed size invalid"); } } if (!ZipNameTransform.IsValidName(name, true)) { throw new ZipException("Name is invalid"); } } if ((((flags & 8) == 0) || (num8 > 0L)) || (num7 > 0L)) { if (num8 != entry.Size) { throw new ZipException(string.Format("Size mismatch between central header({0}) and local header({1})", entry.Size, num8)); } if (((num7 != entry.CompressedSize) && (num7 != 0xffffffffL)) && (num7 != -1L)) { throw new ZipException(string.Format("Compressed size mismatch between central header({0}) and local header({1})", entry.CompressedSize, num7)); } } int num11 = num9 + num10; return (((offsetOfFirstEntry + entry.Offset) + 30L) + num11); } }
/// <summary> /// Test a local header against that provided from the central directory /// </summary> /// <param name="entry"> /// The entry to test against /// </param> /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param> /// <returns>The offset of the entries data in the file</returns> long TestLocalHeader(HfsEntry entry, HeaderTest tests) { lock (baseStream_) { bool testHeader = (tests & HeaderTest.Header) != 0; bool testData = (tests & HeaderTest.Extract) != 0; baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if ((int)ReadLEUint() != HfsConstants.LocalHeaderSignature) { throw new HfsException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)); } short extractVersion = (short)ReadLEUshort(); short localFlags = (short)ReadLEUshort(); short compressionMethod = (short)ReadLEUshort(); short fileTime = (short)ReadLEUshort(); short fileDate = (short)ReadLEUshort(); uint crcValue = ReadLEUint(); long compressedSize = ReadLEUint(); long size = ReadLEUint(); int storedNameLength = ReadLEUshort(); int extraDataLength = ReadLEUshort(); long base_buffpos = baseStream_.Position; byte[] nameData = new byte[storedNameLength]; StreamUtils.ReadFully(baseStream_, nameData); byte[] extraData = new byte[extraDataLength]; StreamUtils.ReadFully(baseStream_, extraData); if (testData) { if (entry.IsFile) { if (!entry.IsCompressionMethodSupported()) { throw new HfsException("Compression method not supported"); } if ((extractVersion > HfsConstants.VersionMadeBy)) { throw new HfsException(string.Format("Version required to extract this entry not supported ({0})", extractVersion)); } } } if (testHeader) { if ((extractVersion <= 63) && // Ignore later versions as we dont know about them.. (extractVersion != 10) && (extractVersion != 11) && (extractVersion != 20) && (extractVersion != 21) && (extractVersion != 25) && (extractVersion != 27) && (extractVersion != 45) && (extractVersion != 46) && (extractVersion != 50) && (extractVersion != 51) && (extractVersion != 52) && (extractVersion != 61) && (extractVersion != 62) && (extractVersion != 63) ) { throw new HfsException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion)); } // Central header flags match local entry flags. if (localFlags != entry.Flags) { throw new HfsException("Central header/local header flags mismatch"); } // Central header compression method matches local entry if (entry.CompressionMethod != (CompressionMethod)compressionMethod) { throw new HfsException("Central header/local header compression method mismatch"); } if (entry.Version != extractVersion) { throw new HfsException("Extract version mismatch"); } // Crc valid for empty entry. // This will also apply to streamed entries where size isnt known and the header cant be patched if ((size == 0) && (compressedSize == 0)) { if (crcValue != 0) { throw new HfsException("Invalid CRC for empty entry"); } } // TODO: make test more correct... can't compare lengths as was done originally as this can fail for MBCS strings // Assuming a code page at this point is not valid? Best is to store the name length in the HfsEntry probably if (entry.Name.Length > storedNameLength) { throw new HfsException("File name length mismatch"); } // Name data has already been read convert it and compare. string localName = HfsConstants.ConvertToStringObfs(nameData, storedNameLength, (int)base_buffpos); // Central directory and local entry name match if (localName != entry.Name) { throw new HfsException("Central header and local header file name mismatch"); } // Directories have zero actual size but can have compressed size if (entry.IsDirectory) { if (size > 0) { throw new HfsException("Directory cannot have size"); } } if (!HfsNameTransform.IsValidName(localName, true)) { throw new HfsException("Name is invalid"); } } // Tests that apply to both data and header. // Size can be verified only if it is known in the local header. // it will always be known in the central header. if (((size > 0) || (compressedSize > 0))) { if (size != entry.Size) { throw new HfsException( string.Format("Size mismatch between central header({0}) and local header({1})", entry.Size, size)); } if (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1) { throw new HfsException( string.Format("Compressed size mismatch between central header({0}) and local header({1})", entry.CompressedSize, compressedSize)); } } int extraLength = storedNameLength + extraDataLength; return offsetOfFirstEntry + entry.Offset + HfsConstants.LocalHeaderBaseSize + extraLength; } }
/// <summary> /// Test a local header against that provided from the central directory /// </summary> /// <param name="entry"> /// The entry to test against /// </param> /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param> /// <returns>The offset of the entries data in the file</returns> long TestLocalHeader(ZipEntry entry, HeaderTest tests) { lock(baseStream_) { bool testHeader = (tests & HeaderTest.Header) != 0; bool testData = (tests & HeaderTest.Extract) != 0; baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) { } short extractVersion = ( short )ReadLEUshort(); short localFlags = ( short )ReadLEUshort(); short compressionMethod = ( short )ReadLEUshort(); short fileTime = ( short )ReadLEUshort(); short fileDate = ( short )ReadLEUshort(); uint crcValue = ReadLEUint(); long compressedSize = ReadLEUint(); long size = ReadLEUint(); int storedNameLength = ReadLEUshort(); int extraDataLength = ReadLEUshort(); byte[] nameData = new byte[storedNameLength]; StreamUtils.ReadFully(baseStream_, nameData); byte[] extraData = new byte[extraDataLength]; StreamUtils.ReadFully(baseStream_, extraData); ZipExtraData localExtraData = new ZipExtraData(extraData); // Extra data / zip64 checks if (localExtraData.Find(1)) { // 2010-03-04 Forum 10512: removed checks for version >= ZipConstants.VersionZip64 // and size or compressedSize = MaxValue, due to rogue creators. size = localExtraData.ReadLong(); compressedSize = localExtraData.ReadLong(); if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) { // These may be valid if patched later if ( (size != -1) && (size != entry.Size)) { } if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) { } } } else { // No zip64 extra data but entry requires it. if ((extractVersion >= ZipConstants.VersionZip64) && (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) { } } if ( testData ) { if ( entry.IsFile ) { if ( !entry.IsCompressionMethodSupported() ) { } if ( (extractVersion > ZipConstants.VersionMadeBy) || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) { } if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0 ) { } } } if (testHeader) { // Name data has already been read convert it and compare. string localName = ZipConstants.ConvertToStringExt(localFlags, nameData); // Directories have zero actual size but can have compressed size if (entry.IsDirectory) { // There may be other cases where the compressed size can be greater than this? // If so until details are known we will be strict. if (entry.IsCrypted) { } else if (compressedSize > 2) { } } } // Tests that apply to both data and header. // Size can be verified only if it is known in the local header. // it will always be known in the central header. int extraLength = storedNameLength + extraDataLength; return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength; } }
long TestLocalHeader(ZipEntry entry, HeaderTest tests) { lock(baseStream_) { bool testHeader = (tests & HeaderTest.Header) != 0; bool testData = (tests & HeaderTest.Extract) != 0; baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) { throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset)); } short extractVersion = ( short )ReadLEUshort(); short localFlags = ( short )ReadLEUshort(); short compressionMethod = ( short )ReadLEUshort(); short fileTime = ( short )ReadLEUshort(); short fileDate = ( short )ReadLEUshort(); uint crcValue = ReadLEUint(); long compressedSize = ReadLEUint(); long size = ReadLEUint(); int storedNameLength = ReadLEUshort(); int extraDataLength = ReadLEUshort(); byte[] nameData = new byte[storedNameLength]; StreamUtils.ReadFully(baseStream_, nameData); byte[] extraData = new byte[extraDataLength]; StreamUtils.ReadFully(baseStream_, extraData); ZipExtraData localExtraData = new ZipExtraData(extraData); if (localExtraData.Find(1)) { if (extractVersion < ZipConstants.VersionZip64) { throw new ZipException( string.Format("Extra data contains Zip64 information but version {0}.{1} is not high enough", extractVersion / 10, extractVersion % 10)); } if (((uint)size != uint.MaxValue) && ((uint)compressedSize != uint.MaxValue)) { throw new ZipException("Entry sizes not correct for Zip64"); } size = localExtraData.ReadLong(); compressedSize = localExtraData.ReadLong(); if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0) { if ( (size != -1) && (size != entry.Size)) { throw new ZipException("Size invalid for descriptor"); } if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) { throw new ZipException("Compressed size invalid for descriptor"); } } } else { if ((extractVersion >= ZipConstants.VersionZip64) && (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue))) { throw new ZipException("Required Zip64 extended information missing"); } } if ( testData ) { if ( entry.IsFile ) { if ( !entry.IsCompressionMethodSupported() ) { throw new ZipException("Compression method not supported"); } if ( (extractVersion > ZipConstants.VersionMadeBy) || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) { throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion)); } if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0 ) { throw new ZipException("The library does not support the zip version required to extract this entry"); } } } if (testHeader) { if ((extractVersion <= 63) && (extractVersion != 10) && (extractVersion != 11) && (extractVersion != 20) && (extractVersion != 21) && (extractVersion != 25) && (extractVersion != 27) && (extractVersion != 45) && (extractVersion != 46) && (extractVersion != 50) && (extractVersion != 51) && (extractVersion != 52) && (extractVersion != 61) && (extractVersion != 62) && (extractVersion != 63) ) { throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion)); } if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0) { throw new ZipException("Reserved bit flags cannot be set."); } if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20)) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion)); } if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) { if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0) { throw new ZipException("Strong encryption flag set but encryption flag is not set"); } if (extractVersion < 50) { throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion)); } } if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27)) { throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion)); } if (localFlags != entry.Flags) { throw new ZipException("Central header/local header flags mismatch"); } if (entry.CompressionMethod != (CompressionMethod)compressionMethod) { throw new ZipException("Central header/local header compression method mismatch"); } if (entry.Version != extractVersion) { throw new ZipException("Extract version mismatch"); } if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0) { if (extractVersion < 62) { throw new ZipException("Strong encryption flag set but version not high enough"); } } if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0) { if ((fileTime != 0) || (fileDate != 0)) { throw new ZipException("Header masked set but date/time values non-zero"); } } if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) { if (crcValue != (uint)entry.Crc) { throw new ZipException("Central header/local header crc mismatch"); } } if ((size == 0) && (compressedSize == 0)) { if (crcValue != 0) { throw new ZipException("Invalid CRC for empty entry"); } } if (entry.Name.Length > storedNameLength) { throw new ZipException("File name length mismatch"); } string localName = ZipConstants.ConvertToStringExt(localFlags, nameData); if (localName != entry.Name) { throw new ZipException("Central header and local header file name mismatch"); } if (entry.IsDirectory) { if (size > 0) { throw new ZipException("Directory cannot have size"); } if (entry.IsCrypted) { if (compressedSize > ZipConstants.CryptoHeaderSize + 2) { throw new ZipException("Directory compressed size invalid"); } } else if (compressedSize > 2) { throw new ZipException("Directory compressed size invalid"); } } if (!ZipNameTransform.IsValidName(localName, true)) { throw new ZipException("Name is invalid"); } } if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) || ((size > 0) || (compressedSize > 0))) { if (size != entry.Size) { throw new ZipException( string.Format("Size mismatch between central header({0}) and local header({1})", entry.Size, size)); } if (compressedSize != entry.CompressedSize) { throw new ZipException( string.Format("Compressed size mismatch between central header({0}) and local header({1})", entry.CompressedSize, compressedSize)); } } int extraLength = storedNameLength + extraDataLength; return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength; } }