Exemplo n.º 1
0
        //bool _isRoot;

        protected internal ZipHelperEntry(ZipHelper owner, string path)
        {
            _owner = owner;
            _path = path;

            if (path == "/" || path == "")
            {
                _zipEntry = null;
                //_isRoot = true;
                _name = "<root>";
            }
            else
            {
                _zipEntry = _owner.GetZipEntry(_path);
                _name = _owner.ExtractName(_path);
            }
        }
Exemplo n.º 2
0
		/// <summary>
		/// Checks, if the local header of the entry at index i matches the
		/// central directory, and returns the offset to the data.
		/// </summary>
		/// <returns>
		/// The start offset of the (compressed) data.
		/// </returns>
		/// <exception cref="System.IO.EndOfStreamException">
		/// The stream ends prematurely
		/// </exception>
		/// <exception cref="Fireball.IO.Compression.Zip.ZipException">
		/// The local header signature is invalid, the entry and central header file name lengths are different
		/// or the local and entry compression methods dont match
		/// </exception>
		long CheckLocalHeader(ZipEntry entry)
		{
			return TestLocalHeader(entry, false, true);
		}
Exemplo n.º 3
0
		/// <summary>
		/// Test the local header against that provided from the central directory
		/// </summary>
		/// <param name="entry">
		/// The entry to test against
		/// </param>
		/// <param name="fullTest">
		/// If true be extremely picky about the testing, otherwise be relaxed
		/// </param>
		/// <param name="extractTest">
		/// Apply extra testing to see if the entry can be extracted by the library
		/// </param>
		/// <returns>The offset of the entries data in the file</returns>
		long TestLocalHeader(ZipEntry entry, bool fullTest, bool extractTest)
		{
			lock(baseStream) 
			{
				baseStream.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
				if (ReadLeInt() != ZipConstants.LOCSIG) {
					throw new ZipException("Wrong local header signature");
				}
				
				short shortValue = (short)ReadLeShort();	 // version required to extract
				if (extractTest == true && shortValue > ZipConstants.VERSION_MADE_BY) {
					throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", shortValue));
				}

				short localFlags = (short)ReadLeShort();				  // general purpose bit flags.
				if (extractTest == true) {
					if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0) {
						throw new ZipException("The library doesnt support the zip version required to extract this entry");
					}
				}
					
				if (localFlags != entry.Flags) {
				   throw new ZipException("Central header/local header flags mismatch");
				}

				if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) {
				   throw new ZipException("Central header/local header compression method mismatch");
				}
	
				shortValue = (short)ReadLeShort();  // file time
				shortValue = (short)ReadLeShort();  // file date
	
				int intValue = ReadLeInt();         // Crc
	
				if (fullTest) {
					if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
						if (intValue != (int)entry.Crc) 
							throw new ZipException("Central header/local header crc mismatch");
					}
				}
	
				intValue = ReadLeInt();	   // compressed Size
				intValue = ReadLeInt();	   // uncompressed size
	
				// 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
				int storedNameLength = ReadLeShort();
				if (entry.Name.Length > storedNameLength) {
					throw new ZipException("file name length mismatch");
				}
					
				int extraLen = storedNameLength + ReadLeShort();
				return offsetOfFirstEntry + entry.Offset + ZipConstants.LOCHDR + extraLen;
			}
		}
Exemplo n.º 4
0
		/// <summary>
		/// Search for and read the central directory of a zip file filling the entries
		/// array.  This is called exactly once by the constructors.
		/// </summary>
		/// <exception cref="System.IO.IOException">
		/// An i/o error occurs.
		/// </exception>
		/// <exception cref="Fireball.IO.Compression.Zip.ZipException">
		/// The central directory is malformed or cannot be found
		/// </exception>
		void ReadEntries()
		{
			// Search for the End Of Central Directory.  When a zip comment is
			// present the directory may start earlier.
			// 
			// TODO: The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
			// This should be compatible with both SFX and ZIP files but has only been tested for Zip files
			// Need to confirm this is valid in all cases.
			// Could also speed this up by reading memory in larger blocks.			

			if (baseStream.CanSeek == false) {
				throw new ZipException("ZipFile stream must be seekable");
			}
			
			long locatedCentralDirOffset = LocateBlockWithSignature(ZipConstants.ENDSIG, baseStream.Length, ZipConstants.ENDHDR, 0xffff);
			if (locatedCentralDirOffset < 0) {
				throw new ZipException("Cannot find central directory");
			}

			int thisDiskNumber            = ReadLeShort();
			int startCentralDirDisk       = ReadLeShort();
			int entriesForThisDisk        = ReadLeShort();
			int entriesForWholeCentralDir = ReadLeShort();
			int centralDirSize            = ReadLeInt();
			int offsetOfCentralDir        = ReadLeInt();
			int commentSize               = ReadLeShort();
			
			byte[] zipComment = new byte[commentSize]; 
			baseStream.Read(zipComment, 0, zipComment.Length); 
			comment = ZipConstants.ConvertToString(zipComment); 
			
/* Its seems possible that this is too strict, more digging required.
			if (thisDiskNumber != 0 || startCentralDirDisk != 0 || entriesForThisDisk != entriesForWholeCentralDir) {
				throw new ZipException("Spanned archives are not currently handled");
			}
*/

			entries = new ZipEntry[entriesForWholeCentralDir];
			
			// SFX support, find the offset of the first entry vis the start of the stream
			// This applies to Zip files that are appended to the end of the SFX stub.
			// Zip files created by some archivers have the offsets altered to reflect the true offsets
			// and so dont require any adjustment here...
			if (offsetOfCentralDir < locatedCentralDirOffset - (4 + centralDirSize)) {
				offsetOfFirstEntry = locatedCentralDirOffset - (4 + centralDirSize + offsetOfCentralDir);
				if (offsetOfFirstEntry <= 0) {
					throw new ZipException("Invalid SFX file");
				}
			}

			baseStream.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
			
			for (int i = 0; i < entriesForThisDisk; i++) {
				if (ReadLeInt() != ZipConstants.CENSIG) {
					throw new ZipException("Wrong Central Directory signature");
				}
				
				int versionMadeBy      = ReadLeShort();
				int versionToExtract   = ReadLeShort();
				int bitFlags           = ReadLeShort();
				int method             = ReadLeShort();
				int dostime            = ReadLeInt();
				int crc                = ReadLeInt();
				int csize              = ReadLeInt();
				int size               = ReadLeInt();
				int nameLen            = ReadLeShort();
				int extraLen           = ReadLeShort();
				int commentLen         = ReadLeShort();
				
				int diskStartNo        = ReadLeShort();  // Not currently used
				int internalAttributes = ReadLeShort();  // Not currently used

				int externalAttributes = ReadLeInt();
				int offset             = ReadLeInt();
				
				byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
				
				baseStream.Read(buffer, 0, nameLen);
				string name = ZipConstants.ConvertToString(buffer, nameLen);
				
				ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy);
				entry.CompressionMethod = (CompressionMethod)method;
				entry.Crc = crc & 0xffffffffL;
				entry.Size = size & 0xffffffffL;
				entry.CompressedSize = csize & 0xffffffffL;
				entry.Flags = bitFlags;
				entry.DosTime = (uint)dostime;
				
				if (extraLen > 0) {
					byte[] extra = new byte[extraLen];
					baseStream.Read(extra, 0, extraLen);
					entry.ExtraData = extra;
				}
				
				if (commentLen > 0) {
					baseStream.Read(buffer, 0, commentLen);
					entry.Comment = ZipConstants.ConvertToString(buffer, commentLen);
				}
				
				entry.ZipFileIndex           = i;
				entry.Offset                 = offset;
				entry.ExternalFileAttributes = externalAttributes;
				
				entries[i] = entry;
			}
		}
Exemplo n.º 5
0
		/// <summary>
		/// Closes the zip input stream
		/// </summary>
		public override void Close()
		{
			base.Close();
			crc = null;
			entry = null;
		}
Exemplo n.º 6
0
		void ProcessDirectory(object sender, DirectoryEventArgs e)
		{
			if ( !e.HasMatchingFiles && createEmptyDirectories ) {
				if ( events != null ) {
					events.OnProcessDirectory(e.Name, e.HasMatchingFiles);
				}
				
				if (e.Name != sourceDirectory) {
					string cleanedName = nameTransform.TransformDirectory(e.Name);
					ZipEntry entry = new ZipEntry(cleanedName);
					outputStream.PutNextEntry(entry);
				}
			}
		}
Exemplo n.º 7
0
		/// <summary>
		/// Creates an input stream reading the given zip entry as
		/// uncompressed data.  Normally zip entry should be an entry
		/// returned by GetEntry().
		/// </summary>
		/// <returns>
		/// the input stream.
		/// </returns>
		/// <exception cref="InvalidOperationException">
		/// The ZipFile has already been closed
		/// </exception>
		/// <exception cref="Fireball.IO.Compression.Zip.ZipException">
		/// The compression method for the entry is unknown
		/// </exception>
		/// <exception cref="IndexOutOfRangeException">
		/// The entry is not found in the ZipFile
		/// </exception>
		public Stream GetInputStream(ZipEntry entry)
		{
			if (entries == null) {
				throw new InvalidOperationException("ZipFile has closed");
			}
			
			int index = entry.ZipFileIndex;
			if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {
				index = FindEntry(entry.Name, true);
				if (index < 0) {
					throw new IndexOutOfRangeException();
				}
			}
			return GetInputStream(index);			
		}
Exemplo n.º 8
0
		Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
		{
			CryptoStream result = null;
			if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION 
			    || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
				PkzipClassicManaged classicManaged = new PkzipClassicManaged();

				OnKeysRequired(entry.Name);
				if (HaveKeys == false) {
					throw new ZipException("No password available for encrypted stream");
				}

				result = new CryptoStream(baseStream, classicManaged.CreateEncryptor(key, iv), CryptoStreamMode.Write);
				if (entry.Crc < 0 || (entry.Flags & 8) != 0) {
					WriteEncryptionHeader(result, entry.DosTime << 16);
				}
				else {
					WriteEncryptionHeader(result, entry.Crc);
				}
			}
			return result;
		}
Exemplo n.º 9
0
		/// <summary>
		/// Closes the current entry, updating header and footer information as required
		/// </summary>
		/// <exception cref="System.IO.IOException">
		/// An I/O error occurs.
		/// </exception>
		/// <exception cref="System.InvalidOperationException">
		/// No entry is active.
		/// </exception>
		public void CloseEntry()
		{
			if (curEntry == null) {
				throw new InvalidOperationException("No open entry");
			}
			
			// First finish the deflater, if appropriate
			if (curMethod == CompressionMethod.Deflated) {
				base.Finish();
			}
			
			long csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size;
			
			if (curEntry.Size < 0) {
				curEntry.Size = size;
			} else if (curEntry.Size != size) {
				throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
			}
			
			if (curEntry.CompressedSize < 0) {
				curEntry.CompressedSize = csize;
			} else if (curEntry.CompressedSize != csize) {
				throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
			}
			
			if (curEntry.Crc < 0) {
				curEntry.Crc = crc.Value;
			} else if (curEntry.Crc != crc.Value) {
				throw new ZipException("crc was " + crc.Value +	", but I expected " + curEntry.Crc);
			}
			
			offset += csize;

			if (offset > 0xffffffff) {
				throw new ZipException("Maximum Zip file size exceeded");
			}
				
			if (curEntry.IsCrypted == true) {
				curEntry.CompressedSize += ZipConstants.CRYPTO_HEADER_SIZE;
			}
				
			// Patch the header if possible
			if (patchEntryHeader == true) {
				long curPos = baseOutputStream.Position;
				baseOutputStream.Seek(headerPatchPos, SeekOrigin.Begin);
				WriteLeInt((int)curEntry.Crc);
				WriteLeInt((int)curEntry.CompressedSize);
				WriteLeInt((int)curEntry.Size);
				baseOutputStream.Seek(curPos, SeekOrigin.Begin);
				patchEntryHeader = false;
			}

			// Add data descriptor if flagged as required
			if ((curEntry.Flags & 8) != 0) {
				WriteLeInt(ZipConstants.EXTSIG);
				WriteLeInt((int)curEntry.Crc);
				WriteLeInt((int)curEntry.CompressedSize);
				WriteLeInt((int)curEntry.Size);
				offset += ZipConstants.EXTHDR;
			}
			
			entries.Add(curEntry);
			curEntry = null;
		}
Exemplo n.º 10
0
		/// <summary>
		/// Starts a new Zip entry. It automatically closes the previous
		/// entry if present.
		/// All entry elements bar name are optional, but must be correct if present.
		/// If the compression method is stored and the output is not patchable
		/// the compression for that entry is automatically changed to deflate level 0
		/// </summary>
		/// <param name="entry">
		/// the entry.
		/// </param>
		/// <exception cref="System.IO.IOException">
		/// if an I/O error occured.
		/// </exception>
		/// <exception cref="System.InvalidOperationException">
		/// if stream was finished
		/// </exception>
		/// <exception cref="ZipException">
		/// Too many entries in the Zip file<br/>
		/// Entry name is too long<br/>
		/// Finish has already been called<br/>
		/// </exception>
		public void PutNextEntry(ZipEntry entry)
		{
			if (entries == null) {
				throw new InvalidOperationException("ZipOutputStream was finished");
			}
			
			if (curEntry != null) {
				CloseEntry();
			}

			if (entries.Count >= 0xffff) {
				throw new ZipException("Too many entries for Zip file");
			}
			
			CompressionMethod method = entry.CompressionMethod;
			int compressionLevel = defaultCompressionLevel;
			
			entry.Flags = 0;
			patchEntryHeader = false;
			bool headerInfoAvailable = true;
			
			if (method == CompressionMethod.Stored) {
				if (entry.CompressedSize >= 0) {
					if (entry.Size < 0) {
						entry.Size = entry.CompressedSize;
					} else if (entry.Size != entry.CompressedSize) {
						throw new ZipException("Method STORED, but compressed size != size");
					}
				} else {
					if (entry.Size >= 0) {
						entry.CompressedSize = entry.Size;
					}
				}
					
				if (entry.Size < 0 || entry.Crc < 0) {
					if (CanPatchEntries == true) {
						headerInfoAvailable = false;
					}
					else {
                  // Cant patch entries so storing is not possible.
						method = CompressionMethod.Deflated;
						compressionLevel = 0;
					}
				}
			}
				
			if (method == CompressionMethod.Deflated) {
				if (entry.Size == 0) {
               // No need to compress - no data.
					entry.CompressedSize = entry.Size;
					entry.Crc = 0;
					method = CompressionMethod.Stored;
				} else if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) {
					headerInfoAvailable = false;
				}
			}
			
			if (headerInfoAvailable == false) {
				if (CanPatchEntries == false) {
					entry.Flags |= 8;
				} else {
					patchEntryHeader = true;
				}
			}
			
			if (Password != null) {
				entry.IsCrypted = true;
				if (entry.Crc < 0) {
               // Need to append data descriptor as crc is used for encryption and its not known.
					entry.Flags |= 8;
				}
			}
			entry.Offset = (int)offset;
			entry.CompressionMethod = (CompressionMethod)method;
			
			curMethod    = method;
			
			// Write the local file header
			WriteLeInt(ZipConstants.LOCSIG);
			
			WriteLeShort(entry.Version);
			WriteLeShort(entry.Flags);
			WriteLeShort((byte)method);
			WriteLeInt((int)entry.DosTime);
			if (headerInfoAvailable == true) {
				WriteLeInt((int)entry.Crc);
				WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CRYPTO_HEADER_SIZE : (int)entry.CompressedSize);
				WriteLeInt((int)entry.Size);
			} else {
				if (patchEntryHeader == true) {
					headerPatchPos = baseOutputStream.Position;
				}
				WriteLeInt(0);	// Crc
				WriteLeInt(0);	// Compressed size
				WriteLeInt(0);	// Uncompressed size
			}
			
			byte[] name = ZipConstants.ConvertToArray(entry.Name);
			
			if (name.Length > 0xFFFF) {
				throw new ZipException("Entry name too long.");
			}

			byte[] extra = entry.ExtraData;
			if (extra == null) {
				extra = new byte[0];
			}

			if (extra.Length > 0xFFFF) {
				throw new ZipException("Extra data too long.");
			}
			
			WriteLeShort(name.Length);
			WriteLeShort(extra.Length);
			baseOutputStream.Write(name, 0, name.Length);
			baseOutputStream.Write(extra, 0, extra.Length);
			
			offset += ZipConstants.LOCHDR + name.Length + extra.Length;
			
			// Activate the entry.
			curEntry = entry;
			crc.Reset();
			if (method == CompressionMethod.Deflated) {
				def.Reset();
				def.SetLevel(compressionLevel);
			}
			size = 0;
			
			if (entry.IsCrypted == true) {
				if (entry.Crc < 0) {			// so testing Zip will says its ok
					WriteEncryptionHeader(entry.DosTime << 16);
				} else {
					WriteEncryptionHeader(entry.Crc);
				}
			}
		}
Exemplo n.º 11
0
		/// <summary>
		/// Creates a copy of the given zip entry.
		/// </summary>
		/// <param name="e">
		/// The entry to copy.
		/// </param>
		public ZipEntry(ZipEntry e)
		{
			known                  = e.known;
			name                   = e.name;
			size                   = e.size;
			compressedSize         = e.compressedSize;
			crc                    = e.crc;
			dosTime                = e.dosTime;
			method                 = e.method;
			ExtraData              = e.ExtraData;     // Note use of property ensuring data is unique
			comment                = e.comment;
			versionToExtract       = e.versionToExtract;
			versionMadeBy          = e.versionMadeBy;
			externalFileAttributes = e.externalFileAttributes;
			flags                  = e.flags;

			zipFileIndex           = -1;
			offset                 = 0;
		}
Exemplo n.º 12
0
		void ExtractEntry(ZipEntry entry)
		{
			bool doExtraction = NameIsValid(entry.Name);
			
			string dirName = null;
			string targetName = null;
			
			if ( doExtraction ) {
				string entryFileName;
				if (Path.IsPathRooted(entry.Name)) {
					string workName = Path.GetPathRoot(entry.Name);
					workName = entry.Name.Substring(workName.Length);
					entryFileName = Path.Combine(Path.GetDirectoryName(workName), Path.GetFileName(entry.Name));
				} else {
					entryFileName = entry.Name;
				}
				
				targetName = Path.Combine(targetDirectory, entryFileName);
				dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
	
				doExtraction = doExtraction && (entryFileName.Length > 0);
			}
			
			if ( doExtraction && !Directory.Exists(dirName) )
			{
				if ( !entry.IsDirectory || this.CreateEmptyDirectories ) {
					try {
						Directory.CreateDirectory(dirName);
					}
					catch {
						doExtraction = false;
					}
				}
			}
			
			if ( doExtraction && entry.IsFile ) {
				ExtractFileEntry(entry, targetName);
			}
		}
Exemplo n.º 13
0
		void ExtractFileEntry(ZipEntry entry, string targetName)
		{
			bool proceed = true;
			if ((overwrite == Overwrite.Prompt) && (confirmDelegate != null)) {
				if (File.Exists(targetName) == true) {
					proceed = confirmDelegate(targetName);
				}
			}

			if ( proceed ) {
				
				if ( events != null ) {
					events.OnProcessFile(entry.Name);
				}
			
				FileStream streamWriter = File.Create(targetName);
			
				try {
					if ( buffer == null ) {
						buffer = new byte[4096];
					}
					
					int size;
		
					do {
						size = inputStream.Read(buffer, 0, buffer.Length);
						streamWriter.Write(buffer, 0, size);
					} while (size > 0);
				}
				finally {
					streamWriter.Close();
				}
	
				if (restoreDateTime) {
					File.SetLastWriteTime(targetName, entry.DateTime);
				}
			}
		}
Exemplo n.º 14
0
		void ProcessFile(object sender, ScanEventArgs e)
		{
			if ( events != null ) {
				events.OnProcessFile(e.Name);
			}
			string cleanedName = nameTransform.TransformFile(e.Name);
			ZipEntry entry = new ZipEntry(cleanedName);
			outputStream.PutNextEntry(entry);
			AddFileContents(e.Name);
		}
Exemplo n.º 15
0
		void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
		{
			byte[] cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
			ReadFully(classicCryptoStream, cryptbuffer);

			if ((entry.Flags & (int)GeneralBitFlags.Descriptor) == 0) {
				if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(entry.Crc >> 24)) {
					throw new ZipException("Invalid password");
				}
			}
			else {
				if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((entry.DosTime >> 8) & 0xff)) {
					throw new ZipException("Invalid password");
				}
			}
		}
Exemplo n.º 16
0
		Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
		{
			CryptoStream result = null;

			if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION 
				|| (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
				PkzipClassicManaged classicManaged = new PkzipClassicManaged();

				OnKeysRequired(entry.Name);
				if (HaveKeys == false) {
					throw new ZipException("No password available for encrypted stream");
				}

				result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, iv), CryptoStreamMode.Read);
				CheckClassicPassword(result, entry);
			}
			else {
				throw new ZipException("Decryption method not supported");
			}

			return result;
		}
Exemplo n.º 17
0
		/// <summary>
		/// Advances to the next entry in the archive
		/// </summary>
		/// <returns>
		/// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
		/// </returns>
		/// <remarks>
		/// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
		/// </remarks>
		/// <exception cref="InvalidOperationException">
		/// Input stream is closed
		/// </exception>
		/// <exception cref="ZipException">
		/// Password is not set, password is invalid, compression method is invalid, 
		/// version required to extract is not supported
		/// </exception>
		public ZipEntry GetNextEntry()
		{
			if (crc == null) {
				throw new InvalidOperationException("Closed.");
			}
			
			if (entry != null) {
				CloseEntry();
			}

			int header = inputBuffer.ReadLeInt();

			if (header == ZipConstants.CENSIG || 
			    header == ZipConstants.ENDSIG || 
			    header == ZipConstants.CENDIGITALSIG || 
			    header == ZipConstants.CENSIG64) {
			    // No more individual entries exist
				Close();
				return null;
			}

			// -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
			// SPANNINGSIG is same as descriptor signature and is untested as yet.
			if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG) {
				header = inputBuffer.ReadLeInt();
			}
			
			if (header != ZipConstants.LOCSIG) {
				throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
			}
			
			short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();
			
			flags          = inputBuffer.ReadLeShort();
			method         = inputBuffer.ReadLeShort();
			uint dostime   = (uint)inputBuffer.ReadLeInt();
			int crc2       = inputBuffer.ReadLeInt();
			csize          = inputBuffer.ReadLeInt();
			size           = inputBuffer.ReadLeInt();
			int nameLen    = inputBuffer.ReadLeShort();
			int extraLen   = inputBuffer.ReadLeShort();
			
			bool isCrypted = (flags & 1) == 1;
			
			byte[] buffer = new byte[nameLen];
			inputBuffer.ReadRawBuffer(buffer);
			
			string name = ZipConstants.ConvertToString(buffer);
			
			entry = new ZipEntry(name, versionRequiredToExtract);
			entry.Flags = flags;
			
			if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CRYPTO_HEADER_SIZE != size))) {
				throw new ZipException("Stored, but compressed != uncompressed");
			}
			
			if (method != (int)CompressionMethod.Stored && method != (int)CompressionMethod.Deflated) {
				throw new ZipException("Unknown compression method " + method);
			}
			
			entry.CompressionMethod = (CompressionMethod)method;
			
			if ((flags & 8) == 0) {
				entry.Crc  = crc2 & 0xFFFFFFFFL;
				entry.Size = size & 0xFFFFFFFFL;
				entry.CompressedSize = csize & 0xFFFFFFFFL;
			} else {
				
				// This allows for GNU, WinZip and possibly other archives, the PKZIP spec says these are zero
				// under these circumstances.
				if (crc2 != 0) {
					entry.Crc = crc2 & 0xFFFFFFFFL;
				}
				
				if (size != 0) {
					entry.Size = size & 0xFFFFFFFFL;
				}
				if (csize != 0) {
					entry.CompressedSize = csize & 0xFFFFFFFFL;
				}
			}
			
			entry.DosTime = dostime;
			
			if (extraLen > 0) {
				byte[] extra = new byte[extraLen];
				inputBuffer.ReadRawBuffer(extra);
				entry.ExtraData = extra;
			}

			internalReader = new ReaderDelegate(InitialRead);
			return entry;
		}
Exemplo n.º 18
0
		/// <summary>
		/// Gets an output stream for the specified <see cref="ZipEntry"/>
		/// </summary>
		/// <param name="entry">The entry to get an outputstream for.</param>
		/// <param name="fileName"></param>
		/// <returns>The output stream obtained for the entry.</returns>
		Stream GetOutputStream(ZipEntry entry, string fileName)
		{
			baseStream.Seek(0, SeekOrigin.End);
			Stream result = File.OpenWrite(fileName);
		
			if (entry.IsCrypted == true)
			{
				result = CreateAndInitEncryptionStream(result, entry);
			}
		
			switch (entry.CompressionMethod) 
			{
				case CompressionMethod.Stored:
					break;
		
				case CompressionMethod.Deflated:
					result = new DeflaterOutputStream(result);
					break;
					
				default:
					throw new ZipException("Unknown compression method " + entry.CompressionMethod);
			}
			return result;
		}
Exemplo n.º 19
0
		/// <summary>
		/// Closes the current zip entry and moves to the next one.
		/// </summary>
		/// <exception cref="InvalidOperationException">
		/// The stream is closed
		/// </exception>
		/// <exception cref="ZipException">
		/// The Zip stream ends early
		/// </exception>
		public void CloseEntry()
		{
			if (crc == null) {
				throw new InvalidOperationException("Closed.");
			}
			
			if (entry == null) {
				return;
			}
			
			if (method == (int)CompressionMethod.Deflated) {
				if ((flags & 8) != 0) {
					// We don't know how much we must skip, read until end.
					byte[] tmp = new byte[2048];
					while (Read(tmp, 0, tmp.Length) > 0)
						;
					// read will close this entry
					return;
				}
				csize -= inf.TotalIn;
				inputBuffer.Available -= inf.RemainingInput;	
			}

			if (inputBuffer.Available > csize && csize >= 0) {
				inputBuffer.Available = (int)((long)inputBuffer.Available - csize);
			} else {
				csize -= inputBuffer.Available;
				inputBuffer.Available = 0;
				while (csize != 0) {
					int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);
					
					if (skipped <= 0) {
						throw new ZipException("Zip archive ends early.");
					}
					
					csize -= skipped;
				}
			}
			
			size = 0;
			crc.Reset();
			if (method == (int)CompressionMethod.Deflated) {
				inf.Reset();
			}
			entry = null;
		}
Exemplo n.º 20
0
			public ZipEntryEnumeration(ZipEntry[] arr)
			{
				array = arr;
			}
Exemplo n.º 21
0
		/// <summary>
		/// Reads a block of bytes from the current zip entry.
		/// </summary>
		/// <returns>
		/// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on end of stream.
		/// </returns>
		/// <exception name="IOException">
		/// An i/o error occured.
		/// </exception>
		/// <exception cref="ZipException">
		/// The deflated stream is corrupted.
		/// </exception>
		/// <exception cref="InvalidOperationException">
		/// The stream is not open.
		/// </exception>
		public int BodyRead(byte[] b, int off, int len)
		{
			if (crc == null) {
				throw new InvalidOperationException("Closed.");
			}
			
			if (entry == null || len <= 0 ) {
				return 0;
			}
			
			bool finished = false;
			
			switch (method) {
				case (int)CompressionMethod.Deflated:
					len = base.Read(b, off, len);
					if (len <= 0) {
						if (!inf.IsFinished) {
							throw new ZipException("Inflater not finished!?");
						}
						inputBuffer.Available = inf.RemainingInput;
						
						if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) {
							throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
						}
						inf.Reset();
						finished = true;
					}
					break;
				
				case (int)CompressionMethod.Stored:
					if (len > csize && csize >= 0) {
						len = (int)csize;
					}
					len = inputBuffer.ReadClearTextBuffer(b, off, len);
					if (len > 0) {
						csize -= len;
						size -= len;
					}
					
					if (csize == 0) {
						finished = true;
					} else {
						if (len < 0) {
							throw new ZipException("EOF in stored block");
						}
					}
					break;
			}
				
			if (len > 0) {
				crc.Update(b, off, len);
			}
			
			if (finished) {
				StopDecrypting();
				
				if ((flags & 8) != 0) {
					ReadDataDescriptor();
				}
				
				if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) {
					throw new ZipException("CRC mismatch");
				}
				crc.Reset();
				entry = null;
			}
			return len;
		}