Ejemplo n.º 1
0
		// NOTE this returns the offset of the first byte after the signature.
		long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
		{
			using ( ZipHelperStream les = new ZipHelperStream(baseStream_) ) {
				return les.LocateBlockWithSignature(signature, endLocation, minimumBlockSize, maximumVariableData);
			}
		}
Ejemplo n.º 2
0
		void RunUpdates()
		{
			long sizeEntries = 0;
			long endOfStream = 0;
			bool allOk = true;
			bool directUpdate = false;
			long destinationPosition = 0; // NOT SFX friendly

			ZipFile workFile;

			if ( IsNewArchive ) {
				workFile = this;
				workFile.baseStream_.Position = 0;
				directUpdate = true;
			}
			else if ( archiveStorage_.UpdateMode == FileUpdateMode.Direct ) {
				workFile = this;
				workFile.baseStream_.Position = 0;
				directUpdate = true;

				// Sort the updates with order offset within copies/modifies, then adds.
				// This ensures that copies will not overwrite any required data.
				updates_.Sort(new UpdateComparer());
			}
			else
			{
				workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
			}

			try {
				foreach ( ZipUpdate update in updates_ ) {
					switch ( update.Command ) {
						case UpdateCommand.Copy:
							if ( directUpdate ) {
								CopyEntryDirect(workFile, update, ref destinationPosition);
							}
							else {
								CopyEntry(workFile, update);
							}
							break;

						case UpdateCommand.Modify:
							// TODO: Direct modifying of an entry.
							ModifyEntry(workFile, update);
							break;

						case UpdateCommand.Add:
							if ( !IsNewArchive && directUpdate ) {
								workFile.baseStream_.Position = destinationPosition;
							}

							AddEntry(workFile, update);

							if ( directUpdate ) {
								destinationPosition = workFile.baseStream_.Position;
							}
							break;
					}
				}

				if ( !IsNewArchive && directUpdate ) {
					workFile.baseStream_.Position = destinationPosition;
				}

				long centralDirOffset = workFile.baseStream_.Position;

				foreach ( ZipUpdate update in updates_ ) {
					sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
				}

				byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
				using ( ZipHelperStream zhs = new ZipHelperStream(workFile.baseStream_) ) {
					zhs.WriteEndOfCentralDirectory(updates_.Count, sizeEntries, centralDirOffset, theComment);
				}

				endOfStream = workFile.baseStream_.Position;
 
				// And now patch entries...
				foreach ( ZipUpdate update in updates_ ) {
					// If the size of the entry is zero leave the crc as 0 as well.
					// The calculated crc will be all bits on...
					if ( (update.CrcPatchOffset > 0) && (update.OutEntry.CompressedSize > 0) ) {
						workFile.baseStream_.Position = update.CrcPatchOffset;
						workFile.WriteLEInt(( int )update.OutEntry.Crc);
					}

					if ( update.SizePatchOffset > 0 ) {
						workFile.baseStream_.Position = update.SizePatchOffset;
						if ( update.Entry.LocalHeaderRequiresZip64 ) {
							workFile.WriteLeLong(update.OutEntry.Size);
							workFile.WriteLeLong(update.OutEntry.CompressedSize);
						}
						else {
							workFile.WriteLEInt(( int )update.OutEntry.CompressedSize);
							workFile.WriteLEInt(( int )update.OutEntry.Size);
						}
					}
				}
			}
			catch(Exception) {
				allOk = false;
			}
			finally {
				if ( directUpdate ) {
					if ( allOk ) {
						workFile.baseStream_.Flush();
						workFile.baseStream_.SetLength(endOfStream);
					}
				}
				else {
					workFile.Close();
				}
			}

			if ( allOk ) {
				if ( directUpdate ) {
					isNewArchive_ = false;
					workFile.baseStream_.Flush();
					ReadEntries();
				}
				else {
					baseStream_.Close();
					Reopen(archiveStorage_.ConvertTemporaryToFinal());
				}
			}
			else {
				workFile.Close();
				if ( !directUpdate && (workFile.Name != null) ) {
					File.Delete(workFile.Name);
				}
			}
		}
Ejemplo n.º 3
0
		void UpdateCommentOnly()
		{
			long baseLength = baseStream_.Length;

			ZipHelperStream updateFile = null;

			if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {
				Stream copyStream = archiveStorage_.MakeTemporaryCopy(baseStream_);
				updateFile = new ZipHelperStream(copyStream);
				updateFile.IsStreamOwner = true;

				baseStream_.Close();
				baseStream_ = null;
			}
			else {
				baseStream_.Close();
				baseStream_ = null;

				updateFile = new ZipHelperStream(Name);
			}

			using ( updateFile ) {
				long locatedCentralDirOffset = 
					updateFile.LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature, 
														baseLength, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);
				if ( locatedCentralDirOffset < 0 ) {
					throw new ZipException("Cannot find central directory");
				}

				const int CentralHeaderCommentSizeOffset = 16;
				updateFile.Position += CentralHeaderCommentSizeOffset;

				byte[] rawComment = newComment_.RawComment;

				updateFile.WriteLEShort(rawComment.Length);
				updateFile.Write(rawComment, 0, rawComment.Length);
				updateFile.SetLength(updateFile.Position);
			}

			if ( archiveStorage_.UpdateMode == FileUpdateMode.Safe ) {
				Reopen(archiveStorage_.ConvertTemporaryToFinal());
			}
			else {
				Reopen();
			}
		}
Ejemplo n.º 4
0
		/// <summary>
		/// Commit current updates, updating this archive.
		/// </summary>
		/// <seealso cref="BeginUpdate"></seealso>
		/// <seealso cref="AbortUpdate"></seealso>
		public void CommitUpdate()
		{
			CheckUpdating();

			if ( contentsEdited_ ) {
				RunUpdates();
			}
			else if ( commentEdited_ ) {
				UpdateCommentOnly();
			}
			else {
				// Create an empty archive if none existed originally.
				if ( (entries_ != null) && (entries_.Length == 0) ) {
					byte[] theComment = (newComment_ != null) ? newComment_.RawComment : ZipConstants.ConvertToArray(comment_);
					using ( ZipHelperStream zhs = new ZipHelperStream(baseStream_) ) {
						zhs.WriteEndOfCentralDirectory(0, 0, 0, theComment);
					}
				}
			}

			PostUpdateCleanup();
		}
Ejemplo n.º 5
0
        /// <summary>
        /// Finishes the stream.  This will write the central directory at the
        /// end of the zip file and flush the stream.
        /// </summary>
        /// <remarks>
        /// This is automatically called when the stream is closed.
        /// </remarks>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurs.
        /// </exception>
        /// <exception cref="ZipException">
        /// Comment exceeds the maximum length<br/>
        /// Entry name exceeds the maximum length
        /// </exception>
        public override void Finish()
        {
            if (entries == null)
            {
                return;
            }

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

            long numEntries  = entries.Count;
            long sizeEntries = 0;

            foreach (ZipEntry entry in entries)
            {
                WriteLeInt(ZipConstants.CentralHeaderSignature);
                WriteLeShort(ZipConstants.VersionMadeBy);
                WriteLeShort(entry.Version);
                WriteLeShort(entry.Flags);
                WriteLeShort((short)entry.CompressionMethod);
                WriteLeInt((int)entry.DosTime);
                WriteLeInt((int)entry.Crc);

#if !FORCE_ZIP64
                if (entry.IsZip64Forced() || (entry.CompressedSize >= uint.MaxValue))
#endif
                {
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)entry.CompressedSize);
                }

#if !FORCE_ZIP64
                if (entry.IsZip64Forced() || (entry.Size >= uint.MaxValue))
#endif
                {
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)entry.Size);
                }

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

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

                ZipExtraData ed = new ZipExtraData(entry.ExtraData);

                if (entry.CentralHeaderRequiresZip64)
                {
                    ed.StartNewEntry();
#if !FORCE_ZIP64
                    if (entry.IsZip64Forced() || (entry.Size >= 0xffffffff))
#endif
                    {
                        ed.AddLeLong(entry.Size);
                    }

#if !FORCE_ZIP64
                    if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffff))
#endif
                    {
                        ed.AddLeLong(entry.CompressedSize);
                    }

                    if (entry.Offset >= 0xffffffff)
                    {
                        ed.AddLeLong(entry.Offset);
                    }

                    ed.AddNewEntry(1);
                }
                else
                {
                    ed.Delete(1);
                }

                byte[] extra = ed.GetEntryData();

                byte[] entryComment = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Comment) : new byte[0];
                if (entryComment.Length > 0xffff)
                {
                    throw new ZipException("Comment too long.");
                }

                WriteLeShort(name.Length);
                WriteLeShort(extra.Length);
                WriteLeShort(entryComment.Length);
                WriteLeShort(0);                        // disk number
                WriteLeShort(0);                        // internal file attributes
                // external file attributes

                if (entry.ExternalFileAttributes != -1)
                {
                    WriteLeInt(entry.ExternalFileAttributes);
                }
                else
                {
                    if (entry.IsDirectory)                                               // mark entry as directory (from nikolam.AT.perfectinfo.com)
                    {
                        WriteLeInt(16);
                    }
                    else
                    {
                        WriteLeInt(0);
                    }
                }

                if (entry.Offset >= uint.MaxValue)
                {
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)entry.Offset);
                }

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

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

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

                sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
            }

            using (ZipHelperStream zhs = new ZipHelperStream(baseOutputStream)) {
                zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
            }

            entries = null;
        }
Ejemplo n.º 6
0
		/// <summary>
		/// Finishes the stream.  This will write the central directory at the
		/// end of the zip file and flush the stream.
		/// </summary>
		/// <remarks>
		/// This is automatically called when the stream is closed.
		/// </remarks>
		/// <exception cref="System.IO.IOException">
		/// An I/O error occurs.
		/// </exception>
		/// <exception cref="ZipException">
		/// Comment exceeds the maximum length<br/>
		/// Entry name exceeds the maximum length
		/// </exception>
		public override void Finish()
		{
			if (entries == null)  {
				return;
			}
			
			if (curEntry != null) {
				CloseEntry();
			}
			
			long numEntries = entries.Count;
			long sizeEntries = 0;
			
			foreach (ZipEntry entry in entries) {
				WriteLeInt(ZipConstants.CentralHeaderSignature); 
				WriteLeShort(ZipConstants.VersionMadeBy);
				WriteLeShort(entry.Version);
				WriteLeShort(entry.Flags);
				WriteLeShort((short)entry.CompressionMethod);
				WriteLeInt((int)entry.DosTime);
				WriteLeInt((int)entry.Crc);

#if !FORCE_ZIP64
				if ( entry.IsZip64Forced() || (entry.CompressedSize >= uint.MaxValue) )
#endif
				{
					WriteLeInt(-1);
				}
				else {
					WriteLeInt((int)entry.CompressedSize);
				}

#if !FORCE_ZIP64
				if ( entry.IsZip64Forced() || (entry.Size >= uint.MaxValue) )
#endif
				{
					WriteLeInt(-1);
				}
				else {
					WriteLeInt((int)entry.Size);
				}
				
				byte[] name = ZipConstants.ConvertToArray(entry.Name);
				
				if (name.Length > 0xffff) {
					throw new ZipException("Name too long.");
				}
				
				ZipExtraData ed = new ZipExtraData(entry.ExtraData);

				if ( entry.CentralHeaderRequiresZip64 ) {
					ed.StartNewEntry();
#if !FORCE_ZIP64
					if ( entry.IsZip64Forced() || (entry.Size >= 0xffffffff) )
#endif
					{
						ed.AddLeLong(entry.Size);
					}

#if !FORCE_ZIP64
					if ( entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffff) )
#endif
					{
						ed.AddLeLong(entry.CompressedSize);
					}

					if ( entry.Offset >= 0xffffffff )
					{
						ed.AddLeLong(entry.Offset);
					}

					ed.AddNewEntry(1);
				}
				else {
					ed.Delete(1);
				}

				byte[] extra = ed.GetEntryData();
				
				byte[] entryComment = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Comment) : new byte[0];
				if (entryComment.Length > 0xffff) {
					throw new ZipException("Comment too long.");
				}
				
				WriteLeShort(name.Length);
				WriteLeShort(extra.Length);
				WriteLeShort(entryComment.Length);
				WriteLeShort(0);	// disk number
				WriteLeShort(0);	// internal file attributes
									// external file attributes

				if (entry.ExternalFileAttributes != -1) {
					WriteLeInt(entry.ExternalFileAttributes);
				} else {
					if (entry.IsDirectory) {                         // mark entry as directory (from nikolam.AT.perfectinfo.com)
						WriteLeInt(16);
					} else {
						WriteLeInt(0);
					}
				}

				if ( entry.Offset >= uint.MaxValue ) {
					WriteLeInt(-1);
				}
				else {
					WriteLeInt((int)entry.Offset);
				}
				
				if ( name.Length > 0 ) {
					baseOutputStream.Write(name,    0, name.Length);
				}

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

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

				sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
			}
			
			using ( ZipHelperStream zhs = new ZipHelperStream(baseOutputStream) ) {
				zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
			}

			entries = null;
		}