LCOV - code coverage report
Current view: top level - xpcom/io - nsStringStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 90 172 52.3 %
Date: 2017-07-14 16:53:18 Functions: 21 35 60.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             :  * Based on original code from nsIStringStream.cpp
       9             :  */
      10             : 
      11             : #include "ipc/IPCMessageUtils.h"
      12             : 
      13             : #include "nsStringStream.h"
      14             : #include "nsStreamUtils.h"
      15             : #include "nsReadableUtils.h"
      16             : #include "nsICloneableInputStream.h"
      17             : #include "nsISeekableStream.h"
      18             : #include "nsISupportsPrimitives.h"
      19             : #include "nsCRT.h"
      20             : #include "prerror.h"
      21             : #include "plstr.h"
      22             : #include "nsIClassInfoImpl.h"
      23             : #include "mozilla/Attributes.h"
      24             : #include "mozilla/ipc/InputStreamUtils.h"
      25             : #include "nsIIPCSerializableInputStream.h"
      26             : 
      27             : using namespace mozilla::ipc;
      28             : using mozilla::Maybe;
      29             : using mozilla::Some;
      30             : 
      31             : //-----------------------------------------------------------------------------
      32             : // nsIStringInputStream implementation
      33             : //-----------------------------------------------------------------------------
      34             : 
      35             : class nsStringInputStream final
      36             :   : public nsIStringInputStream
      37             :   , public nsISeekableStream
      38             :   , public nsISupportsCString
      39             :   , public nsIIPCSerializableInputStream
      40             :   , public nsICloneableInputStream
      41             : {
      42             : public:
      43             :   NS_DECL_THREADSAFE_ISUPPORTS
      44             :   NS_DECL_NSIINPUTSTREAM
      45             :   NS_DECL_NSISTRINGINPUTSTREAM
      46             :   NS_DECL_NSISEEKABLESTREAM
      47             :   NS_DECL_NSISUPPORTSPRIMITIVE
      48             :   NS_DECL_NSISUPPORTSCSTRING
      49             :   NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
      50             :   NS_DECL_NSICLONEABLEINPUTSTREAM
      51             : 
      52          87 :   nsStringInputStream()
      53          87 :   {
      54          87 :     Clear();
      55          87 :   }
      56             : 
      57           0 :   explicit nsStringInputStream(const nsStringInputStream& aOther)
      58           0 :     : mOffset(aOther.mOffset)
      59             :   {
      60             :     // Use Assign() here because we don't want the life of the clone to be
      61             :     // dependent on the life of the original stream.
      62           0 :     mData.Assign(aOther.mData);
      63           0 :   }
      64             : 
      65             : private:
      66          86 :   ~nsStringInputStream()
      67          86 :   {
      68          86 :   }
      69             : 
      70      104029 :   uint32_t Length() const
      71             :   {
      72      104029 :     return mData.Length();
      73             :   }
      74             : 
      75       52017 :   uint32_t LengthRemaining() const
      76             :   {
      77       52017 :     return Length() - mOffset;
      78             :   }
      79             : 
      80          93 :   void Clear()
      81             :   {
      82          93 :     mData.SetIsVoid(true);
      83          93 :   }
      84             : 
      85       52017 :   bool Closed()
      86             :   {
      87       52017 :     return mData.IsVoid();
      88             :   }
      89             : 
      90             :   nsDependentCSubstring mData;
      91             :   uint32_t mOffset;
      92             : };
      93             : 
      94             : // This class needs to support threadsafe refcounting since people often
      95             : // allocate a string stream, and then read it from a background thread.
      96         451 : NS_IMPL_ADDREF(nsStringInputStream)
      97         536 : NS_IMPL_RELEASE(nsStringInputStream)
      98             : 
      99           3 : NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
     100             :                   NS_STRINGINPUTSTREAM_CID)
     101         358 : NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream,
     102             :                            nsIStringInputStream,
     103             :                            nsIInputStream,
     104             :                            nsISupportsCString,
     105             :                            nsISeekableStream,
     106             :                            nsIIPCSerializableInputStream,
     107             :                            nsICloneableInputStream)
     108           0 : NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream,
     109             :                             nsIStringInputStream,
     110             :                             nsIInputStream,
     111             :                             nsISupportsCString,
     112             :                             nsISeekableStream,
     113             :                             nsICloneableInputStream)
     114             : 
     115             : /////////
     116             : // nsISupportsCString implementation
     117             : /////////
     118             : 
     119             : NS_IMETHODIMP
     120           0 : nsStringInputStream::GetType(uint16_t* aType)
     121             : {
     122           0 :   *aType = TYPE_CSTRING;
     123           0 :   return NS_OK;
     124             : }
     125             : 
     126             : NS_IMETHODIMP
     127           0 : nsStringInputStream::GetData(nsACString& data)
     128             : {
     129             :   // The stream doesn't have any data when it is closed.  We could fake it
     130             :   // and return an empty string here, but it seems better to keep this return
     131             :   // value consistent with the behavior of the other 'getter' methods.
     132           0 :   if (NS_WARN_IF(Closed())) {
     133           0 :     return NS_BASE_STREAM_CLOSED;
     134             :   }
     135             : 
     136           0 :   data.Assign(mData);
     137           0 :   return NS_OK;
     138             : }
     139             : 
     140             : NS_IMETHODIMP
     141           6 : nsStringInputStream::SetData(const nsACString& aData)
     142             : {
     143           6 :   mData.Assign(aData);
     144           6 :   mOffset = 0;
     145           6 :   return NS_OK;
     146             : }
     147             : 
     148             : NS_IMETHODIMP
     149           0 : nsStringInputStream::ToString(char** aResult)
     150             : {
     151             :   // NOTE: This method may result in data loss, so we do not implement it.
     152           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     153             : }
     154             : 
     155             : /////////
     156             : // nsIStringInputStream implementation
     157             : /////////
     158             : 
     159             : NS_IMETHODIMP
     160           1 : nsStringInputStream::SetData(const char* aData, int32_t aDataLen)
     161             : {
     162           1 :   if (NS_WARN_IF(!aData)) {
     163           0 :     return NS_ERROR_INVALID_ARG;
     164             :   }
     165           1 :   mData.Assign(aData, aDataLen);
     166           1 :   mOffset = 0;
     167           1 :   return NS_OK;
     168             : }
     169             : 
     170             : NS_IMETHODIMP
     171          74 : nsStringInputStream::AdoptData(char* aData, int32_t aDataLen)
     172             : {
     173          74 :   if (NS_WARN_IF(!aData)) {
     174           0 :     return NS_ERROR_INVALID_ARG;
     175             :   }
     176          74 :   mData.Adopt(aData, aDataLen);
     177          74 :   mOffset = 0;
     178          74 :   return NS_OK;
     179             : }
     180             : 
     181             : NS_IMETHODIMP
     182           6 : nsStringInputStream::ShareData(const char* aData, int32_t aDataLen)
     183             : {
     184           6 :   if (NS_WARN_IF(!aData)) {
     185           0 :     return NS_ERROR_INVALID_ARG;
     186             :   }
     187             : 
     188           6 :   if (aDataLen < 0) {
     189           0 :     aDataLen = strlen(aData);
     190             :   }
     191             : 
     192           6 :   mData.Rebind(aData, aDataLen);
     193           6 :   mOffset = 0;
     194           6 :   return NS_OK;
     195             : }
     196             : 
     197             : NS_IMETHODIMP_(size_t)
     198           0 : nsStringInputStream::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
     199             : {
     200           0 :   size_t n = aMallocSizeOf(this);
     201           0 :   n += mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     202           0 :   return n;
     203             : }
     204             : 
     205             : /////////
     206             : // nsIInputStream implementation
     207             : /////////
     208             : 
     209             : NS_IMETHODIMP
     210           6 : nsStringInputStream::Close()
     211             : {
     212           6 :   Clear();
     213           6 :   return NS_OK;
     214             : }
     215             : 
     216             : NS_IMETHODIMP
     217           5 : nsStringInputStream::Available(uint64_t* aLength)
     218             : {
     219           5 :   NS_ASSERTION(aLength, "null ptr");
     220             : 
     221           5 :   if (Closed()) {
     222           0 :     return NS_BASE_STREAM_CLOSED;
     223             :   }
     224             : 
     225           5 :   *aLength = LengthRemaining();
     226           5 :   return NS_OK;
     227             : }
     228             : 
     229             : NS_IMETHODIMP
     230       39757 : nsStringInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount)
     231             : {
     232       39757 :   NS_ASSERTION(aBuf, "null ptr");
     233       39757 :   return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
     234             : }
     235             : 
     236             : NS_IMETHODIMP
     237       52012 : nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
     238             :                                   uint32_t aCount, uint32_t* aResult)
     239             : {
     240       52012 :   NS_ASSERTION(aResult, "null ptr");
     241       52012 :   NS_ASSERTION(Length() >= mOffset, "bad stream state");
     242             : 
     243       52012 :   if (Closed()) {
     244           0 :     return NS_BASE_STREAM_CLOSED;
     245             :   }
     246             : 
     247             :   // We may be at end-of-file
     248       52012 :   uint32_t maxCount = LengthRemaining();
     249       52012 :   if (maxCount == 0) {
     250           9 :     *aResult = 0;
     251           9 :     return NS_OK;
     252             :   }
     253             : 
     254       52003 :   if (aCount > maxCount) {
     255           4 :     aCount = maxCount;
     256             :   }
     257       52003 :   nsresult rv = aWriter(this, aClosure, mData.BeginReading() + mOffset, 0,
     258       52003 :                         aCount, aResult);
     259       52003 :   if (NS_SUCCEEDED(rv)) {
     260       52003 :     NS_ASSERTION(*aResult <= aCount,
     261             :                  "writer should not write more than we asked it to write");
     262       52003 :     mOffset += *aResult;
     263             :   }
     264             : 
     265             :   // errors returned from the writer end here!
     266       52003 :   return NS_OK;
     267             : }
     268             : 
     269             : NS_IMETHODIMP
     270           3 : nsStringInputStream::IsNonBlocking(bool* aNonBlocking)
     271             : {
     272           3 :   *aNonBlocking = true;
     273           3 :   return NS_OK;
     274             : }
     275             : 
     276             : /////////
     277             : // nsISeekableStream implementation
     278             : /////////
     279             : 
     280             : NS_IMETHODIMP
     281           0 : nsStringInputStream::Seek(int32_t aWhence, int64_t aOffset)
     282             : {
     283           0 :   if (Closed()) {
     284           0 :     return NS_BASE_STREAM_CLOSED;
     285             :   }
     286             : 
     287             :   // Compute new stream position.  The given offset may be a negative value.
     288             : 
     289           0 :   int64_t newPos = aOffset;
     290           0 :   switch (aWhence) {
     291             :     case NS_SEEK_SET:
     292           0 :       break;
     293             :     case NS_SEEK_CUR:
     294           0 :       newPos += mOffset;
     295           0 :       break;
     296             :     case NS_SEEK_END:
     297           0 :       newPos += Length();
     298           0 :       break;
     299             :     default:
     300           0 :       NS_ERROR("invalid aWhence");
     301           0 :       return NS_ERROR_INVALID_ARG;
     302             :   }
     303             : 
     304           0 :   if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length())) {
     305           0 :     return NS_ERROR_INVALID_ARG;
     306             :   }
     307             : 
     308           0 :   mOffset = (uint32_t)newPos;
     309           0 :   return NS_OK;
     310             : }
     311             : 
     312             : NS_IMETHODIMP
     313           0 : nsStringInputStream::Tell(int64_t* aOutWhere)
     314             : {
     315           0 :   if (Closed()) {
     316           0 :     return NS_BASE_STREAM_CLOSED;
     317             :   }
     318             : 
     319           0 :   *aOutWhere = mOffset;
     320           0 :   return NS_OK;
     321             : }
     322             : 
     323             : NS_IMETHODIMP
     324           0 : nsStringInputStream::SetEOF()
     325             : {
     326           0 :   if (Closed()) {
     327           0 :     return NS_BASE_STREAM_CLOSED;
     328             :   }
     329             : 
     330           0 :   mOffset = Length();
     331           0 :   return NS_OK;
     332             : }
     333             : 
     334             : /////////
     335             : // nsIIPCSerializableInputStream implementation
     336             : /////////
     337             : 
     338             : void
     339           0 : nsStringInputStream::Serialize(InputStreamParams& aParams,
     340             :                                FileDescriptorArray& /* aFDs */)
     341             : {
     342           0 :   StringInputStreamParams params;
     343           0 :   params.data() = PromiseFlatCString(mData);
     344           0 :   aParams = params;
     345           0 : }
     346             : 
     347             : bool
     348           0 : nsStringInputStream::Deserialize(const InputStreamParams& aParams,
     349             :                                  const FileDescriptorArray& /* aFDs */)
     350             : {
     351           0 :   if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
     352           0 :     NS_ERROR("Received unknown parameters from the other process!");
     353           0 :     return false;
     354             :   }
     355             : 
     356             :   const StringInputStreamParams& params =
     357           0 :     aParams.get_StringInputStreamParams();
     358             : 
     359           0 :   if (NS_FAILED(SetData(params.data()))) {
     360           0 :     NS_WARNING("SetData failed!");
     361           0 :     return false;
     362             :   }
     363             : 
     364           0 :   return true;
     365             : }
     366             : 
     367             : Maybe<uint64_t>
     368           0 : nsStringInputStream::ExpectedSerializedLength()
     369             : {
     370           0 :   return Some(static_cast<uint64_t>(Length()));
     371             : }
     372             : 
     373             : /////////
     374             : // nsICloneableInputStream implementation
     375             : /////////
     376             : 
     377             : NS_IMETHODIMP
     378           0 : nsStringInputStream::GetCloneable(bool* aCloneableOut)
     379             : {
     380           0 :   *aCloneableOut = true;
     381           0 :   return NS_OK;
     382             : }
     383             : 
     384             : NS_IMETHODIMP
     385           0 : nsStringInputStream::Clone(nsIInputStream** aCloneOut)
     386             : {
     387           0 :   RefPtr<nsIInputStream> ref = new nsStringInputStream(*this);
     388           0 :   ref.forget(aCloneOut);
     389           0 :   return NS_OK;
     390             : }
     391             : 
     392             : nsresult
     393           6 : NS_NewByteInputStream(nsIInputStream** aStreamResult,
     394             :                       const char* aStringToRead, int32_t aLength,
     395             :                       nsAssignmentType aAssignment)
     396             : {
     397           6 :   NS_PRECONDITION(aStreamResult, "null out ptr");
     398             : 
     399          12 :   RefPtr<nsStringInputStream> stream = new nsStringInputStream();
     400             : 
     401             :   nsresult rv;
     402           6 :   switch (aAssignment) {
     403             :     case NS_ASSIGNMENT_COPY:
     404           0 :       rv = stream->SetData(aStringToRead, aLength);
     405           0 :       break;
     406             :     case NS_ASSIGNMENT_DEPEND:
     407           6 :       rv = stream->ShareData(aStringToRead, aLength);
     408           6 :       break;
     409             :     case NS_ASSIGNMENT_ADOPT:
     410           0 :       rv = stream->AdoptData(const_cast<char*>(aStringToRead), aLength);
     411           0 :       break;
     412             :     default:
     413           0 :       NS_ERROR("invalid assignment type");
     414           0 :       rv = NS_ERROR_INVALID_ARG;
     415             :   }
     416             : 
     417           6 :   if (NS_FAILED(rv)) {
     418           0 :     return rv;
     419             :   }
     420             : 
     421           6 :   stream.forget(aStreamResult);
     422           6 :   return NS_OK;
     423             : }
     424             : 
     425             : nsresult
     426           6 : NS_NewCStringInputStream(nsIInputStream** aStreamResult,
     427             :                          const nsACString& aStringToRead)
     428             : {
     429           6 :   NS_PRECONDITION(aStreamResult, "null out ptr");
     430             : 
     431          12 :   RefPtr<nsStringInputStream> stream = new nsStringInputStream();
     432             : 
     433           6 :   stream->SetData(aStringToRead);
     434             : 
     435           6 :   stream.forget(aStreamResult);
     436          12 :   return NS_OK;
     437             : }
     438             : 
     439             : // factory method for constructing a nsStringInputStream object
     440             : nsresult
     441          75 : nsStringInputStreamConstructor(nsISupports* aOuter, REFNSIID aIID,
     442             :                                void** aResult)
     443             : {
     444          75 :   *aResult = nullptr;
     445             : 
     446          75 :   if (NS_WARN_IF(aOuter)) {
     447           0 :     return NS_ERROR_NO_AGGREGATION;
     448             :   }
     449             : 
     450         150 :   RefPtr<nsStringInputStream> inst = new nsStringInputStream();
     451          75 :   return inst->QueryInterface(aIID, aResult);
     452             : }

Generated by: LCOV version 1.13