예제 #1
0
		void ReadHeader() 
		{
			// 1. Check the two magic bytes
			Crc32Checksum headCRC = new Crc32Checksum();
			int magic = baseInputStream.ReadByte();

			if (magic < 0) {
				throw new EndOfStreamException("EOS reading GZIP header");
			}

			headCRC.Update(magic);
			if (magic != (GZipConstants.GzipMagic >> 8)) {
				throw new GZipException("Error GZIP header, first magic byte doesn't match");
			}
				
			magic = baseInputStream.ReadByte();

			if (magic < 0) {
				throw new EndOfStreamException("EOS reading GZIP header");
			}
			
			if (magic != (GZipConstants.GzipMagic & 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 = baseInputStream.ReadByte();

			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 = baseInputStream.ReadByte();
			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 = baseInputStream.ReadByte();
				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 = baseInputStream.ReadByte();
					if (readByte < 0) {
						throw new EndOfStreamException("EOS reading GZIP header");
					}
					headCRC.Update(readByte);
				}

				if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0) {
					throw new EndOfStreamException("EOS reading GZIP header");
				}
				
				int len1, len2;
				len1 = baseInputStream.ReadByte();
				len2 = baseInputStream.ReadByte();
				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 = baseInputStream.ReadByte();
					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 = baseInputStream.ReadByte()) > 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 = baseInputStream.ReadByte()) > 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 = baseInputStream.ReadByte();
				if (crcval < 0) {
					throw new EndOfStreamException("EOS reading GZIP header");
				}
				
				tempByte = baseInputStream.ReadByte();
				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;
		}
예제 #2
0
		/// <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);
						}

                        Crc32Checksum crc = new Crc32Checksum();

                        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);
		}
예제 #3
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.
			Crc32Checksum crc = new Crc32Checksum();
			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;
			}
		}
예제 #4
0
		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.
			Crc32Checksum crc = new Crc32Checksum();
			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;
			}
		}
예제 #5
0
		/// <summary>
		/// Closes the zip input stream
		/// </summary>
		public override void Close()
		{
			internalReader = ReadingNotAvailable;
			crc = null;
			entry = null;

			base.Close();
		}