/// <summary> /// Test an archive for integrity/validity /// </summary> /// <param name="testData">Perform low level data Crc check</param> /// <param name="strategy">The <see cref="TestStrategy"></see> to apply.</param> /// <param name="resultHandler">The <see cref="ZipTestResultHandler"></see> handler to call during testing.</param> /// <returns>true if all tests pass, false otherwise</returns> public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler) { TestStatus status = new TestStatus(this); if (resultHandler != null) { resultHandler(status, null); } HeaderTest test = testData ? (HeaderTest.Header | HeaderTest.Extract) : HeaderTest.Header; bool testing = true; try { int entryIndex = 0; while (testing && (entryIndex < Count)) { if (resultHandler != null) { status.SetEntry(this[entryIndex]); status.SetOperation(TestOperation.EntryHeader); resultHandler(status, null); } try { TestLocalHeader(this[entryIndex], test); } catch (ZipException ex) { status.AddError(); if (resultHandler != null) { resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message)); } if (strategy == TestStrategy.FindFirstError) { testing = false; } } if (testing && testData && this[entryIndex].IsFile) { if (resultHandler != null) { status.SetOperation(TestOperation.EntryData); resultHandler(status, null); } Stream entryStream = this.GetInputStream(this[entryIndex]); Crc32 crc = new Crc32(); byte[] buffer = new byte[4096]; long totalBytes = 0; int bytesRead; while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) { crc.Update(buffer, 0, bytesRead); if (resultHandler != null) { totalBytes += bytesRead; status.SetBytesTested(totalBytes); resultHandler(status, null); } } if (this[entryIndex].Crc != crc.Value) { status.AddError(); if (resultHandler != null) { resultHandler(status, "CRC mismatch"); } if (strategy == TestStrategy.FindFirstError) { testing = false; } } if ((this[entryIndex].Flags & (int) GeneralBitFlags.Descriptor) != 0) { ZipHelperStream helper = new ZipHelperStream(baseStream_); DescriptorData data = new DescriptorData(); helper.ReadDataDescriptor(this[entryIndex].LocalHeaderRequiresZip64, data); if (this[entryIndex].Crc != data.Crc) { status.AddError(); } if (this[entryIndex].CompressedSize != data.CompressedSize) { status.AddError(); } if (this[entryIndex].Size != data.Size) { status.AddError(); } } } if (resultHandler != null) { status.SetOperation(TestOperation.EntryComplete); resultHandler(status, null); } entryIndex += 1; } if (resultHandler != null) { status.SetOperation(TestOperation.MiscellaneousTests); resultHandler(status, null); } // TODO: the 'Corrina Johns' test where local headers are missing from // the central directory. They are therefore invisible to many archivers. } catch (Exception ex) { status.AddError(); if (resultHandler != null) { resultHandler(status, string.Format("Exception during test - '{0}'", ex.Message)); } } if (resultHandler != null) { status.SetOperation(TestOperation.Complete); status.SetEntry(null); resultHandler(status, null); } return (status.ErrorCount == 0); }
/// <summary> /// Read data descriptor at the end of compressed data. /// </summary> /// <param name="zip64">if set to <c>true</c> [zip64].</param> /// <param name="data">The data to fill in.</param> /// <returns>Returns the number of bytes read in the descriptor.</returns> public void ReadDataDescriptor(bool zip64, DescriptorData data) { int intValue = ReadLEInt(); // In theory this may not be a descriptor according to PKZIP appnote. // In practise its always there. if (intValue != ZipConstants.DataDescriptorSignature) { throw new ZipException("Data descriptor signature not found"); } data.Crc = ReadLEInt(); if (zip64) { data.CompressedSize = ReadLELong(); data.Size = ReadLELong(); } else { data.CompressedSize = ReadLEInt(); data.Size = ReadLEInt(); } }