Beispiel #1
0
            /// <summary>
            /// Return the start offset for piece number pieceNumber.
            /// </summary>
            /// <remarks>
            /// pieceNumber is assumed to be a valid number. If it isn't, an assertion will fail.
            /// </remarks>
            internal long GetStartOffset(int pieceNumber)
            {
                //Make sure that the stream has been initialized for this piece number
                PieceStreamInfo pieceStreamInfo = RetrievePiece(pieceNumber);

                return(pieceStreamInfo.StartOffset);
            }
Beispiel #2
0
            //------------------------------------------------------
            //
            //   Internal Methods
            //
            //------------------------------------------------------

            /// <summary>
            /// Given an offset in the part, locate the piece that contains it.
            /// </summary>
            internal int GetPieceNumberFromOffset(long offset)
            {
                // Find the piece whose range includes offset.
                PieceStreamInfo temporaryPieceInfo = new PieceStreamInfo(_temporaryMemoryStream, offset);
                int             pieceNumber        = _pieceStreamInfoList.BinarySearch(temporaryPieceInfo);

                if (pieceNumber >= 0)
                {
                    // Found the piece that starts at offset 'offset'.
                    return(pieceNumber);
                }

                // ~pieceNumber represents the place at which we would insert a piece starting at offset.
                // offset belongs therefore to the preceding piece.
                pieceNumber = (~pieceNumber - 1);

                // If the list contains data about pieces following pieceNumber, then we know offset precedes those
                // and is therefore in the scope of the piece at pieceNumber.
                if (pieceNumber < _indexOfLastPieceStreamInfoAccessed)
                {
                    return(pieceNumber);
                }

                // The following tests may have to be repeated until we load enough descriptors to cover offset.
                // If there is no error in part numbering, we'll eventually find either the last part
                // or an intermediate part whose range contains offset.
                while (pieceNumber < _lastPieceIndex)
                {
                    // Make sure we have a descriptor and stream for piece pieceNumber.
                    PieceStreamInfo currentPieceInfo = RetrievePiece(pieceNumber);

                    // If the piece at pieceNumber is not expandable, then its length has to be taken into account.
                    // currentPieceInfo.Stream is guaranteed to be non-null
                    if (offset < checked (currentPieceInfo.StartOffset + currentPieceInfo.Stream.Length))
                    {
                        break;
                    }
                    // offset is not covered by any piece whose descriptor has been loaded.
                    // Keep loading piece descriptors.
                    checked
                    {
                        ++pieceNumber;
                    }
                }

                // If pieceNumber is the number of the last piece in the part, it is expandable and therefore
                // contains offset.
                // Else the pieceNumber should be less than the _lastPieceIndex
                Invariant.Assert(pieceNumber <= _lastPieceIndex, "We should have found the valid pieceNumber earlier");

                return(pieceNumber);
            }
Beispiel #3
0
            //------------------------------------------------------
            //
            //   Private Methods
            //
            //------------------------------------------------------

            /// <summary>
            /// Return the descriptor for piece number pieceNumber.
            /// This method does lazy initializations of the streams corresponding
            /// to the pieces that make up the part.
            /// </summary>
            /// <remarks>
            /// pieceNumber is assumed to be a valid number. If it isn't, an assertion will fail.
            /// </remarks>
            private PieceStreamInfo RetrievePiece(int pieceNumber)
            {
                if (pieceNumber > _lastPieceIndex)
                {
                    throw new ArgumentException(SR.Get(SRID.PieceDoesNotExist));
                }

                if (_indexOfLastPieceStreamInfoAccessed >= pieceNumber)
                {
                    return(_pieceStreamInfoList[pieceNumber]);
                }

                // The search below supposes the list is initially non-empty.
                // This invariant is enforced by the constructor.

                // Load descriptors for all pieces from _indexOfLastPieceStreamInfoAccessed+1 through pieceNumber.

                PieceStreamInfo currentPieceStreamInfo = _pieceStreamInfoList[_indexOfLastPieceStreamInfoAccessed];

                //we retrieve piece streams "upto the requested piece number" rather than getting just the
                //stream corresponding "to the requested piece number" for the following two reasons -
                //a. We need to be able to calculate the correct startOffset and as such need the lengths
                //   of all the intermediate streams
                //b. We also want to make sure that the intermediate streams do exists as it would be an
                //   error if they are missing or corrupt.
                for (int i = _indexOfLastPieceStreamInfoAccessed + 1; i <= pieceNumber; ++i)
                {
                    // Compute StartOffset.
                    long newStartOffset = checked (currentPieceStreamInfo.StartOffset + currentPieceStreamInfo.Stream.Length);

                    // Compute pieceInfoStream.Stream.
                    Stream pieceStream = _sortedPieceInfoList[pieceNumber].ZipFileInfo.GetStream(
                        _fileMode, _fileAccess);

                    // Update _pieceStreamInfoArray.
                    _indexOfLastPieceStreamInfoAccessed = i;
                    currentPieceStreamInfo = new PieceStreamInfo(pieceStream, newStartOffset);

                    // !!!Implementation Note!!!
                    // List<> always adds the new item at the end of the list.
                    // _sortedPieceInfoList is sorted by the piecenumbers and so, when we add
                    // members to _pieceStreamInfoList they also get added in a sorted manner.
                    // If every the implementation changes, we must make sure that the
                    // _pieceStreamInfoList still remains sorted by the piecenumbers as we
                    // perform a binary search on this list in GetPieceNumberFromOffset method
                    _pieceStreamInfoList.Add(currentPieceStreamInfo);
                }
                return(_pieceStreamInfoList[pieceNumber]);
            }
Beispiel #4
0
            /// <summary>
            /// This method is called to implement SetLength. If it changes
            /// the actual last piece, the next call to flush will perform the
            /// necessary renaming and deletion(s).
            /// </summary>
            internal void SetLogicalLastPiece(int pieceNumber)
            {
                //The Logical piece that we are setting should not be greater than the
                //last piece index
                Invariant.Assert(pieceNumber <= _lastPieceIndex);

                //Make sure that the stream has been initialized for this piece number
                PieceStreamInfo piece = RetrievePiece(pieceNumber);

                // Update _lastPiece and record whether this invalidates physical pieces.
                if (_lastPieceIndex > pieceNumber)
                {
                    _logicalEndPrecedesPhysicalEnd = true;
                    _lastPieceIndex = pieceNumber;
                    // To avoid any potential for confusion, remove any invalidated piece from _pieceStreamInfoArray.
                    _indexOfLastPieceStreamInfoAccessed = _lastPieceIndex;
                    _pieceStreamInfoList.RemoveRange(_indexOfLastPieceStreamInfoAccessed + 1, _pieceStreamInfoList.Count - (_indexOfLastPieceStreamInfoAccessed + 1));
                }
            }