bool ReadHeader() { // Initialize CRC for this block crc = new Crc32(); // Make sure there is data in file. We can't rely on ReadLeByte() to fill the buffer, as this could be EOF, // which is fine, but ReadLeByte() throws an exception if it doesn't find data, so we do this part ourselves. if (inputBuffer.Available <= 0) { inputBuffer.Fill(); if (inputBuffer.Available <= 0) { // No header, EOF. return false; } } // 1. Check the two magic bytes Crc32 headCRC = new Crc32(); int magic = inputBuffer.ReadLeByte(); if (magic < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(magic); if (magic != (GZipConstants.GZIP_MAGIC >> 8)) { throw new GZipException("Error GZIP header, first magic byte doesn't match"); } //magic = baseInputStream.ReadByte(); magic = inputBuffer.ReadLeByte(); if (magic < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) { throw new GZipException("Error GZIP header, second magic byte doesn't match"); } headCRC.Update(magic); // 2. Check the compression type (must be 8) int compressionType = inputBuffer.ReadLeByte(); if ( compressionType < 0 ) { throw new EndOfStreamException("EOS reading GZIP header"); } if ( compressionType != 8 ) { throw new GZipException("Error GZIP header, data not in deflate format"); } headCRC.Update(compressionType); // 3. Check the flags int flags = inputBuffer.ReadLeByte(); if (flags < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(flags); /* This flag byte is divided into individual bits as follows: bit 0 FTEXT bit 1 FHCRC bit 2 FEXTRA bit 3 FNAME bit 4 FCOMMENT bit 5 reserved bit 6 reserved bit 7 reserved */ // 3.1 Check the reserved bits are zero if ((flags & 0xE0) != 0) { throw new GZipException("Reserved flag bits in GZIP header != 0"); } // 4.-6. Skip the modification time, extra flags, and OS type for (int i=0; i< 6; i++) { int readByte = inputBuffer.ReadLeByte(); if (readByte < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(readByte); } // 7. Read extra field if ((flags & GZipConstants.FEXTRA) != 0) { // Skip subfield id for (int i=0; i< 2; i++) { int readByte = inputBuffer.ReadLeByte(); if (readByte < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(readByte); } if (inputBuffer.ReadLeByte() < 0 || inputBuffer.ReadLeByte() < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } int len1, len2; len1 = inputBuffer.ReadLeByte(); len2 = inputBuffer.ReadLeByte(); if ((len1 < 0) || (len2 < 0)) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(len1); headCRC.Update(len2); int extraLen = (len1 << 8) | len2; for (int i = 0; i < extraLen;i++) { int readByte = inputBuffer.ReadLeByte(); if (readByte < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(readByte); } } // 8. Read file name if ((flags & GZipConstants.FNAME) != 0) { int readByte; while ( (readByte = inputBuffer.ReadLeByte()) > 0) { headCRC.Update(readByte); } if (readByte < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(readByte); } // 9. Read comment if ((flags & GZipConstants.FCOMMENT) != 0) { int readByte; while ( (readByte = inputBuffer.ReadLeByte()) > 0) { headCRC.Update(readByte); } if (readByte < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } headCRC.Update(readByte); } // 10. Read header CRC if ((flags & GZipConstants.FHCRC) != 0) { int tempByte; int crcval = inputBuffer.ReadLeByte(); if (crcval < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } tempByte = inputBuffer.ReadLeByte(); if (tempByte < 0) { throw new EndOfStreamException("EOS reading GZIP header"); } crcval = (crcval << 8) | tempByte; if (crcval != ((int) headCRC.Value & 0xffff)) { throw new GZipException("Header CRC value mismatch"); } } readGZIPHeader = true; return true; }
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; } }