//------------------------------------------------------
        //
        //   Private Methods
        //
        //------------------------------------------------------

        private void EnsurePieceStream(bool isLastPiece)
        {
            if (_pieceStream != null)
            {
                // Normally, the pieces are actually closed automatically for us by the
                // underlying ZipIO logic, but in the case of the last piece (when we
                // are called by our own Dispose(bool) method) we must close it explicitly.
                if (isLastPiece)
                {
                    _pieceStream.Close();
                }

                // We detect that the stream has been closed by inspecting the CanWrite property
                // since this is guaranteed not to throw even when the stream is disposed.
                if (!_pieceStream.CanWrite)
                {
                    // increment our piece number so we can generate the correct
                    // one below
                    checked { ++_currentPieceNumber; }

                    // release it to trigger the new piece creation below
                    _pieceStream = null;
                }
            }

            if (_pieceStream == null)
            {
                string pieceName = PieceNameHelper.CreatePieceName(
                    _partName,
                    _currentPieceNumber,
                    isLastPiece);
                string pieceZipName = ZipPackage.GetZipItemNameFromOpcName(pieceName);

                ZipFileInfo zipFileInfo = _archive.AddFile(pieceZipName, _compressionMethod, _deflateOption);
                // We've just created the file, so the mode can only be Create, not CreateNew.
                // (At least, this is part of ZipFileInfo's belief system.)
                _pieceStream = zipFileInfo.GetStream(FileMode.Create, _access);
            }
        }
Example #2
0
        /// <summary>
        /// Return true and create a PieceInfo if the name in the input ZipFileInfo parses
        /// as a piece name.
        /// </summary>
        /// <remarks>
        /// No Uri validation is carried out at this level. All that is checked is valid piece
        /// syntax. So the _prefixName returned as part of the PieceInfo will not necessarily
        /// a part name. For example, it could be the name of the content type stream.
        /// </remarks>
        internal static bool TryCreatePieceInfo(ZipFileInfo zipFileInfo, out PieceInfo pieceInfo)
        {
            Invariant.Assert(zipFileInfo != null);

            pieceInfo = null;

            // Try to parse as a piece name.
            PieceNameInfo pieceNameConstituents;
            bool          result = PieceNameHelper.TryParseAsPieceName(zipFileInfo.Name,
                                                                       out pieceNameConstituents);

            // Return the result and the output parameter.
            if (result)
            {
                pieceInfo = new PieceInfo(zipFileInfo,
                                          pieceNameConstituents.PartUri,
                                          pieceNameConstituents.PrefixName,
                                          pieceNameConstituents.PieceNumber,
                                          pieceNameConstituents.IsLastPiece);
            }

            return(result);
        }
Example #3
0
            /// <summary>
            /// If the logical end precedes the physical end, delete invalidated pieces
            /// and rename the logical end to a name containing ".last".
            /// </summary>
            private void UpdatePhysicalEndIfNecessary()
            {
                if (!_logicalEndPrecedesPhysicalEnd)
                {
                    return;
                }

                // Delete invalidated pieces.
                int pieceNumber = _lastPieceIndex + 1;

                while (pieceNumber < _sortedPieceInfoList.Count)
                {
                    _zipArchive.DeleteFile(_sortedPieceInfoList[pieceNumber].ZipFileInfo.Name);
                    pieceNumber++;
                }

                _sortedPieceInfoList.RemoveRange(_lastPieceIndex + 1, _sortedPieceInfoList.Count - (_lastPieceIndex + 1));

                // Since there is no rename in Zip I/O, getting the last piece to have .last
                // in its name necessarily involves creating a new piece. The simplest and most
                // effective solution consists in adding an empty terminal piece.

                // Number of the new physical last piece.
                int lastPiece = _lastPieceIndex + 1;

                // Record the compression parameters of the first piece to apply them to the new piece.
                // (Though this part will be created as empty, it may grow later.)
                ZipFileInfo           firstPieceInfo    = _sortedPieceInfoList[0].ZipFileInfo;
                CompressionMethodEnum compressionMethod = firstPieceInfo.CompressionMethod;
                DeflateOptionEnum     deflateOption     = firstPieceInfo.DeflateOption;

                // We have to special-case SetLength(0), because in that case, there is no nonempty
                // piece at all; and only the last piece is allowed to be empty.
                if (_lastPieceIndex == 0 && _pieceStreamInfoList[0].Stream.Length == 0)
                {
                    _zipArchive.DeleteFile(firstPieceInfo.Name);

                    // The list of piece descriptors now becomes totally empty.
                    // This temporarily violates an invariant that should obtain again
                    // on exiting this function.
                    _indexOfLastPieceStreamInfoAccessed = -1;
                    //Remove all the items in the list
                    _pieceStreamInfoList.Clear();
                    lastPiece = 0; // Create "[0].last.piece"
                }

                string newLastPieceFileName = PieceNameHelper.CreatePieceName(
                    _sortedPieceInfoList[0].PrefixName,
                    lastPiece,
                    true /* last piece */);

                ZipFileInfo newLastPieceInfo = _zipArchive.AddFile(newLastPieceFileName,
                                                                   compressionMethod, deflateOption);

                _lastPieceIndex = lastPiece;

                //We need to update the _sortedPieceInfoList with this new last piece information
                _sortedPieceInfoList.Add(
                    new PieceInfo(
                        newLastPieceInfo,
                        _sortedPieceInfoList[0].PartUri,
                        _sortedPieceInfoList[0].PrefixName,
                        _lastPieceIndex,
                        true /* last piece */));

                // If we have been creating [0].last.piece, create a stream descriptor for it.
                // (In other cases, create on demand, as usual.)
                if (lastPiece == 0)
                {
                    Stream pieceStream = newLastPieceInfo.GetStream(_fileMode, _fileAccess);
                    _indexOfLastPieceStreamInfoAccessed = 0;

                    //The list should be empty at this point
                    Invariant.Assert(_pieceStreamInfoList.Count == 0);
                    _pieceStreamInfoList.Add(new PieceStreamInfo(pieceStream, 0 /*startOffset*/));
                }

                // Mark update complete.
                _logicalEndPrecedesPhysicalEnd = false;
            }