LCOV - code coverage report
Current view: top level - dom/file - FileReader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 398 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 37 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "FileReader.h"
       8             : 
       9             : #include "nsIEventTarget.h"
      10             : #include "nsIGlobalObject.h"
      11             : #include "nsITimer.h"
      12             : #include "nsITransport.h"
      13             : #include "nsIStreamTransportService.h"
      14             : 
      15             : #include "mozilla/Base64.h"
      16             : #include "mozilla/CheckedInt.h"
      17             : #include "mozilla/dom/DOMError.h"
      18             : #include "mozilla/dom/File.h"
      19             : #include "mozilla/dom/FileReaderBinding.h"
      20             : #include "mozilla/dom/ProgressEvent.h"
      21             : #include "mozilla/Encoding.h"
      22             : #include "nsCycleCollectionParticipant.h"
      23             : #include "nsDOMJSUtils.h"
      24             : #include "nsError.h"
      25             : #include "nsNetCID.h"
      26             : #include "nsNetUtil.h"
      27             : #include "xpcpublic.h"
      28             : 
      29             : #include "WorkerPrivate.h"
      30             : #include "WorkerScope.h"
      31             : 
      32             : namespace mozilla {
      33             : namespace dom {
      34             : 
      35             : using namespace workers;
      36             : 
      37             : #define ABORT_STR "abort"
      38             : #define LOAD_STR "load"
      39             : #define LOADSTART_STR "loadstart"
      40             : #define LOADEND_STR "loadend"
      41             : #define ERROR_STR "error"
      42             : #define PROGRESS_STR "progress"
      43             : 
      44             : const uint64_t kUnknownSize = uint64_t(-1);
      45             : 
      46             : static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
      47             : 
      48             : NS_IMPL_CYCLE_COLLECTION_CLASS(FileReader)
      49             : 
      50           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileReader,
      51             :                                                   DOMEventTargetHelper)
      52           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBlob)
      53           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressNotifier)
      54           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
      55           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      56             : 
      57           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileReader,
      58             :                                                 DOMEventTargetHelper)
      59           0 :   tmp->Shutdown();
      60           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlob)
      61           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressNotifier)
      62           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
      63           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      64             : 
      65           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(FileReader,
      66             :                                                DOMEventTargetHelper)
      67           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
      68           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
      69             : 
      70           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileReader)
      71           0 :   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
      72           0 :   NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
      73           0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
      74           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
      75             : 
      76           0 : NS_IMPL_ADDREF_INHERITED(FileReader, DOMEventTargetHelper)
      77           0 : NS_IMPL_RELEASE_INHERITED(FileReader, DOMEventTargetHelper)
      78             : 
      79             : class MOZ_RAII FileReaderDecreaseBusyCounter
      80             : {
      81             :   RefPtr<FileReader> mFileReader;
      82             : public:
      83           0 :   explicit FileReaderDecreaseBusyCounter(FileReader* aFileReader)
      84           0 :     : mFileReader(aFileReader)
      85           0 :   {}
      86             : 
      87           0 :   ~FileReaderDecreaseBusyCounter()
      88           0 :   {
      89           0 :     mFileReader->DecreaseBusyCounter();
      90           0 :   }
      91             : };
      92             : 
      93             : void
      94           0 : FileReader::RootResultArrayBuffer()
      95             : {
      96           0 :   mozilla::HoldJSObjects(this);
      97           0 : }
      98             : 
      99             : //FileReader constructors/initializers
     100             : 
     101           0 : FileReader::FileReader(nsIGlobalObject* aGlobal,
     102           0 :                        WorkerPrivate* aWorkerPrivate)
     103             :   : DOMEventTargetHelper(aGlobal)
     104             :   , mFileData(nullptr)
     105             :   , mDataLen(0)
     106             :   , mDataFormat(FILE_AS_BINARY)
     107             :   , mResultArrayBuffer(nullptr)
     108             :   , mProgressEventWasDelayed(false)
     109             :   , mTimerIsActive(false)
     110             :   , mReadyState(EMPTY)
     111             :   , mTotal(0)
     112             :   , mTransferred(0)
     113             :   , mBusyCount(0)
     114           0 :   , mWorkerPrivate(aWorkerPrivate)
     115             : {
     116           0 :   MOZ_ASSERT(aGlobal);
     117           0 :   MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
     118             : 
     119           0 :   if (NS_IsMainThread()) {
     120           0 :     mTarget = aGlobal->EventTargetFor(TaskCategory::Other);
     121             :   } else {
     122           0 :     mTarget = GetCurrentThreadSerialEventTarget();
     123             :   }
     124             : 
     125           0 :   SetDOMStringToNull(mResult);
     126           0 : }
     127             : 
     128           0 : FileReader::~FileReader()
     129             : {
     130           0 :   Shutdown();
     131           0 :   DropJSObjects(this);
     132           0 : }
     133             : 
     134             : /* static */ already_AddRefed<FileReader>
     135           0 : FileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
     136             : {
     137           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     138           0 :   WorkerPrivate* workerPrivate = nullptr;
     139             : 
     140           0 :   if (!NS_IsMainThread()) {
     141           0 :     JSContext* cx = aGlobal.Context();
     142           0 :     workerPrivate = GetWorkerPrivateFromContext(cx);
     143           0 :     MOZ_ASSERT(workerPrivate);
     144             :   }
     145             : 
     146           0 :   RefPtr<FileReader> fileReader = new FileReader(global, workerPrivate);
     147             : 
     148           0 :   return fileReader.forget();
     149             : }
     150             : 
     151             : // nsIInterfaceRequestor
     152             : 
     153             : NS_IMETHODIMP
     154           0 : FileReader::GetInterface(const nsIID & aIID, void **aResult)
     155             : {
     156           0 :   return QueryInterface(aIID, aResult);
     157             : }
     158             : 
     159             : void
     160           0 : FileReader::GetResult(JSContext* aCx,
     161             :                       JS::MutableHandle<JS::Value> aResult,
     162             :                       ErrorResult& aRv)
     163             : {
     164           0 :   JS::Rooted<JS::Value> result(aCx);
     165             : 
     166           0 :   if (mDataFormat == FILE_AS_ARRAYBUFFER) {
     167           0 :     if (mReadyState == DONE && mResultArrayBuffer) {
     168           0 :       result.setObject(*mResultArrayBuffer);
     169             :     } else {
     170           0 :       result.setNull();
     171             :     }
     172             : 
     173           0 :     if (!JS_WrapValue(aCx, &result)) {
     174           0 :       aRv.Throw(NS_ERROR_FAILURE);
     175           0 :       return;
     176             :     }
     177             : 
     178           0 :     aResult.set(result);
     179           0 :     return;
     180             :   }
     181             : 
     182           0 :   nsString tmpResult = mResult;
     183           0 :   if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
     184           0 :     aRv.Throw(NS_ERROR_FAILURE);
     185           0 :     return;
     186             :   }
     187             : }
     188             : 
     189             : static nsresult
     190           0 : ReadFuncBinaryString(nsIInputStream* in,
     191             :                      void* closure,
     192             :                      const char* fromRawSegment,
     193             :                      uint32_t toOffset,
     194             :                      uint32_t count,
     195             :                      uint32_t *writeCount)
     196             : {
     197           0 :   char16_t* dest = static_cast<char16_t*>(closure) + toOffset;
     198           0 :   char16_t* end = dest + count;
     199           0 :   const unsigned char* source = (const unsigned char*)fromRawSegment;
     200           0 :   while (dest != end) {
     201           0 :     *dest = *source;
     202           0 :     ++dest;
     203           0 :     ++source;
     204             :   }
     205           0 :   *writeCount = count;
     206             : 
     207           0 :   return NS_OK;
     208             : }
     209             : 
     210             : void
     211           0 : FileReader::OnLoadEndArrayBuffer()
     212             : {
     213           0 :   AutoJSAPI jsapi;
     214           0 :   if (!jsapi.Init(GetParentObject())) {
     215           0 :     FreeDataAndDispatchError(NS_ERROR_FAILURE);
     216           0 :     return;
     217             :   }
     218             : 
     219           0 :   RootResultArrayBuffer();
     220             : 
     221           0 :   JSContext* cx = jsapi.cx();
     222             : 
     223           0 :   mResultArrayBuffer = JS_NewArrayBufferWithContents(cx, mDataLen, mFileData);
     224           0 :   if (mResultArrayBuffer) {
     225           0 :     mFileData = nullptr; // Transfer ownership
     226           0 :     FreeDataAndDispatchSuccess();
     227           0 :     return;
     228             :   }
     229             : 
     230             :   // Let's handle the error status.
     231             : 
     232           0 :   JS::Rooted<JS::Value> exceptionValue(cx);
     233           0 :   if (!JS_GetPendingException(cx, &exceptionValue) ||
     234             :       // This should not really happen, exception should always be an object.
     235           0 :       !exceptionValue.isObject()) {
     236           0 :     JS_ClearPendingException(jsapi.cx());
     237           0 :     FreeDataAndDispatchError(NS_ERROR_OUT_OF_MEMORY);
     238           0 :     return;
     239             :   }
     240             : 
     241           0 :   JS_ClearPendingException(jsapi.cx());
     242             : 
     243           0 :   JS::Rooted<JSObject*> exceptionObject(cx, &exceptionValue.toObject());
     244           0 :   JSErrorReport* er = JS_ErrorFromException(cx, exceptionObject);
     245           0 :   if (!er || er->message()) {
     246           0 :     FreeDataAndDispatchError(NS_ERROR_OUT_OF_MEMORY);
     247           0 :     return;
     248             :   }
     249             : 
     250           0 :   nsAutoString errorName;
     251           0 :   JSFlatString* name = js::GetErrorTypeName(cx, er->exnType);
     252           0 :   if (name) {
     253           0 :     AssignJSFlatString(errorName, name);
     254             :   }
     255             : 
     256             :   mError =
     257           0 :     new DOMError(GetOwner(), errorName,
     258           0 :                  NS_ConvertUTF8toUTF16(er->message().c_str()));
     259             : 
     260           0 :   FreeDataAndDispatchError();
     261             : }
     262             : 
     263             : nsresult
     264           0 : FileReader::DoAsyncWait()
     265             : {
     266           0 :   nsresult rv = IncreaseBusyCounter();
     267           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     268           0 :     return rv;
     269             :   }
     270             : 
     271           0 :   rv = mAsyncStream->AsyncWait(this,
     272             :                                /* aFlags*/ 0,
     273             :                                /* aRequestedCount */ 0,
     274           0 :                                mTarget);
     275           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     276           0 :     DecreaseBusyCounter();
     277           0 :     return rv;
     278             :   }
     279             : 
     280           0 :   return NS_OK;
     281             : }
     282             : 
     283             : nsresult
     284           0 : FileReader::DoReadData(uint64_t aCount)
     285             : {
     286           0 :   MOZ_ASSERT(mAsyncStream);
     287             : 
     288           0 :   uint32_t bytesRead = 0;
     289             : 
     290           0 :   if (mDataFormat == FILE_AS_BINARY) {
     291             :     //Continuously update our binary string as data comes in
     292           0 :     uint32_t oldLen = mResult.Length();
     293           0 :     MOZ_ASSERT(mResult.Length() == mDataLen, "unexpected mResult length");
     294           0 :     if (uint64_t(oldLen) + aCount > UINT32_MAX)
     295           0 :       return NS_ERROR_OUT_OF_MEMORY;
     296           0 :     char16_t *buf = nullptr;
     297           0 :     mResult.GetMutableData(&buf, oldLen + aCount, fallible);
     298           0 :     NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
     299             : 
     300             :     nsresult rv;
     301             : 
     302             :     // nsFileStreams do not implement ReadSegment. In case here we are dealing
     303             :     // with a nsIAsyncInputStream, in content process, we need to wrap a
     304             :     // nsIBufferedInputStream around it.
     305           0 :     if (!mBufferedStream) {
     306           0 :       rv = NS_NewBufferedInputStream(getter_AddRefs(mBufferedStream),
     307           0 :                                      mAsyncStream, 8192);
     308           0 :       NS_ENSURE_SUCCESS(rv, rv);
     309             :     }
     310             : 
     311           0 :     rv = mBufferedStream->ReadSegments(ReadFuncBinaryString, buf + oldLen,
     312           0 :                                        aCount, &bytesRead);
     313           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     314           0 :       return rv;
     315             :     }
     316             : 
     317           0 :     mResult.Truncate(oldLen + bytesRead);
     318             :   }
     319             :   else {
     320           0 :     CheckedInt<uint64_t> size = mDataLen;
     321           0 :     size += aCount;
     322             : 
     323             :     //Update memory buffer to reflect the contents of the file
     324           0 :     if (!size.isValid() ||
     325             :         // PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
     326             :         // XXX: it's likely that this check is unnecessary and the comment is
     327             :         // wrong because we no longer use PR_Realloc outside of NSPR and NSS.
     328           0 :         size.value() > UINT32_MAX ||
     329           0 :         size.value() > mTotal) {
     330           0 :       return NS_ERROR_OUT_OF_MEMORY;
     331             :     }
     332             : 
     333           0 :     MOZ_DIAGNOSTIC_ASSERT(mFileData);
     334           0 :     MOZ_RELEASE_ASSERT((mDataLen + aCount) <= mTotal);
     335             : 
     336           0 :     nsresult rv = mAsyncStream->Read(mFileData + mDataLen, aCount, &bytesRead);
     337           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     338           0 :       return rv;
     339             :     }
     340             :   }
     341             : 
     342           0 :   mDataLen += bytesRead;
     343           0 :   return NS_OK;
     344             : }
     345             : 
     346             : // Helper methods
     347             : 
     348             : void
     349           0 : FileReader::ReadFileContent(Blob& aBlob,
     350             :                             const nsAString &aCharset,
     351             :                             eDataFormat aDataFormat,
     352             :                             ErrorResult& aRv)
     353             : {
     354           0 :   if (mReadyState == LOADING) {
     355           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     356           0 :     return;
     357             :   }
     358             : 
     359           0 :   mError = nullptr;
     360             : 
     361           0 :   SetDOMStringToNull(mResult);
     362           0 :   mResultArrayBuffer = nullptr;
     363             : 
     364           0 :   mAsyncStream = nullptr;
     365           0 :   mBufferedStream = nullptr;
     366             : 
     367           0 :   mTransferred = 0;
     368           0 :   mTotal = 0;
     369           0 :   mReadyState = EMPTY;
     370           0 :   FreeFileData();
     371             : 
     372           0 :   mBlob = &aBlob;
     373           0 :   mDataFormat = aDataFormat;
     374           0 :   CopyUTF16toUTF8(aCharset, mCharset);
     375             : 
     376             :   nsresult rv;
     377             :   nsCOMPtr<nsIStreamTransportService> sts =
     378           0 :     do_GetService(kStreamTransportServiceCID, &rv);
     379           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     380           0 :     aRv.Throw(rv);
     381           0 :     return;
     382             :   }
     383             : 
     384           0 :   nsCOMPtr<nsIInputStream> stream;
     385           0 :   mBlob->GetInternalStream(getter_AddRefs(stream), aRv);
     386           0 :   if (NS_WARN_IF(aRv.Failed())) {
     387           0 :     return;
     388             :   }
     389             : 
     390           0 :   mAsyncStream = do_QueryInterface(stream);
     391           0 :   if (!mAsyncStream) {
     392           0 :     nsCOMPtr<nsITransport> transport;
     393           0 :     aRv = sts->CreateInputTransport(stream,
     394             :                                     /* aStartOffset */ 0,
     395             :                                     /* aReadLimit */ -1,
     396             :                                     /* aCloseWhenDone */ true,
     397           0 :                                     getter_AddRefs(transport));
     398           0 :     if (NS_WARN_IF(aRv.Failed())) {
     399           0 :       return;
     400             :     }
     401             : 
     402           0 :     nsCOMPtr<nsIInputStream> wrapper;
     403           0 :     aRv = transport->OpenInputStream(/* aFlags */ 0,
     404             :                                      /* aSegmentSize */ 0,
     405             :                                      /* aSegmentCount */ 0,
     406           0 :                                      getter_AddRefs(wrapper));
     407           0 :     if (NS_WARN_IF(aRv.Failed())) {
     408           0 :       return;
     409             :     }
     410             : 
     411           0 :     mAsyncStream = do_QueryInterface(wrapper);
     412             :   }
     413             : 
     414           0 :   MOZ_ASSERT(mAsyncStream);
     415             : 
     416           0 :   mTotal = mBlob->GetSize(aRv);
     417           0 :   if (NS_WARN_IF(aRv.Failed())) {
     418           0 :     return;
     419             :   }
     420             : 
     421             :   // Binary Format doesn't need a post-processing of the data. Everything is
     422             :   // written directly into mResult.
     423           0 :   if (mDataFormat != FILE_AS_BINARY) {
     424           0 :     if (mDataFormat == FILE_AS_ARRAYBUFFER) {
     425           0 :       mFileData = js_pod_malloc<char>(mTotal);
     426             :     } else {
     427           0 :       mFileData = (char *) malloc(mTotal);
     428             :     }
     429             : 
     430           0 :     if (!mFileData) {
     431           0 :       NS_WARNING("Preallocation failed for ReadFileData");
     432           0 :       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     433           0 :       return;
     434             :     }
     435             :   }
     436             : 
     437           0 :   aRv = DoAsyncWait();
     438           0 :   if (NS_WARN_IF(aRv.Failed())) {
     439           0 :     FreeFileData();
     440           0 :     return;
     441             :   }
     442             : 
     443             :   //FileReader should be in loading state here
     444           0 :   mReadyState = LOADING;
     445           0 :   DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));
     446             : }
     447             : 
     448             : nsresult
     449           0 : FileReader::GetAsText(Blob *aBlob,
     450             :                       const nsACString &aCharset,
     451             :                       const char *aFileData,
     452             :                       uint32_t aDataLen,
     453             :                       nsAString& aResult)
     454             : {
     455             :   // Try the API argument.
     456           0 :   const Encoding* encoding = Encoding::ForLabel(aCharset);
     457           0 :   if (!encoding) {
     458             :     // API argument failed. Try the type property of the blob.
     459           0 :     nsAutoString type16;
     460           0 :     aBlob->GetType(type16);
     461           0 :     NS_ConvertUTF16toUTF8 type(type16);
     462           0 :     nsAutoCString specifiedCharset;
     463             :     bool haveCharset;
     464             :     int32_t charsetStart, charsetEnd;
     465             :     NS_ExtractCharsetFromContentType(type,
     466             :                                      specifiedCharset,
     467             :                                      &haveCharset,
     468             :                                      &charsetStart,
     469           0 :                                      &charsetEnd);
     470           0 :     encoding = Encoding::ForLabel(specifiedCharset);
     471           0 :     if (!encoding) {
     472             :       // Type property failed. Use UTF-8.
     473           0 :       encoding = UTF_8_ENCODING;
     474             :     }
     475             :   }
     476             : 
     477             :   auto data = MakeSpan(reinterpret_cast<const uint8_t*>(aFileData),
     478           0 :                        aDataLen);
     479             :   nsresult rv;
     480           0 :   Tie(rv, encoding) = encoding->Decode(data, aResult);
     481           0 :   return NS_FAILED(rv) ? rv : NS_OK;
     482             : }
     483             : 
     484             : nsresult
     485           0 : FileReader::GetAsDataURL(Blob *aBlob,
     486             :                          const char *aFileData,
     487             :                          uint32_t aDataLen,
     488             :                          nsAString& aResult)
     489             : {
     490           0 :   aResult.AssignLiteral("data:");
     491             : 
     492           0 :   nsAutoString contentType;
     493           0 :   aBlob->GetType(contentType);
     494           0 :   if (!contentType.IsEmpty()) {
     495           0 :     aResult.Append(contentType);
     496             :   } else {
     497           0 :     aResult.AppendLiteral("application/octet-stream");
     498             :   }
     499           0 :   aResult.AppendLiteral(";base64,");
     500             : 
     501           0 :   nsCString encodedData;
     502           0 :   nsresult rv = Base64Encode(Substring(aFileData, aDataLen), encodedData);
     503           0 :   NS_ENSURE_SUCCESS(rv, rv);
     504             : 
     505           0 :   if (!AppendASCIItoUTF16(encodedData, aResult, fallible)) {
     506           0 :     return NS_ERROR_OUT_OF_MEMORY;
     507             :   }
     508             : 
     509           0 :   return NS_OK;
     510             : }
     511             : 
     512             : /* virtual */ JSObject*
     513           0 : FileReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     514             : {
     515           0 :   return FileReaderBinding::Wrap(aCx, this, aGivenProto);
     516             : }
     517             : 
     518             : void
     519           0 : FileReader::StartProgressEventTimer()
     520             : {
     521           0 :   if (!mProgressNotifier) {
     522           0 :     mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
     523             :   }
     524             : 
     525           0 :   if (mProgressNotifier) {
     526           0 :     mProgressEventWasDelayed = false;
     527           0 :     mTimerIsActive = true;
     528           0 :     mProgressNotifier->Cancel();
     529           0 :     mProgressNotifier->SetTarget(mTarget);
     530           0 :     mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
     531           0 :                                         nsITimer::TYPE_ONE_SHOT);
     532             :   }
     533           0 : }
     534             : 
     535             : void
     536           0 : FileReader::ClearProgressEventTimer()
     537             : {
     538           0 :   mProgressEventWasDelayed = false;
     539           0 :   mTimerIsActive = false;
     540           0 :   if (mProgressNotifier) {
     541           0 :     mProgressNotifier->Cancel();
     542             :   }
     543           0 : }
     544             : 
     545             : void
     546           0 : FileReader::FreeDataAndDispatchSuccess()
     547             : {
     548           0 :   FreeFileData();
     549           0 :   mResult.SetIsVoid(false);
     550           0 :   mAsyncStream = nullptr;
     551           0 :   mBufferedStream = nullptr;
     552           0 :   mBlob = nullptr;
     553             : 
     554             :   // Dispatch event to signify end of a successful operation
     555           0 :   DispatchProgressEvent(NS_LITERAL_STRING(LOAD_STR));
     556           0 :   DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
     557           0 : }
     558             : 
     559             : void
     560           0 : FileReader::FreeDataAndDispatchError()
     561             : {
     562           0 :   MOZ_ASSERT(mError);
     563             : 
     564           0 :   FreeFileData();
     565           0 :   mResult.SetIsVoid(true);
     566           0 :   mAsyncStream = nullptr;
     567           0 :   mBufferedStream = nullptr;
     568           0 :   mBlob = nullptr;
     569             : 
     570             :   // Dispatch error event to signify load failure
     571           0 :   DispatchProgressEvent(NS_LITERAL_STRING(ERROR_STR));
     572           0 :   DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
     573           0 : }
     574             : 
     575             : void
     576           0 : FileReader::FreeDataAndDispatchError(nsresult aRv)
     577             : {
     578             :   // Set the status attribute, and dispatch the error event
     579           0 :   switch (aRv) {
     580             :   case NS_ERROR_FILE_NOT_FOUND:
     581           0 :     mError = new DOMError(GetOwner(), NS_LITERAL_STRING("NotFoundError"));
     582           0 :     break;
     583             :   case NS_ERROR_FILE_ACCESS_DENIED:
     584           0 :     mError = new DOMError(GetOwner(), NS_LITERAL_STRING("SecurityError"));
     585           0 :     break;
     586             :   default:
     587           0 :     mError = new DOMError(GetOwner(), NS_LITERAL_STRING("NotReadableError"));
     588           0 :     break;
     589             :   }
     590             : 
     591           0 :   FreeDataAndDispatchError();
     592           0 : }
     593             : 
     594             : nsresult
     595           0 : FileReader::DispatchProgressEvent(const nsAString& aType)
     596             : {
     597           0 :   ProgressEventInit init;
     598           0 :   init.mBubbles = false;
     599           0 :   init.mCancelable = false;
     600           0 :   init.mLoaded = mTransferred;
     601             : 
     602           0 :   if (mTotal != kUnknownSize) {
     603           0 :     init.mLengthComputable = true;
     604           0 :     init.mTotal = mTotal;
     605             :   } else {
     606           0 :     init.mLengthComputable = false;
     607           0 :     init.mTotal = 0;
     608             :   }
     609             :   RefPtr<ProgressEvent> event =
     610           0 :     ProgressEvent::Constructor(this, aType, init);
     611           0 :   event->SetTrusted(true);
     612             : 
     613           0 :   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
     614             : }
     615             : 
     616             : // nsITimerCallback
     617             : NS_IMETHODIMP
     618           0 : FileReader::Notify(nsITimer* aTimer)
     619             : {
     620             :   nsresult rv;
     621           0 :   mTimerIsActive = false;
     622             : 
     623           0 :   if (mProgressEventWasDelayed) {
     624           0 :     rv = DispatchProgressEvent(NS_LITERAL_STRING("progress"));
     625           0 :     NS_ENSURE_SUCCESS(rv, rv);
     626             : 
     627           0 :     StartProgressEventTimer();
     628             :   }
     629             : 
     630           0 :   return NS_OK;
     631             : }
     632             : 
     633             : // InputStreamCallback
     634             : NS_IMETHODIMP
     635           0 : FileReader::OnInputStreamReady(nsIAsyncInputStream* aStream)
     636             : {
     637           0 :   if (mReadyState != LOADING || aStream != mAsyncStream) {
     638           0 :     return NS_OK;
     639             :   }
     640             : 
     641             :   // We use this class to decrease the busy counter at the end of this method.
     642             :   // In theory we can do it immediatelly but, for debugging reasons, we want to
     643             :   // be 100% sure we have a workerHolder when OnLoadEnd() is called.
     644           0 :   FileReaderDecreaseBusyCounter RAII(this);
     645             : 
     646             :   uint64_t count;
     647           0 :   nsresult rv = aStream->Available(&count);
     648             : 
     649           0 :   if (NS_SUCCEEDED(rv) && count) {
     650           0 :     rv = DoReadData(count);
     651             : 
     652           0 :     if (NS_SUCCEEDED(rv)) {
     653           0 :       rv = DoAsyncWait();
     654             :     }
     655             :   }
     656             : 
     657           0 :   if (NS_FAILED(rv) || !count) {
     658           0 :     if (rv == NS_BASE_STREAM_CLOSED) {
     659           0 :       rv = NS_OK;
     660             :     }
     661           0 :     return OnLoadEnd(rv);
     662             :   }
     663             : 
     664           0 :   mTransferred += count;
     665             : 
     666             :   //Notify the timer is the appropriate timeframe has passed
     667           0 :   if (mTimerIsActive) {
     668           0 :     mProgressEventWasDelayed = true;
     669             :   } else {
     670           0 :     rv = DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR));
     671           0 :     NS_ENSURE_SUCCESS(rv, rv);
     672             : 
     673           0 :     StartProgressEventTimer();
     674             :   }
     675             : 
     676           0 :   return NS_OK;
     677             : }
     678             : 
     679             : nsresult
     680           0 : FileReader::OnLoadEnd(nsresult aStatus)
     681             : {
     682             :   // Cancel the progress event timer
     683           0 :   ClearProgressEventTimer();
     684             : 
     685             :   // FileReader must be in DONE stage after an operation
     686           0 :   mReadyState = DONE;
     687             : 
     688             :   // Quick return, if failed.
     689           0 :   if (NS_FAILED(aStatus)) {
     690           0 :     FreeDataAndDispatchError(aStatus);
     691           0 :     return NS_OK;
     692             :   }
     693             : 
     694             :   // In case we read a different number of bytes, we can assume that the
     695             :   // underlying storage has changed. We should not continue.
     696           0 :   if (mDataLen != mTotal) {
     697           0 :     FreeDataAndDispatchError(NS_ERROR_FAILURE);
     698           0 :     return NS_OK;
     699             :   }
     700             : 
     701             :   // ArrayBuffer needs a custom handling.
     702           0 :   if (mDataFormat == FILE_AS_ARRAYBUFFER) {
     703           0 :     OnLoadEndArrayBuffer();
     704           0 :     return NS_OK;
     705             :   }
     706             : 
     707           0 :   nsresult rv = NS_OK;
     708             : 
     709             :   // We don't do anything special for Binary format.
     710             : 
     711           0 :   if (mDataFormat == FILE_AS_DATAURL) {
     712           0 :     rv = GetAsDataURL(mBlob, mFileData, mDataLen, mResult);
     713           0 :   } else if (mDataFormat == FILE_AS_TEXT) {
     714           0 :     if (!mFileData && mDataLen) {
     715           0 :       rv = NS_ERROR_OUT_OF_MEMORY;
     716           0 :     } else if (!mFileData) {
     717           0 :       rv = GetAsText(mBlob, mCharset, "", mDataLen, mResult);
     718             :     } else {
     719           0 :       rv = GetAsText(mBlob, mCharset, mFileData, mDataLen, mResult);
     720             :     }
     721             :   }
     722             : 
     723           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     724           0 :     FreeDataAndDispatchError(rv);
     725           0 :     return NS_OK;
     726             :   }
     727             : 
     728           0 :   FreeDataAndDispatchSuccess();
     729           0 :   return NS_OK;
     730             : }
     731             : 
     732             : void
     733           0 : FileReader::Abort()
     734             : {
     735           0 :   if (mReadyState == EMPTY || mReadyState == DONE) {
     736           0 :     return;
     737             :   }
     738             : 
     739           0 :   MOZ_ASSERT(mReadyState == LOADING);
     740             : 
     741           0 :   ClearProgressEventTimer();
     742             : 
     743           0 :   mReadyState = DONE;
     744             : 
     745             :   // XXX The spec doesn't say this
     746           0 :   mError = new DOMError(GetOwner(), NS_LITERAL_STRING("AbortError"));
     747             : 
     748             :   // Revert status and result attributes
     749           0 :   SetDOMStringToNull(mResult);
     750           0 :   mResultArrayBuffer = nullptr;
     751             : 
     752           0 :   mAsyncStream = nullptr;
     753           0 :   mBufferedStream = nullptr;
     754           0 :   mBlob = nullptr;
     755             : 
     756             :   //Clean up memory buffer
     757           0 :   FreeFileData();
     758             : 
     759             :   // Dispatch the events
     760           0 :   DispatchProgressEvent(NS_LITERAL_STRING(ABORT_STR));
     761           0 :   DispatchProgressEvent(NS_LITERAL_STRING(LOADEND_STR));
     762             : }
     763             : 
     764             : nsresult
     765           0 : FileReader::IncreaseBusyCounter()
     766             : {
     767           0 :   if (mWorkerPrivate && mBusyCount++ == 0 &&
     768           0 :       !HoldWorker(mWorkerPrivate, Closing)) {
     769           0 :     return NS_ERROR_FAILURE;
     770             :   }
     771             : 
     772           0 :   return NS_OK;
     773             : }
     774             : 
     775             : void
     776           0 : FileReader::DecreaseBusyCounter()
     777             : {
     778           0 :   MOZ_ASSERT_IF(mWorkerPrivate, mBusyCount);
     779           0 :   if (mWorkerPrivate && --mBusyCount == 0) {
     780           0 :     ReleaseWorker();
     781             :   }
     782           0 : }
     783             : 
     784             : bool
     785           0 : FileReader::Notify(Status aStatus)
     786             : {
     787           0 :   MOZ_ASSERT(mWorkerPrivate);
     788           0 :   mWorkerPrivate->AssertIsOnWorkerThread();
     789             : 
     790           0 :   if (aStatus > Running) {
     791           0 :     Shutdown();
     792             :   }
     793             : 
     794           0 :   return true;
     795             : }
     796             : 
     797             : void
     798           0 : FileReader::Shutdown()
     799             : {
     800           0 :   mReadyState = DONE;
     801             : 
     802           0 :   if (mAsyncStream) {
     803           0 :     mAsyncStream->Close();
     804           0 :     mAsyncStream = nullptr;
     805             :   }
     806             : 
     807           0 :   if (mBufferedStream) {
     808           0 :     mBufferedStream->Close();
     809           0 :     mBufferedStream = nullptr;
     810             :   }
     811             : 
     812           0 :   FreeFileData();
     813           0 :   mResultArrayBuffer = nullptr;
     814             : 
     815           0 :   if (mWorkerPrivate && mBusyCount != 0) {
     816           0 :     ReleaseWorker();
     817           0 :     mWorkerPrivate = nullptr;
     818           0 :     mBusyCount = 0;
     819             :   }
     820           0 : }
     821             : 
     822             : } // dom namespace
     823             : } // mozilla namespace

Generated by: LCOV version 1.13