From 17561de5b9402e69dd9cc371a50c655bd2be1fe5 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 15 May 2019 18:28:00 +0000 Subject: [PATCH] Bug 1551962. Add a way to create an input stream from a moved nsTArray. r=froydnj Differential Revision: https://phabricator.services.mozilla.com/D31296 --HG-- extra : moz-landing-system : lando --- xpcom/io/nsStringStream.cpp | 44 +++++++++++++++++++++++++++++++++++++ xpcom/io/nsStringStream.h | 14 +++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/xpcom/io/nsStringStream.cpp b/xpcom/io/nsStringStream.cpp index de9f9212a6c4..eae8d901e875 100644 --- a/xpcom/io/nsStringStream.cpp +++ b/xpcom/io/nsStringStream.cpp @@ -22,6 +22,7 @@ #include "nsIClassInfoImpl.h" #include "mozilla/Attributes.h" #include "mozilla/ipc/InputStreamUtils.h" +#include "mozilla/Maybe.h" #include "mozilla/ReentrantMonitor.h" #include "nsIIPCSerializableInputStream.h" #include "XPCOMModule.h" @@ -54,6 +55,8 @@ class nsStringInputStream final : public nsIStringInputStream, nsresult Init(nsCString&& aString); + nsresult Init(nsTArray&& aArray); + private: ~nsStringInputStream() {} @@ -72,12 +75,16 @@ class nsStringInputStream final : public nsIStringInputStream, nsDependentCSubstring mData; uint32_t mOffset; + // If we were initialized from an nsTArray, we store its data here. + Maybe> mArray; + mozilla::ReentrantMonitor mMon; }; nsresult nsStringInputStream::Init(nsCString&& aString) { ReentrantMonitorAutoEnter lock(mMon); + mArray.reset(); if (!mData.Assign(std::move(aString), fallible)) { return NS_ERROR_OUT_OF_MEMORY; } @@ -86,6 +93,24 @@ nsresult nsStringInputStream::Init(nsCString&& aString) { return NS_OK; } +nsresult nsStringInputStream::Init(nsTArray&& aArray) { + ReentrantMonitorAutoEnter lock(mMon); + + mArray.reset(); + mArray.emplace(std::move(aArray)); + mOffset = 0; + + if (mArray->IsEmpty()) { + // Not sure it's safe to Rebind() with a null pointer. Pretty + // sure it's not, in fact. + mData.Truncate(); + } else { + mData.Rebind(reinterpret_cast(mArray->Elements()), + mArray->Length()); + } + return NS_OK; +} + // This class needs to support threadsafe refcounting since people often // allocate a string stream, and then read it from a background thread. NS_IMPL_ADDREF(nsStringInputStream) @@ -132,6 +157,7 @@ NS_IMETHODIMP nsStringInputStream::SetData(const nsACString& aData) { ReentrantMonitorAutoEnter lock(mMon); + mArray.reset(); if (NS_WARN_IF(!mData.Assign(aData, fallible))) { return NS_ERROR_OUT_OF_MEMORY; } @@ -158,6 +184,7 @@ nsStringInputStream::SetData(const char* aData, int32_t aDataLen) { return NS_ERROR_INVALID_ARG; } + mArray.reset(); if (NS_WARN_IF(!mData.Assign(aData, aDataLen, fallible))) { return NS_ERROR_OUT_OF_MEMORY; } @@ -173,6 +200,7 @@ nsStringInputStream::AdoptData(char* aData, int32_t aDataLen) { if (NS_WARN_IF(!aData)) { return NS_ERROR_INVALID_ARG; } + mArray.reset(); mData.Adopt(aData, aDataLen); mOffset = 0; return NS_OK; @@ -186,6 +214,7 @@ nsStringInputStream::ShareData(const char* aData, int32_t aDataLen) { return NS_ERROR_INVALID_ARG; } + mArray.reset(); if (aDataLen < 0) { aDataLen = strlen(aData); } @@ -486,6 +515,21 @@ nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult, return NS_OK; } +nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult, + nsTArray&& aArray) { + MOZ_ASSERT(aStreamResult, "null out ptr"); + + RefPtr stream = new nsStringInputStream(); + + nsresult rv = stream->Init(std::move(aArray)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + stream.forget(aStreamResult); + return NS_OK; +} + nsresult NS_NewCStringInputStream(nsIInputStream** aStreamResult, const nsACString& aStringToRead) { MOZ_ASSERT(aStreamResult, "null out ptr"); diff --git a/xpcom/io/nsStringStream.h b/xpcom/io/nsStringStream.h index 1fdb35d20a29..b2101b14abac 100644 --- a/xpcom/io/nsStringStream.h +++ b/xpcom/io/nsStringStream.h @@ -10,6 +10,7 @@ #include "nsIStringStream.h" #include "nsString.h" #include "nsMemory.h" +#include "nsTArray.h" /** * Implements: @@ -43,14 +44,21 @@ * If aAssignment is NS_ASSIGNMENT_ADOPT, then the resulting stream refers * directly to the given buffer (aStringToRead) and will free aStringToRead * once the stream is closed. - * - * If aLength is less than zero, then the length of aStringToRead will be - * determined by scanning the buffer for the first null byte. */ extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult, mozilla::Span aStringToRead, nsAssignmentType aAssignment); +/** + * Factory method to get an nsIInputStream from an nsTArray representing a byte + * buffer. This will take ownership of the data and empty out the nsTArray. + * + * Result will implement nsIStringInputStream, nsITellableStream and + * nsISeekableStream. + */ +extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult, + nsTArray&& aArray); + /** * Factory method to get an nsInputStream from an nsACString. Result will * implement nsIStringInputStream, nsTellableStream and nsISeekableStream.