/// <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); }
//------------------------------------------------------ // // 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); }
//------------------------------------------------------ // // 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]); }
/// <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)); } }