Ejemplo n.º 1
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 by offset within copies/modifies, then adds.
                // This ensures that data required by copies will not be overwritten.
                updates_.Sort(new UpdateComparer());
            }
            else {
                workFile = ZipFile.Create(archiveStorage_.GetTemporaryOutput());
                workFile.UseZip64 = UseZip64;

                if (key != null) {
                    workFile.key = (byte[])key.Clone();
                }
            }

            try {
                foreach ( ZipUpdate update in updates_ ) {
                    if (update != null) {
                        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 will take some legwork.
                                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_ ) {
                    if (update != null) {
                        sizeEntries += workFile.WriteCentralDirectoryHeader(update.OutEntry);
                    }
                }

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

                endOfStream = workFile.baseStream_.Position;

                // And now patch entries...
                foreach ( ZipUpdate update in updates_ ) {
                    if (update != null)
                    {

                        // 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.OutEntry.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.º 2
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 ( entry.IsZip64Forced() ||
                    (entry.CompressedSize >= uint.MaxValue) )
                {
                    WriteLeInt(-1);
                }
                else {
                    WriteLeInt((int)entry.CompressedSize);
                }

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

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

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

                ZipExtraData ed = new ZipExtraData(entry.ExtraData);

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

                    if ( entry.IsZip64Forced() ||
                        (entry.CompressedSize >= 0xffffffff) )
                    {
                        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.Flags, 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.º 3
0
        /// <summary>
        /// Commit current updates, updating this archive.
        /// </summary>
        /// <seealso cref="BeginUpdate()"></seealso>
        /// <seealso cref="AbortUpdate"></seealso>
        /// <exception cref="ObjectDisposedException">ZipFile has been closed.</exception>
        public void CommitUpdate()
        {
            if ( isDisposed_ ) {
                throw new ObjectDisposedException("ZipFile");
            }

            CheckUpdating();

            try {
                updateIndex_.Clear();
                updateIndex_=null;

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

            }
            finally {
                PostUpdateCleanup();
            }
        }