void CopyEntryDataDirect(ZipUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sourcePosition) { long bytesToCopy = update.Entry.CompressedSize; // NOTE: Compressed size is updated elsewhere. Crc32 crc = new Crc32(); byte[] buffer = GetBuffer(); long targetBytes = bytesToCopy; long totalBytesRead = 0; int bytesRead; do { int readSize = buffer.Length; if ( bytesToCopy < readSize ) { readSize = (int)bytesToCopy; } stream.Position = sourcePosition; bytesRead = stream.Read(buffer, 0, readSize); if ( bytesRead > 0 ) { if ( updateCrc ) { crc.Update(buffer, 0, bytesRead); } stream.Position = destinationPosition; stream.Write(buffer, 0, bytesRead); destinationPosition += bytesRead; sourcePosition += bytesRead; bytesToCopy -= bytesRead; totalBytesRead += bytesRead; } } while ( (bytesRead > 0) && (bytesToCopy > 0) ); if ( totalBytesRead != targetBytes ) { throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead)); } if ( updateCrc ) { update.OutEntry.Crc = crc.Value; } }
/// <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> /// <exception cref="ObjectDisposedException">The object has already been closed.</exception> public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandler resultHandler) { if (isDisposed_) { throw new ObjectDisposedException("ZipFile"); } 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); } Crc32 crc = new Crc32(); using (Stream entryStream = this.GetInputStream(this[entryIndex])) { 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); }
void CopyBytes(ZipUpdate update, Stream destination, Stream source, long bytesToCopy, bool updateCrc) { if ( destination == source ) { throw new InvalidOperationException("Destination and source are the same"); } // NOTE: Compressed size is updated elsewhere. Crc32 crc = new Crc32(); byte[] buffer = GetBuffer(); long targetBytes = bytesToCopy; long totalBytesRead = 0; int bytesRead; do { int readSize = buffer.Length; if ( bytesToCopy < readSize ) { readSize = (int)bytesToCopy; } bytesRead = source.Read(buffer, 0, readSize); if ( bytesRead > 0 ) { if ( updateCrc ) { crc.Update(buffer, 0, bytesRead); } destination.Write(buffer, 0, bytesRead); bytesToCopy -= bytesRead; totalBytesRead += bytesRead; } } while ( (bytesRead > 0) && (bytesToCopy > 0) ); if ( totalBytesRead != targetBytes ) { throw new ZipException(string.Format("Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead)); } if ( updateCrc ) { update.OutEntry.Crc = crc.Value; } }