content/base/src/nsDOMFileReader.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsDOMFileReader.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,557 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsDOMFileReader.h"
    1.10 +
    1.11 +#include "nsContentCID.h"
    1.12 +#include "nsContentUtils.h"
    1.13 +#include "nsDOMClassInfoID.h"
    1.14 +#include "nsDOMFile.h"
    1.15 +#include "nsError.h"
    1.16 +#include "nsIConverterInputStream.h"
    1.17 +#include "nsIDocument.h"
    1.18 +#include "nsIFile.h"
    1.19 +#include "nsIFileStreams.h"
    1.20 +#include "nsIInputStream.h"
    1.21 +#include "nsIMIMEService.h"
    1.22 +#include "nsIUnicodeDecoder.h"
    1.23 +#include "nsNetCID.h"
    1.24 +#include "nsNetUtil.h"
    1.25 +
    1.26 +#include "nsLayoutCID.h"
    1.27 +#include "nsXPIDLString.h"
    1.28 +#include "nsReadableUtils.h"
    1.29 +#include "nsIURI.h"
    1.30 +#include "nsStreamUtils.h"
    1.31 +#include "nsXPCOM.h"
    1.32 +#include "nsIDOMEventListener.h"
    1.33 +#include "nsJSEnvironment.h"
    1.34 +#include "nsIScriptGlobalObject.h"
    1.35 +#include "nsCExternalHandlerService.h"
    1.36 +#include "nsIStreamConverterService.h"
    1.37 +#include "nsCycleCollectionParticipant.h"
    1.38 +#include "nsIScriptObjectPrincipal.h"
    1.39 +#include "nsHostObjectProtocolHandler.h"
    1.40 +#include "mozilla/Base64.h"
    1.41 +#include "mozilla/DOMEventTargetHelper.h"
    1.42 +#include "mozilla/Preferences.h"
    1.43 +#include "mozilla/dom/EncodingUtils.h"
    1.44 +#include "mozilla/dom/FileReaderBinding.h"
    1.45 +#include "xpcpublic.h"
    1.46 +#include "nsIScriptSecurityManager.h"
    1.47 +#include "nsDOMJSUtils.h"
    1.48 +
    1.49 +#include "jsfriendapi.h"
    1.50 +
    1.51 +using namespace mozilla;
    1.52 +using namespace mozilla::dom;
    1.53 +
    1.54 +#define LOAD_STR "load"
    1.55 +#define LOADSTART_STR "loadstart"
    1.56 +#define LOADEND_STR "loadend"
    1.57 +
    1.58 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileReader)
    1.59 +
    1.60 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileReader,
    1.61 +                                                  FileIOObject)
    1.62 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFile)
    1.63 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
    1.64 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1.65 +
    1.66 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMFileReader,
    1.67 +                                                FileIOObject)
    1.68 +  tmp->mResultArrayBuffer = nullptr;
    1.69 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFile)
    1.70 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
    1.71 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1.72 +
    1.73 +
    1.74 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMFileReader,
    1.75 +                                               DOMEventTargetHelper)
    1.76 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
    1.77 +NS_IMPL_CYCLE_COLLECTION_TRACE_END
    1.78 +
    1.79 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMFileReader)
    1.80 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    1.81 +  NS_INTERFACE_MAP_ENTRY(nsIDOMFileReader)
    1.82 +  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
    1.83 +  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    1.84 +NS_INTERFACE_MAP_END_INHERITING(FileIOObject)
    1.85 +
    1.86 +NS_IMPL_ADDREF_INHERITED(nsDOMFileReader, FileIOObject)
    1.87 +NS_IMPL_RELEASE_INHERITED(nsDOMFileReader, FileIOObject)
    1.88 +
    1.89 +NS_IMPL_EVENT_HANDLER(nsDOMFileReader, load)
    1.90 +NS_IMPL_EVENT_HANDLER(nsDOMFileReader, loadend)
    1.91 +NS_IMPL_EVENT_HANDLER(nsDOMFileReader, loadstart)
    1.92 +NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, abort, FileIOObject)
    1.93 +NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, progress, FileIOObject)
    1.94 +NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, error, FileIOObject)
    1.95 +
    1.96 +void
    1.97 +nsDOMFileReader::RootResultArrayBuffer()
    1.98 +{
    1.99 +  mozilla::HoldJSObjects(this);
   1.100 +}
   1.101 +
   1.102 +//nsDOMFileReader constructors/initializers
   1.103 +
   1.104 +nsDOMFileReader::nsDOMFileReader()
   1.105 +  : mFileData(nullptr),
   1.106 +    mDataLen(0), mDataFormat(FILE_AS_BINARY),
   1.107 +    mResultArrayBuffer(nullptr)
   1.108 +{
   1.109 +  SetDOMStringToNull(mResult);
   1.110 +  SetIsDOMBinding();
   1.111 +}
   1.112 +
   1.113 +nsDOMFileReader::~nsDOMFileReader()
   1.114 +{
   1.115 +  FreeFileData();
   1.116 +  mResultArrayBuffer = nullptr;
   1.117 +  mozilla::DropJSObjects(this);
   1.118 +}
   1.119 +
   1.120 +
   1.121 +/**
   1.122 + * This Init method is called from the factory constructor.
   1.123 + */
   1.124 +nsresult
   1.125 +nsDOMFileReader::Init()
   1.126 +{
   1.127 +  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   1.128 +  nsCOMPtr<nsIPrincipal> principal;
   1.129 +  if (secMan) {
   1.130 +    secMan->GetSystemPrincipal(getter_AddRefs(principal));
   1.131 +  }
   1.132 +  NS_ENSURE_STATE(principal);
   1.133 +  mPrincipal.swap(principal);
   1.134 +
   1.135 +  // Instead of grabbing some random global from the context stack,
   1.136 +  // let's use the default one (junk scope) for now.
   1.137 +  // We should move away from this Init...
   1.138 +  nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal();
   1.139 +  NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
   1.140 +  BindToOwner(global);
   1.141 +  return NS_OK;
   1.142 +}
   1.143 +
   1.144 +/* static */ already_AddRefed<nsDOMFileReader>
   1.145 +nsDOMFileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
   1.146 +{
   1.147 +  nsRefPtr<nsDOMFileReader> fileReader = new nsDOMFileReader();
   1.148 +
   1.149 +  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.GetAsSupports());
   1.150 +  if (!owner) {
   1.151 +    NS_WARNING("Unexpected nsIJSNativeInitializer owner");
   1.152 +    aRv.Throw(NS_ERROR_FAILURE);
   1.153 +    return nullptr;
   1.154 +  }
   1.155 +
   1.156 +  fileReader->BindToOwner(owner);
   1.157 +
   1.158 +  // This object is bound to a |window|,
   1.159 +  // so reset the principal.
   1.160 +  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(owner);
   1.161 +  if (!scriptPrincipal) {
   1.162 +    aRv.Throw(NS_ERROR_FAILURE);
   1.163 +    return nullptr;
   1.164 +  }
   1.165 +  fileReader->mPrincipal = scriptPrincipal->GetPrincipal();
   1.166 +  return fileReader.forget();
   1.167 +}
   1.168 +
   1.169 +// nsIInterfaceRequestor
   1.170 +
   1.171 +NS_IMETHODIMP
   1.172 +nsDOMFileReader::GetInterface(const nsIID & aIID, void **aResult)
   1.173 +{
   1.174 +  return QueryInterface(aIID, aResult);
   1.175 +}
   1.176 +
   1.177 +// nsIDOMFileReader
   1.178 +
   1.179 +NS_IMETHODIMP
   1.180 +nsDOMFileReader::GetReadyState(uint16_t *aReadyState)
   1.181 +{
   1.182 +  *aReadyState = ReadyState();
   1.183 +  return NS_OK;
   1.184 +}
   1.185 +
   1.186 +void
   1.187 +nsDOMFileReader::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   1.188 +                           ErrorResult& aRv)
   1.189 +{
   1.190 +  aRv = GetResult(aCx, aResult);
   1.191 +}
   1.192 +
   1.193 +NS_IMETHODIMP
   1.194 +nsDOMFileReader::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
   1.195 +{
   1.196 +  JS::Rooted<JS::Value> result(aCx);
   1.197 +  if (mDataFormat == FILE_AS_ARRAYBUFFER) {
   1.198 +    if (mReadyState == nsIDOMFileReader::DONE && mResultArrayBuffer) {
   1.199 +      result.setObject(*mResultArrayBuffer);
   1.200 +    } else {
   1.201 +      result.setNull();
   1.202 +    }
   1.203 +    if (!JS_WrapValue(aCx, &result)) {
   1.204 +      return NS_ERROR_FAILURE;
   1.205 +    }
   1.206 +    aResult.set(result);
   1.207 +    return NS_OK;
   1.208 +  }
   1.209 +
   1.210 +  nsString tmpResult = mResult;
   1.211 +  if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
   1.212 +    return NS_ERROR_FAILURE;
   1.213 +  }
   1.214 +  return NS_OK;
   1.215 +}
   1.216 +
   1.217 +NS_IMETHODIMP
   1.218 +nsDOMFileReader::GetError(nsISupports** aError)
   1.219 +{
   1.220 +  NS_IF_ADDREF(*aError = GetError());
   1.221 +  return NS_OK;
   1.222 +}
   1.223 +
   1.224 +NS_IMETHODIMP
   1.225 +nsDOMFileReader::ReadAsArrayBuffer(nsIDOMBlob* aFile, JSContext* aCx)
   1.226 +{
   1.227 +  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   1.228 +  ErrorResult rv;
   1.229 +  ReadAsArrayBuffer(aCx, aFile, rv);
   1.230 +  return rv.ErrorCode();
   1.231 +}
   1.232 +
   1.233 +NS_IMETHODIMP
   1.234 +nsDOMFileReader::ReadAsBinaryString(nsIDOMBlob* aFile)
   1.235 +{
   1.236 +  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   1.237 +  ErrorResult rv;
   1.238 +  ReadAsBinaryString(aFile, rv);
   1.239 +  return rv.ErrorCode();
   1.240 +}
   1.241 +
   1.242 +NS_IMETHODIMP
   1.243 +nsDOMFileReader::ReadAsText(nsIDOMBlob* aFile,
   1.244 +                            const nsAString &aCharset)
   1.245 +{
   1.246 +  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   1.247 +  ErrorResult rv;
   1.248 +  ReadAsText(aFile, aCharset, rv);
   1.249 +  return rv.ErrorCode();
   1.250 +}
   1.251 +
   1.252 +NS_IMETHODIMP
   1.253 +nsDOMFileReader::ReadAsDataURL(nsIDOMBlob* aFile)
   1.254 +{
   1.255 +  NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER);
   1.256 +  ErrorResult rv;
   1.257 +  ReadAsDataURL(aFile, rv);
   1.258 +  return rv.ErrorCode();
   1.259 +}
   1.260 +
   1.261 +NS_IMETHODIMP
   1.262 +nsDOMFileReader::Abort()
   1.263 +{
   1.264 +  ErrorResult rv;
   1.265 +  FileIOObject::Abort(rv);
   1.266 +  return rv.ErrorCode();
   1.267 +}
   1.268 +
   1.269 +/* virtual */ void
   1.270 +nsDOMFileReader::DoAbort(nsAString& aEvent)
   1.271 +{
   1.272 +  // Revert status and result attributes
   1.273 +  SetDOMStringToNull(mResult);
   1.274 +  mResultArrayBuffer = nullptr;
   1.275 +    
   1.276 +  // Non-null channel indicates a read is currently active
   1.277 +  if (mChannel) {
   1.278 +    // Cancel request requires an error status
   1.279 +    mChannel->Cancel(NS_ERROR_FAILURE);
   1.280 +    mChannel = nullptr;
   1.281 +  }
   1.282 +  mFile = nullptr;
   1.283 +
   1.284 +  //Clean up memory buffer
   1.285 +  FreeFileData();
   1.286 +
   1.287 +  // Tell the base class which event to dispatch
   1.288 +  aEvent = NS_LITERAL_STRING(LOADEND_STR);
   1.289 +}
   1.290 +
   1.291 +static
   1.292 +NS_METHOD
   1.293 +ReadFuncBinaryString(nsIInputStream* in,
   1.294 +                     void* closure,
   1.295 +                     const char* fromRawSegment,
   1.296 +                     uint32_t toOffset,
   1.297 +                     uint32_t count,
   1.298 +                     uint32_t *writeCount)
   1.299 +{
   1.300 +  char16_t* dest = static_cast<char16_t*>(closure) + toOffset;
   1.301 +  char16_t* end = dest + count;
   1.302 +  const unsigned char* source = (const unsigned char*)fromRawSegment;
   1.303 +  while (dest != end) {
   1.304 +    *dest = *source;
   1.305 +    ++dest;
   1.306 +    ++source;
   1.307 +  }
   1.308 +  *writeCount = count;
   1.309 +
   1.310 +  return NS_OK;
   1.311 +}
   1.312 +
   1.313 +nsresult
   1.314 +nsDOMFileReader::DoOnDataAvailable(nsIRequest *aRequest,
   1.315 +                                   nsISupports *aContext,
   1.316 +                                   nsIInputStream *aInputStream,
   1.317 +                                   uint64_t aOffset,
   1.318 +                                   uint32_t aCount)
   1.319 +{
   1.320 +  if (mDataFormat == FILE_AS_BINARY) {
   1.321 +    //Continuously update our binary string as data comes in
   1.322 +    NS_ASSERTION(mResult.Length() == aOffset,
   1.323 +                 "unexpected mResult length");
   1.324 +    uint32_t oldLen = mResult.Length();
   1.325 +    if (uint64_t(oldLen) + aCount > UINT32_MAX)
   1.326 +      return NS_ERROR_OUT_OF_MEMORY;
   1.327 +
   1.328 +    char16_t *buf = nullptr;
   1.329 +    mResult.GetMutableData(&buf, oldLen + aCount, fallible_t());
   1.330 +    NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
   1.331 +
   1.332 +    uint32_t bytesRead = 0;
   1.333 +    aInputStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount,
   1.334 +                               &bytesRead);
   1.335 +    NS_ASSERTION(bytesRead == aCount, "failed to read data");
   1.336 +  }
   1.337 +  else if (mDataFormat == FILE_AS_ARRAYBUFFER) {
   1.338 +    uint32_t bytesRead = 0;
   1.339 +    aInputStream->Read((char*)JS_GetArrayBufferData(mResultArrayBuffer) + aOffset,
   1.340 +                       aCount, &bytesRead);
   1.341 +    NS_ASSERTION(bytesRead == aCount, "failed to read data");
   1.342 +  }
   1.343 +  else {
   1.344 +    //Update memory buffer to reflect the contents of the file
   1.345 +    if (aOffset + aCount > UINT32_MAX) {
   1.346 +      // PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
   1.347 +      return NS_ERROR_OUT_OF_MEMORY;
   1.348 +    }
   1.349 +    mFileData = (char *)moz_realloc(mFileData, aOffset + aCount);
   1.350 +    NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
   1.351 +
   1.352 +    uint32_t bytesRead = 0;
   1.353 +    aInputStream->Read(mFileData + aOffset, aCount, &bytesRead);
   1.354 +    NS_ASSERTION(bytesRead == aCount, "failed to read data");
   1.355 +
   1.356 +    mDataLen += aCount;
   1.357 +  }
   1.358 +
   1.359 +  return NS_OK;
   1.360 +}
   1.361 +
   1.362 +nsresult
   1.363 +nsDOMFileReader::DoOnStopRequest(nsIRequest *aRequest,
   1.364 +                                 nsISupports *aContext,
   1.365 +                                 nsresult aStatus,
   1.366 +                                 nsAString& aSuccessEvent,
   1.367 +                                 nsAString& aTerminationEvent)
   1.368 +{
   1.369 +  // Make sure we drop all the objects that could hold files open now.
   1.370 +  nsCOMPtr<nsIChannel> channel;
   1.371 +  mChannel.swap(channel);
   1.372 +
   1.373 +  nsCOMPtr<nsIDOMBlob> file;
   1.374 +  mFile.swap(file);
   1.375 +
   1.376 +  aSuccessEvent = NS_LITERAL_STRING(LOAD_STR);
   1.377 +  aTerminationEvent = NS_LITERAL_STRING(LOADEND_STR);
   1.378 +
   1.379 +  // Clear out the data if necessary
   1.380 +  if (NS_FAILED(aStatus)) {
   1.381 +    FreeFileData();
   1.382 +    return NS_OK;
   1.383 +  }
   1.384 +
   1.385 +  nsresult rv = NS_OK;
   1.386 +  switch (mDataFormat) {
   1.387 +    case FILE_AS_ARRAYBUFFER:
   1.388 +      break; //Already accumulated mResultArrayBuffer
   1.389 +    case FILE_AS_BINARY:
   1.390 +      break; //Already accumulated mResult
   1.391 +    case FILE_AS_TEXT:
   1.392 +      if (!mFileData) {
   1.393 +        if (mDataLen) {
   1.394 +          rv = NS_ERROR_OUT_OF_MEMORY;
   1.395 +          break;
   1.396 +        }
   1.397 +        rv = GetAsText(file, mCharset, "", mDataLen, mResult);
   1.398 +        break;
   1.399 +      }
   1.400 +      rv = GetAsText(file, mCharset, mFileData, mDataLen, mResult);
   1.401 +      break;
   1.402 +    case FILE_AS_DATAURL:
   1.403 +      rv = GetAsDataURL(file, mFileData, mDataLen, mResult);
   1.404 +      break;
   1.405 +  }
   1.406 +  
   1.407 +  mResult.SetIsVoid(false);
   1.408 +
   1.409 +  FreeFileData();
   1.410 +
   1.411 +  return rv;
   1.412 +}
   1.413 +
   1.414 +// Helper methods
   1.415 +
   1.416 +void
   1.417 +nsDOMFileReader::ReadFileContent(JSContext* aCx,
   1.418 +                                 nsIDOMBlob* aFile,
   1.419 +                                 const nsAString &aCharset,
   1.420 +                                 eDataFormat aDataFormat,
   1.421 +                                 ErrorResult& aRv)
   1.422 +{
   1.423 +  MOZ_ASSERT(aFile);
   1.424 +
   1.425 +  //Implicit abort to clear any other activity going on
   1.426 +  Abort();
   1.427 +  mError = nullptr;
   1.428 +  SetDOMStringToNull(mResult);
   1.429 +  mTransferred = 0;
   1.430 +  mTotal = 0;
   1.431 +  mReadyState = nsIDOMFileReader::EMPTY;
   1.432 +  FreeFileData();
   1.433 +
   1.434 +  mFile = aFile;
   1.435 +  mDataFormat = aDataFormat;
   1.436 +  CopyUTF16toUTF8(aCharset, mCharset);
   1.437 +
   1.438 +  //Establish a channel with our file
   1.439 +  {
   1.440 +    // Hold the internal URL alive only as long as necessary
   1.441 +    // After the channel is created it will own whatever is backing
   1.442 +    // the DOMFile.
   1.443 +    nsDOMFileInternalUrlHolder urlHolder(mFile, mPrincipal);
   1.444 +
   1.445 +    nsCOMPtr<nsIURI> uri;
   1.446 +    aRv = NS_NewURI(getter_AddRefs(uri), urlHolder.mUrl);
   1.447 +    NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode());
   1.448 +
   1.449 +    nsCOMPtr<nsILoadGroup> loadGroup;
   1.450 +    if (HasOrHasHadOwner()) {
   1.451 +      if (!GetOwner()) {
   1.452 +        aRv.Throw(NS_ERROR_FAILURE);
   1.453 +        return;
   1.454 +      }
   1.455 +      nsIDocument* doc = GetOwner()->GetExtantDoc();
   1.456 +      if (doc) {
   1.457 +        loadGroup = doc->GetDocumentLoadGroup();
   1.458 +      }
   1.459 +    }
   1.460 +
   1.461 +    aRv = NS_NewChannel(getter_AddRefs(mChannel), uri, nullptr, loadGroup,
   1.462 +                        nullptr, nsIRequest::LOAD_BACKGROUND);
   1.463 +    NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode());
   1.464 +  }
   1.465 +
   1.466 +  //Obtain the total size of the file before reading
   1.467 +  mTotal = mozilla::dom::kUnknownSize;
   1.468 +  mFile->GetSize(&mTotal);
   1.469 +
   1.470 +  aRv = mChannel->AsyncOpen(this, nullptr);
   1.471 +  NS_ENSURE_SUCCESS_VOID(aRv.ErrorCode());
   1.472 +
   1.473 +  //FileReader should be in loading state here
   1.474 +  mReadyState = nsIDOMFileReader::LOADING;
   1.475 +  DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));
   1.476 +
   1.477 +  if (mDataFormat == FILE_AS_ARRAYBUFFER) {
   1.478 +    RootResultArrayBuffer();
   1.479 +    mResultArrayBuffer = JS_NewArrayBuffer(aCx, mTotal);
   1.480 +    if (!mResultArrayBuffer) {
   1.481 +      NS_WARNING("Failed to create JS array buffer");
   1.482 +      aRv.Throw(NS_ERROR_FAILURE);
   1.483 +    }
   1.484 +  }
   1.485 +}
   1.486 +
   1.487 +nsresult
   1.488 +nsDOMFileReader::GetAsText(nsIDOMBlob *aFile,
   1.489 +                           const nsACString &aCharset,
   1.490 +                           const char *aFileData,
   1.491 +                           uint32_t aDataLen,
   1.492 +                           nsAString& aResult)
   1.493 +{
   1.494 +  // The BOM sniffing is baked into the "decode" part of the Encoding
   1.495 +  // Standard, which the File API references.
   1.496 +  nsAutoCString encoding;
   1.497 +  if (!nsContentUtils::CheckForBOM(
   1.498 +        reinterpret_cast<const unsigned char *>(aFileData),
   1.499 +        aDataLen,
   1.500 +        encoding)) {
   1.501 +    // BOM sniffing failed. Try the API argument.
   1.502 +    if (!EncodingUtils::FindEncodingForLabel(aCharset,
   1.503 +                                             encoding)) {
   1.504 +      // API argument failed. Try the type property of the blob.
   1.505 +      nsAutoString type16;
   1.506 +      aFile->GetType(type16);
   1.507 +      NS_ConvertUTF16toUTF8 type(type16);
   1.508 +      nsAutoCString specifiedCharset;
   1.509 +      bool haveCharset;
   1.510 +      int32_t charsetStart, charsetEnd;
   1.511 +      NS_ExtractCharsetFromContentType(type,
   1.512 +                                       specifiedCharset,
   1.513 +                                       &haveCharset,
   1.514 +                                       &charsetStart,
   1.515 +                                       &charsetEnd);
   1.516 +      if (!EncodingUtils::FindEncodingForLabel(specifiedCharset, encoding)) {
   1.517 +        // Type property failed. Use UTF-8.
   1.518 +        encoding.AssignLiteral("UTF-8");
   1.519 +      }
   1.520 +    }
   1.521 +  }
   1.522 +
   1.523 +  nsDependentCSubstring data(aFileData, aDataLen);
   1.524 +  return nsContentUtils::ConvertStringFromEncoding(encoding, data, aResult);
   1.525 +}
   1.526 +
   1.527 +nsresult
   1.528 +nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile,
   1.529 +                              const char *aFileData,
   1.530 +                              uint32_t aDataLen,
   1.531 +                              nsAString& aResult)
   1.532 +{
   1.533 +  aResult.AssignLiteral("data:");
   1.534 +
   1.535 +  nsresult rv;
   1.536 +  nsString contentType;
   1.537 +  rv = aFile->GetType(contentType);
   1.538 +  if (NS_SUCCEEDED(rv) && !contentType.IsEmpty()) {
   1.539 +    aResult.Append(contentType);
   1.540 +  } else {
   1.541 +    aResult.AppendLiteral("application/octet-stream");
   1.542 +  }
   1.543 +  aResult.AppendLiteral(";base64,");
   1.544 +
   1.545 +  nsCString encodedData;
   1.546 +  rv = Base64Encode(Substring(aFileData, aDataLen), encodedData);
   1.547 +  NS_ENSURE_SUCCESS(rv, rv);
   1.548 +
   1.549 +  if (!AppendASCIItoUTF16(encodedData, aResult, fallible_t())) {
   1.550 +    return NS_ERROR_OUT_OF_MEMORY;
   1.551 +  }
   1.552 +
   1.553 +  return NS_OK;
   1.554 +}
   1.555 +
   1.556 +/* virtual */ JSObject*
   1.557 +nsDOMFileReader::WrapObject(JSContext* aCx)
   1.558 +{
   1.559 +  return FileReaderBinding::Wrap(aCx, this);
   1.560 +}

mercurial