LCOV - code coverage report
Current view: top level - xpcom/io - nsStorageStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 272 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 40 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * The storage stream provides an internal buffer that can be filled by a
       9             :  * client using a single output stream.  One or more independent input streams
      10             :  * can be created to read the data out non-destructively.  The implementation
      11             :  * uses a segmented buffer internally to avoid realloc'ing of large buffers,
      12             :  * with the attendant performance loss and heap fragmentation.
      13             :  */
      14             : 
      15             : #include "nsAlgorithm.h"
      16             : #include "nsStorageStream.h"
      17             : #include "nsSegmentedBuffer.h"
      18             : #include "nsStreamUtils.h"
      19             : #include "nsCOMPtr.h"
      20             : #include "nsICloneableInputStream.h"
      21             : #include "nsIInputStream.h"
      22             : #include "nsIIPCSerializableInputStream.h"
      23             : #include "nsISeekableStream.h"
      24             : #include "mozilla/Logging.h"
      25             : #include "mozilla/Attributes.h"
      26             : #include "mozilla/Likely.h"
      27             : #include "mozilla/MathAlgorithms.h"
      28             : #include "mozilla/ipc/InputStreamUtils.h"
      29             : 
      30             : using mozilla::ipc::InputStreamParams;
      31             : using mozilla::ipc::StringInputStreamParams;
      32             : using mozilla::Maybe;
      33             : using mozilla::Some;
      34             : 
      35             : //
      36             : // Log module for StorageStream logging...
      37             : //
      38             : // To enable logging (see prlog.h for full details):
      39             : //
      40             : //    set MOZ_LOG=StorageStreamLog:5
      41             : //    set MOZ_LOG_FILE=storage.log
      42             : //
      43             : // This enables LogLevel::Debug level information and places all output in
      44             : // the file storage.log.
      45             : //
      46             : static LazyLogModule sStorageStreamLog("nsStorageStream");
      47             : #ifdef LOG
      48             : #undef LOG
      49             : #endif
      50             : #define LOG(args) MOZ_LOG(sStorageStreamLog, mozilla::LogLevel::Debug, args)
      51             : 
      52           0 : nsStorageStream::nsStorageStream()
      53             :   : mSegmentedBuffer(0), mSegmentSize(0), mWriteInProgress(false),
      54           0 :     mLastSegmentNum(-1), mWriteCursor(0), mSegmentEnd(0), mLogicalLength(0)
      55             : {
      56           0 :   LOG(("Creating nsStorageStream [%p].\n", this));
      57           0 : }
      58             : 
      59           0 : nsStorageStream::~nsStorageStream()
      60             : {
      61           0 :   delete mSegmentedBuffer;
      62           0 : }
      63             : 
      64           0 : NS_IMPL_ISUPPORTS(nsStorageStream,
      65             :                   nsIStorageStream,
      66             :                   nsIOutputStream)
      67             : 
      68             : NS_IMETHODIMP
      69           0 : nsStorageStream::Init(uint32_t aSegmentSize, uint32_t aMaxSize)
      70             : {
      71           0 :   mSegmentedBuffer = new nsSegmentedBuffer();
      72           0 :   mSegmentSize = aSegmentSize;
      73           0 :   mSegmentSizeLog2 = mozilla::FloorLog2(aSegmentSize);
      74             : 
      75             :   // Segment size must be a power of two
      76           0 :   if (mSegmentSize != ((uint32_t)1 << mSegmentSizeLog2)) {
      77           0 :     return NS_ERROR_INVALID_ARG;
      78             :   }
      79             : 
      80           0 :   return mSegmentedBuffer->Init(aSegmentSize, aMaxSize);
      81             : }
      82             : 
      83             : NS_IMETHODIMP
      84           0 : nsStorageStream::GetOutputStream(int32_t aStartingOffset,
      85             :                                  nsIOutputStream** aOutputStream)
      86             : {
      87           0 :   if (NS_WARN_IF(!aOutputStream)) {
      88           0 :     return NS_ERROR_INVALID_ARG;
      89             :   }
      90           0 :   if (NS_WARN_IF(!mSegmentedBuffer)) {
      91           0 :     return NS_ERROR_NOT_INITIALIZED;
      92             :   }
      93             : 
      94           0 :   if (mWriteInProgress) {
      95           0 :     return NS_ERROR_NOT_AVAILABLE;
      96             :   }
      97             : 
      98           0 :   nsresult rv = Seek(aStartingOffset);
      99           0 :   if (NS_FAILED(rv)) {
     100           0 :     return rv;
     101             :   }
     102             : 
     103             :   // Enlarge the last segment in the buffer so that it is the same size as
     104             :   // all the other segments in the buffer.  (It may have been realloc'ed
     105             :   // smaller in the Close() method.)
     106           0 :   if (mLastSegmentNum >= 0)
     107           0 :     if (mSegmentedBuffer->ReallocLastSegment(mSegmentSize)) {
     108             :       // Need to re-Seek, since realloc changed segment base pointer
     109           0 :       rv = Seek(aStartingOffset);
     110           0 :       if (NS_FAILED(rv)) {
     111           0 :         return rv;
     112             :       }
     113             :     }
     114             : 
     115           0 :   NS_ADDREF(this);
     116           0 :   *aOutputStream = static_cast<nsIOutputStream*>(this);
     117           0 :   mWriteInProgress = true;
     118           0 :   return NS_OK;
     119             : }
     120             : 
     121             : NS_IMETHODIMP
     122           0 : nsStorageStream::Close()
     123             : {
     124           0 :   if (NS_WARN_IF(!mSegmentedBuffer)) {
     125           0 :     return NS_ERROR_NOT_INITIALIZED;
     126             :   }
     127             : 
     128           0 :   mWriteInProgress = false;
     129             : 
     130           0 :   int32_t segmentOffset = SegOffset(mLogicalLength);
     131             : 
     132             :   // Shrink the final segment in the segmented buffer to the minimum size
     133             :   // needed to contain the data, so as to conserve memory.
     134           0 :   if (segmentOffset) {
     135           0 :     mSegmentedBuffer->ReallocLastSegment(segmentOffset);
     136             :   }
     137             : 
     138           0 :   mWriteCursor = 0;
     139           0 :   mSegmentEnd = 0;
     140             : 
     141           0 :   LOG(("nsStorageStream [%p] Close mWriteCursor=%p mSegmentEnd=%p\n",
     142             :        this, mWriteCursor, mSegmentEnd));
     143             : 
     144           0 :   return NS_OK;
     145             : }
     146             : 
     147             : NS_IMETHODIMP
     148           0 : nsStorageStream::Flush()
     149             : {
     150           0 :   return NS_OK;
     151             : }
     152             : 
     153             : NS_IMETHODIMP
     154           0 : nsStorageStream::Write(const char* aBuffer, uint32_t aCount,
     155             :                        uint32_t* aNumWritten)
     156             : {
     157           0 :   if (NS_WARN_IF(!aNumWritten) || NS_WARN_IF(!aBuffer)) {
     158           0 :     return NS_ERROR_INVALID_ARG;
     159             :   }
     160           0 :   if (NS_WARN_IF(!mSegmentedBuffer)) {
     161           0 :     return NS_ERROR_NOT_INITIALIZED;
     162             :   }
     163             : 
     164             :   const char* readCursor;
     165             :   uint32_t count, availableInSegment, remaining;
     166           0 :   nsresult rv = NS_OK;
     167             : 
     168           0 :   LOG(("nsStorageStream [%p] Write mWriteCursor=%p mSegmentEnd=%p aCount=%d\n",
     169             :        this, mWriteCursor, mSegmentEnd, aCount));
     170             : 
     171           0 :   remaining = aCount;
     172           0 :   readCursor = aBuffer;
     173             :   // If no segments have been created yet, create one even if we don't have
     174             :   // to write any data; this enables creating an input stream which reads from
     175             :   // the very end of the data for any amount of data in the stream (i.e.
     176             :   // this stream contains N bytes of data and newInputStream(N) is called),
     177             :   // even for N=0 (with the caveat that we require .write("", 0) be called to
     178             :   // initialize internal buffers).
     179           0 :   bool firstTime = mSegmentedBuffer->GetSegmentCount() == 0;
     180           0 :   while (remaining || MOZ_UNLIKELY(firstTime)) {
     181           0 :     firstTime = false;
     182           0 :     availableInSegment = mSegmentEnd - mWriteCursor;
     183           0 :     if (!availableInSegment) {
     184           0 :       mWriteCursor = mSegmentedBuffer->AppendNewSegment();
     185           0 :       if (!mWriteCursor) {
     186           0 :         mSegmentEnd = 0;
     187           0 :         rv = NS_ERROR_OUT_OF_MEMORY;
     188           0 :         goto out;
     189             :       }
     190           0 :       mLastSegmentNum++;
     191           0 :       mSegmentEnd = mWriteCursor + mSegmentSize;
     192           0 :       availableInSegment = mSegmentEnd - mWriteCursor;
     193           0 :       LOG(("nsStorageStream [%p] Write (new seg) mWriteCursor=%p mSegmentEnd=%p\n",
     194             :            this, mWriteCursor, mSegmentEnd));
     195             :     }
     196             : 
     197           0 :     count = XPCOM_MIN(availableInSegment, remaining);
     198           0 :     memcpy(mWriteCursor, readCursor, count);
     199           0 :     remaining -= count;
     200           0 :     readCursor += count;
     201           0 :     mWriteCursor += count;
     202           0 :     LOG(("nsStorageStream [%p] Writing mWriteCursor=%p mSegmentEnd=%p count=%d\n",
     203             :          this, mWriteCursor, mSegmentEnd, count));
     204             :   }
     205             : 
     206             : out:
     207           0 :   *aNumWritten = aCount - remaining;
     208           0 :   mLogicalLength += *aNumWritten;
     209             : 
     210           0 :   LOG(("nsStorageStream [%p] Wrote mWriteCursor=%p mSegmentEnd=%p numWritten=%d\n",
     211             :        this, mWriteCursor, mSegmentEnd, *aNumWritten));
     212           0 :   return rv;
     213             : }
     214             : 
     215             : NS_IMETHODIMP
     216           0 : nsStorageStream::WriteFrom(nsIInputStream* aInStr, uint32_t aCount,
     217             :                            uint32_t* aResult)
     218             : {
     219           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     220             : }
     221             : 
     222             : NS_IMETHODIMP
     223           0 : nsStorageStream::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
     224             :                                uint32_t aCount, uint32_t* aResult)
     225             : {
     226           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     227             : }
     228             : 
     229             : NS_IMETHODIMP
     230           0 : nsStorageStream::IsNonBlocking(bool* aNonBlocking)
     231             : {
     232           0 :   *aNonBlocking = false;
     233           0 :   return NS_OK;
     234             : }
     235             : 
     236             : NS_IMETHODIMP
     237           0 : nsStorageStream::GetLength(uint32_t* aLength)
     238             : {
     239           0 :   *aLength = mLogicalLength;
     240           0 :   return NS_OK;
     241             : }
     242             : 
     243             : // Truncate the buffer by deleting the end segments
     244             : NS_IMETHODIMP
     245           0 : nsStorageStream::SetLength(uint32_t aLength)
     246             : {
     247           0 :   if (NS_WARN_IF(!mSegmentedBuffer)) {
     248           0 :     return NS_ERROR_NOT_INITIALIZED;
     249             :   }
     250             : 
     251           0 :   if (mWriteInProgress) {
     252           0 :     return NS_ERROR_NOT_AVAILABLE;
     253             :   }
     254             : 
     255           0 :   if (aLength > mLogicalLength) {
     256           0 :     return NS_ERROR_INVALID_ARG;
     257             :   }
     258             : 
     259           0 :   int32_t newLastSegmentNum = SegNum(aLength);
     260           0 :   int32_t segmentOffset = SegOffset(aLength);
     261           0 :   if (segmentOffset == 0) {
     262           0 :     newLastSegmentNum--;
     263             :   }
     264             : 
     265           0 :   while (newLastSegmentNum < mLastSegmentNum) {
     266           0 :     mSegmentedBuffer->DeleteLastSegment();
     267           0 :     mLastSegmentNum--;
     268             :   }
     269             : 
     270           0 :   mLogicalLength = aLength;
     271           0 :   return NS_OK;
     272             : }
     273             : 
     274             : NS_IMETHODIMP
     275           0 : nsStorageStream::GetWriteInProgress(bool* aWriteInProgress)
     276             : {
     277           0 :   *aWriteInProgress = mWriteInProgress;
     278           0 :   return NS_OK;
     279             : }
     280             : 
     281             : nsresult
     282           0 : nsStorageStream::Seek(int32_t aPosition)
     283             : {
     284           0 :   if (NS_WARN_IF(!mSegmentedBuffer)) {
     285           0 :     return NS_ERROR_NOT_INITIALIZED;
     286             :   }
     287             : 
     288             :   // An argument of -1 means "seek to end of stream"
     289           0 :   if (aPosition == -1) {
     290           0 :     aPosition = mLogicalLength;
     291             :   }
     292             : 
     293             :   // Seeking beyond the buffer end is illegal
     294           0 :   if ((uint32_t)aPosition > mLogicalLength) {
     295           0 :     return NS_ERROR_INVALID_ARG;
     296             :   }
     297             : 
     298             :   // Seeking backwards in the write stream results in truncation
     299           0 :   SetLength(aPosition);
     300             : 
     301             :   // Special handling for seek to start-of-buffer
     302           0 :   if (aPosition == 0) {
     303           0 :     mWriteCursor = 0;
     304           0 :     mSegmentEnd = 0;
     305           0 :     LOG(("nsStorageStream [%p] Seek mWriteCursor=%p mSegmentEnd=%p\n",
     306             :          this, mWriteCursor, mSegmentEnd));
     307           0 :     return NS_OK;
     308             :   }
     309             : 
     310             :   // Segment may have changed, so reset pointers
     311           0 :   mWriteCursor = mSegmentedBuffer->GetSegment(mLastSegmentNum);
     312           0 :   NS_ASSERTION(mWriteCursor, "null mWriteCursor");
     313           0 :   mSegmentEnd = mWriteCursor + mSegmentSize;
     314             : 
     315             :   // Adjust write cursor for current segment offset.  This test is necessary
     316             :   // because SegNum may reference the next-to-be-allocated segment, in which
     317             :   // case we need to be pointing at the end of the last segment.
     318           0 :   int32_t segmentOffset = SegOffset(aPosition);
     319           0 :   if (segmentOffset == 0 && (SegNum(aPosition) > (uint32_t) mLastSegmentNum)) {
     320           0 :     mWriteCursor = mSegmentEnd;
     321             :   } else {
     322           0 :     mWriteCursor += segmentOffset;
     323             :   }
     324             : 
     325           0 :   LOG(("nsStorageStream [%p] Seek mWriteCursor=%p mSegmentEnd=%p\n",
     326             :        this, mWriteCursor, mSegmentEnd));
     327           0 :   return NS_OK;
     328             : }
     329             : 
     330             : ////////////////////////////////////////////////////////////////////////////////
     331             : 
     332             : // There can be many nsStorageInputStreams for a single nsStorageStream
     333             : class nsStorageInputStream final
     334             :   : public nsIInputStream
     335             :   , public nsISeekableStream
     336             :   , public nsIIPCSerializableInputStream
     337             :   , public nsICloneableInputStream
     338             : {
     339             : public:
     340           0 :   nsStorageInputStream(nsStorageStream* aStorageStream, uint32_t aSegmentSize)
     341           0 :     : mStorageStream(aStorageStream), mReadCursor(0),
     342             :       mSegmentEnd(0), mSegmentNum(0),
     343             :       mSegmentSize(aSegmentSize), mLogicalCursor(0),
     344           0 :       mStatus(NS_OK)
     345             :   {
     346           0 :   }
     347             : 
     348             :   NS_DECL_THREADSAFE_ISUPPORTS
     349             :   NS_DECL_NSIINPUTSTREAM
     350             :   NS_DECL_NSISEEKABLESTREAM
     351             :   NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
     352             :   NS_DECL_NSICLONEABLEINPUTSTREAM
     353             : 
     354             : private:
     355           0 :   ~nsStorageInputStream()
     356           0 :   {
     357           0 :   }
     358             : 
     359             : protected:
     360             :   nsresult Seek(uint32_t aPosition);
     361             : 
     362             :   friend class nsStorageStream;
     363             : 
     364             : private:
     365             :   RefPtr<nsStorageStream> mStorageStream;
     366             :   uint32_t         mReadCursor;    // Next memory location to read byte, or 0
     367             :   uint32_t         mSegmentEnd;    // One byte past end of current buffer segment
     368             :   uint32_t         mSegmentNum;    // Segment number containing read cursor
     369             :   uint32_t         mSegmentSize;   // All segments, except the last, are of this size
     370             :   uint32_t         mLogicalCursor; // Logical offset into stream
     371             :   nsresult         mStatus;
     372             : 
     373           0 :   uint32_t SegNum(uint32_t aPosition)
     374             :   {
     375           0 :     return aPosition >> mStorageStream->mSegmentSizeLog2;
     376             :   }
     377           0 :   uint32_t SegOffset(uint32_t aPosition)
     378             :   {
     379           0 :     return aPosition & (mSegmentSize - 1);
     380             :   }
     381             : };
     382             : 
     383           0 : NS_IMPL_ISUPPORTS(nsStorageInputStream,
     384             :                   nsIInputStream,
     385             :                   nsISeekableStream,
     386             :                   nsIIPCSerializableInputStream,
     387             :                   nsICloneableInputStream)
     388             : 
     389             : NS_IMETHODIMP
     390           0 : nsStorageStream::NewInputStream(int32_t aStartingOffset,
     391             :                                 nsIInputStream** aInputStream)
     392             : {
     393           0 :   if (NS_WARN_IF(!mSegmentedBuffer)) {
     394           0 :     return NS_ERROR_NOT_INITIALIZED;
     395             :   }
     396             : 
     397             :   RefPtr<nsStorageInputStream> inputStream =
     398           0 :     new nsStorageInputStream(this, mSegmentSize);
     399             : 
     400           0 :   nsresult rv = inputStream->Seek(aStartingOffset);
     401           0 :   if (NS_FAILED(rv)) {
     402           0 :     return rv;
     403             :   }
     404             : 
     405           0 :   inputStream.forget(aInputStream);
     406           0 :   return NS_OK;
     407             : }
     408             : 
     409             : NS_IMETHODIMP
     410           0 : nsStorageInputStream::Close()
     411             : {
     412           0 :   mStatus = NS_BASE_STREAM_CLOSED;
     413           0 :   return NS_OK;
     414             : }
     415             : 
     416             : NS_IMETHODIMP
     417           0 : nsStorageInputStream::Available(uint64_t* aAvailable)
     418             : {
     419           0 :   if (NS_FAILED(mStatus)) {
     420           0 :     return mStatus;
     421             :   }
     422             : 
     423           0 :   *aAvailable = mStorageStream->mLogicalLength - mLogicalCursor;
     424           0 :   return NS_OK;
     425             : }
     426             : 
     427             : NS_IMETHODIMP
     428           0 : nsStorageInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aNumRead)
     429             : {
     430           0 :   return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aNumRead);
     431             : }
     432             : 
     433             : NS_IMETHODIMP
     434           0 : nsStorageInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
     435             :                                    uint32_t aCount, uint32_t* aNumRead)
     436             : {
     437           0 :   *aNumRead = 0;
     438           0 :   if (mStatus == NS_BASE_STREAM_CLOSED) {
     439           0 :     return NS_OK;
     440             :   }
     441           0 :   if (NS_FAILED(mStatus)) {
     442           0 :     return mStatus;
     443             :   }
     444             : 
     445             :   uint32_t count, availableInSegment, remainingCapacity, bytesConsumed;
     446             :   nsresult rv;
     447             : 
     448           0 :   remainingCapacity = aCount;
     449           0 :   while (remainingCapacity) {
     450           0 :     availableInSegment = mSegmentEnd - mReadCursor;
     451           0 :     if (!availableInSegment) {
     452           0 :       uint32_t available = mStorageStream->mLogicalLength - mLogicalCursor;
     453           0 :       if (!available) {
     454           0 :         goto out;
     455             :       }
     456             : 
     457             :       // We have data in the stream, but if mSegmentEnd is zero, then we
     458             :       // were likely constructed prior to any data being written into
     459             :       // the stream.  Therefore, if mSegmentEnd is non-zero, we should
     460             :       // move into the next segment; otherwise, we should stay in this
     461             :       // segment so our input state can be updated and we can properly
     462             :       // perform the initial read.
     463           0 :       if (mSegmentEnd > 0) {
     464           0 :         mSegmentNum++;
     465             :       }
     466           0 :       mReadCursor = 0;
     467           0 :       mSegmentEnd = XPCOM_MIN(mSegmentSize, available);
     468           0 :       availableInSegment = mSegmentEnd;
     469             :     }
     470           0 :     const char* cur = mStorageStream->mSegmentedBuffer->GetSegment(mSegmentNum);
     471             : 
     472           0 :     count = XPCOM_MIN(availableInSegment, remainingCapacity);
     473           0 :     rv = aWriter(this, aClosure, cur + mReadCursor, aCount - remainingCapacity,
     474           0 :                  count, &bytesConsumed);
     475           0 :     if (NS_FAILED(rv) || (bytesConsumed == 0)) {
     476           0 :       break;
     477             :     }
     478           0 :     remainingCapacity -= bytesConsumed;
     479           0 :     mReadCursor += bytesConsumed;
     480           0 :     mLogicalCursor += bytesConsumed;
     481             :   }
     482             : 
     483             : out:
     484           0 :   *aNumRead = aCount - remainingCapacity;
     485             : 
     486           0 :   bool isWriteInProgress = false;
     487           0 :   if (NS_FAILED(mStorageStream->GetWriteInProgress(&isWriteInProgress))) {
     488           0 :     isWriteInProgress = false;
     489             :   }
     490             : 
     491           0 :   if (*aNumRead == 0 && isWriteInProgress) {
     492           0 :     return NS_BASE_STREAM_WOULD_BLOCK;
     493             :   }
     494             : 
     495           0 :   return NS_OK;
     496             : }
     497             : 
     498             : NS_IMETHODIMP
     499           0 : nsStorageInputStream::IsNonBlocking(bool* aNonBlocking)
     500             : {
     501             :   // TODO: This class should implement nsIAsyncInputStream so that callers
     502             :   // have some way of dealing with NS_BASE_STREAM_WOULD_BLOCK errors.
     503             : 
     504           0 :   *aNonBlocking = true;
     505           0 :   return NS_OK;
     506             : }
     507             : 
     508             : NS_IMETHODIMP
     509           0 : nsStorageInputStream::Seek(int32_t aWhence, int64_t aOffset)
     510             : {
     511           0 :   if (NS_FAILED(mStatus)) {
     512           0 :     return mStatus;
     513             :   }
     514             : 
     515           0 :   int64_t pos = aOffset;
     516             : 
     517           0 :   switch (aWhence) {
     518             :     case NS_SEEK_SET:
     519           0 :       break;
     520             :     case NS_SEEK_CUR:
     521           0 :       pos += mLogicalCursor;
     522           0 :       break;
     523             :     case NS_SEEK_END:
     524           0 :       pos += mStorageStream->mLogicalLength;
     525           0 :       break;
     526             :     default:
     527           0 :       NS_NOTREACHED("unexpected whence value");
     528           0 :       return NS_ERROR_UNEXPECTED;
     529             :   }
     530           0 :   if (pos == int64_t(mLogicalCursor)) {
     531           0 :     return NS_OK;
     532             :   }
     533             : 
     534           0 :   return Seek(pos);
     535             : }
     536             : 
     537             : NS_IMETHODIMP
     538           0 : nsStorageInputStream::Tell(int64_t* aResult)
     539             : {
     540           0 :   if (NS_FAILED(mStatus)) {
     541           0 :     return mStatus;
     542             :   }
     543             : 
     544           0 :   *aResult = mLogicalCursor;
     545           0 :   return NS_OK;
     546             : }
     547             : 
     548             : NS_IMETHODIMP
     549           0 : nsStorageInputStream::SetEOF()
     550             : {
     551           0 :   NS_NOTREACHED("nsStorageInputStream::SetEOF");
     552           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     553             : }
     554             : 
     555             : nsresult
     556           0 : nsStorageInputStream::Seek(uint32_t aPosition)
     557             : {
     558           0 :   uint32_t length = mStorageStream->mLogicalLength;
     559           0 :   if (aPosition > length) {
     560           0 :     return NS_ERROR_INVALID_ARG;
     561             :   }
     562             : 
     563           0 :   if (length == 0) {
     564           0 :     return NS_OK;
     565             :   }
     566             : 
     567           0 :   mSegmentNum = SegNum(aPosition);
     568           0 :   mReadCursor = SegOffset(aPosition);
     569           0 :   uint32_t available = length - aPosition;
     570           0 :   mSegmentEnd = mReadCursor + XPCOM_MIN(mSegmentSize - mReadCursor, available);
     571           0 :   mLogicalCursor = aPosition;
     572           0 :   return NS_OK;
     573             : }
     574             : 
     575             : void
     576           0 : nsStorageInputStream::Serialize(InputStreamParams& aParams, FileDescriptorArray&)
     577             : {
     578           0 :   nsCString combined;
     579             :   int64_t offset;
     580           0 :   mozilla::DebugOnly<nsresult> rv = Tell(&offset);
     581           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     582             : 
     583             :   uint64_t remaining;
     584           0 :   rv = Available(&remaining);
     585           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     586             : 
     587           0 :   combined.SetCapacity(remaining);
     588           0 :   uint32_t numRead = 0;
     589             : 
     590           0 :   rv = Read(combined.BeginWriting(), remaining, &numRead);
     591           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     592           0 :   MOZ_ASSERT(numRead == remaining);
     593           0 :   combined.SetLength(numRead);
     594             : 
     595           0 :   rv = Seek(NS_SEEK_SET, offset);
     596           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     597             : 
     598           0 :   StringInputStreamParams params;
     599           0 :   params.data() = combined;
     600           0 :   aParams = params;
     601           0 : }
     602             : 
     603             : Maybe<uint64_t>
     604           0 : nsStorageInputStream::ExpectedSerializedLength()
     605             : {
     606           0 :   uint64_t remaining = 0;
     607           0 :   DebugOnly<nsresult> rv = Available(&remaining);
     608           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     609           0 :   return Some(remaining);
     610             : }
     611             : 
     612             : bool
     613           0 : nsStorageInputStream::Deserialize(const InputStreamParams& aParams,
     614             :                                   const FileDescriptorArray&)
     615             : {
     616           0 :   NS_NOTREACHED("We should never attempt to deserialize a storage input stream.");
     617           0 :   return false;
     618             : }
     619             : 
     620             : NS_IMETHODIMP
     621           0 : nsStorageInputStream::GetCloneable(bool* aCloneableOut)
     622             : {
     623           0 :   *aCloneableOut = true;
     624           0 :   return NS_OK;
     625             : }
     626             : 
     627             : NS_IMETHODIMP
     628           0 : nsStorageInputStream::Clone(nsIInputStream** aCloneOut)
     629             : {
     630           0 :   return mStorageStream->NewInputStream(mLogicalCursor, aCloneOut);
     631             : }
     632             : 
     633             : nsresult
     634           0 : NS_NewStorageStream(uint32_t aSegmentSize, uint32_t aMaxSize,
     635             :                     nsIStorageStream** aResult)
     636             : {
     637           0 :   RefPtr<nsStorageStream> storageStream = new nsStorageStream();
     638           0 :   nsresult rv = storageStream->Init(aSegmentSize, aMaxSize);
     639           0 :   if (NS_FAILED(rv)) {
     640           0 :     return rv;
     641             :   }
     642           0 :   storageStream.forget(aResult);
     643           0 :   return NS_OK;
     644             : }
     645             : 
     646             : // Undefine LOG, so that other .cpp files (or their includes) won't complain
     647             : // about it already being defined, when we build in unified mode.
     648             : #undef LOG

Generated by: LCOV version 1.13