зеркало из https://github.com/mozilla/gecko-dev.git
232 строки
5.2 KiB
C++
232 строки
5.2 KiB
C++
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* 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 "CloneableWithRangeMediaResource.h"
|
|
|
|
#include "mozilla/Monitor.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsIAsyncInputStream.h"
|
|
#include "nsNetCID.h"
|
|
|
|
namespace mozilla {
|
|
|
|
namespace {
|
|
|
|
class InputStreamReader final : public nsIInputStreamCallback
|
|
{
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
static already_AddRefed<InputStreamReader>
|
|
Create(nsICloneableInputStreamWithRange* aStream, int64_t aStart,
|
|
uint32_t aLength)
|
|
{
|
|
MOZ_ASSERT(aStream);
|
|
|
|
nsCOMPtr<nsIInputStream> stream;
|
|
nsresult rv = aStream->CloneWithRange(aStart, aLength,
|
|
getter_AddRefs(stream));
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<InputStreamReader> reader = new InputStreamReader(stream);
|
|
return reader.forget();
|
|
}
|
|
|
|
nsresult
|
|
Read(char* aBuffer, uint32_t aSize, uint32_t* aRead)
|
|
{
|
|
uint32_t done = 0;
|
|
do {
|
|
uint32_t read;
|
|
nsresult rv = SyncRead(aBuffer + done, aSize - done, &read);
|
|
if (NS_WARN_IF(NS_FAILED(rv)) || read == 0) {
|
|
return rv;
|
|
}
|
|
done += read;
|
|
} while(done != aSize);
|
|
|
|
*aRead = done;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHOD
|
|
OnInputStreamReady(nsIAsyncInputStream* aStream) override
|
|
{
|
|
// Let's continue with SyncRead().
|
|
MonitorAutoLock lock(mMonitor);
|
|
return lock.Notify();
|
|
}
|
|
|
|
private:
|
|
explicit InputStreamReader(nsIInputStream* aStream)
|
|
: mStream(aStream)
|
|
, mMonitor("InputStreamReader::mMonitor")
|
|
{
|
|
MOZ_ASSERT(aStream);
|
|
}
|
|
|
|
~InputStreamReader() = default;
|
|
|
|
nsresult
|
|
SyncRead(char* aBuffer, uint32_t aSize, uint32_t* aRead)
|
|
{
|
|
while (1) {
|
|
nsresult rv = mStream->Read(aBuffer, aSize, aRead);
|
|
// All good.
|
|
if (rv == NS_BASE_STREAM_CLOSED || NS_SUCCEEDED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
// An error.
|
|
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
|
return rv;
|
|
}
|
|
|
|
// We need to proceed async.
|
|
if (!mAsyncStream) {
|
|
mAsyncStream = do_QueryInterface(mStream);
|
|
}
|
|
|
|
if (!mAsyncStream) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIEventTarget> target =
|
|
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
|
MOZ_ASSERT(target);
|
|
|
|
{
|
|
// We wait for ::OnInputStreamReady() to be called.
|
|
MonitorAutoLock lock(mMonitor);
|
|
|
|
rv = mAsyncStream->AsyncWait(this, 0, aSize, target);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
lock.Wait();
|
|
}
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIInputStream> mStream;
|
|
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
|
|
Monitor mMonitor;
|
|
};
|
|
|
|
NS_IMPL_ADDREF(InputStreamReader);
|
|
NS_IMPL_RELEASE(InputStreamReader);
|
|
|
|
NS_INTERFACE_MAP_BEGIN(InputStreamReader)
|
|
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
} // anonymous
|
|
|
|
void
|
|
CloneableWithRangeMediaResource::MaybeInitialize()
|
|
{
|
|
if (!mInitialized) {
|
|
mInitialized = true;
|
|
mCallback->NotifyDataEnded(NS_OK);
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
CloneableWithRangeMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
|
|
{
|
|
MaybeInitialize();
|
|
aRanges += MediaByteRange(0, (int64_t)mSize);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
CloneableWithRangeMediaResource::Open(nsIStreamListener** aStreamListener)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aStreamListener);
|
|
|
|
*aStreamListener = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
CloneableWithRangeMediaResource::Close()
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
already_AddRefed<nsIPrincipal>
|
|
CloneableWithRangeMediaResource::GetCurrentPrincipal()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
|
if (!secMan || !mChannel) {
|
|
return nullptr;
|
|
}
|
|
|
|
secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
|
|
return principal.forget();
|
|
}
|
|
|
|
nsresult
|
|
CloneableWithRangeMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset,
|
|
uint32_t aCount)
|
|
{
|
|
MaybeInitialize();
|
|
if (!aCount) {
|
|
return NS_OK;
|
|
}
|
|
|
|
RefPtr<InputStreamReader> reader =
|
|
InputStreamReader::Create(mStream, aOffset, aCount);
|
|
if (!reader) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
uint32_t bytes = 0;
|
|
nsresult rv = reader->Read(aBuffer, aCount, &bytes);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurrentPosition = bytes + aOffset;
|
|
return bytes == aCount ? NS_OK : NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult
|
|
CloneableWithRangeMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
|
|
uint32_t aCount, uint32_t* aBytes)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
RefPtr<InputStreamReader> reader =
|
|
InputStreamReader::Create(mStream, aOffset, aCount);
|
|
if (!reader) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult rv = reader->Read(aBuffer, aCount, aBytes);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mCurrentPosition = *aBytes + aOffset;
|
|
return NS_OK;
|
|
}
|
|
|
|
int64_t CloneableWithRangeMediaResource::Tell()
|
|
{
|
|
MaybeInitialize();
|
|
return mCurrentPosition;
|
|
}
|
|
|
|
} // mozilla namespace
|