зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1748719 - Make nsStringInputStream more flexible as to the backing data buffer, r=mccr8
This change aims to make the way that the nsStringInputStream owns the backing data buffer more flexible. This has a few impacts, including allowing arbitrarily large payload sizes on 64-bit platforms, not requiring as complex checks around borrowed string buffers or nsTArray data storage, and supporting custom data ownership schemes such as those used by blobs. The new system uses a separate refcounted object internally to provide the contiguous backing buffer, with the nsStringInputStream wrapping it and providing the `nsIInputStream` interface and cursor. This also avoids issues around the buffer being mutated during reads, as mutating the `nsIInputStream` no longer mutates the actual data storage object. Differential Revision: https://phabricator.services.mozilla.com/D135162
This commit is contained in:
Родитель
7a827c900c
Коммит
4f556b1bea
|
@ -17,19 +17,6 @@
|
|||
|
||||
namespace mozilla::dom {
|
||||
|
||||
NS_IMPL_ADDREF(MemoryBlobImpl::DataOwnerAdapter)
|
||||
NS_IMPL_RELEASE(MemoryBlobImpl::DataOwnerAdapter)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(MemoryBlobImpl::DataOwnerAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITellableStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
|
||||
mSerializableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// static
|
||||
already_AddRefed<MemoryBlobImpl> MemoryBlobImpl::CreateWithCustomLastModified(
|
||||
void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
|
||||
|
@ -51,70 +38,12 @@ already_AddRefed<MemoryBlobImpl> MemoryBlobImpl::CreateWithLastModifiedNow(
|
|||
}
|
||||
|
||||
nsresult MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
size_t aStart, size_t aLength,
|
||||
nsIInputStream** _retval) {
|
||||
nsresult rv;
|
||||
MOZ_ASSERT(aDataOwner, "Uh ...");
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
|
||||
rv = NS_NewByteInputStream(
|
||||
getter_AddRefs(stream),
|
||||
Span(static_cast<const char*>(aDataOwner->mData) + aStart, aLength),
|
||||
NS_ASSIGNMENT_DEPEND);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_retval = new MemoryBlobImpl::DataOwnerAdapter(aDataOwner, stream,
|
||||
aLength));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MemoryBlobImpl::DataOwnerAdapter::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
mozilla::ipc::ChildToParentStreamActorManager* aManager) {
|
||||
SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
|
||||
aSizeUsed, aManager);
|
||||
}
|
||||
|
||||
void MemoryBlobImpl::DataOwnerAdapter::Serialize(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed,
|
||||
mozilla::ipc::ParentToChildStreamActorManager* aManager) {
|
||||
SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
|
||||
aSizeUsed, aManager);
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
void MemoryBlobImpl::DataOwnerAdapter::SerializeInternal(
|
||||
mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
|
||||
MOZ_ASSERT(aSizeUsed);
|
||||
|
||||
// If we'd be serializing the underlying nsStringInputStream as a pipe,
|
||||
// serialize ourselves as a pipe directly instead to avoid the string copy in
|
||||
// nsStringInputStream's serialize method. Otherwise we'll delegate and
|
||||
// serialize as a string internally.
|
||||
if (mLength >= aMaxSize) {
|
||||
*aSizeUsed = 0;
|
||||
mozilla::ipc::InputStreamHelper::SerializeInputStreamAsPipe(
|
||||
this, aParams, aDelayedStart, aManager);
|
||||
return;
|
||||
}
|
||||
|
||||
mSerializableInputStream->Serialize(aParams, aFileDescriptors, aDelayedStart,
|
||||
aMaxSize, aSizeUsed, aManager);
|
||||
}
|
||||
|
||||
bool MemoryBlobImpl::DataOwnerAdapter::Deserialize(
|
||||
const mozilla::ipc::InputStreamParams&, const FileDescriptorArray&) {
|
||||
MOZ_CRASH("This method should never be called");
|
||||
return false;
|
||||
Span data{static_cast<const char*>(aDataOwner->mData) + aStart, aLength};
|
||||
RefPtr adapter = new MemoryBlobImpl::DataOwnerAdapter(aDataOwner, data);
|
||||
return NS_NewByteInputStream(_retval, adapter);
|
||||
}
|
||||
|
||||
already_AddRefed<BlobImpl> MemoryBlobImpl::CreateSlice(
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/StreamBufferSource.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICloneableInputStream.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
@ -104,53 +105,31 @@ class MemoryBlobImpl final : public BaseBlobImpl {
|
|||
uint64_t mLength;
|
||||
};
|
||||
|
||||
class DataOwnerAdapter final : public nsIInputStream,
|
||||
public nsISeekableStream,
|
||||
public nsIIPCSerializableInputStream,
|
||||
public nsICloneableInputStream {
|
||||
class DataOwnerAdapter final : public StreamBufferSource {
|
||||
using DataOwner = MemoryBlobImpl::DataOwner;
|
||||
|
||||
public:
|
||||
static nsresult Create(DataOwner* aDataOwner, uint32_t aStart,
|
||||
uint32_t aLength, nsIInputStream** _retval);
|
||||
static nsresult Create(DataOwner* aDataOwner, size_t aStart, size_t aLength,
|
||||
nsIInputStream** _retval);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
Span<const char> Data() override { return mData; }
|
||||
|
||||
// These are mandatory.
|
||||
NS_FORWARD_NSIINPUTSTREAM(mStream->)
|
||||
NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
|
||||
NS_FORWARD_NSITELLABLESTREAM(mSeekableStream->)
|
||||
NS_FORWARD_NSICLONEABLEINPUTSTREAM(mCloneableInputStream->)
|
||||
// This StreamBufferSource is owning, as the `mData` span references the
|
||||
// immutable data buffer owned by `mDataOwner` which is being kept alive.
|
||||
bool Owning() override { return true; }
|
||||
|
||||
// The memory usage from `DataOwner` is reported elsewhere, so we don't need
|
||||
// to record it here.
|
||||
size_t SizeOfExcludingThisEvenIfShared(MallocSizeOf) override { return 0; }
|
||||
|
||||
private:
|
||||
~DataOwnerAdapter() = default;
|
||||
|
||||
DataOwnerAdapter(DataOwner* aDataOwner, nsIInputStream* aStream,
|
||||
uint32_t aLength)
|
||||
: mDataOwner(aDataOwner),
|
||||
mStream(aStream),
|
||||
mSeekableStream(do_QueryInterface(aStream)),
|
||||
mSerializableInputStream(do_QueryInterface(aStream)),
|
||||
mCloneableInputStream(do_QueryInterface(aStream)),
|
||||
mLength(aLength) {
|
||||
MOZ_ASSERT(
|
||||
mSeekableStream && mSerializableInputStream && mCloneableInputStream,
|
||||
"Somebody gave us the wrong stream!");
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors,
|
||||
bool aDelayedStart, uint32_t aMaxSize,
|
||||
uint32_t* aSizeUsed, M* aManager);
|
||||
DataOwnerAdapter(DataOwner* aDataOwner, Span<const char> aData)
|
||||
: mDataOwner(aDataOwner), mData(aData) {}
|
||||
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
|
||||
nsCOMPtr<nsICloneableInputStream> mCloneableInputStream;
|
||||
uint32_t mLength;
|
||||
Span<const char> mData;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_StreamBufferSource_h
|
||||
#define mozilla_StreamBufferSource_h
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsString.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class StreamBufferSource {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StreamBufferSource)
|
||||
|
||||
virtual Span<const char> Data() = 0;
|
||||
|
||||
virtual nsresult GetData(nsACString& aString) {
|
||||
Span<const char> data = Data();
|
||||
if (!aString.Assign(data.Elements(), data.Length(), fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual bool Owning() = 0;
|
||||
|
||||
virtual size_t SizeOfExcludingThisIfUnshared(MallocSizeOf aMallocSizeOf) {
|
||||
return SizeOfExcludingThisEvenIfShared(aMallocSizeOf);
|
||||
}
|
||||
size_t SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) {
|
||||
if (mRefCnt > 1) {
|
||||
return 0;
|
||||
}
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
virtual size_t SizeOfExcludingThisEvenIfShared(
|
||||
MallocSizeOf aMallocSizeOf) = 0;
|
||||
size_t SizeOfIncludingThisEvenIfShared(MallocSizeOf aMallocSizeOf) {
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += SizeOfExcludingThisEvenIfShared(aMallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~StreamBufferSource() = default;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StreamBufferSource_h
|
|
@ -99,6 +99,7 @@ EXPORTS.mozilla += [
|
|||
"SnappyCompressOutputStream.h",
|
||||
"SnappyFrameUtils.h",
|
||||
"SnappyUncompressInputStream.h",
|
||||
"StreamBufferSource.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
|
@ -7,9 +7,14 @@
|
|||
|
||||
%{C++
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
namespace mozilla {
|
||||
class StreamBufferSource;
|
||||
} // namespace mozilla
|
||||
%}
|
||||
|
||||
native MallocSizeOf(mozilla::MallocSizeOf);
|
||||
[ptr] native StreamBufferSource(mozilla::StreamBufferSource);
|
||||
|
||||
/**
|
||||
* nsIStringInputStream
|
||||
|
@ -71,6 +76,14 @@ interface nsIStringInputStream : nsIInputStream
|
|||
*/
|
||||
[noscript] void shareData(in string data, in long dataLen);
|
||||
|
||||
/**
|
||||
* SetDataSource - assign data to the input stream. the input stream holds
|
||||
* a strong reference to the given data buffer until it is destroyed.
|
||||
*
|
||||
* @param source - stream data source
|
||||
*/
|
||||
[noscript] void setDataSource(in StreamBufferSource source);
|
||||
|
||||
[noscript, notxpcom]
|
||||
size_t SizeOfIncludingThisIfUnshared(in MallocSizeOf aMallocSizeOf);
|
||||
|
||||
|
|
|
@ -24,15 +24,81 @@
|
|||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/StreamBufferSource.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "XPCOMModule.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using mozilla::fallible;
|
||||
using mozilla::MakeRefPtr;
|
||||
using mozilla::MallocSizeOf;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::ReentrantMonitorAutoEnter;
|
||||
using mozilla::Some;
|
||||
using mozilla::Span;
|
||||
using mozilla::StreamBufferSource;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// StreamBufferSource implementations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsTArraySource final : public StreamBufferSource {
|
||||
public:
|
||||
explicit nsTArraySource(nsTArray<uint8_t>&& aArray)
|
||||
: mArray(std::move(aArray)) {}
|
||||
|
||||
Span<const char> Data() override {
|
||||
return Span{reinterpret_cast<const char*>(mArray.Elements()),
|
||||
mArray.Length()};
|
||||
}
|
||||
|
||||
bool Owning() override { return true; }
|
||||
|
||||
size_t SizeOfExcludingThisEvenIfShared(MallocSizeOf aMallocSizeOf) override {
|
||||
return mArray.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
nsTArray<uint8_t> mArray;
|
||||
};
|
||||
|
||||
class nsCStringSource final : public StreamBufferSource {
|
||||
public:
|
||||
nsCStringSource() = default;
|
||||
|
||||
Span<const char> Data() override { return mString; }
|
||||
|
||||
nsresult GetData(nsACString& aString) override {
|
||||
if (!aString.Assign(mString, mozilla::fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool Owning() override { return true; }
|
||||
|
||||
size_t SizeOfExcludingThisIfUnshared(MallocSizeOf aMallocSizeOf) override {
|
||||
return mString.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThisEvenIfShared(MallocSizeOf aMallocSizeOf) override {
|
||||
return mString.SizeOfExcludingThisEvenIfShared(aMallocSizeOf);
|
||||
}
|
||||
|
||||
nsCString mString;
|
||||
};
|
||||
|
||||
class nsBorrowedSource final : public StreamBufferSource {
|
||||
public:
|
||||
explicit nsBorrowedSource(Span<const char> aBuffer) : mBuffer(aBuffer) {}
|
||||
|
||||
Span<const char> Data() override { return mBuffer; }
|
||||
|
||||
bool Owning() override { return false; }
|
||||
|
||||
size_t SizeOfExcludingThisEvenIfShared(MallocSizeOf aMallocSizeOf) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Span<const char> mBuffer;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIStringInputStream implementation
|
||||
|
@ -54,7 +120,7 @@ class nsStringInputStream final : public nsIStringInputStream,
|
|||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
NS_DECL_NSICLONEABLEINPUTSTREAM
|
||||
|
||||
nsStringInputStream() : mOffset(0), mMon("nsStringInputStream") { Clear(); }
|
||||
nsStringInputStream() = default;
|
||||
|
||||
nsresult Init(nsCString&& aString);
|
||||
|
||||
|
@ -67,51 +133,31 @@ class nsStringInputStream final : public nsIStringInputStream,
|
|||
void SerializeInternal(InputStreamParams& aParams, bool aDelayedStart,
|
||||
uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager);
|
||||
|
||||
uint32_t Length() const { return mData.Length(); }
|
||||
size_t Length() const { return mSource ? mSource->Data().Length() : 0; }
|
||||
|
||||
uint32_t LengthRemaining() const { return Length() - mOffset; }
|
||||
size_t LengthRemaining() const { return Length() - mOffset; }
|
||||
|
||||
void Clear() { mData.SetIsVoid(true); }
|
||||
void Clear() { mSource = nullptr; }
|
||||
|
||||
bool Closed() { return mData.IsVoid(); }
|
||||
bool Closed() { return !mSource; }
|
||||
|
||||
nsDependentCSubstring mData;
|
||||
uint32_t mOffset;
|
||||
RefPtr<StreamBufferSource> mSource;
|
||||
size_t mOffset = 0;
|
||||
|
||||
// If we were initialized from an nsTArray, we store its data here.
|
||||
Maybe<nsTArray<uint8_t>> mArray;
|
||||
|
||||
mozilla::ReentrantMonitor mMon;
|
||||
mozilla::ReentrantMonitor mMon{"nsStringInputStream"};
|
||||
};
|
||||
|
||||
nsresult nsStringInputStream::Init(nsCString&& aString) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
mArray.reset();
|
||||
if (!mData.Assign(std::move(aString), fallible)) {
|
||||
auto source = MakeRefPtr<nsCStringSource>();
|
||||
if (!source->mString.Assign(std::move(aString), fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
return NS_OK;
|
||||
return SetDataSource(source);
|
||||
}
|
||||
|
||||
nsresult nsStringInputStream::Init(nsTArray<uint8_t>&& 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<const char*>(mArray->Elements()),
|
||||
mArray->Length());
|
||||
}
|
||||
return NS_OK;
|
||||
auto source = MakeRefPtr<nsTArraySource>(std::move(aArray));
|
||||
return SetDataSource(source);
|
||||
}
|
||||
|
||||
// This class needs to support threadsafe refcounting since people often
|
||||
|
@ -152,21 +198,16 @@ nsStringInputStream::GetData(nsACString& data) {
|
|||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
data.Assign(mData);
|
||||
return NS_OK;
|
||||
return mSource->GetData(data);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringInputStream::SetData(const nsACString& aData) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
mArray.reset();
|
||||
if (NS_WARN_IF(!mData.Assign(aData, fallible))) {
|
||||
auto source = MakeRefPtr<nsCStringSource>();
|
||||
if (!source->mString.Assign(aData, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
return NS_OK;
|
||||
return SetDataSource(source);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -181,19 +222,15 @@ nsStringInputStream::ToString(char** aResult) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsStringInputStream::SetData(const char* aData, int32_t aDataLen) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
if (NS_WARN_IF(!aData)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mArray.reset();
|
||||
if (NS_WARN_IF(!mData.Assign(aData, aDataLen, fallible))) {
|
||||
auto source = MakeRefPtr<nsCStringSource>();
|
||||
if (NS_WARN_IF(!source->mString.Assign(aData, aDataLen, fallible))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
return NS_OK;
|
||||
return SetDataSource(source);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -203,31 +240,35 @@ nsStringInputStream::SetUTF8Data(const nsACString& aData) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsStringInputStream::AdoptData(char* aData, int32_t aDataLen) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
if (NS_WARN_IF(!aData)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mArray.reset();
|
||||
mData.Adopt(aData, aDataLen);
|
||||
mOffset = 0;
|
||||
return NS_OK;
|
||||
|
||||
auto source = MakeRefPtr<nsCStringSource>();
|
||||
source->mString.Adopt(aData, aDataLen);
|
||||
return SetDataSource(source);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringInputStream::ShareData(const char* aData, int32_t aDataLen) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
if (NS_WARN_IF(!aData)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mArray.reset();
|
||||
if (aDataLen < 0) {
|
||||
aDataLen = strlen(aData);
|
||||
size_t length = aDataLen < 0 ? strlen(aData) : size_t(aDataLen);
|
||||
auto source = MakeRefPtr<nsBorrowedSource>(Span{aData, length});
|
||||
return SetDataSource(source);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStringInputStream::SetDataSource(StreamBufferSource* aSource) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
if (NS_WARN_IF(!aSource)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mData.Rebind(aData, aDataLen);
|
||||
mSource = aSource;
|
||||
mOffset = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -237,7 +278,9 @@ nsStringInputStream::SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) {
|
|||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
if (mSource) {
|
||||
n += mSource->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -247,7 +290,9 @@ nsStringInputStream::SizeOfIncludingThisEvenIfShared(
|
|||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += mData.SizeOfExcludingThisEvenIfShared(aMallocSizeOf);
|
||||
if (mSource) {
|
||||
n += mSource->SizeOfIncludingThisEvenIfShared(aMallocSizeOf);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -296,7 +341,7 @@ nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
|||
}
|
||||
|
||||
// We may be at end-of-file
|
||||
uint32_t maxCount = LengthRemaining();
|
||||
size_t maxCount = LengthRemaining();
|
||||
if (maxCount == 0) {
|
||||
*aResult = 0;
|
||||
return NS_OK;
|
||||
|
@ -306,26 +351,24 @@ nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
|||
aCount = maxCount;
|
||||
}
|
||||
|
||||
nsDependentCSubstring tempData;
|
||||
tempData.SetIsVoid(true);
|
||||
if (mData.GetDataFlags() & nsACString::DataFlags::OWNED) {
|
||||
tempData.Assign(std::move(mData));
|
||||
mData.Rebind(tempData.BeginReading(), tempData.EndReading());
|
||||
}
|
||||
RefPtr<StreamBufferSource> source = mSource;
|
||||
size_t offset = mOffset;
|
||||
|
||||
nsresult rv = aWriter(this, aClosure, mData.BeginReading() + mOffset, 0,
|
||||
nsresult rv = aWriter(this, aClosure, source->Data().Elements() + offset, 0,
|
||||
aCount, aResult);
|
||||
|
||||
if (!mData.IsVoid() && !tempData.IsVoid()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mData == tempData, "String was replaced!");
|
||||
mData.SetIsVoid(true);
|
||||
mData.Assign(std::move(tempData));
|
||||
if (Closed()) {
|
||||
NS_WARNING("nsStringInputStream was closed during ReadSegments");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(mSource == source, "String was replaced!");
|
||||
MOZ_RELEASE_ASSERT(mOffset == offset, "Nested read operation!");
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(*aResult <= aCount,
|
||||
"writer should not write more than we asked it to write");
|
||||
mOffset += *aResult;
|
||||
mOffset = offset + *aResult;
|
||||
}
|
||||
|
||||
// errors returned from the writer end here!
|
||||
|
@ -357,21 +400,21 @@ nsStringInputStream::Seek(int32_t aWhence, int64_t aOffset) {
|
|||
case NS_SEEK_SET:
|
||||
break;
|
||||
case NS_SEEK_CUR:
|
||||
newPos += mOffset;
|
||||
newPos += (int64_t)mOffset;
|
||||
break;
|
||||
case NS_SEEK_END:
|
||||
newPos += Length();
|
||||
newPos += (int64_t)Length();
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("invalid aWhence");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length())) {
|
||||
if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > (int64_t)Length())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mOffset = (uint32_t)newPos;
|
||||
mOffset = (size_t)newPos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -399,7 +442,7 @@ nsStringInputStream::Tell(int64_t* aOutWhere) {
|
|||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
*aOutWhere = mOffset;
|
||||
*aOutWhere = (int64_t)mOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -428,17 +471,18 @@ void nsStringInputStream::SerializeInternal(InputStreamParams& aParams,
|
|||
uint32_t* aSizeUsed, M* aManager) {
|
||||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Closed(), "cannot send a closed stream!");
|
||||
MOZ_ASSERT(aSizeUsed);
|
||||
*aSizeUsed = 0;
|
||||
|
||||
if (Length() >= aMaxSize) {
|
||||
// If the input stream is non-owning (i.e. it was initialized with
|
||||
// `ShareData`), request mutable access to `mData`, forcing our string to
|
||||
// take ownership so that it doesn't go away while async copying.
|
||||
if (!mArray && !(mData.GetDataFlags() & (nsCString::DataFlags::REFCOUNTED |
|
||||
nsCString::DataFlags::OWNED |
|
||||
nsCString::DataFlags::LITERAL))) {
|
||||
mData.BeginWriting();
|
||||
// `ShareData`), create a new owning source so that it doesn't go away while
|
||||
// async copying.
|
||||
if (!mSource->Owning()) {
|
||||
auto source = MakeRefPtr<nsCStringSource>();
|
||||
source->mString.Assign(nsDependentCSubstring{mSource->Data()});
|
||||
mSource = source;
|
||||
}
|
||||
|
||||
InputStreamHelper::SerializeInputStreamAsPipe(this, aParams, aDelayedStart,
|
||||
|
@ -449,7 +493,7 @@ void nsStringInputStream::SerializeInternal(InputStreamParams& aParams,
|
|||
*aSizeUsed = Length();
|
||||
|
||||
StringInputStreamParams params;
|
||||
params.data() = PromiseFlatCString(mData);
|
||||
mSource->GetData(params.data());
|
||||
aParams = params;
|
||||
}
|
||||
|
||||
|
@ -485,9 +529,14 @@ nsStringInputStream::Clone(nsIInputStream** aCloneOut) {
|
|||
ReentrantMonitorAutoEnter lock(mMon);
|
||||
|
||||
RefPtr<nsStringInputStream> ref = new nsStringInputStream();
|
||||
nsresult rv = ref->SetData(mData);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
if (mSource && !mSource->Owning()) {
|
||||
auto data = mSource->Data();
|
||||
nsresult rv = ref->SetData(data.Elements(), data.Length());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
ref->mSource = mSource;
|
||||
}
|
||||
|
||||
// mOffset is overwritten by SetData().
|
||||
|
@ -544,6 +593,21 @@ nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
|
||||
mozilla::StreamBufferSource* aSource) {
|
||||
MOZ_ASSERT(aStreamResult, "null out ptr");
|
||||
|
||||
RefPtr<nsStringInputStream> stream = new nsStringInputStream();
|
||||
|
||||
nsresult rv = stream->SetDataSource(aSource);
|
||||
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");
|
||||
|
|
|
@ -59,6 +59,16 @@ extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
|
|||
extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
|
||||
nsTArray<uint8_t>&& aArray);
|
||||
|
||||
/**
|
||||
* Factory method to get an nsIInputStream from an arbitrary StreamBufferSource.
|
||||
* This will take a strong reference to the source.
|
||||
*
|
||||
* Result will implement nsIStringInputStream, nsITellableStream and
|
||||
* nsISeekableStream.
|
||||
*/
|
||||
extern nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult,
|
||||
mozilla::StreamBufferSource* aSource);
|
||||
|
||||
/**
|
||||
* Factory method to get an nsInputStream from an nsACString. Result will
|
||||
* implement nsIStringInputStream, nsTellableStream and nsISeekableStream.
|
||||
|
|
Загрузка…
Ссылка в новой задаче