xpcom/io/nsStringStream.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim:set ts=4 sts=4 sw=4 cin et: */
     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/. */
     7 /**
     8  * Based on original code from nsIStringStream.cpp
     9  */
    11 #include "ipc/IPCMessageUtils.h"
    13 #include "nsStringStream.h"
    14 #include "nsStreamUtils.h"
    15 #include "nsReadableUtils.h"
    16 #include "nsISeekableStream.h"
    17 #include "nsISupportsPrimitives.h"
    18 #include "nsCRT.h"
    19 #include "prerror.h"
    20 #include "plstr.h"
    21 #include "nsIClassInfoImpl.h"
    22 #include "mozilla/Attributes.h"
    23 #include "mozilla/ipc/InputStreamUtils.h"
    24 #include "nsIIPCSerializableInputStream.h"
    26 using namespace mozilla::ipc;
    28 //-----------------------------------------------------------------------------
    29 // nsIStringInputStream implementation
    30 //-----------------------------------------------------------------------------
    32 class nsStringInputStream MOZ_FINAL : public nsIStringInputStream
    33                                     , public nsISeekableStream
    34                                     , public nsISupportsCString
    35                                     , public nsIIPCSerializableInputStream
    36 {
    37 public:
    38     NS_DECL_THREADSAFE_ISUPPORTS
    39     NS_DECL_NSIINPUTSTREAM
    40     NS_DECL_NSISTRINGINPUTSTREAM
    41     NS_DECL_NSISEEKABLESTREAM
    42     NS_DECL_NSISUPPORTSPRIMITIVE
    43     NS_DECL_NSISUPPORTSCSTRING
    44     NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
    46     nsStringInputStream()
    47     {
    48         Clear();
    49     }
    51 private:
    52     ~nsStringInputStream()
    53     {}
    55     uint32_t Length() const
    56     {
    57         return mData.Length();
    58     }
    60     uint32_t LengthRemaining() const
    61     {
    62         return Length() - mOffset;
    63     }
    65     void Clear()
    66     {
    67         mData.SetIsVoid(true);
    68     }
    70     bool Closed()
    71     {
    72         return mData.IsVoid();
    73     }
    75     nsDependentCSubstring mData;
    76     uint32_t mOffset;
    77 };
    79 // This class needs to support threadsafe refcounting since people often
    80 // allocate a string stream, and then read it from a background thread.
    81 NS_IMPL_ADDREF(nsStringInputStream)
    82 NS_IMPL_RELEASE(nsStringInputStream)
    84 NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
    85                   NS_STRINGINPUTSTREAM_CID)
    86 NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream,
    87                            nsIStringInputStream,
    88                            nsIInputStream,
    89                            nsISupportsCString,
    90                            nsISeekableStream,
    91                            nsIIPCSerializableInputStream)
    92 NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream,
    93                             nsIStringInputStream,
    94                             nsIInputStream,
    95                             nsISupportsCString,
    96                             nsISeekableStream)
    98 /////////
    99 // nsISupportsCString implementation
   100 /////////
   102 NS_IMETHODIMP
   103 nsStringInputStream::GetType(uint16_t *type)
   104 {
   105     *type = TYPE_CSTRING;
   106     return NS_OK;
   107 }
   109 NS_IMETHODIMP
   110 nsStringInputStream::GetData(nsACString &data)
   111 {
   112     // The stream doesn't have any data when it is closed.  We could fake it
   113     // and return an empty string here, but it seems better to keep this return
   114     // value consistent with the behavior of the other 'getter' methods.
   115     if (NS_WARN_IF(Closed()))
   116         return NS_BASE_STREAM_CLOSED;
   118     data.Assign(mData);
   119     return NS_OK;
   120 }
   122 NS_IMETHODIMP
   123 nsStringInputStream::SetData(const nsACString &data)
   124 {
   125     mData.Assign(data);
   126     mOffset = 0;
   127     return NS_OK;
   128 }
   130 NS_IMETHODIMP
   131 nsStringInputStream::ToString(char **result)
   132 {
   133     // NOTE: This method may result in data loss, so we do not implement it.
   134     return NS_ERROR_NOT_IMPLEMENTED;
   135 }
   137 /////////
   138 // nsIStringInputStream implementation
   139 /////////
   141 NS_IMETHODIMP
   142 nsStringInputStream::SetData(const char *data, int32_t dataLen)
   143 {
   144     if (NS_WARN_IF(!data))
   145         return NS_ERROR_INVALID_ARG;
   146     mData.Assign(data, dataLen);
   147     mOffset = 0;
   148     return NS_OK;
   149 }
   151 NS_IMETHODIMP
   152 nsStringInputStream::AdoptData(char *data, int32_t dataLen)
   153 {
   154     if (NS_WARN_IF(!data))
   155         return NS_ERROR_INVALID_ARG;
   156     mData.Adopt(data, dataLen);
   157     mOffset = 0;
   158     return NS_OK;
   159 }
   161 NS_IMETHODIMP
   162 nsStringInputStream::ShareData(const char *data, int32_t dataLen)
   163 {
   164     if (NS_WARN_IF(!data))
   165         return NS_ERROR_INVALID_ARG;
   167     if (dataLen < 0)
   168         dataLen = strlen(data);
   170     mData.Rebind(data, dataLen);
   171     mOffset = 0;
   172     return NS_OK;
   173 }
   175 /////////
   176 // nsIInputStream implementation
   177 /////////
   179 NS_IMETHODIMP
   180 nsStringInputStream::Close()
   181 {
   182     Clear();
   183     return NS_OK;
   184 }
   186 NS_IMETHODIMP
   187 nsStringInputStream::Available(uint64_t *aLength)
   188 {
   189     NS_ASSERTION(aLength, "null ptr");
   191     if (Closed())
   192         return NS_BASE_STREAM_CLOSED;
   194     *aLength = LengthRemaining();
   195     return NS_OK;
   196 }
   198 NS_IMETHODIMP
   199 nsStringInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount)
   200 {
   201     NS_ASSERTION(aBuf, "null ptr");
   202     return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
   203 }
   205 NS_IMETHODIMP
   206 nsStringInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
   207                                   uint32_t aCount, uint32_t *result)
   208 {
   209     NS_ASSERTION(result, "null ptr");
   210     NS_ASSERTION(Length() >= mOffset, "bad stream state");
   212     if (Closed())
   213         return NS_BASE_STREAM_CLOSED;
   215     // We may be at end-of-file
   216     uint32_t maxCount = LengthRemaining();
   217     if (maxCount == 0) {
   218         *result = 0;
   219         return NS_OK;
   220     }
   222     if (aCount > maxCount)
   223         aCount = maxCount;
   224     nsresult rv = writer(this, closure, mData.BeginReading() + mOffset, 0, aCount, result);
   225     if (NS_SUCCEEDED(rv)) {
   226         NS_ASSERTION(*result <= aCount,
   227                      "writer should not write more than we asked it to write");
   228         mOffset += *result;
   229     }
   231     // errors returned from the writer end here!
   232     return NS_OK;
   233 }
   235 NS_IMETHODIMP
   236 nsStringInputStream::IsNonBlocking(bool *aNonBlocking)
   237 {
   238     *aNonBlocking = true;
   239     return NS_OK;
   240 }
   242 /////////
   243 // nsISeekableStream implementation
   244 /////////
   246 NS_IMETHODIMP 
   247 nsStringInputStream::Seek(int32_t whence, int64_t offset)
   248 {
   249     if (Closed())
   250         return NS_BASE_STREAM_CLOSED;
   252     // Compute new stream position.  The given offset may be a negative value.
   254     int64_t newPos = offset;
   255     switch (whence) {
   256     case NS_SEEK_SET:
   257         break;
   258     case NS_SEEK_CUR:
   259         newPos += mOffset;
   260         break;
   261     case NS_SEEK_END:
   262         newPos += Length();
   263         break;
   264     default:
   265         NS_ERROR("invalid whence");
   266         return NS_ERROR_INVALID_ARG;
   267     }
   269     if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length()))
   270         return NS_ERROR_INVALID_ARG;
   272     mOffset = (uint32_t)newPos;
   273     return NS_OK;
   274 }
   276 NS_IMETHODIMP
   277 nsStringInputStream::Tell(int64_t* outWhere)
   278 {
   279     if (Closed())
   280         return NS_BASE_STREAM_CLOSED;
   282     *outWhere = mOffset;
   283     return NS_OK;
   284 }
   286 NS_IMETHODIMP
   287 nsStringInputStream::SetEOF()
   288 {
   289     if (Closed())
   290         return NS_BASE_STREAM_CLOSED;
   292     mOffset = Length();
   293     return NS_OK;
   294 }
   296 void
   297 nsStringInputStream::Serialize(InputStreamParams& aParams,
   298                                FileDescriptorArray& /* aFDs */)
   299 {
   300     StringInputStreamParams params;
   301     params.data() = PromiseFlatCString(mData);
   302     aParams = params;
   303 }
   305 bool
   306 nsStringInputStream::Deserialize(const InputStreamParams& aParams,
   307                                  const FileDescriptorArray& /* aFDs */)
   308 {
   309     if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
   310         NS_ERROR("Received unknown parameters from the other process!");
   311         return false;
   312     }
   314     const StringInputStreamParams& params =
   315         aParams.get_StringInputStreamParams();
   317     if (NS_FAILED(SetData(params.data()))) {
   318         NS_WARNING("SetData failed!");
   319         return false;
   320     }
   322     return true;
   323 }
   325 nsresult
   326 NS_NewByteInputStream(nsIInputStream** aStreamResult,
   327                       const char* aStringToRead, int32_t aLength,
   328                       nsAssignmentType aAssignment)
   329 {
   330     NS_PRECONDITION(aStreamResult, "null out ptr");
   332     nsStringInputStream* stream = new nsStringInputStream();
   333     if (! stream)
   334         return NS_ERROR_OUT_OF_MEMORY;
   336     NS_ADDREF(stream);
   338     nsresult rv;
   339     switch (aAssignment) {
   340     case NS_ASSIGNMENT_COPY:
   341         rv = stream->SetData(aStringToRead, aLength);
   342         break;
   343     case NS_ASSIGNMENT_DEPEND:
   344         rv = stream->ShareData(aStringToRead, aLength);
   345         break;
   346     case NS_ASSIGNMENT_ADOPT:
   347         rv = stream->AdoptData(const_cast<char*>(aStringToRead), aLength);
   348         break;
   349     default:
   350         NS_ERROR("invalid assignment type");
   351         rv = NS_ERROR_INVALID_ARG;
   352     }
   354     if (NS_FAILED(rv)) {
   355         NS_RELEASE(stream);
   356         return rv;
   357     }
   359     *aStreamResult = stream;
   360     return NS_OK;
   361 }
   363 nsresult
   364 NS_NewStringInputStream(nsIInputStream** aStreamResult,
   365                         const nsAString& aStringToRead)
   366 {
   367     NS_LossyConvertUTF16toASCII data(aStringToRead); // truncates high-order bytes
   368     return NS_NewCStringInputStream(aStreamResult, data);
   369 }
   371 nsresult
   372 NS_NewCStringInputStream(nsIInputStream** aStreamResult,
   373                          const nsACString& aStringToRead)
   374 {
   375     NS_PRECONDITION(aStreamResult, "null out ptr");
   377     nsStringInputStream* stream = new nsStringInputStream();
   378     if (! stream)
   379         return NS_ERROR_OUT_OF_MEMORY;
   381     NS_ADDREF(stream);
   383     stream->SetData(aStringToRead);
   385     *aStreamResult = stream;
   386     return NS_OK;
   387 }
   389 // factory method for constructing a nsStringInputStream object
   390 nsresult
   391 nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
   392 {
   393     *result = nullptr;
   395     if (NS_WARN_IF(outer))
   396         return NS_ERROR_NO_AGGREGATION;
   398     nsStringInputStream *inst = new nsStringInputStream();
   399     if (!inst)
   400         return NS_ERROR_OUT_OF_MEMORY;
   402     NS_ADDREF(inst);
   403     nsresult rv = inst->QueryInterface(iid, result);
   404     NS_RELEASE(inst);
   406     return rv;
   407 }

mercurial