Beispiel #1
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.ArgumentNullException">
		/// if entry passed is null.
		/// </exception>
		/// <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 ( entry == null ) {
				throw new ArgumentNullException("entry");
			}

			if (entries == null) {
				throw new InvalidOperationException("ZipOutputStream was finished");
			}
			
			if (curEntry != null) {
				CloseEntry();
			}

			if (entries.Count == int.MaxValue) {
				throw new ZipException("Too many entries for Zip file");
			}
			
			CompressionMethod method = entry.CompressionMethod;
			int compressionLevel = defaultCompressionLevel;
			
			// Clear flags that the library manages internally
			entry.Flags &= (int)GeneralBitFlags.UnicodeText;
			patchEntryHeader = false;
			bool headerInfoAvailable = true;
			
			if (method == CompressionMethod.Stored) {
				// Cant store values in a data descriptor as you cant extract stored files
				// if the length isnt known.
				entry.Flags &= ~8;
				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 {
						// Can't 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) {
					// Only way to record size and compressed size is to append a data descriptor
					// after compressed data.
					entry.Flags |= 8;
				} else {
					patchEntryHeader = true;
				}
			}
			
			if (Password != null) {
				entry.IsCrypted = true;
				if (entry.Crc < 0) {
					// Need to append a data descriptor as the crc isnt available for use
					// with encryption, the date is used instead.  Setting the flag
					// indicates this to the decompressor.
					entry.Flags |= 8;
				}
			}

			entry.Offset = offset;
			entry.CompressionMethod = (CompressionMethod)method;
			
			curMethod = method;
			sizePatchPos = -1;
			
			if ( (useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)) ) {
				entry.ForceZip64();
			}

			// Write the local file header
			WriteLeInt(ZipConstants.LocalHeaderSignature);
			
			WriteLeShort(entry.Version);
			WriteLeShort(entry.Flags);
			WriteLeShort((byte)method);
			WriteLeInt((int)entry.DosTime);

			// TODO: Refactor header writing.  Its done in several places.
			if (headerInfoAvailable == true) {
				WriteLeInt((int)entry.Crc);
				if ( entry.LocalHeaderRequiresZip64 ) {
					WriteLeInt(-1);
					WriteLeInt(-1);
				}
				else {
					WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
					WriteLeInt((int)entry.Size);
				}
			} else {
				if (patchEntryHeader == true) {
					crcPatchPos = baseOutputStream_.Position;
				}
				WriteLeInt(0);	// Crc
				
				if ( patchEntryHeader ) {
					sizePatchPos = baseOutputStream_.Position;
				}

				// For local header both sizes appear in Zip64 Extended Information
				if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
					WriteLeInt(-1);
					WriteLeInt(-1);
				}
				else {
					WriteLeInt(0);	// Compressed size
					WriteLeInt(0);	// Uncompressed size
				}
			}

			byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
			
			if (name.Length > 0xFFFF) {
				throw new ZipException("Entry name too long.");
			}

			ZipExtraData ed = new ZipExtraData(entry.ExtraData);

			if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
				ed.StartNewEntry();
				if (headerInfoAvailable) {
					ed.AddLeLong(entry.Size);
					ed.AddLeLong(entry.CompressedSize);
				}
				else {
					ed.AddLeLong(-1);
					ed.AddLeLong(-1);
				}
				ed.AddNewEntry(1);

				if ( !ed.Find(1) ) {
					throw new ZipException("Internal error cant find extra data");
				}
				
				if ( patchEntryHeader ) {
					sizePatchPos = ed.CurrentReadIndex;
				}
			}
			else {
				ed.Delete(1);
			}
			
			byte[] extra = ed.GetEntryData();

			WriteLeShort(name.Length);
			WriteLeShort(extra.Length);

			if ( name.Length > 0 ) {
				baseOutputStream_.Write(name, 0, name.Length);
			}
			
			if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
				sizePatchPos += baseOutputStream_.Position;
			}

			if ( extra.Length > 0 ) {
				baseOutputStream_.Write(extra, 0, extra.Length);
			}
			
			offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;
			
			// Activate the entry.
			curEntry = entry;
			crc.Reset();
			if (method == CompressionMethod.Deflated) {
				deflater_.Reset();
				deflater_.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);
				}
			}
		}
Beispiel #2
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.ArgumentNullException">
        /// if entry passed is null.
        /// </exception>
        /// <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 (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            if (entries == null)
            {
                throw new InvalidOperationException("ZipOutputStream was finished");
            }

            if (curEntry != null)
            {
                CloseEntry();
            }

            if (entries.Count == int.MaxValue)
            {
                throw new ZipException("Too many entries for Zip file");
            }

            CompressionMethod method = entry.CompressionMethod;
            int compressionLevel     = defaultCompressionLevel;

            // Clear flags that the library manages internally
            entry.Flags     &= (int)GeneralBitFlags.UnicodeText;
            patchEntryHeader = false;
            bool headerInfoAvailable = true;

            if (method == CompressionMethod.Stored)
            {
                // Cant store values in a data descriptor as you cant extract stored files
                // if the length isnt known.
                entry.Flags &= ~8;
                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
                    {
                        // Can't 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)
                {
                    // Only way to record size and compressed size is to append a data descriptor
                    // after compressed data.
                    entry.Flags |= 8;
                }
                else
                {
                    patchEntryHeader = true;
                }
            }

            if (Password != null)
            {
                entry.IsCrypted = true;
                if (entry.Crc < 0)
                {
                    // Need to append a data descriptor as the crc isnt available for use
                    // with encryption, the date is used instead.  Setting the flag
                    // indicates this to the decompressor.
                    entry.Flags |= 8;
                }
            }

            entry.Offset            = offset;
            entry.CompressionMethod = (CompressionMethod)method;

            curMethod = method;

            if ((useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)))
            {
                entry.ForceZip64();
            }

            // Write the local file header
            WriteLeInt(ZipConstants.LocalHeaderSignature);

            WriteLeShort(entry.Version);
            WriteLeShort(entry.Flags);
            WriteLeShort((byte)method);
            WriteLeInt((int)entry.DosTime);

            // TODO: Refactor header writing.  Its done in several places.
            if (headerInfoAvailable == true)
            {
                WriteLeInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
                    WriteLeInt((int)entry.Size);
                }
            }
            else
            {
                if (patchEntryHeader == true)
                {
                    crcPatchPos = baseOutputStream.Position;
                }
                WriteLeInt(0);                  // Crc

                if (patchEntryHeader)
                {
                    sizePatchPos = baseOutputStream.Position;
                }

                // For local header both sizes appear in Zip64 Extended Information
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(0);                      // Compressed size
                    WriteLeInt(0);                      // Uncompressed size
                }
            }

            byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new ZipException("Entry name too long.");
            }

            ZipExtraData ed = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64)
            {
                ed.StartNewEntry();
                ed.AddLeLong(-1);
                ed.AddLeLong(-1);
                ed.AddNewEntry(1);

                if (!ed.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }

                if (patchEntryHeader)
                {
                    sizePatchPos = ed.CurrentReadIndex;
                }
            }
            else
            {
                ed.Delete(1);
            }

            byte[] extra = ed.GetEntryData();

            WriteLeShort(name.Length);
            WriteLeShort(extra.Length);

            if (name.Length > 0)
            {
                baseOutputStream.Write(name, 0, name.Length);
            }

            if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
            {
                sizePatchPos += baseOutputStream.Position;
            }

            if (extra.Length > 0)
            {
                baseOutputStream.Write(extra, 0, extra.Length);
            }

            offset += ZipConstants.LocalHeaderBaseSize + 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);
                }
            }
        }
Beispiel #3
0
 public void PutNextEntry(ZipEntry entry)
 {
     bool hasCrc;
     if (entry == null)
     {
         throw new ArgumentNullException(nameof(entry));
     }
     if (_entries == null)
     {
         throw new InvalidOperationException("ZipOutputStream was finished");
     }
     if (_curEntry != null)
     {
         CloseEntry();
     }
     if (_entries.Count == 0x7fffffff)
     {
         throw new ZipException("Too many entries for Zip file");
     }
     CompressionMethod compressionMethod = entry.CompressionMethod;
     int compressionLevel = _defaultCompressionLevel;
     entry.Flags &= 0x800;
     _patchEntryHeader = false;
     if (entry.Size == 0L)
     {
         entry.CompressedSize = entry.Size;
         entry.Crc = 0L;
         compressionMethod = CompressionMethod.Stored;
         hasCrc = true;
     }
     else
     {
         hasCrc = (entry.Size >= 0L) && entry.HasCrc;
         if (compressionMethod == CompressionMethod.Stored)
         {
             if (!hasCrc)
             {
                 if (!CanPatchEntries)
                 {
                     compressionMethod = CompressionMethod.Deflated;
                     compressionLevel = 0;
                 }
             }
             else
             {
                 entry.CompressedSize = entry.Size;
                 hasCrc = entry.HasCrc;
             }
         }
     }
     if (!hasCrc)
     {
         if (!CanPatchEntries)
         {
             entry.Flags |= 8;
         }
         else
         {
             _patchEntryHeader = true;
         }
     }
     if (Password != null)
     {
         entry.IsCrypted = true;
         if (entry.Crc < 0L)
         {
             entry.Flags |= 8;
         }
     }
     entry.Offset = _offset;
     entry.CompressionMethod = compressionMethod;
     _curMethod = compressionMethod;
     _sizePatchPos = -1L;
     if ((_useZip64 == UseZip64.On) || ((entry.Size < 0L) && (_useZip64 == UseZip64.Dynamic)))
     {
         entry.ForceZip64();
     }
     WriteLeInt(ZipConstants.LocalHeaderSignature);
     WriteLeShort(entry.Version);
     WriteLeShort(entry.Flags);
     WriteLeShort((byte)entry.CompressionMethodForHeader);
     WriteLeInt((int)entry.DosTime);
     if (hasCrc)
     {
         WriteLeInt((int)entry.Crc);
         if (entry.LocalHeaderRequiresZip64)
         {
             WriteLeInt(-1);
             WriteLeInt(-1);
         }
         else
         {
             WriteLeInt(entry.IsCrypted ? (((int)entry.CompressedSize) + 12) : ((int)entry.CompressedSize));
             WriteLeInt((int)entry.Size);
         }
     }
     else
     {
         if (_patchEntryHeader)
         {
             _crcPatchPos = BaseOutputStream.Position;
         }
         WriteLeInt(0);
         if (_patchEntryHeader)
         {
             _sizePatchPos = BaseOutputStream.Position;
         }
         if (entry.LocalHeaderRequiresZip64 || _patchEntryHeader)
         {
             WriteLeInt(-1);
             WriteLeInt(-1);
         }
         else
         {
             WriteLeInt(0);
             WriteLeInt(0);
         }
     }
     byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
     if (buffer.Length > 0xffff)
     {
         throw new ZipException("Entry name too long.");
     }
     ZipExtraData extraData = new ZipExtraData(entry.ExtraData);
     if (entry.LocalHeaderRequiresZip64)
     {
         extraData.StartNewEntry();
         if (hasCrc)
         {
             extraData.AddLeLong(entry.Size);
             extraData.AddLeLong(entry.CompressedSize);
         }
         else
         {
             extraData.AddLeLong(-1L);
             extraData.AddLeLong(-1L);
         }
         extraData.AddNewEntry(1);
         if (!extraData.Find(1))
         {
             throw new ZipException("Internal error cant find extra data");
         }
         if (_patchEntryHeader)
         {
             _sizePatchPos = extraData.CurrentReadIndex;
         }
     }
     else
     {
         extraData.Delete(1);
     }
     if (entry.AesKeySize > 0)
     {
         AddExtraDataAes(entry, extraData);
     }
     byte[] entryData = extraData.GetEntryData();
     WriteLeShort(buffer.Length);
     WriteLeShort(entryData.Length);
     if (buffer.Length > 0)
     {
         BaseOutputStream.Write(buffer, 0, buffer.Length);
     }
     if (entry.LocalHeaderRequiresZip64 && _patchEntryHeader)
     {
         _sizePatchPos += BaseOutputStream.Position;
     }
     if (entryData.Length > 0)
     {
         BaseOutputStream.Write(entryData, 0, entryData.Length);
     }
     _offset += (30 + buffer.Length) + entryData.Length;
     if (entry.AesKeySize > 0)
     {
         _offset += entry.AesOverheadSize;
     }
     _curEntry = entry;
     _crc.Reset();
     if (compressionMethod == CompressionMethod.Deflated)
     {
         Deflater.Reset();
         Deflater.SetLevel(compressionLevel);
     }
     _size = 0L;
     if (entry.IsCrypted)
     {
         if (entry.AesKeySize > 0)
         {
             WriteAesHeader(entry);
         }
         else if (entry.Crc < 0L)
         {
             WriteEncryptionHeader(entry.DosTime << 0x10);
         }
         else
         {
             WriteEncryptionHeader(entry.Crc);
         }
     }
 }
Beispiel #4
0
        public void PutNextEntry(ZipEntry entry)
        {
            bool hasCrc;

            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }
            if (_entries == null)
            {
                throw new InvalidOperationException("ZipOutputStream was finished");
            }
            if (_curEntry != null)
            {
                CloseEntry();
            }
            if (_entries.Count == 0x7fffffff)
            {
                throw new ZipException("Too many entries for Zip file");
            }
            CompressionMethod compressionMethod = entry.CompressionMethod;
            int compressionLevel = _defaultCompressionLevel;

            entry.Flags      &= 0x800;
            _patchEntryHeader = false;
            if (entry.Size == 0L)
            {
                entry.CompressedSize = entry.Size;
                entry.Crc            = 0L;
                compressionMethod    = CompressionMethod.Stored;
                hasCrc = true;
            }
            else
            {
                hasCrc = (entry.Size >= 0L) && entry.HasCrc;
                if (compressionMethod == CompressionMethod.Stored)
                {
                    if (!hasCrc)
                    {
                        if (!CanPatchEntries)
                        {
                            compressionMethod = CompressionMethod.Deflated;
                            compressionLevel  = 0;
                        }
                    }
                    else
                    {
                        entry.CompressedSize = entry.Size;
                        hasCrc = entry.HasCrc;
                    }
                }
            }
            if (!hasCrc)
            {
                if (!CanPatchEntries)
                {
                    entry.Flags |= 8;
                }
                else
                {
                    _patchEntryHeader = true;
                }
            }
            if (Password != null)
            {
                entry.IsCrypted = true;
                if (entry.Crc < 0L)
                {
                    entry.Flags |= 8;
                }
            }
            entry.Offset            = _offset;
            entry.CompressionMethod = compressionMethod;
            _curMethod    = compressionMethod;
            _sizePatchPos = -1L;
            if ((_useZip64 == UseZip64.On) || ((entry.Size < 0L) && (_useZip64 == UseZip64.Dynamic)))
            {
                entry.ForceZip64();
            }
            WriteLeInt(ZipConstants.LocalHeaderSignature);
            WriteLeShort(entry.Version);
            WriteLeShort(entry.Flags);
            WriteLeShort((byte)entry.CompressionMethodForHeader);
            WriteLeInt((int)entry.DosTime);
            if (hasCrc)
            {
                WriteLeInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(entry.IsCrypted ? (((int)entry.CompressedSize) + 12) : ((int)entry.CompressedSize));
                    WriteLeInt((int)entry.Size);
                }
            }
            else
            {
                if (_patchEntryHeader)
                {
                    _crcPatchPos = BaseOutputStream.Position;
                }
                WriteLeInt(0);
                if (_patchEntryHeader)
                {
                    _sizePatchPos = BaseOutputStream.Position;
                }
                if (entry.LocalHeaderRequiresZip64 || _patchEntryHeader)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(0);
                    WriteLeInt(0);
                }
            }
            byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
            if (buffer.Length > 0xffff)
            {
                throw new ZipException("Entry name too long.");
            }
            ZipExtraData extraData = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64)
            {
                extraData.StartNewEntry();
                if (hasCrc)
                {
                    extraData.AddLeLong(entry.Size);
                    extraData.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    extraData.AddLeLong(-1L);
                    extraData.AddLeLong(-1L);
                }
                extraData.AddNewEntry(1);
                if (!extraData.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }
                if (_patchEntryHeader)
                {
                    _sizePatchPos = extraData.CurrentReadIndex;
                }
            }
            else
            {
                extraData.Delete(1);
            }
            if (entry.AesKeySize > 0)
            {
                AddExtraDataAes(entry, extraData);
            }
            byte[] entryData = extraData.GetEntryData();
            WriteLeShort(buffer.Length);
            WriteLeShort(entryData.Length);
            if (buffer.Length > 0)
            {
                BaseOutputStream.Write(buffer, 0, buffer.Length);
            }
            if (entry.LocalHeaderRequiresZip64 && _patchEntryHeader)
            {
                _sizePatchPos += BaseOutputStream.Position;
            }
            if (entryData.Length > 0)
            {
                BaseOutputStream.Write(entryData, 0, entryData.Length);
            }
            _offset += (30 + buffer.Length) + entryData.Length;
            if (entry.AesKeySize > 0)
            {
                _offset += entry.AesOverheadSize;
            }
            _curEntry = entry;
            _crc.Reset();
            if (compressionMethod == CompressionMethod.Deflated)
            {
                Deflater.Reset();
                Deflater.SetLevel(compressionLevel);
            }
            _size = 0L;
            if (entry.IsCrypted)
            {
                if (entry.AesKeySize > 0)
                {
                    WriteAesHeader(entry);
                }
                else if (entry.Crc < 0L)
                {
                    WriteEncryptionHeader(entry.DosTime << 0x10);
                }
                else
                {
                    WriteEncryptionHeader(entry.Crc);
                }
            }
        }