michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsDOMBlobBuilder_h michael@0: #define nsDOMBlobBuilder_h michael@0: michael@0: #include "nsDOMFile.h" michael@0: michael@0: #include "mozilla/CheckedInt.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include michael@0: michael@0: #define NS_DOMMULTIPARTBLOB_CID { 0x47bf0b43, 0xf37e, 0x49ef, \ michael@0: { 0x81, 0xa0, 0x18, 0xba, 0xc0, 0x57, 0xb5, 0xcc } } michael@0: #define NS_DOMMULTIPARTBLOB_CONTRACTID "@mozilla.org/dom/multipart-blob;1" michael@0: michael@0: #define NS_DOMMULTIPARTFILE_CID { 0xc3361f77, 0x60d1, 0x4ea9, \ michael@0: { 0x94, 0x96, 0xdf, 0x5d, 0x6f, 0xcd, 0xd7, 0x8f } } michael@0: #define NS_DOMMULTIPARTFILE_CONTRACTID "@mozilla.org/dom/multipart-file;1" michael@0: michael@0: class nsDOMMultipartFile : public nsDOMFile, michael@0: public nsIJSNativeInitializer michael@0: { michael@0: public: michael@0: // Create as a file michael@0: nsDOMMultipartFile(nsTArray > aBlobs, michael@0: const nsAString& aName, michael@0: const nsAString& aContentType) michael@0: : nsDOMFile(aName, aContentType, UINT64_MAX), michael@0: mBlobs(aBlobs), michael@0: mIsFromNsiFile(false) michael@0: { michael@0: } michael@0: michael@0: // Create as a blob michael@0: nsDOMMultipartFile(nsTArray >& aBlobs, michael@0: const nsAString& aContentType) michael@0: : nsDOMFile(aContentType, UINT64_MAX), michael@0: mBlobs(aBlobs), michael@0: mIsFromNsiFile(false) michael@0: { michael@0: } michael@0: michael@0: // Create as a file to be later initialized michael@0: nsDOMMultipartFile(const nsAString& aName) michael@0: : nsDOMFile(aName, EmptyString(), UINT64_MAX), michael@0: mIsFromNsiFile(false) michael@0: { michael@0: } michael@0: michael@0: // Create as a blob to be later initialized michael@0: nsDOMMultipartFile() michael@0: : nsDOMFile(EmptyString(), UINT64_MAX), michael@0: mIsFromNsiFile(false) michael@0: { michael@0: } michael@0: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: michael@0: // nsIJSNativeInitializer michael@0: NS_IMETHOD Initialize(nsISupports* aOwner, michael@0: JSContext* aCx, michael@0: JSObject* aObj, michael@0: const JS::CallArgs& aArgs) MOZ_OVERRIDE; michael@0: michael@0: typedef nsIDOMBlob* (*UnwrapFuncPtr)(JSContext*, JSObject*); michael@0: nsresult InitBlob(JSContext* aCx, michael@0: uint32_t aArgc, michael@0: JS::Value* aArgv, michael@0: UnwrapFuncPtr aUnwrapFunc); michael@0: nsresult InitFile(JSContext* aCx, michael@0: uint32_t aArgc, michael@0: JS::Value* aArgv); michael@0: nsresult InitChromeFile(JSContext* aCx, michael@0: uint32_t aArgc, michael@0: JS::Value* aArgv); michael@0: michael@0: already_AddRefed michael@0: CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) MOZ_OVERRIDE; michael@0: michael@0: NS_IMETHOD GetSize(uint64_t*) MOZ_OVERRIDE; michael@0: NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE; michael@0: michael@0: static nsresult michael@0: NewFile(const nsAString& aName, nsISupports* *aNewObject); michael@0: michael@0: // DOMClassInfo constructor (for Blob([b1, "foo"], { type: "image/png" })) michael@0: static nsresult michael@0: NewBlob(nsISupports* *aNewObject); michael@0: michael@0: // DOMClassInfo constructor (for File([b1, "foo"], { type: "image/png", michael@0: // name: "foo.png" })) michael@0: inline static nsresult michael@0: NewFile(nsISupports* *aNewObject) michael@0: { michael@0: // Initialization will set the filename, so we can pass in an empty string michael@0: // for now. michael@0: return NewFile(EmptyString(), aNewObject); michael@0: } michael@0: michael@0: virtual const nsTArray >* michael@0: GetSubBlobs() const MOZ_OVERRIDE { return &mBlobs; } michael@0: michael@0: NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue, michael@0: bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc); michael@0: michael@0: nsTArray > mBlobs; michael@0: bool mIsFromNsiFile; michael@0: }; michael@0: michael@0: class BlobSet { michael@0: public: michael@0: BlobSet() michael@0: : mData(nullptr), mDataLen(0), mDataBufferLen(0) michael@0: {} michael@0: michael@0: nsresult AppendVoidPtr(const void* aData, uint32_t aLength); michael@0: nsresult AppendString(JSString* aString, bool nativeEOL, JSContext* aCx); michael@0: nsresult AppendBlob(nsIDOMBlob* aBlob); michael@0: nsresult AppendArrayBuffer(JSObject* aBuffer); michael@0: nsresult AppendBlobs(const nsTArray >& aBlob); michael@0: michael@0: nsTArray >& GetBlobs() { Flush(); return mBlobs; } michael@0: michael@0: already_AddRefed michael@0: GetBlobInternal(const nsACString& aContentType) michael@0: { michael@0: nsCOMPtr blob = michael@0: new nsDOMMultipartFile(GetBlobs(), NS_ConvertASCIItoUTF16(aContentType)); michael@0: return blob.forget(); michael@0: } michael@0: michael@0: protected: michael@0: bool ExpandBufferSize(uint64_t aSize) michael@0: { michael@0: using mozilla::CheckedUint32; michael@0: michael@0: if (mDataBufferLen >= mDataLen + aSize) { michael@0: mDataLen += aSize; michael@0: return true; michael@0: } michael@0: michael@0: // Start at 1 or we'll loop forever. michael@0: CheckedUint32 bufferLen = michael@0: std::max(static_cast(mDataBufferLen), 1); michael@0: while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize) michael@0: bufferLen *= 2; michael@0: michael@0: if (!bufferLen.isValid()) michael@0: return false; michael@0: michael@0: void* data = moz_realloc(mData, bufferLen.value()); michael@0: if (!data) michael@0: return false; michael@0: michael@0: mData = data; michael@0: mDataBufferLen = bufferLen.value(); michael@0: mDataLen += aSize; michael@0: return true; michael@0: } michael@0: michael@0: void Flush() { michael@0: if (mData) { michael@0: // If we have some data, create a blob for it michael@0: // and put it on the stack michael@0: michael@0: nsCOMPtr blob = michael@0: new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString()); michael@0: mBlobs.AppendElement(blob); michael@0: mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer michael@0: mDataLen = 0; michael@0: mDataBufferLen = 0; michael@0: } michael@0: } michael@0: michael@0: nsTArray > mBlobs; michael@0: void* mData; michael@0: uint64_t mDataLen; michael@0: uint64_t mDataBufferLen; michael@0: }; michael@0: michael@0: #endif