mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 08:42:13 +00:00
c4b00a432d
Differential Revision: https://phabricator.services.mozilla.com/D199852
669 lines
18 KiB
C++
669 lines
18 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "SlicedInputStream.h"
|
|
#include "mozilla/ipc/InputStreamUtils.h"
|
|
#include "mozilla/CheckedInt.h"
|
|
#include "mozilla/ScopeExit.h"
|
|
#include "nsISeekableStream.h"
|
|
#include "nsStreamUtils.h"
|
|
|
|
namespace mozilla {
|
|
|
|
using namespace ipc;
|
|
|
|
NS_IMPL_ADDREF(SlicedInputStream);
|
|
NS_IMPL_RELEASE(SlicedInputStream);
|
|
|
|
NS_INTERFACE_MAP_BEGIN(SlicedInputStream)
|
|
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
|
|
mWeakCloneableInputStream || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
|
|
nsIIPCSerializableInputStream,
|
|
mWeakIPCSerializableInputStream || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream,
|
|
mWeakSeekableInputStream || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITellableStream,
|
|
mWeakTellableInputStream || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
|
|
mWeakAsyncInputStream || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
|
|
mWeakAsyncInputStream || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLength,
|
|
mWeakInputStreamLength || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
|
|
nsIAsyncInputStreamLength, mWeakAsyncInputStreamLength || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
|
|
nsIInputStreamLengthCallback,
|
|
mWeakAsyncInputStreamLength || !mInputStream)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
SlicedInputStream::SlicedInputStream(
|
|
already_AddRefed<nsIInputStream> aInputStream, uint64_t aStart,
|
|
uint64_t aLength)
|
|
: mWeakCloneableInputStream(nullptr),
|
|
mWeakIPCSerializableInputStream(nullptr),
|
|
mWeakSeekableInputStream(nullptr),
|
|
mWeakTellableInputStream(nullptr),
|
|
mWeakAsyncInputStream(nullptr),
|
|
mWeakInputStreamLength(nullptr),
|
|
mWeakAsyncInputStreamLength(nullptr),
|
|
mStart(aStart),
|
|
mLength(aLength),
|
|
mCurPos(0),
|
|
mClosed(false),
|
|
mAsyncWaitFlags(0),
|
|
mAsyncWaitRequestedCount(0),
|
|
mMutex("SlicedInputStream::mMutex") {
|
|
nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
|
|
SetSourceStream(inputStream.forget());
|
|
}
|
|
|
|
SlicedInputStream::SlicedInputStream()
|
|
: mWeakCloneableInputStream(nullptr),
|
|
mWeakIPCSerializableInputStream(nullptr),
|
|
mWeakSeekableInputStream(nullptr),
|
|
mWeakTellableInputStream(nullptr),
|
|
mWeakAsyncInputStream(nullptr),
|
|
mWeakInputStreamLength(nullptr),
|
|
mWeakAsyncInputStreamLength(nullptr),
|
|
mStart(0),
|
|
mLength(0),
|
|
mCurPos(0),
|
|
mClosed(false),
|
|
mAsyncWaitFlags(0),
|
|
mAsyncWaitRequestedCount(0),
|
|
mMutex("SlicedInputStream::mMutex") {}
|
|
|
|
SlicedInputStream::~SlicedInputStream() = default;
|
|
|
|
void SlicedInputStream::SetSourceStream(
|
|
already_AddRefed<nsIInputStream> aInputStream) {
|
|
MOZ_ASSERT(!mInputStream);
|
|
|
|
mInputStream = std::move(aInputStream);
|
|
|
|
nsCOMPtr<nsICloneableInputStream> cloneableStream =
|
|
do_QueryInterface(mInputStream);
|
|
if (cloneableStream && SameCOMIdentity(mInputStream, cloneableStream)) {
|
|
mWeakCloneableInputStream = cloneableStream;
|
|
}
|
|
|
|
nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
|
|
do_QueryInterface(mInputStream);
|
|
if (serializableStream && SameCOMIdentity(mInputStream, serializableStream)) {
|
|
mWeakIPCSerializableInputStream = serializableStream;
|
|
}
|
|
|
|
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mInputStream);
|
|
if (seekableStream && SameCOMIdentity(mInputStream, seekableStream)) {
|
|
mWeakSeekableInputStream = seekableStream;
|
|
}
|
|
|
|
nsCOMPtr<nsITellableStream> tellableStream = do_QueryInterface(mInputStream);
|
|
if (tellableStream && SameCOMIdentity(mInputStream, tellableStream)) {
|
|
mWeakTellableInputStream = tellableStream;
|
|
}
|
|
|
|
nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
|
|
do_QueryInterface(mInputStream);
|
|
if (asyncInputStream && SameCOMIdentity(mInputStream, asyncInputStream)) {
|
|
mWeakAsyncInputStream = asyncInputStream;
|
|
}
|
|
|
|
nsCOMPtr<nsIInputStreamLength> streamLength = do_QueryInterface(mInputStream);
|
|
if (streamLength && SameCOMIdentity(mInputStream, streamLength)) {
|
|
mWeakInputStreamLength = streamLength;
|
|
}
|
|
|
|
nsCOMPtr<nsIAsyncInputStreamLength> asyncStreamLength =
|
|
do_QueryInterface(mInputStream);
|
|
if (asyncStreamLength && SameCOMIdentity(mInputStream, asyncStreamLength)) {
|
|
mWeakAsyncInputStreamLength = asyncStreamLength;
|
|
}
|
|
}
|
|
|
|
uint64_t SlicedInputStream::AdjustRange(uint64_t aRange) {
|
|
CheckedUint64 range(aRange);
|
|
range += mCurPos;
|
|
|
|
// Let's remove extra length from the end.
|
|
if (range.isValid() && range.value() > mStart + mLength) {
|
|
aRange -= XPCOM_MIN((uint64_t)aRange, range.value() - (mStart + mLength));
|
|
}
|
|
|
|
// Let's remove extra length from the begin.
|
|
if (mCurPos < mStart) {
|
|
aRange -= XPCOM_MIN((uint64_t)aRange, mStart - mCurPos);
|
|
}
|
|
|
|
return aRange;
|
|
}
|
|
|
|
// nsIInputStream interface
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Close() {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
|
|
mClosed = true;
|
|
return mInputStream->Close();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Available(uint64_t* aLength) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
|
|
if (mClosed) {
|
|
return NS_BASE_STREAM_CLOSED;
|
|
}
|
|
|
|
nsresult rv = mInputStream->Available(aLength);
|
|
if (rv == NS_BASE_STREAM_CLOSED) {
|
|
mClosed = true;
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
*aLength = AdjustRange(*aLength);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::StreamStatus() {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
|
|
if (mClosed) {
|
|
return NS_BASE_STREAM_CLOSED;
|
|
}
|
|
|
|
nsresult rv = mInputStream->StreamStatus();
|
|
if (rv == NS_BASE_STREAM_CLOSED) {
|
|
mClosed = true;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) {
|
|
*aReadCount = 0;
|
|
|
|
if (mClosed) {
|
|
return NS_OK;
|
|
}
|
|
|
|
if (mCurPos < mStart) {
|
|
nsCOMPtr<nsISeekableStream> seekableStream =
|
|
do_QueryInterface(mInputStream);
|
|
if (seekableStream) {
|
|
nsresult rv =
|
|
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, mStart);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurPos = mStart;
|
|
} else {
|
|
char buf[4096];
|
|
while (mCurPos < mStart) {
|
|
uint32_t bytesRead;
|
|
uint64_t bufCount = XPCOM_MIN(mStart - mCurPos, (uint64_t)sizeof(buf));
|
|
nsresult rv = mInputStream->Read(buf, bufCount, &bytesRead);
|
|
if (NS_SUCCEEDED(rv) && bytesRead == 0) {
|
|
mClosed = true;
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurPos += bytesRead;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Let's reduce aCount in case it's too big.
|
|
if (mCurPos + aCount > mStart + mLength) {
|
|
aCount = mStart + mLength - mCurPos;
|
|
}
|
|
|
|
// Nothing else to read.
|
|
if (!aCount) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult rv = mInputStream->Read(aBuffer, aCount, aReadCount);
|
|
if (NS_SUCCEEDED(rv) && *aReadCount == 0) {
|
|
mClosed = true;
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurPos += *aReadCount;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
|
uint32_t aCount, uint32_t* aResult) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::IsNonBlocking(bool* aNonBlocking) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
return mInputStream->IsNonBlocking(aNonBlocking);
|
|
}
|
|
|
|
// nsICloneableInputStream interface
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::GetCloneable(bool* aCloneable) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakCloneableInputStream);
|
|
|
|
*aCloneable = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Clone(nsIInputStream** aResult) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakCloneableInputStream);
|
|
|
|
nsCOMPtr<nsIInputStream> clonedStream;
|
|
nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIInputStream> sis =
|
|
new SlicedInputStream(clonedStream.forget(), mStart, mLength);
|
|
|
|
sis.forget(aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
// nsIAsyncInputStream interface
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::CloseWithStatus(nsresult aStatus) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakAsyncInputStream);
|
|
|
|
mClosed = true;
|
|
return mWeakAsyncInputStream->CloseWithStatus(aStatus);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::AsyncWait(nsIInputStreamCallback* aCallback, uint32_t aFlags,
|
|
uint32_t aRequestedCount,
|
|
nsIEventTarget* aEventTarget) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakAsyncInputStream);
|
|
|
|
nsCOMPtr<nsIInputStreamCallback> callback = aCallback ? this : nullptr;
|
|
|
|
uint32_t flags = aFlags;
|
|
uint32_t requestedCount = aRequestedCount;
|
|
|
|
{
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (NS_WARN_IF(mAsyncWaitCallback && aCallback &&
|
|
mAsyncWaitCallback != aCallback)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
mAsyncWaitCallback = aCallback;
|
|
|
|
// If we haven't started retrieving data, let's see if we can seek.
|
|
// If we cannot seek, we will do consecutive reads.
|
|
if (mCurPos < mStart && mWeakSeekableInputStream) {
|
|
nsresult rv = mWeakSeekableInputStream->Seek(
|
|
nsISeekableStream::NS_SEEK_SET, mStart);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurPos = mStart;
|
|
}
|
|
|
|
mAsyncWaitFlags = aFlags;
|
|
mAsyncWaitRequestedCount = aRequestedCount;
|
|
mAsyncWaitEventTarget = aEventTarget;
|
|
|
|
// If we are not at the right position, let's do an asyncWait just internal.
|
|
if (mCurPos < mStart) {
|
|
flags = 0;
|
|
requestedCount = mStart - mCurPos;
|
|
}
|
|
}
|
|
|
|
return mWeakAsyncInputStream->AsyncWait(callback, flags, requestedCount,
|
|
aEventTarget);
|
|
}
|
|
|
|
// nsIInputStreamCallback
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|
MOZ_ASSERT(mInputStream);
|
|
MOZ_ASSERT(mWeakAsyncInputStream);
|
|
MOZ_ASSERT(mWeakAsyncInputStream == aStream);
|
|
|
|
nsCOMPtr<nsIInputStreamCallback> callback;
|
|
uint32_t asyncWaitFlags = 0;
|
|
uint32_t asyncWaitRequestedCount = 0;
|
|
nsCOMPtr<nsIEventTarget> asyncWaitEventTarget;
|
|
|
|
{
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
// We have been canceled in the meanwhile.
|
|
if (!mAsyncWaitCallback) {
|
|
return NS_OK;
|
|
}
|
|
|
|
auto raii = MakeScopeExit([&] {
|
|
mMutex.AssertCurrentThreadOwns();
|
|
mAsyncWaitCallback = nullptr;
|
|
mAsyncWaitEventTarget = nullptr;
|
|
});
|
|
|
|
asyncWaitFlags = mAsyncWaitFlags;
|
|
asyncWaitRequestedCount = mAsyncWaitRequestedCount;
|
|
asyncWaitEventTarget = mAsyncWaitEventTarget;
|
|
|
|
// If at the end of this locked block, the callback is not null, it will be
|
|
// executed, otherwise, we are going to exec another AsyncWait().
|
|
callback = mAsyncWaitCallback;
|
|
|
|
if (mCurPos < mStart) {
|
|
char buf[4096];
|
|
nsresult rv = NS_OK;
|
|
while (mCurPos < mStart) {
|
|
uint32_t bytesRead;
|
|
uint64_t bufCount = XPCOM_MIN(mStart - mCurPos, (uint64_t)sizeof(buf));
|
|
rv = mInputStream->Read(buf, bufCount, &bytesRead);
|
|
if (NS_SUCCEEDED(rv) && bytesRead == 0) {
|
|
mClosed = true;
|
|
break;
|
|
}
|
|
|
|
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
|
asyncWaitFlags = 0;
|
|
asyncWaitRequestedCount = mStart - mCurPos;
|
|
// Here we want to exec another AsyncWait().
|
|
callback = nullptr;
|
|
break;
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
break;
|
|
}
|
|
|
|
mCurPos += bytesRead;
|
|
}
|
|
|
|
// Now we are ready to do the 'real' asyncWait.
|
|
if (mCurPos >= mStart) {
|
|
// We don't want to nullify the callback now, because it will be needed
|
|
// at the next ::OnInputStreamReady.
|
|
raii.release();
|
|
callback = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (callback) {
|
|
return callback->OnInputStreamReady(this);
|
|
}
|
|
|
|
return mWeakAsyncInputStream->AsyncWait(
|
|
this, asyncWaitFlags, asyncWaitRequestedCount, asyncWaitEventTarget);
|
|
}
|
|
|
|
// nsIIPCSerializableInputStream
|
|
|
|
void SlicedInputStream::SerializedComplexity(uint32_t aMaxSize,
|
|
uint32_t* aSizeUsed,
|
|
uint32_t* aPipes,
|
|
uint32_t* aTransferables) {
|
|
InputStreamHelper::SerializedComplexity(mInputStream, aMaxSize, aSizeUsed,
|
|
aPipes, aTransferables);
|
|
|
|
// If we're going to be serializing a pipe to transfer the sliced data, and we
|
|
// are getting no efficiency improvements from transferables, stream this
|
|
// sliced input stream directly as a pipe to avoid streaming data which will
|
|
// be sliced off anyway.
|
|
if (*aPipes > 0 && *aTransferables == 0) {
|
|
*aSizeUsed = 0;
|
|
*aPipes = 1;
|
|
*aTransferables = 0;
|
|
}
|
|
}
|
|
|
|
void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
|
|
uint32_t aMaxSize, uint32_t* aSizeUsed) {
|
|
MOZ_ASSERT(mInputStream);
|
|
MOZ_ASSERT(mWeakIPCSerializableInputStream);
|
|
|
|
uint32_t sizeUsed = 0, pipes = 0, transferables = 0;
|
|
SerializedComplexity(aMaxSize, &sizeUsed, &pipes, &transferables);
|
|
if (pipes > 0 && transferables == 0) {
|
|
InputStreamHelper::SerializeInputStreamAsPipe(this, aParams);
|
|
return;
|
|
}
|
|
|
|
SlicedInputStreamParams params;
|
|
InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
|
|
aMaxSize, aSizeUsed);
|
|
params.start() = mStart;
|
|
params.length() = mLength;
|
|
params.curPos() = mCurPos;
|
|
params.closed() = mClosed;
|
|
|
|
aParams = params;
|
|
}
|
|
|
|
bool SlicedInputStream::Deserialize(
|
|
const mozilla::ipc::InputStreamParams& aParams) {
|
|
MOZ_ASSERT(!mInputStream);
|
|
MOZ_ASSERT(!mWeakIPCSerializableInputStream);
|
|
|
|
if (aParams.type() != InputStreamParams::TSlicedInputStreamParams) {
|
|
NS_ERROR("Received unknown parameters from the other process!");
|
|
return false;
|
|
}
|
|
|
|
const SlicedInputStreamParams& params = aParams.get_SlicedInputStreamParams();
|
|
|
|
nsCOMPtr<nsIInputStream> stream =
|
|
InputStreamHelper::DeserializeInputStream(params.stream());
|
|
if (!stream) {
|
|
NS_WARNING("Deserialize failed!");
|
|
return false;
|
|
}
|
|
|
|
SetSourceStream(stream.forget());
|
|
|
|
mStart = params.start();
|
|
mLength = params.length();
|
|
mCurPos = params.curPos();
|
|
mClosed = params.closed();
|
|
|
|
return true;
|
|
}
|
|
|
|
// nsISeekableStream
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Seek(int32_t aWhence, int64_t aOffset) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakSeekableInputStream);
|
|
|
|
int64_t offset;
|
|
nsresult rv;
|
|
|
|
switch (aWhence) {
|
|
case NS_SEEK_SET:
|
|
offset = mStart + aOffset;
|
|
break;
|
|
case NS_SEEK_CUR:
|
|
// mCurPos could be lower than mStart if the reading has not started yet.
|
|
offset = XPCOM_MAX(mStart, mCurPos) + aOffset;
|
|
break;
|
|
case NS_SEEK_END: {
|
|
uint64_t available;
|
|
rv = mInputStream->Available(&available);
|
|
if (rv == NS_BASE_STREAM_CLOSED) {
|
|
mClosed = true;
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
offset = XPCOM_MIN(mStart + mLength, available) + aOffset;
|
|
break;
|
|
}
|
|
default:
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
|
|
if (offset < (int64_t)mStart || offset > (int64_t)(mStart + mLength)) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
rv = mWeakSeekableInputStream->Seek(NS_SEEK_SET, offset);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurPos = offset;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::SetEOF() {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakSeekableInputStream);
|
|
|
|
mClosed = true;
|
|
return mWeakSeekableInputStream->SetEOF();
|
|
}
|
|
|
|
// nsITellableStream
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Tell(int64_t* aResult) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakTellableInputStream);
|
|
|
|
int64_t tell = 0;
|
|
|
|
nsresult rv = mWeakTellableInputStream->Tell(&tell);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
if (tell < (int64_t)mStart) {
|
|
*aResult = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
*aResult = tell - mStart;
|
|
if (*aResult > (int64_t)mLength) {
|
|
*aResult = mLength;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// nsIInputStreamLength
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::Length(int64_t* aLength) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakInputStreamLength);
|
|
|
|
nsresult rv = mWeakInputStreamLength->Length(aLength);
|
|
if (rv == NS_BASE_STREAM_CLOSED) {
|
|
mClosed = true;
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
if (*aLength == -1) {
|
|
return NS_OK;
|
|
}
|
|
|
|
*aLength = (int64_t)AdjustRange((uint64_t)*aLength);
|
|
return NS_OK;
|
|
}
|
|
|
|
// nsIAsyncInputStreamLength
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
|
|
nsIEventTarget* aEventTarget) {
|
|
NS_ENSURE_STATE(mInputStream);
|
|
NS_ENSURE_STATE(mWeakAsyncInputStreamLength);
|
|
|
|
nsCOMPtr<nsIInputStreamLengthCallback> callback = aCallback ? this : nullptr;
|
|
{
|
|
MutexAutoLock lock(mMutex);
|
|
mAsyncWaitLengthCallback = aCallback;
|
|
}
|
|
|
|
return mWeakAsyncInputStreamLength->AsyncLengthWait(callback, aEventTarget);
|
|
}
|
|
|
|
// nsIInputStreamLengthCallback
|
|
|
|
NS_IMETHODIMP
|
|
SlicedInputStream::OnInputStreamLengthReady(nsIAsyncInputStreamLength* aStream,
|
|
int64_t aLength) {
|
|
MOZ_ASSERT(mInputStream);
|
|
MOZ_ASSERT(mWeakAsyncInputStreamLength);
|
|
MOZ_ASSERT(mWeakAsyncInputStreamLength == aStream);
|
|
|
|
nsCOMPtr<nsIInputStreamLengthCallback> callback;
|
|
{
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
// We have been canceled in the meanwhile.
|
|
if (!mAsyncWaitLengthCallback) {
|
|
return NS_OK;
|
|
}
|
|
|
|
callback.swap(mAsyncWaitLengthCallback);
|
|
}
|
|
|
|
if (aLength != -1) {
|
|
aLength = (int64_t)AdjustRange((uint64_t)aLength);
|
|
}
|
|
|
|
MOZ_ASSERT(callback);
|
|
return callback->OnInputStreamLengthReady(this, aLength);
|
|
}
|
|
|
|
} // namespace mozilla
|