mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-18 14:56:07 +00:00
Bug 730765 - Media cache shouldn't be used when loading from blob: urls. r=biesi
This commit is contained in:
parent
b89a18ff9f
commit
6ad35d0369
@ -42,6 +42,7 @@ nsReferencedElement.h \
|
||||
nsTreeSanitizer.h \
|
||||
nsXMLNameSpaceMap.h \
|
||||
nsIXFormsUtilityService.h \
|
||||
nsBlobProtocolHandler.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/dom mozilla
|
||||
|
51
content/base/public/nsBlobProtocolHandler.h
Normal file
51
content/base/public/nsBlobProtocolHandler.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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 nsBlobProtocolHandler_h
|
||||
#define nsBlobProtocolHandler_h
|
||||
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define BLOBURI_SCHEME "blob"
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIPrincipal;
|
||||
class nsIInputStream;
|
||||
|
||||
inline bool IsBlobURI(nsIURI* aUri)
|
||||
{
|
||||
bool isBlob;
|
||||
return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
|
||||
}
|
||||
|
||||
extern nsresult
|
||||
NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
|
||||
|
||||
class nsBlobProtocolHandler : public nsIProtocolHandler
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIProtocolHandler methods:
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
|
||||
// nsBlobProtocolHandler methods:
|
||||
nsBlobProtocolHandler() {}
|
||||
virtual ~nsBlobProtocolHandler() {}
|
||||
|
||||
// Methods for managing uri->file mapping
|
||||
static void AddFileDataEntry(nsACString& aUri,
|
||||
nsIDOMBlob* aFile,
|
||||
nsIPrincipal* aPrincipal);
|
||||
static void RemoveFileDataEntry(nsACString& aUri);
|
||||
static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
|
||||
};
|
||||
|
||||
#define NS_BLOBPROTOCOLHANDLER_CID \
|
||||
{ 0xb43964aa, 0xa078, 0x44b2, \
|
||||
{ 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
|
||||
|
||||
#endif /* nsBlobProtocolHandler_h */
|
@ -163,8 +163,8 @@ nsBlobProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
|
||||
uri,
|
||||
stream);
|
||||
uri,
|
||||
stream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal);
|
||||
@ -195,3 +195,23 @@ nsBlobProtocolHandler::AllowPort(int32_t port, const char *scheme,
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
|
||||
{
|
||||
NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
|
||||
|
||||
*aStream = nullptr;
|
||||
|
||||
nsCString spec;
|
||||
aURI->GetSpec(spec);
|
||||
|
||||
FileDataInfo* info =
|
||||
GetFileDataInfo(spec);
|
||||
|
||||
if (!info) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
return info->mFile->GetInternalStream(aStream);
|
||||
}
|
||||
|
@ -6,11 +6,23 @@
|
||||
#define nsBlobProtocolHandler_h
|
||||
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define BLOBURI_SCHEME "blob"
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIPrincipal;
|
||||
class nsIInputStream;
|
||||
|
||||
inline bool IsBlobURI(nsIURI* aUri)
|
||||
{
|
||||
bool isBlob;
|
||||
return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
|
||||
}
|
||||
|
||||
extern nsresult
|
||||
NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
|
||||
|
||||
class nsBlobProtocolHandler : public nsIProtocolHandler
|
||||
{
|
||||
@ -26,11 +38,10 @@ public:
|
||||
|
||||
// Methods for managing uri->file mapping
|
||||
static void AddFileDataEntry(nsACString& aUri,
|
||||
nsIDOMBlob* aFile,
|
||||
nsIDOMBlob* aFile,
|
||||
nsIPrincipal* aPrincipal);
|
||||
static void RemoveFileDataEntry(nsACString& aUri);
|
||||
static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
|
||||
|
||||
};
|
||||
|
||||
#define NS_BLOBPROTOCOLHANDLER_CID \
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "mozilla/Util.h" // for DebugOnly
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsBlobProtocolHandler.h"
|
||||
|
||||
static const uint32_t HTTP_OK_CODE = 200;
|
||||
static const uint32_t HTTP_PARTIAL_RESPONSE_CODE = 206;
|
||||
@ -1105,14 +1106,15 @@ nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener)
|
||||
// implements nsISeekableStream, so we have to find the underlying
|
||||
// file and reopen it
|
||||
nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(mChannel));
|
||||
if (!fc)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
if (fc) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fc->GetFile(getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fc->GetFile(getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file);
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file);
|
||||
} else if (IsBlobURI(mURI)) {
|
||||
rv = NS_GetStreamForBlobURI(mURI, getter_AddRefs(mInput));
|
||||
}
|
||||
} else {
|
||||
// Ensure that we never load a local file from some page on a
|
||||
// web server.
|
||||
@ -1262,7 +1264,7 @@ MediaResource*
|
||||
MediaResource::Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(),
|
||||
"MediaResource::Open called on non-main thread");
|
||||
"MediaResource::Open called on non-main thread");
|
||||
|
||||
// If the channel was redirected, we want the post-redirect URI;
|
||||
// but if the URI scheme was expanded, say from chrome: to jar:file:,
|
||||
@ -1272,7 +1274,7 @@ MediaResource::Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel)
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
|
||||
if (fc) {
|
||||
if (fc || IsBlobURI(uri)) {
|
||||
return new FileMediaResource(aDecoder, aChannel, uri);
|
||||
}
|
||||
return new ChannelMediaResource(aDecoder, aChannel, uri);
|
||||
|
@ -44,9 +44,11 @@ interface nsIFileInputStream : nsIInputStream
|
||||
const long CLOSE_ON_EOF = 1<<2;
|
||||
|
||||
/**
|
||||
* If this is set, the file will be reopened whenever Seek(0) occurs. If
|
||||
* the file is already open and the seek occurs, it will happen naturally.
|
||||
* (The file will only be reopened if it is closed for some reason.)
|
||||
* If this is set, the file will be reopened whenever we reach the start of
|
||||
* the file, either by doing a Seek(0, NS_SEEK_CUR), or by doing a relative
|
||||
* seek that happen to reach the beginning of the file. If the file is
|
||||
* already open and the seek occurs, it will happen naturally. (The file
|
||||
* will only be reopened if it is closed for some reason.)
|
||||
*/
|
||||
const long REOPEN_ON_REWIND = 1<<3;
|
||||
|
||||
|
@ -409,6 +409,14 @@ nsFileInputStream::Init(nsIFile* aFile, int32_t aIOFlags, int32_t aPerm,
|
||||
NS_IMETHODIMP
|
||||
nsFileInputStream::Close()
|
||||
{
|
||||
// Get the cache position at the time the file was close. This allows
|
||||
// NS_SEEK_CUR on a closed file that has been opened with
|
||||
// REOPEN_ON_REWIND.
|
||||
if (mBehaviorFlags & REOPEN_ON_REWIND) {
|
||||
// Get actual position. Not one modified by subclasses
|
||||
nsFileStreamBase::Tell(&mCachedPosition);
|
||||
}
|
||||
|
||||
// null out mLineBuffer in case Close() is called again after failing
|
||||
PR_FREEIF(mLineBuffer);
|
||||
nsresult rv = nsFileStreamBase::Close();
|
||||
@ -460,9 +468,15 @@ nsFileInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
PR_FREEIF(mLineBuffer); // this invalidates the line buffer
|
||||
if (!mFD) {
|
||||
if (mBehaviorFlags & REOPEN_ON_REWIND) {
|
||||
nsresult rv = Reopen();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
rv = Open(mFile, mIOFlags, mPerm);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If the file was closed, and we do a relative seek, use the
|
||||
// position we cached when we closed the file to seek to the right
|
||||
// location.
|
||||
if (aWhence == NS_SEEK_CUR) {
|
||||
aWhence = NS_SEEK_SET;
|
||||
aOffset += mCachedPosition;
|
||||
}
|
||||
} else {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
@ -472,6 +486,18 @@ nsFileInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
return nsFileStreamBase::Seek(aWhence, aOffset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileInputStream::Tell(int64_t *aResult)
|
||||
{
|
||||
return nsFileStreamBase::Tell(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileInputStream::Available(uint64_t *aResult)
|
||||
{
|
||||
return nsFileStreamBase::Available(aResult);
|
||||
}
|
||||
|
||||
void
|
||||
nsFileInputStream::Serialize(InputStreamParams& aParams)
|
||||
{
|
||||
|
@ -111,10 +111,8 @@ public:
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
|
||||
NS_IMETHOD Close();
|
||||
NS_IMETHOD Available(uint64_t* _retval)
|
||||
{
|
||||
return nsFileStreamBase::Available(_retval);
|
||||
}
|
||||
NS_IMETHOD Tell(int64_t *aResult);
|
||||
NS_IMETHOD Available(uint64_t* _retval);
|
||||
NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval);
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
|
||||
uint32_t aCount, uint32_t* _retval)
|
||||
@ -131,12 +129,10 @@ public:
|
||||
NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset);
|
||||
|
||||
nsFileInputStream()
|
||||
: mIOFlags(0), mPerm(0)
|
||||
{
|
||||
mLineBuffer = nullptr;
|
||||
}
|
||||
: mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0)
|
||||
{}
|
||||
|
||||
virtual ~nsFileInputStream()
|
||||
virtual ~nsFileInputStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
@ -160,16 +156,17 @@ protected:
|
||||
*/
|
||||
int32_t mPerm;
|
||||
|
||||
/**
|
||||
* Cached position for Tell for automatically reopening streams.
|
||||
*/
|
||||
int64_t mCachedPosition;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Internal, called to open a file. Parameters are the same as their
|
||||
* Init() analogues.
|
||||
*/
|
||||
nsresult Open(nsIFile* file, int32_t ioFlags, int32_t perm);
|
||||
/**
|
||||
* Reopen the file (for OPEN_ON_READ only!)
|
||||
*/
|
||||
nsresult Reopen() { return Open(mFile, mIOFlags, mPerm); }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -50,7 +50,7 @@ private:
|
||||
const char* aFromRawSegment, uint32_t aToOffset,
|
||||
uint32_t aCount, uint32_t *aWriteCount);
|
||||
|
||||
nsCOMArray<nsIInputStream> mStreams;
|
||||
nsTArray<nsCOMPtr<nsIInputStream> > mStreams;
|
||||
uint32_t mCurrentStream;
|
||||
bool mStartedReadingCurrent;
|
||||
nsresult mStatus;
|
||||
@ -83,7 +83,7 @@ nsMultiplexInputStream::nsMultiplexInputStream()
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::GetCount(uint32_t *aCount)
|
||||
{
|
||||
*aCount = mStreams.Count();
|
||||
*aCount = mStreams.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -91,14 +91,14 @@ nsMultiplexInputStream::GetCount(uint32_t *aCount)
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::AppendStream(nsIInputStream *aStream)
|
||||
{
|
||||
return mStreams.AppendObject(aStream) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
return mStreams.AppendElement(aStream) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* void insertStream (in nsIInputStream stream, in unsigned long index); */
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, uint32_t aIndex)
|
||||
{
|
||||
bool result = mStreams.InsertObjectAt(aStream, aIndex);
|
||||
bool result = mStreams.InsertElementAt(aIndex, aStream);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
if (mCurrentStream > aIndex ||
|
||||
(mCurrentStream == aIndex && mStartedReadingCurrent))
|
||||
@ -110,8 +110,7 @@ nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, uint32_t aIndex)
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::RemoveStream(uint32_t aIndex)
|
||||
{
|
||||
bool result = mStreams.RemoveObjectAt(aIndex);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_NOT_AVAILABLE);
|
||||
mStreams.RemoveElementAt(aIndex);
|
||||
if (mCurrentStream > aIndex)
|
||||
--mCurrentStream;
|
||||
else if (mCurrentStream == aIndex)
|
||||
@ -124,7 +123,7 @@ nsMultiplexInputStream::RemoveStream(uint32_t aIndex)
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream **_retval)
|
||||
{
|
||||
*_retval = mStreams.SafeObjectAt(aIndex);
|
||||
*_retval = mStreams.SafeElementAt(aIndex, nullptr);
|
||||
NS_ENSURE_TRUE(*_retval, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
NS_ADDREF(*_retval);
|
||||
@ -139,7 +138,7 @@ nsMultiplexInputStream::Close()
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
uint32_t len = mStreams.Count();
|
||||
uint32_t len = mStreams.Length();
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
nsresult rv2 = mStreams[i]->Close();
|
||||
// We still want to close all streams, but we should return an error
|
||||
@ -159,7 +158,7 @@ nsMultiplexInputStream::Available(uint64_t *_retval)
|
||||
nsresult rv;
|
||||
uint64_t avail = 0;
|
||||
|
||||
uint32_t len = mStreams.Count();
|
||||
uint32_t len = mStreams.Length();
|
||||
for (uint32_t i = mCurrentStream; i < len; i++) {
|
||||
uint64_t streamAvail;
|
||||
rv = mStreams[i]->Available(&streamAvail);
|
||||
@ -187,7 +186,7 @@ nsMultiplexInputStream::Read(char * aBuf, uint32_t aCount, uint32_t *_retval)
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
uint32_t len = mStreams.Count();
|
||||
uint32_t len = mStreams.Length();
|
||||
while (mCurrentStream < len && aCount) {
|
||||
uint32_t read;
|
||||
rv = mStreams[mCurrentStream]->Read(aBuf, aCount, &read);
|
||||
@ -241,7 +240,7 @@ nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
|
||||
state.mClosure = aClosure;
|
||||
state.mDone = false;
|
||||
|
||||
uint32_t len = mStreams.Count();
|
||||
uint32_t len = mStreams.Length();
|
||||
while (mCurrentStream < len && aCount) {
|
||||
uint32_t read;
|
||||
rv = mStreams[mCurrentStream]->ReadSegments(ReadSegCb, &state, aCount, &read);
|
||||
@ -299,7 +298,7 @@ nsMultiplexInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure,
|
||||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
uint32_t len = mStreams.Count();
|
||||
uint32_t len = mStreams.Length();
|
||||
if (len == 0) {
|
||||
// Claim to be non-blocking, since we won't block the caller.
|
||||
// On the other hand we'll never return NS_BASE_STREAM_WOULD_BLOCK,
|
||||
@ -329,20 +328,208 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// rewinding to start is easy, and should be the most common case
|
||||
if (aWhence == NS_SEEK_SET && aOffset == 0)
|
||||
{
|
||||
uint32_t i, last;
|
||||
last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream;
|
||||
for (i = 0; i < last; ++i) {
|
||||
nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStreams[i]);
|
||||
NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE);
|
||||
uint32_t oldCurrentStream = mCurrentStream;
|
||||
bool oldStartedReadingCurrent = mStartedReadingCurrent;
|
||||
|
||||
rv = stream->Seek(NS_SEEK_SET, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aWhence == NS_SEEK_SET) {
|
||||
int64_t remaining = aOffset;
|
||||
if (aOffset == 0) {
|
||||
mCurrentStream = 0;
|
||||
}
|
||||
mCurrentStream = 0;
|
||||
mStartedReadingCurrent = false;
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
if (!stream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// See if all remaining streams should be rewound
|
||||
if (remaining == 0) {
|
||||
if (i < oldCurrentStream ||
|
||||
(i == oldCurrentStream && oldStartedReadingCurrent)) {
|
||||
rv = stream->Seek(NS_SEEK_SET, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get position in current stream
|
||||
int64_t streamPos;
|
||||
if (i > oldCurrentStream ||
|
||||
(i == oldCurrentStream && !oldStartedReadingCurrent)) {
|
||||
streamPos = 0;
|
||||
}
|
||||
else {
|
||||
rv = stream->Tell(&streamPos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// See if we need to seek current stream forward or backward
|
||||
if (remaining < streamPos) {
|
||||
rv = stream->Seek(NS_SEEK_SET, remaining);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = remaining != 0;
|
||||
|
||||
remaining = 0;
|
||||
}
|
||||
else if (remaining > streamPos) {
|
||||
if (i < oldCurrentStream) {
|
||||
// We're already at end so no need to seek this stream
|
||||
remaining -= streamPos;
|
||||
}
|
||||
else {
|
||||
uint64_t avail;
|
||||
rv = mStreams[i]->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int64_t newPos = streamPos +
|
||||
NS_MIN((int64_t)avail, remaining);
|
||||
|
||||
rv = stream->Seek(NS_SEEK_SET, newPos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = true;
|
||||
|
||||
remaining -= newPos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(remaining == streamPos, "Huh?");
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aWhence == NS_SEEK_CUR && aOffset > 0) {
|
||||
int64_t remaining = aOffset;
|
||||
for (uint32_t i = mCurrentStream; remaining && i < mStreams.Length(); ++i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
|
||||
uint64_t avail;
|
||||
rv = mStreams[i]->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int64_t seek = NS_MIN((int64_t)avail, remaining);
|
||||
|
||||
rv = stream->Seek(NS_SEEK_CUR, seek);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = true;
|
||||
|
||||
remaining -= seek;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aWhence == NS_SEEK_CUR && aOffset < 0) {
|
||||
int64_t remaining = -aOffset;
|
||||
for (uint32_t i = mCurrentStream; remaining && i != (uint32_t)-1; --i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
|
||||
int64_t pos;
|
||||
rv = stream->Tell(&pos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int64_t seek = NS_MIN(pos, remaining);
|
||||
|
||||
rv = stream->Seek(NS_SEEK_CUR, -seek);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = seek != -pos;
|
||||
|
||||
remaining -= seek;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aWhence == NS_SEEK_CUR) {
|
||||
NS_ASSERTION(aOffset == 0, "Should have handled all non-zero values");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aWhence == NS_SEEK_END) {
|
||||
if (aOffset > 0) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
int64_t remaining = aOffset;
|
||||
for (uint32_t i = mStreams.Length() - 1; i != (uint32_t)-1; --i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
|
||||
// See if all remaining streams should be seeked to end
|
||||
if (remaining == 0) {
|
||||
if (i >= oldCurrentStream) {
|
||||
rv = stream->Seek(NS_SEEK_END, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get position in current stream
|
||||
int64_t streamPos;
|
||||
if (i < oldCurrentStream) {
|
||||
streamPos = 0;
|
||||
} else {
|
||||
uint64_t avail;
|
||||
rv = mStreams[i]->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
streamPos = avail;
|
||||
}
|
||||
|
||||
// See if we have enough data in the current stream.
|
||||
if (NS_ABS(remaining) < streamPos) {
|
||||
rv = stream->Seek(NS_SEEK_END, remaining);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = true;
|
||||
|
||||
remaining = 0;
|
||||
} else if (NS_ABS(remaining) > streamPos) {
|
||||
if (i > oldCurrentStream ||
|
||||
(i == oldCurrentStream && !oldStartedReadingCurrent)) {
|
||||
// We're already at start so no need to seek this stream
|
||||
remaining += streamPos;
|
||||
} else {
|
||||
int64_t avail;
|
||||
rv = stream->Tell(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int64_t newPos = streamPos + NS_MIN(avail, NS_ABS(remaining));
|
||||
|
||||
rv = stream->Seek(NS_SEEK_END, -newPos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentStream = i;
|
||||
mStartedReadingCurrent = true;
|
||||
|
||||
remaining += newPos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(remaining == streamPos, "Huh?");
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -408,7 +595,7 @@ nsMultiplexInputStream::Serialize(InputStreamParams& aParams)
|
||||
{
|
||||
MultiplexInputStreamParams params;
|
||||
|
||||
uint32_t streamCount = mStreams.Count();
|
||||
uint32_t streamCount = mStreams.Length();
|
||||
|
||||
if (streamCount) {
|
||||
InfallibleTArray<InputStreamParams>& streams = params.streams();
|
||||
@ -416,7 +603,7 @@ nsMultiplexInputStream::Serialize(InputStreamParams& aParams)
|
||||
streams.SetCapacity(streamCount);
|
||||
for (uint32_t index = 0; index < streamCount; index++) {
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
|
||||
do_QueryInterface(mStreams.ObjectAt(index));
|
||||
do_QueryInterface(mStreams[index]);
|
||||
NS_ASSERTION(serializable, "Child stream isn't serializable!");
|
||||
|
||||
if (serializable) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user