2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2011-08-16 07:40:38 +04:00
|
|
|
|
|
|
|
#include "FileReaderSync.h"
|
|
|
|
|
2013-06-05 18:04:23 +04:00
|
|
|
#include "jsfriendapi.h"
|
2016-08-23 07:09:32 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2013-06-05 18:04:23 +04:00
|
|
|
#include "mozilla/Base64.h"
|
2014-10-08 20:15:23 +04:00
|
|
|
#include "mozilla/dom/File.h"
|
2017-06-16 15:11:03 +03:00
|
|
|
#include "mozilla/Encoding.h"
|
2013-06-05 18:04:23 +04:00
|
|
|
#include "mozilla/dom/FileReaderSyncBinding.h"
|
2012-09-21 06:47:47 +04:00
|
|
|
#include "nsCExternalHandlerService.h"
|
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
#include "nsCOMPtr.h"
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2012-09-21 06:47:47 +04:00
|
|
|
#include "nsIConverterInputStream.h"
|
|
|
|
#include "nsIInputStream.h"
|
2017-03-23 12:53:40 +03:00
|
|
|
#include "nsIMultiplexInputStream.h"
|
2017-05-09 12:04:49 +03:00
|
|
|
#include "nsStreamUtils.h"
|
2017-03-23 12:53:40 +03:00
|
|
|
#include "nsStringStream.h"
|
2012-09-21 06:47:47 +04:00
|
|
|
#include "nsISupportsImpl.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
2017-04-25 23:23:46 +03:00
|
|
|
#include "nsIAsyncInputStream.h"
|
2018-01-31 10:25:30 +03:00
|
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
|
|
|
#include "mozilla/dom/WorkerRunnable.h"
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-11-10 19:45:52 +04:00
|
|
|
using namespace mozilla;
|
2014-10-08 20:15:22 +04:00
|
|
|
using namespace mozilla::dom;
|
2013-08-23 09:17:08 +04:00
|
|
|
using mozilla::dom::GlobalObject;
|
2012-09-21 06:47:47 +04:00
|
|
|
using mozilla::dom::Optional;
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
// static
|
2013-09-30 08:15:37 +04:00
|
|
|
already_AddRefed<FileReaderSync> FileReaderSync::Constructor(
|
2013-08-23 09:17:08 +04:00
|
|
|
const GlobalObject& aGlobal, ErrorResult& aRv) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<FileReaderSync> frs = new FileReaderSync();
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2013-09-30 08:15:37 +04:00
|
|
|
return frs.forget();
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
|
|
|
|
2015-01-09 00:56:42 +03:00
|
|
|
bool FileReaderSync::WrapObject(JSContext* aCx,
|
Bug 1117172 part 2. Change the non-wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, Codegen.py, and
StructuredClone.cpp. The rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/WrapObject\((JSContext *\* *(?:aCx|cx)),(\s*)(JS::MutableHandle<JSObject\*> aReflector)/WrapObject(\1,\2JS::Handle<JSObject*> aGivenProto,\2\3/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx)), this, aReflector/\1, this, aGivenProto, aReflector/'
2015-03-19 17:13:32 +03:00
|
|
|
JS::Handle<JSObject*> aGivenProto,
|
2015-01-09 00:56:42 +03:00
|
|
|
JS::MutableHandle<JSObject*> aReflector) {
|
2018-06-26 00:20:54 +03:00
|
|
|
return FileReaderSync_Binding::Wrap(aCx, this, aGivenProto, aReflector);
|
2013-06-05 18:04:23 +04:00
|
|
|
}
|
|
|
|
|
2013-09-30 08:15:37 +04:00
|
|
|
void FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aScopeObj,
|
2015-05-12 15:09:51 +03:00
|
|
|
Blob& aBlob,
|
2014-06-12 00:26:52 +04:00
|
|
|
JS::MutableHandle<JSObject*> aRetval,
|
2012-09-21 06:47:47 +04:00
|
|
|
ErrorResult& aRv) {
|
2015-05-19 17:36:37 +03:00
|
|
|
uint64_t blobSize = aBlob.GetSize(aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2014-06-12 00:26:52 +04:00
|
|
|
return;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
|
|
|
|
2018-05-24 00:57:42 +03:00
|
|
|
UniquePtr<char[], JS::FreePolicy> bufferData(
|
|
|
|
js_pod_arena_malloc<char>(js::ArrayBufferContentsArena, blobSize));
|
2014-10-07 21:44:07 +04:00
|
|
|
if (!bufferData) {
|
2014-02-13 21:17:41 +04:00
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
2014-06-12 00:26:52 +04:00
|
|
|
return;
|
2014-02-13 21:17:41 +04:00
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
nsCOMPtr<nsIInputStream> stream;
|
2017-10-02 14:53:12 +03:00
|
|
|
aBlob.CreateInputStream(getter_AddRefs(stream), aRv);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2014-06-12 00:26:52 +04:00
|
|
|
return;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
uint32_t numRead;
|
2017-05-09 12:03:40 +03:00
|
|
|
aRv = SyncRead(stream, bufferData.get(), blobSize, &numRead);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2014-06-12 00:26:52 +04:00
|
|
|
return;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
2017-05-09 12:04:49 +03:00
|
|
|
|
|
|
|
// The file is changed in the meantime?
|
|
|
|
if (numRead != blobSize) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
2014-10-07 21:44:07 +04:00
|
|
|
|
|
|
|
JSObject* arrayBuffer =
|
|
|
|
JS_NewArrayBufferWithContents(aCx, blobSize, bufferData.get());
|
|
|
|
if (!arrayBuffer) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
2016-02-20 06:06:25 +03:00
|
|
|
// arrayBuffer takes the ownership when it is not null. Otherwise we
|
|
|
|
// need to release it explicitly.
|
|
|
|
mozilla::Unused << bufferData.release();
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2014-10-07 21:44:07 +04:00
|
|
|
aRetval.set(arrayBuffer);
|
2012-09-21 06:47:47 +04:00
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2015-05-12 15:09:51 +03:00
|
|
|
void FileReaderSync::ReadAsBinaryString(Blob& aBlob, nsAString& aResult,
|
2012-09-21 06:47:47 +04:00
|
|
|
ErrorResult& aRv) {
|
|
|
|
nsCOMPtr<nsIInputStream> stream;
|
2017-10-02 14:53:12 +03:00
|
|
|
aBlob.CreateInputStream(getter_AddRefs(stream), aRv);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2012-09-21 06:47:47 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
uint32_t numRead;
|
|
|
|
do {
|
|
|
|
char readBuf[4096];
|
2017-05-09 12:03:40 +03:00
|
|
|
aRv = SyncRead(stream, readBuf, sizeof(readBuf), &numRead);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2012-09-21 06:47:47 +04:00
|
|
|
return;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
uint32_t oldLength = aResult.Length();
|
|
|
|
AppendASCIItoUTF16(Substring(readBuf, readBuf + numRead), aResult);
|
|
|
|
if (aResult.Length() - oldLength != numRead) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
2012-09-21 06:47:47 +04:00
|
|
|
} while (numRead > 0);
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2015-05-12 15:09:51 +03:00
|
|
|
void FileReaderSync::ReadAsText(Blob& aBlob,
|
2012-09-21 06:47:47 +04:00
|
|
|
const Optional<nsAString>& aEncoding,
|
|
|
|
nsAString& aResult, ErrorResult& aRv) {
|
|
|
|
nsCOMPtr<nsIInputStream> stream;
|
2017-10-02 14:53:12 +03:00
|
|
|
aBlob.CreateInputStream(getter_AddRefs(stream), aRv);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2012-09-21 06:47:47 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2017-03-23 12:53:40 +03:00
|
|
|
nsCString sniffBuf;
|
|
|
|
if (!sniffBuf.SetLength(3, fallible)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t numRead = 0;
|
2017-05-09 12:03:40 +03:00
|
|
|
aRv = SyncRead(stream, sniffBuf.BeginWriting(), sniffBuf.Length(), &numRead);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2013-12-17 14:47:25 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2017-05-09 12:04:49 +03:00
|
|
|
// No data, we don't need to continue.
|
|
|
|
if (numRead == 0) {
|
|
|
|
aResult.Truncate();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-16 15:11:03 +03:00
|
|
|
// Try the API argument.
|
|
|
|
const Encoding* encoding =
|
|
|
|
aEncoding.WasPassed() ? Encoding::ForLabel(aEncoding.Value()) : nullptr;
|
|
|
|
if (!encoding) {
|
|
|
|
// API argument failed. Try the type property of the blob.
|
|
|
|
nsAutoString type16;
|
|
|
|
aBlob.GetType(type16);
|
|
|
|
NS_ConvertUTF16toUTF8 type(type16);
|
|
|
|
nsAutoCString specifiedCharset;
|
|
|
|
bool haveCharset;
|
|
|
|
int32_t charsetStart, charsetEnd;
|
|
|
|
NS_ExtractCharsetFromContentType(type, specifiedCharset, &haveCharset,
|
|
|
|
&charsetStart, &charsetEnd);
|
|
|
|
encoding = Encoding::ForLabel(specifiedCharset);
|
|
|
|
if (!encoding) {
|
|
|
|
// Type property failed. Use UTF-8.
|
|
|
|
encoding = UTF_8_ENCODING;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
2013-12-17 14:47:25 +04:00
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2017-03-23 12:53:40 +03:00
|
|
|
if (numRead < sniffBuf.Length()) {
|
|
|
|
sniffBuf.Truncate(numRead);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's recreate the full stream using a:
|
2017-05-09 12:04:07 +03:00
|
|
|
// multiplexStream(syncStream + original stream)
|
2017-03-23 12:53:40 +03:00
|
|
|
// In theory, we could try to see if the inputStream is a nsISeekableStream,
|
|
|
|
// but this doesn't work correctly for nsPipe3 - See bug 1349570.
|
|
|
|
|
2017-05-05 22:34:57 +03:00
|
|
|
nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
|
|
|
|
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
|
|
|
if (NS_WARN_IF(!multiplexStream)) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
2017-05-05 15:44:18 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:04:07 +03:00
|
|
|
nsCOMPtr<nsIInputStream> sniffStringStream;
|
|
|
|
aRv = NS_NewCStringInputStream(getter_AddRefs(sniffStringStream), sniffBuf);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRv = multiplexStream->AppendStream(sniffStringStream);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-08 12:23:02 +03:00
|
|
|
uint64_t blobSize = aBlob.GetSize(aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:04:07 +03:00
|
|
|
nsCOMPtr<nsIInputStream> syncStream;
|
2017-10-19 12:39:30 +03:00
|
|
|
aRv = ConvertAsyncToSyncStream(blobSize - sniffBuf.Length(), stream.forget(),
|
2017-09-08 12:23:02 +03:00
|
|
|
getter_AddRefs(syncStream));
|
2017-03-23 12:53:40 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-23 08:53:35 +03:00
|
|
|
// ConvertAsyncToSyncStream returns a null syncStream if the stream has been
|
|
|
|
// already closed or there is nothing to read.
|
|
|
|
if (syncStream) {
|
|
|
|
aRv = multiplexStream->AppendStream(syncStream);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
2012-09-21 06:47:47 +04:00
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2017-06-16 15:11:03 +03:00
|
|
|
nsAutoCString charset;
|
|
|
|
encoding->Name(charset);
|
2017-09-19 17:26:21 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> multiplex(do_QueryInterface(multiplexStream));
|
|
|
|
aRv = ConvertStream(multiplex, charset.get(), aResult);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2012-09-21 06:47:47 +04:00
|
|
|
return;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
2012-09-21 06:47:47 +04:00
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2015-05-12 15:09:51 +03:00
|
|
|
void FileReaderSync::ReadAsDataURL(Blob& aBlob, nsAString& aResult,
|
2012-09-21 06:47:47 +04:00
|
|
|
ErrorResult& aRv) {
|
|
|
|
nsAutoString scratchResult;
|
|
|
|
scratchResult.AssignLiteral("data:");
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
nsString contentType;
|
2014-10-08 20:15:22 +04:00
|
|
|
aBlob.GetType(contentType);
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
if (contentType.IsEmpty()) {
|
|
|
|
scratchResult.AppendLiteral("application/octet-stream");
|
|
|
|
} else {
|
|
|
|
scratchResult.Append(contentType);
|
|
|
|
}
|
|
|
|
scratchResult.AppendLiteral(";base64,");
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
nsCOMPtr<nsIInputStream> stream;
|
2017-10-02 14:53:12 +03:00
|
|
|
aBlob.CreateInputStream(getter_AddRefs(stream), aRv);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2012-09-21 06:47:47 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2017-09-08 12:23:02 +03:00
|
|
|
uint64_t blobSize = aBlob.GetSize(aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:04:49 +03:00
|
|
|
nsCOMPtr<nsIInputStream> syncStream;
|
2017-10-19 12:39:30 +03:00
|
|
|
aRv = ConvertAsyncToSyncStream(blobSize, stream.forget(),
|
|
|
|
getter_AddRefs(syncStream));
|
2017-05-09 12:04:49 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-23 08:53:35 +03:00
|
|
|
MOZ_ASSERT(syncStream);
|
|
|
|
|
2017-05-09 12:04:49 +03:00
|
|
|
uint64_t size;
|
|
|
|
aRv = syncStream->Available(&size);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2017-05-04 15:51:11 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:04:49 +03:00
|
|
|
// The file is changed in the meantime?
|
|
|
|
if (blobSize != size) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
nsAutoString encodedData;
|
2017-05-09 12:04:49 +03:00
|
|
|
aRv = Base64EncodeInputStream(syncStream, encodedData, size);
|
2015-05-19 17:36:37 +03:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
2012-09-21 06:47:47 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
scratchResult.Append(encodedData);
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
aResult = scratchResult;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
nsresult FileReaderSync::ConvertStream(nsIInputStream* aStream,
|
|
|
|
const char* aCharset,
|
|
|
|
nsAString& aResult) {
|
|
|
|
nsCOMPtr<nsIConverterInputStream> converterStream =
|
|
|
|
do_CreateInstance("@mozilla.org/intl/converter-input-stream;1");
|
|
|
|
NS_ENSURE_TRUE(converterStream, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
nsresult rv = converterStream->Init(
|
|
|
|
aStream, aCharset, 8192,
|
|
|
|
nsIConverterInputStream::DEFAULT_REPLACEMENT_CHARACTER);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2018-10-02 00:38:01 +03:00
|
|
|
nsCOMPtr<nsIUnicharInputStream> unicharStream = converterStream;
|
2012-09-21 06:47:47 +04:00
|
|
|
NS_ENSURE_TRUE(unicharStream, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
uint32_t numChars;
|
|
|
|
nsString result;
|
|
|
|
while (NS_SUCCEEDED(unicharStream->ReadString(8192, result, &numChars)) &&
|
|
|
|
numChars > 0) {
|
|
|
|
uint32_t oldLength = aResult.Length();
|
|
|
|
aResult.Append(result);
|
|
|
|
if (aResult.Length() - oldLength != result.Length()) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2011-08-16 07:40:38 +04:00
|
|
|
}
|
2012-09-21 06:47:47 +04:00
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2012-09-21 06:47:47 +04:00
|
|
|
return rv;
|
|
|
|
}
|
2011-08-16 07:40:38 +04:00
|
|
|
|
2017-04-25 23:23:46 +03:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// This runnable is used to terminate the sync event loop.
|
|
|
|
class ReadReadyRunnable final : public WorkerSyncRunnable {
|
|
|
|
public:
|
|
|
|
ReadReadyRunnable(WorkerPrivate* aWorkerPrivate,
|
|
|
|
nsIEventTarget* aSyncLoopTarget)
|
|
|
|
: WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) {}
|
|
|
|
|
|
|
|
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
|
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
MOZ_ASSERT(mSyncLoopTarget);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIEventTarget> syncLoopTarget;
|
|
|
|
mSyncLoopTarget.swap(syncLoopTarget);
|
|
|
|
|
|
|
|
aWorkerPrivate->StopSyncLoop(syncLoopTarget, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
~ReadReadyRunnable() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
// This class implements nsIInputStreamCallback and it will be called when the
|
|
|
|
// stream is ready to be read.
|
|
|
|
class ReadCallback final : public nsIInputStreamCallback {
|
|
|
|
public:
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
|
|
|
|
ReadCallback(WorkerPrivate* aWorkerPrivate, nsIEventTarget* aEventTarget)
|
|
|
|
: mWorkerPrivate(aWorkerPrivate), mEventTarget(aEventTarget) {}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
OnInputStreamReady(nsIAsyncInputStream* aStream) override {
|
|
|
|
// I/O Thread. Now we need to block the sync event loop.
|
|
|
|
RefPtr<ReadReadyRunnable> runnable =
|
|
|
|
new ReadReadyRunnable(mWorkerPrivate, mEventTarget);
|
|
|
|
return mEventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
~ReadCallback() {}
|
|
|
|
|
|
|
|
// The worker is kept alive because of the sync event loop.
|
|
|
|
WorkerPrivate* mWorkerPrivate;
|
|
|
|
nsCOMPtr<nsIEventTarget> mEventTarget;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(ReadCallback);
|
|
|
|
NS_IMPL_RELEASE(ReadCallback);
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(ReadCallback)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2017-05-09 12:03:40 +03:00
|
|
|
nsresult FileReaderSync::SyncRead(nsIInputStream* aStream, char* aBuffer,
|
|
|
|
uint32_t aBufferSize, uint32_t* aRead) {
|
2017-04-25 23:23:46 +03:00
|
|
|
MOZ_ASSERT(aStream);
|
|
|
|
MOZ_ASSERT(aBuffer);
|
|
|
|
MOZ_ASSERT(aRead);
|
|
|
|
|
|
|
|
// Let's try to read, directly.
|
|
|
|
nsresult rv = aStream->Read(aBuffer, aBufferSize, aRead);
|
2017-05-09 12:03:40 +03:00
|
|
|
|
|
|
|
// Nothing else to read.
|
|
|
|
if (rv == NS_BASE_STREAM_CLOSED || (NS_SUCCEEDED(rv) && *aRead == 0)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// An error.
|
|
|
|
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
2017-04-25 23:23:46 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:03:40 +03:00
|
|
|
// All good.
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Not enough data, let's read recursively.
|
|
|
|
if (*aRead != aBufferSize) {
|
|
|
|
uint32_t byteRead = 0;
|
|
|
|
rv = SyncRead(aStream, aBuffer + *aRead, aBufferSize - *aRead, &byteRead);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aRead += byteRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-04-25 23:23:46 +03:00
|
|
|
// We need to proceed async.
|
|
|
|
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
|
|
|
if (!asyncStream) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2018-02-05 21:55:07 +03:00
|
|
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
2017-04-25 23:23:46 +03:00
|
|
|
MOZ_ASSERT(workerPrivate);
|
|
|
|
|
2018-07-12 20:33:41 +03:00
|
|
|
AutoSyncLoopHolder syncLoop(workerPrivate, Canceling);
|
2017-04-25 23:23:46 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIEventTarget> syncLoopTarget = syncLoop.GetEventTarget();
|
|
|
|
if (!syncLoopTarget) {
|
|
|
|
// SyncLoop creation can fail if the worker is shutting down.
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<ReadCallback> callback =
|
|
|
|
new ReadCallback(workerPrivate, syncLoopTarget);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIEventTarget> target =
|
|
|
|
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
|
|
|
MOZ_ASSERT(target);
|
|
|
|
|
|
|
|
rv = asyncStream->AsyncWait(callback, 0, aBufferSize, target);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!syncLoop.Run()) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, we can try to read again.
|
2017-05-09 12:03:40 +03:00
|
|
|
return SyncRead(aStream, aBuffer, aBufferSize, aRead);
|
2017-05-05 15:44:18 +03:00
|
|
|
}
|
2017-05-09 12:04:07 +03:00
|
|
|
|
2017-09-08 12:23:02 +03:00
|
|
|
nsresult FileReaderSync::ConvertAsyncToSyncStream(
|
2017-10-19 12:39:30 +03:00
|
|
|
uint64_t aStreamSize, already_AddRefed<nsIInputStream> aAsyncStream,
|
2017-05-09 12:04:07 +03:00
|
|
|
nsIInputStream** aSyncStream) {
|
2018-05-30 22:15:35 +03:00
|
|
|
nsCOMPtr<nsIInputStream> asyncInputStream = std::move(aAsyncStream);
|
2017-10-19 12:39:30 +03:00
|
|
|
|
2017-05-09 12:04:49 +03:00
|
|
|
// If the stream is not async, we just need it to be bufferable.
|
2017-10-19 12:39:30 +03:00
|
|
|
nsCOMPtr<nsIAsyncInputStream> asyncStream =
|
|
|
|
do_QueryInterface(asyncInputStream);
|
2017-05-09 12:04:07 +03:00
|
|
|
if (!asyncStream) {
|
2017-10-19 12:39:30 +03:00
|
|
|
return NS_NewBufferedInputStream(aSyncStream, asyncInputStream.forget(),
|
|
|
|
4096);
|
2017-05-09 12:04:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoCString buffer;
|
2017-09-08 12:23:02 +03:00
|
|
|
if (!buffer.SetLength(aStreamSize, fallible)) {
|
2017-05-09 12:04:07 +03:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t read;
|
2017-09-08 12:23:02 +03:00
|
|
|
nsresult rv =
|
2017-10-19 12:39:30 +03:00
|
|
|
SyncRead(asyncInputStream, buffer.BeginWriting(), aStreamSize, &read);
|
2017-05-09 12:04:07 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-09-08 12:23:02 +03:00
|
|
|
if (read != aStreamSize) {
|
2017-05-09 12:04:07 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
rv = NS_NewCStringInputStream(aSyncStream, std::move(buffer));
|
2017-05-09 12:04:07 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|