mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 726593 - Implement FileHandle. r=bent
This commit is contained in:
parent
97add2a393
commit
6e3e5ab48b
@ -166,6 +166,7 @@
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
@BINPATH@/components/dom_devicestorage.xpt
|
||||
@BINPATH@/components/dom_events.xpt
|
||||
@BINPATH@/components/dom_file.xpt
|
||||
@BINPATH@/components/dom_geolocation.xpt
|
||||
@BINPATH@/components/dom_network.xpt
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
|
@ -171,6 +171,7 @@
|
||||
@BINPATH@/components/dom_css.xpt
|
||||
@BINPATH@/components/dom_devicestorage.xpt
|
||||
@BINPATH@/components/dom_events.xpt
|
||||
@BINPATH@/components/dom_file.xpt
|
||||
@BINPATH@/components/dom_geolocation.xpt
|
||||
@BINPATH@/components/dom_network.xpt
|
||||
@BINPATH@/components/dom_notification.xpt
|
||||
|
@ -550,8 +550,10 @@ public:
|
||||
* @return boolean indicating whether a BOM was detected.
|
||||
*/
|
||||
static bool CheckForBOM(const unsigned char* aBuffer, PRUint32 aLength,
|
||||
nsACString& aCharset, bool *bigEndian = nsnull);
|
||||
nsACString& aCharset, bool *bigEndian = nsnull);
|
||||
|
||||
static nsresult GuessCharset(const char *aData, PRUint32 aDataLen,
|
||||
nsACString &aCharset);
|
||||
|
||||
/**
|
||||
* Determine whether aContent is in some way associated with aForm. If the
|
||||
|
@ -43,6 +43,19 @@ class nsDOMFileBase : public nsIDOMFile,
|
||||
public:
|
||||
typedef mozilla::dom::indexedDB::FileInfo FileInfo;
|
||||
|
||||
virtual already_AddRefed<nsIDOMBlob>
|
||||
CreateSlice(PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType) = 0;
|
||||
|
||||
virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
|
||||
GetSubBlobs() const { return nsnull; }
|
||||
|
||||
NS_DECL_NSIDOMBLOB
|
||||
NS_DECL_NSIDOMFILE
|
||||
NS_DECL_NSIXHRSENDABLE
|
||||
NS_DECL_NSIMUTABLE
|
||||
|
||||
protected:
|
||||
nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
: mIsFile(true), mImmutable(false), mContentType(aContentType),
|
||||
@ -60,8 +73,8 @@ public:
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
nsDOMFileBase(const nsAString& aContentType,
|
||||
PRUint64 aStart, PRUint64 aLength)
|
||||
nsDOMFileBase(const nsAString& aContentType, PRUint64 aStart,
|
||||
PRUint64 aLength)
|
||||
: mIsFile(false), mImmutable(false), mContentType(aContentType),
|
||||
mStart(aStart), mLength(aLength)
|
||||
{
|
||||
@ -73,36 +86,35 @@ public:
|
||||
|
||||
virtual ~nsDOMFileBase() {}
|
||||
|
||||
virtual already_AddRefed<nsIDOMBlob>
|
||||
CreateSlice(PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType) = 0;
|
||||
|
||||
virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
|
||||
GetSubBlobs() const { return nsnull; }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMBLOB
|
||||
NS_DECL_NSIDOMFILE
|
||||
NS_DECL_NSIXHRSENDABLE
|
||||
NS_DECL_NSIMUTABLE
|
||||
|
||||
protected:
|
||||
bool IsSizeUnknown()
|
||||
bool IsSizeUnknown() const
|
||||
{
|
||||
return mLength == UINT64_MAX;
|
||||
}
|
||||
|
||||
virtual bool IsStoredFile()
|
||||
virtual bool IsStoredFile() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsWholeFile()
|
||||
virtual bool IsWholeFile() const
|
||||
{
|
||||
NS_NOTREACHED("Should only be called on dom blobs backed by files!");
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsSnapshot() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FileInfo* GetFileInfo() const
|
||||
{
|
||||
NS_ASSERTION(IsStoredFile(), "Should only be called on stored files!");
|
||||
NS_ASSERTION(!mFileInfos.IsEmpty(), "Must have at least one file info!");
|
||||
|
||||
return mFileInfos.ElementAt(0);
|
||||
}
|
||||
|
||||
bool mIsFile;
|
||||
bool mImmutable;
|
||||
nsString mContentType;
|
||||
@ -115,13 +127,53 @@ protected:
|
||||
nsTArray<nsRefPtr<FileInfo> > mFileInfos;
|
||||
};
|
||||
|
||||
class nsDOMFileFile : public nsDOMFileBase,
|
||||
class nsDOMFile : public nsDOMFileBase
|
||||
{
|
||||
public:
|
||||
nsDOMFile(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
: nsDOMFileBase(aName, aContentType, aLength)
|
||||
{ }
|
||||
|
||||
nsDOMFile(const nsAString& aContentType, PRUint64 aLength)
|
||||
: nsDOMFileBase(aContentType, aLength)
|
||||
{ }
|
||||
|
||||
nsDOMFile(const nsAString& aContentType, PRUint64 aStart, PRUint64 aLength)
|
||||
: nsDOMFileBase(aContentType, aStart, aLength)
|
||||
{ }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
class nsDOMFileCC : public nsDOMFileBase
|
||||
{
|
||||
public:
|
||||
nsDOMFileCC(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
: nsDOMFileBase(aName, aContentType, aLength)
|
||||
{ }
|
||||
|
||||
nsDOMFileCC(const nsAString& aContentType, PRUint64 aLength)
|
||||
: nsDOMFileBase(aContentType, aLength)
|
||||
{ }
|
||||
|
||||
nsDOMFileCC(const nsAString& aContentType, PRUint64 aStart, PRUint64 aLength)
|
||||
: nsDOMFileBase(aContentType, aStart, aLength)
|
||||
{ }
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMFileCC, nsIDOMFile)
|
||||
};
|
||||
|
||||
class nsDOMFileFile : public nsDOMFile,
|
||||
public nsIJSNativeInitializer
|
||||
{
|
||||
public:
|
||||
// Create as a file
|
||||
nsDOMFileFile(nsIFile *aFile)
|
||||
: nsDOMFileBase(EmptyString(), EmptyString(), UINT64_MAX),
|
||||
: nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX),
|
||||
mFile(aFile), mWholeFile(true), mStoredFile(false)
|
||||
{
|
||||
NS_ASSERTION(mFile, "must have file");
|
||||
@ -130,10 +182,19 @@ public:
|
||||
mFile->GetLeafName(mName);
|
||||
}
|
||||
|
||||
// Create as a file
|
||||
nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength, nsIFile *aFile)
|
||||
: nsDOMFile(aName, aContentType, aLength),
|
||||
mFile(aFile), mWholeFile(true), mStoredFile(false)
|
||||
{
|
||||
NS_ASSERTION(mFile, "must have file");
|
||||
}
|
||||
|
||||
// Create as a blob
|
||||
nsDOMFileFile(nsIFile *aFile, const nsAString& aContentType,
|
||||
nsISupports *aCacheToken)
|
||||
: nsDOMFileBase(aContentType, UINT64_MAX),
|
||||
: nsDOMFile(aContentType, UINT64_MAX),
|
||||
mFile(aFile), mWholeFile(true), mStoredFile(false),
|
||||
mCacheToken(aCacheToken)
|
||||
{
|
||||
@ -142,20 +203,19 @@ public:
|
||||
|
||||
// Create as a file with custom name
|
||||
nsDOMFileFile(nsIFile *aFile, const nsAString& aName)
|
||||
: nsDOMFileBase(EmptyString(), EmptyString(), UINT64_MAX),
|
||||
: nsDOMFile(aName, EmptyString(), UINT64_MAX),
|
||||
mFile(aFile), mWholeFile(true), mStoredFile(false)
|
||||
{
|
||||
NS_ASSERTION(mFile, "must have file");
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
mName.Assign(aName);
|
||||
}
|
||||
|
||||
// Create as a stored file
|
||||
nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength, nsIFile* aFile,
|
||||
FileInfo* aFileInfo)
|
||||
: nsDOMFileBase(aName, aContentType, aLength),
|
||||
: nsDOMFile(aName, aContentType, aLength),
|
||||
mFile(aFile), mWholeFile(true), mStoredFile(true)
|
||||
{
|
||||
NS_ASSERTION(mFile, "must have file");
|
||||
@ -165,7 +225,7 @@ public:
|
||||
// Create as a stored blob
|
||||
nsDOMFileFile(const nsAString& aContentType, PRUint64 aLength,
|
||||
nsIFile* aFile, FileInfo* aFileInfo)
|
||||
: nsDOMFileBase(aContentType, aLength),
|
||||
: nsDOMFile(aContentType, aLength),
|
||||
mFile(aFile), mWholeFile(true), mStoredFile(true)
|
||||
{
|
||||
NS_ASSERTION(mFile, "must have file");
|
||||
@ -174,7 +234,7 @@ public:
|
||||
|
||||
// Create as a file to be later initialized
|
||||
nsDOMFileFile()
|
||||
: nsDOMFileBase(EmptyString(), EmptyString(), UINT64_MAX),
|
||||
: nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX),
|
||||
mWholeFile(true), mStoredFile(false)
|
||||
{
|
||||
// Lazily get the content type and size
|
||||
@ -206,7 +266,7 @@ protected:
|
||||
// Create slice
|
||||
nsDOMFileFile(const nsDOMFileFile* aOther, PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFileBase(aContentType, aOther->mStart + aStart, aLength),
|
||||
: nsDOMFile(aContentType, aOther->mStart + aStart, aLength),
|
||||
mFile(aOther->mFile), mWholeFile(false),
|
||||
mStoredFile(aOther->mStoredFile), mCacheToken(aOther->mCacheToken)
|
||||
{
|
||||
@ -216,32 +276,30 @@ protected:
|
||||
if (mStoredFile) {
|
||||
FileInfo* fileInfo;
|
||||
|
||||
if (!mozilla::dom::indexedDB::IndexedDatabaseManager::IsClosed()) {
|
||||
mozilla::dom::indexedDB::IndexedDatabaseManager::FileMutex().Lock();
|
||||
using mozilla::dom::indexedDB::IndexedDatabaseManager;
|
||||
|
||||
if (IndexedDatabaseManager::IsClosed()) {
|
||||
fileInfo = aOther->GetFileInfo();
|
||||
}
|
||||
|
||||
NS_ASSERTION(!aOther->mFileInfos.IsEmpty(),
|
||||
"A stored file must have at least one file info!");
|
||||
|
||||
fileInfo = aOther->mFileInfos.ElementAt(0);
|
||||
|
||||
if (!mozilla::dom::indexedDB::IndexedDatabaseManager::IsClosed()) {
|
||||
mozilla::dom::indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
|
||||
else {
|
||||
mozilla::MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
|
||||
fileInfo = aOther->GetFileInfo();
|
||||
}
|
||||
|
||||
mFileInfos.AppendElement(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsIDOMBlob>
|
||||
CreateSlice(PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
virtual bool IsStoredFile()
|
||||
virtual bool IsStoredFile() const
|
||||
{
|
||||
return mStoredFile;
|
||||
}
|
||||
|
||||
virtual bool IsWholeFile()
|
||||
virtual bool IsWholeFile() const
|
||||
{
|
||||
return mWholeFile;
|
||||
}
|
||||
@ -252,7 +310,7 @@ protected:
|
||||
nsCOMPtr<nsISupports> mCacheToken;
|
||||
};
|
||||
|
||||
class nsDOMMemoryFile : public nsDOMFileBase
|
||||
class nsDOMMemoryFile : public nsDOMFile
|
||||
{
|
||||
public:
|
||||
// Create as file
|
||||
@ -260,7 +318,7 @@ public:
|
||||
PRUint64 aLength,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFileBase(aName, aContentType, aLength),
|
||||
: nsDOMFile(aName, aContentType, aLength),
|
||||
mDataOwner(new DataOwner(aMemoryBuffer))
|
||||
{
|
||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||
@ -270,7 +328,7 @@ public:
|
||||
nsDOMMemoryFile(void *aMemoryBuffer,
|
||||
PRUint64 aLength,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFileBase(aContentType, aLength),
|
||||
: nsDOMFile(aContentType, aLength),
|
||||
mDataOwner(new DataOwner(aMemoryBuffer))
|
||||
{
|
||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||
@ -282,7 +340,7 @@ protected:
|
||||
// Create slice
|
||||
nsDOMMemoryFile(const nsDOMMemoryFile* aOther, PRUint64 aStart,
|
||||
PRUint64 aLength, const nsAString& aContentType)
|
||||
: nsDOMFileBase(aContentType, aOther->mStart + aStart, aLength),
|
||||
: nsDOMFile(aContentType, aOther->mStart + aStart, aLength),
|
||||
mDataOwner(aOther->mDataOwner)
|
||||
{
|
||||
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
|
||||
|
@ -178,6 +178,10 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsIDOMDocumentType.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "nsICharsetDetectionObserver.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
|
||||
extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
|
||||
const char** next, PRUnichar* result);
|
||||
extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
|
||||
@ -190,21 +194,6 @@ using namespace mozilla;
|
||||
|
||||
const char kLoadAsData[] = "loadAsData";
|
||||
|
||||
/**
|
||||
* Default values for the ViewportInfo structure.
|
||||
*/
|
||||
static const float kViewportMinScale = 0.0;
|
||||
static const float kViewportMaxScale = 10.0;
|
||||
static const PRUint32 kViewportMinWidth = 200;
|
||||
static const PRUint32 kViewportMaxWidth = 10000;
|
||||
static const PRUint32 kViewportMinHeight = 223;
|
||||
static const PRUint32 kViewportMaxHeight = 10000;
|
||||
static const PRInt32 kViewportDefaultScreenWidth = 980;
|
||||
|
||||
static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
|
||||
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
|
||||
|
||||
nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
|
||||
nsIXPConnect *nsContentUtils::sXPConnect;
|
||||
nsIScriptSecurityManager *nsContentUtils::sSecurityManager;
|
||||
@ -260,6 +249,23 @@ nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
|
||||
nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
|
||||
bool nsContentUtils::sFragmentParsingActive = false;
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Default values for the ViewportInfo structure.
|
||||
*/
|
||||
static const float kViewportMinScale = 0.0;
|
||||
static const float kViewportMaxScale = 10.0;
|
||||
static const PRUint32 kViewportMinWidth = 200;
|
||||
static const PRUint32 kViewportMaxWidth = 10000;
|
||||
static const PRUint32 kViewportMinHeight = 223;
|
||||
static const PRUint32 kViewportMaxHeight = 10000;
|
||||
static const PRInt32 kViewportDefaultScreenWidth = 980;
|
||||
|
||||
static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
|
||||
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
|
||||
|
||||
static PLDHashTable sEventListenerManagersHash;
|
||||
|
||||
class EventListenerManagerMapEntry : public PLDHashEntryHdr
|
||||
@ -301,14 +307,36 @@ EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
|
||||
lm->~EventListenerManagerMapEntry();
|
||||
}
|
||||
|
||||
class nsSameOriginChecker : public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor
|
||||
class SameOriginChecker : public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
};
|
||||
|
||||
class CharsetDetectionObserver : public nsICharsetDetectionObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf)
|
||||
{
|
||||
mCharset = aCharset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsACString& GetResult() const
|
||||
{
|
||||
return mCharset;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCString mCharset;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */
|
||||
TimeDuration
|
||||
nsContentUtils::HandlingUserInputTimeout()
|
||||
@ -3536,6 +3564,89 @@ nsContentUtils::CheckForBOM(const unsigned char* aBuffer, PRUint32 aLength,
|
||||
return found;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CharsetDetectionObserver,
|
||||
nsICharsetDetectionObserver)
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsContentUtils::GuessCharset(const char *aData, PRUint32 aDataLen,
|
||||
nsACString &aCharset)
|
||||
{
|
||||
// First try the universal charset detector
|
||||
nsCOMPtr<nsICharsetDetector> detector =
|
||||
do_CreateInstance(NS_CHARSET_DETECTOR_CONTRACTID_BASE
|
||||
"universal_charset_detector");
|
||||
if (!detector) {
|
||||
// No universal charset detector, try the default charset detector
|
||||
const nsAdoptingCString& detectorName =
|
||||
Preferences::GetLocalizedCString("intl.charset.detector");
|
||||
if (!detectorName.IsEmpty()) {
|
||||
nsCAutoString detectorContractID;
|
||||
detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
|
||||
detectorContractID += detectorName;
|
||||
detector = do_CreateInstance(detectorContractID.get());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// The charset detector doesn't work for empty (null) aData. Testing
|
||||
// aDataLen instead of aData so that we catch potential errors.
|
||||
if (detector && aDataLen) {
|
||||
nsRefPtr<CharsetDetectionObserver> observer =
|
||||
new CharsetDetectionObserver();
|
||||
|
||||
rv = detector->Init(observer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool dummy;
|
||||
rv = detector->DoIt(aData, aDataLen, &dummy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = detector->Done();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aCharset = observer->GetResult();
|
||||
} else {
|
||||
// no charset detector available, check the BOM
|
||||
unsigned char sniffBuf[3];
|
||||
PRUint32 numRead =
|
||||
(aDataLen >= sizeof(sniffBuf) ? sizeof(sniffBuf) : aDataLen);
|
||||
memcpy(sniffBuf, aData, numRead);
|
||||
|
||||
bool bigEndian;
|
||||
if (CheckForBOM(sniffBuf, numRead, aCharset, &bigEndian) &&
|
||||
aCharset.EqualsLiteral("UTF-16")) {
|
||||
if (bigEndian) {
|
||||
aCharset.AppendLiteral("BE");
|
||||
}
|
||||
else {
|
||||
aCharset.AppendLiteral("LE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aCharset.IsEmpty()) {
|
||||
// no charset detected, default to the system charset
|
||||
nsCOMPtr<nsIPlatformCharset> platformCharset =
|
||||
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = platformCharset->GetCharset(kPlatformCharsetSel_PlainTextInFile,
|
||||
aCharset);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to get the system charset!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aCharset.IsEmpty()) {
|
||||
// no sniffed or default charset, assume UTF-8
|
||||
aCharset.AssignLiteral("UTF-8");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::RegisterShutdownObserver(nsIObserver* aObserver)
|
||||
@ -5517,7 +5628,7 @@ nsIInterfaceRequestor*
|
||||
nsContentUtils::GetSameOriginChecker()
|
||||
{
|
||||
if (!sSameOriginChecker) {
|
||||
sSameOriginChecker = new nsSameOriginChecker();
|
||||
sSameOriginChecker = new SameOriginChecker();
|
||||
NS_IF_ADDREF(sSameOriginChecker);
|
||||
}
|
||||
return sSameOriginChecker;
|
||||
@ -5549,15 +5660,15 @@ nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsSameOriginChecker,
|
||||
NS_IMPL_ISUPPORTS2(SameOriginChecker,
|
||||
nsIChannelEventSink,
|
||||
nsIInterfaceRequestor)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
|
||||
nsIChannel *aNewChannel,
|
||||
PRUint32 aFlags,
|
||||
nsIAsyncVerifyRedirectCallback *cb)
|
||||
SameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
|
||||
nsIChannel *aNewChannel,
|
||||
PRUint32 aFlags,
|
||||
nsIAsyncVerifyRedirectCallback *cb)
|
||||
{
|
||||
NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
|
||||
|
||||
@ -5570,7 +5681,7 @@ nsSameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
|
||||
SameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
|
||||
{
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMMultipartFile, nsDOMFileBase,
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMMultipartFile, nsDOMFile,
|
||||
nsIJSNativeInitializer)
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -139,6 +139,15 @@ nsDOMMultipartFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsDOMMultipartFile::NewFile(const nsAString& aName, nsISupports* *aNewObject)
|
||||
{
|
||||
nsCOMPtr<nsISupports> file =
|
||||
do_QueryObject(new nsDOMMultipartFile(aName));
|
||||
file.forget(aNewObject);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsDOMMultipartFile::NewBlob(nsISupports* *aNewObject)
|
||||
{
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
class nsDOMMultipartFile : public nsDOMFileBase,
|
||||
class nsDOMMultipartFile : public nsDOMFile,
|
||||
public nsIJSNativeInitializer
|
||||
{
|
||||
public:
|
||||
@ -20,7 +20,7 @@ public:
|
||||
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFileBase(aName, aContentType, UINT64_MAX),
|
||||
: nsDOMFile(aName, aContentType, UINT64_MAX),
|
||||
mBlobs(aBlobs)
|
||||
{
|
||||
}
|
||||
@ -28,14 +28,20 @@ public:
|
||||
// Create as a blob
|
||||
nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFileBase(aContentType, UINT64_MAX),
|
||||
: nsDOMFile(aContentType, UINT64_MAX),
|
||||
mBlobs(aBlobs)
|
||||
{
|
||||
}
|
||||
|
||||
// Create as a file to be later initialized
|
||||
nsDOMMultipartFile(const nsAString& aName)
|
||||
: nsDOMFile(aName, EmptyString(), UINT64_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
// Create as a blob to be later initialized
|
||||
nsDOMMultipartFile()
|
||||
: nsDOMFileBase(EmptyString(), UINT64_MAX)
|
||||
: nsDOMFile(EmptyString(), UINT64_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
@ -60,6 +66,9 @@ public:
|
||||
NS_IMETHOD GetSize(PRUint64*);
|
||||
NS_IMETHOD GetInternalStream(nsIInputStream**);
|
||||
|
||||
static nsresult
|
||||
NewFile(const nsAString& aName, nsISupports* *aNewObject);
|
||||
|
||||
// DOMClassInfo constructor (for Blob([b1, "foo"], { type: "image/png" }))
|
||||
static nsresult
|
||||
NewBlob(nsISupports* *aNewObject);
|
||||
|
@ -103,23 +103,6 @@ nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// nsDOMFileBase implementation
|
||||
|
||||
DOMCI_DATA(File, nsDOMFileBase)
|
||||
DOMCI_DATA(Blob, nsDOMFileBase)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMFileBase)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutable)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// Threadsafe when GetMutable() == false
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsDOMFileBase)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsDOMFileBase)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileBase::GetName(nsAString &aFileName)
|
||||
{
|
||||
@ -302,7 +285,7 @@ nsDOMFileBase::GetFileId()
|
||||
{
|
||||
PRInt64 id = -1;
|
||||
|
||||
if (IsStoredFile() && IsWholeFile()) {
|
||||
if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
|
||||
if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
|
||||
indexedDB::IndexedDatabaseManager::FileMutex().Lock();
|
||||
}
|
||||
@ -353,7 +336,14 @@ nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
|
||||
// A slice created from a stored file must keep the file info alive.
|
||||
// However, we don't support sharing of slices yet, so the slice must be
|
||||
// copied again. That's why we have to ignore the first file info.
|
||||
PRUint32 startIndex = IsStoredFile() && !IsWholeFile() ? 1 : 0;
|
||||
// Snapshots are handled in a similar way (they have to be copied).
|
||||
PRUint32 startIndex;
|
||||
if (IsStoredFile() && (!IsWholeFile() || IsSnapshot())) {
|
||||
startIndex = 1;
|
||||
}
|
||||
else {
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(indexedDB::IndexedDatabaseManager::FileMutex());
|
||||
|
||||
@ -419,10 +409,48 @@ nsDOMFileBase::SetMutable(bool aMutable)
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// nsDOMFile implementation
|
||||
|
||||
DOMCI_DATA(File, nsDOMFile)
|
||||
DOMCI_DATA(Blob, nsDOMFile)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMFile)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutable)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// Threadsafe when GetMutable() == false
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsDOMFile)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsDOMFile)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// nsDOMFileCC implementation
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_0(nsDOMFileCC)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileCC)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutable)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileCC)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileCC)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// nsDOMFileFile implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMFileFile, nsDOMFileBase,
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMFileFile, nsDOMFile,
|
||||
nsIJSNativeInitializer)
|
||||
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
|
@ -11,14 +11,12 @@
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsCharsetAlias.h"
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsIConverterInputStream.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -97,7 +95,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMFileReader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileReader)
|
||||
NS_INTERFACE_MAP_END_INHERITING(FileIOObject)
|
||||
|
||||
@ -112,15 +109,6 @@ nsDOMFileReader::RootResultArrayBuffer()
|
||||
static_cast<nsDOMEventTargetHelper*>(this)), this);
|
||||
}
|
||||
|
||||
//nsICharsetDetectionObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMFileReader::Notify(const char *aCharset, nsDetectionConfident aConf)
|
||||
{
|
||||
mCharset = aCharset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//nsDOMFileReader constructors/initializers
|
||||
|
||||
nsDOMFileReader::nsDOMFileReader()
|
||||
@ -457,7 +445,7 @@ nsDOMFileReader::GetAsText(const nsACString &aCharset,
|
||||
if (!aCharset.IsEmpty()) {
|
||||
charsetGuess = aCharset;
|
||||
} else {
|
||||
rv = GuessCharset(aFileData, aDataLen, charsetGuess);
|
||||
rv = nsContentUtils::GuessCharset(aFileData, aDataLen, charsetGuess);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -540,80 +528,3 @@ nsDOMFileReader::ConvertStream(const char *aFileData,
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMFileReader::GuessCharset(const char *aFileData,
|
||||
PRUint32 aDataLen,
|
||||
nsACString &aCharset)
|
||||
{
|
||||
// First try the universal charset detector
|
||||
nsCOMPtr<nsICharsetDetector> detector
|
||||
= do_CreateInstance(NS_CHARSET_DETECTOR_CONTRACTID_BASE
|
||||
"universal_charset_detector");
|
||||
if (!detector) {
|
||||
// No universal charset detector, try the default charset detector
|
||||
const nsAdoptingCString& detectorName =
|
||||
Preferences::GetLocalizedCString("intl.charset.detector");
|
||||
if (!detectorName.IsEmpty()) {
|
||||
nsCAutoString detectorContractID;
|
||||
detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
|
||||
detectorContractID += detectorName;
|
||||
detector = do_CreateInstance(detectorContractID.get());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
// The charset detector doesn't work for empty (null) aFileData. Testing
|
||||
// aDataLen instead of aFileData so that we catch potential errors.
|
||||
if (detector && aDataLen != 0) {
|
||||
mCharset.Truncate();
|
||||
detector->Init(this);
|
||||
|
||||
bool done;
|
||||
|
||||
rv = detector->DoIt(aFileData, aDataLen, &done);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = detector->Done();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aCharset = mCharset;
|
||||
} else {
|
||||
// no charset detector available, check the BOM
|
||||
unsigned char sniffBuf[3];
|
||||
PRUint32 numRead = (aDataLen >= sizeof(sniffBuf) ? sizeof(sniffBuf) : aDataLen);
|
||||
memcpy(sniffBuf, aFileData, numRead);
|
||||
|
||||
if (numRead >= 2 &&
|
||||
sniffBuf[0] == 0xfe &&
|
||||
sniffBuf[1] == 0xff) {
|
||||
aCharset = "UTF-16BE";
|
||||
} else if (numRead >= 2 &&
|
||||
sniffBuf[0] == 0xff &&
|
||||
sniffBuf[1] == 0xfe) {
|
||||
aCharset = "UTF-16LE";
|
||||
} else if (numRead >= 3 &&
|
||||
sniffBuf[0] == 0xef &&
|
||||
sniffBuf[1] == 0xbb &&
|
||||
sniffBuf[2] == 0xbf) {
|
||||
aCharset = "UTF-8";
|
||||
}
|
||||
}
|
||||
|
||||
if (aCharset.IsEmpty()) {
|
||||
// no charset detected, default to the system charset
|
||||
nsCOMPtr<nsIPlatformCharset> platformCharset =
|
||||
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = platformCharset->GetCharset(kPlatformCharsetSel_PlainTextInFile,
|
||||
aCharset);
|
||||
}
|
||||
}
|
||||
|
||||
if (aCharset.IsEmpty()) {
|
||||
// no sniffed or default charset, try UTF-8
|
||||
aCharset.AssignLiteral("UTF-8");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "nsIJSNativeInitializer.h"
|
||||
#include "prtime.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "nsICharsetDetectionObserver.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMFileReader.h"
|
||||
@ -34,8 +32,7 @@ class nsDOMFileReader : public mozilla::dom::FileIOObject,
|
||||
public nsIDOMFileReader,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsSupportsWeakReference,
|
||||
public nsIJSNativeInitializer,
|
||||
public nsICharsetDetectionObserver
|
||||
public nsIJSNativeInitializer
|
||||
{
|
||||
public:
|
||||
nsDOMFileReader();
|
||||
@ -54,13 +51,10 @@ public:
|
||||
NS_DECL_EVENT_HANDLER(loadend)
|
||||
NS_DECL_EVENT_HANDLER(loadstart)
|
||||
|
||||
// nsIJSNativeInitializer
|
||||
NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
|
||||
// nsIJSNativeInitializer
|
||||
NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
|
||||
PRUint32 argc, jsval* argv);
|
||||
|
||||
// nsICharsetDetectionObserver
|
||||
NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
|
||||
|
||||
// FileIOObject overrides
|
||||
NS_IMETHOD DoAbort(nsAString& aEvent);
|
||||
NS_IMETHOD DoOnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
|
||||
@ -88,7 +82,6 @@ protected:
|
||||
nsresult GetAsText(const nsACString &aCharset,
|
||||
const char *aFileData, PRUint32 aDataLen, nsAString &aResult);
|
||||
nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, PRUint32 aDataLen, nsAString &aResult);
|
||||
nsresult GuessCharset(const char *aFileData, PRUint32 aDataLen, nsACString &aCharset);
|
||||
nsresult ConvertStream(const char *aFileData, PRUint32 aDataLen, const char *aCharset, nsAString &aResult);
|
||||
|
||||
void FreeFileData() {
|
||||
|
@ -616,7 +616,7 @@ protected:
|
||||
// Non-null only when we are able to get a os-file representation of the
|
||||
// response, i.e. when loading from a file, or when the http-stream
|
||||
// caches into a file or is reading from a cached file.
|
||||
nsRefPtr<nsDOMFileBase> mDOMFile;
|
||||
nsRefPtr<nsDOMFile> mDOMFile;
|
||||
// We stream data to mBuilder when response type is "blob" or "moz-blob"
|
||||
// and mDOMFile is null.
|
||||
nsRefPtr<nsDOMBlobBuilder> mBuilder;
|
||||
|
@ -193,4 +193,50 @@ private:
|
||||
xpc_TryUnmarkWrappedGrayObject(tmp->mOn##_event##Listener->GetInner()); \
|
||||
}
|
||||
|
||||
/* Use this macro to declare functions that forward the behavior of this
|
||||
* interface to another object.
|
||||
* This macro doesn't forward PreHandleEvent because sometimes subclasses
|
||||
* want to override it.
|
||||
*/
|
||||
#define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \
|
||||
NS_SCRIPTABLE NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, PRUint8 _argc) { \
|
||||
return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \
|
||||
} \
|
||||
NS_IMETHOD AddSystemEventListener(const nsAString & type, nsIDOMEventListener *listener, bool aUseCapture, bool aWantsUntrusted, PRUint8 _argc) { \
|
||||
return _to AddSystemEventListener(type, listener, aUseCapture, aWantsUntrusted, _argc); \
|
||||
} \
|
||||
NS_SCRIPTABLE NS_IMETHOD RemoveEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture) { \
|
||||
return _to RemoveEventListener(type, listener, useCapture); \
|
||||
} \
|
||||
NS_IMETHOD RemoveSystemEventListener(const nsAString & type, nsIDOMEventListener *listener, bool aUseCapture) { \
|
||||
return _to RemoveSystemEventListener(type, listener, aUseCapture); \
|
||||
} \
|
||||
NS_SCRIPTABLE NS_IMETHOD DispatchEvent(nsIDOMEvent *evt, bool *_retval NS_OUTPARAM) { \
|
||||
return _to DispatchEvent(evt, _retval); \
|
||||
} \
|
||||
virtual nsIDOMEventTarget * GetTargetForDOMEvent(void) { \
|
||||
return _to GetTargetForDOMEvent(); \
|
||||
} \
|
||||
virtual nsIDOMEventTarget * GetTargetForEventTargetChain(void) { \
|
||||
return _to GetTargetForEventTargetChain(); \
|
||||
} \
|
||||
virtual nsresult WillHandleEvent(nsEventChainPostVisitor & aVisitor) { \
|
||||
return _to WillHandleEvent(aVisitor); \
|
||||
} \
|
||||
virtual nsresult PostHandleEvent(nsEventChainPostVisitor & aVisitor) { \
|
||||
return _to PostHandleEvent(aVisitor); \
|
||||
} \
|
||||
virtual nsresult DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent, nsPresContext *aPresContext, nsEventStatus *aEventStatus) { \
|
||||
return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); \
|
||||
} \
|
||||
virtual nsEventListenerManager * GetListenerManager(bool aMayCreate) { \
|
||||
return _to GetListenerManager(aMayCreate); \
|
||||
} \
|
||||
virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv NS_OUTPARAM) { \
|
||||
return _to GetContextForEventHandlers(aRv); \
|
||||
} \
|
||||
virtual JSContext * GetJSContextForEventHandlers(void) { \
|
||||
return _to GetJSContextForEventHandlers(); \
|
||||
}
|
||||
|
||||
#endif // nsDOMEventTargetHelper_h_
|
||||
|
@ -1042,7 +1042,7 @@ size_t sqlite3_quota_fread(
|
||||
** the write if we exceed quota.
|
||||
*/
|
||||
size_t sqlite3_quota_fwrite(
|
||||
void *pBuf, /* Take content to write from here */
|
||||
const void *pBuf, /* Take content to write from here */
|
||||
size_t size, /* Size of each element */
|
||||
size_t nmemb, /* Number of elements */
|
||||
quota_FILE *p /* Write to this quota_FILE objecct */
|
||||
@ -1052,7 +1052,7 @@ size_t sqlite3_quota_fwrite(
|
||||
sqlite3_int64 szNew;
|
||||
quotaFile *pFile;
|
||||
size_t rc;
|
||||
|
||||
|
||||
iOfst = ftell(p->f);
|
||||
iEnd = iOfst + size*nmemb;
|
||||
pFile = p->pFile;
|
||||
@ -1091,7 +1091,7 @@ size_t sqlite3_quota_fwrite(
|
||||
pFile->iSize = iNewEnd;
|
||||
quotaLeave();
|
||||
}
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1160,6 +1160,13 @@ long sqlite3_quota_ftell(quota_FILE *p){
|
||||
return ftell(p->f);
|
||||
}
|
||||
|
||||
/*
|
||||
** Test the error indicator for the given file.
|
||||
*/
|
||||
int sqlite3_quota_ferror(quota_FILE *p){
|
||||
return ferror(p->f);
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate a file to szNew bytes.
|
||||
*/
|
||||
@ -1237,6 +1244,25 @@ sqlite3_int64 sqlite3_quota_file_size(quota_FILE *p){
|
||||
return p->pFile ? p->pFile->iSize : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine the amount of data in bytes available for reading
|
||||
** in the given file.
|
||||
*/
|
||||
long sqlite3_quota_file_available(quota_FILE *p){
|
||||
FILE* f = p->f;
|
||||
long pos1, pos2;
|
||||
int rc;
|
||||
pos1 = ftell(f);
|
||||
if ( pos1 < 0 ) return -1;
|
||||
rc = fseek(f, 0, SEEK_END);
|
||||
if ( rc != 0 ) return -1;
|
||||
pos2 = ftell(f);
|
||||
if ( pos2 < 0 ) return -1;
|
||||
rc = fseek(f, pos1, SEEK_SET);
|
||||
if ( rc != 0 ) return -1;
|
||||
return pos2 - pos1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove a managed file. Update quotas accordingly.
|
||||
*/
|
||||
|
@ -162,7 +162,7 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode);
|
||||
** the sum of sizes of all files from going over quota.
|
||||
*/
|
||||
size_t sqlite3_quota_fread(void*, size_t, size_t, quota_FILE*);
|
||||
size_t sqlite3_quota_fwrite(void*, size_t, size_t, quota_FILE*);
|
||||
size_t sqlite3_quota_fwrite(const void*, size_t, size_t, quota_FILE*);
|
||||
|
||||
/*
|
||||
** Flush all written content held in memory buffers out to disk.
|
||||
@ -190,6 +190,13 @@ int sqlite3_quota_fseek(quota_FILE*, long, int);
|
||||
void sqlite3_quota_rewind(quota_FILE*);
|
||||
long sqlite3_quota_ftell(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Test the error indicator for the given file.
|
||||
**
|
||||
** Return non-zero if the error indicator is set.
|
||||
*/
|
||||
int sqlite3_quota_ferror(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Truncate a file previously opened by sqlite3_quota_fopen(). Return
|
||||
** zero on success and non-zero on any kind of failure.
|
||||
@ -198,7 +205,7 @@ long sqlite3_quota_ftell(quota_FILE*);
|
||||
** Any attempt to "truncate" a file to a larger size results in
|
||||
** undefined behavior.
|
||||
*/
|
||||
int sqlite3_quota_ftrunate(quota_FILE*, sqlite3_int64 newSize);
|
||||
int sqlite3_quota_ftruncate(quota_FILE*, sqlite3_int64 newSize);
|
||||
|
||||
/*
|
||||
** Return the last modification time of the opened file, in seconds
|
||||
@ -232,6 +239,14 @@ sqlite3_int64 sqlite3_quota_file_size(quota_FILE*);
|
||||
*/
|
||||
sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Determine the amount of data in bytes available for reading
|
||||
** in the given file.
|
||||
**
|
||||
** Return -1 if the amount cannot be determined for some reason.
|
||||
*/
|
||||
long sqlite3_quota_file_available(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Delete a file from the disk, if that file is under quota management.
|
||||
** Adjust quotas accordingly.
|
||||
|
@ -50,6 +50,7 @@ DIRS += \
|
||||
battery \
|
||||
contacts \
|
||||
devicestorage \
|
||||
file \
|
||||
power \
|
||||
settings \
|
||||
sms \
|
||||
|
@ -17,8 +17,8 @@ using mozilla::dom::DOMRequest;
|
||||
using mozilla::dom::DOMRequestService;
|
||||
|
||||
DOMRequest::DOMRequest(nsIDOMWindow* aWindow)
|
||||
: mDone(false)
|
||||
, mResult(JSVAL_VOID)
|
||||
: mResult(JSVAL_VOID)
|
||||
, mDone(false)
|
||||
, mRooted(false)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
@ -34,14 +34,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
tmp->mResult = JSVAL_VOID;
|
||||
tmp->UnrootResultVal();
|
||||
if (tmp->mRooted) {
|
||||
tmp->mResult = JSVAL_VOID;
|
||||
tmp->UnrootResultVal();
|
||||
}
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mError)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest,
|
||||
@ -98,35 +102,54 @@ DOMRequest::GetError(nsIDOMDOMError** aError)
|
||||
void
|
||||
DOMRequest::FireSuccess(jsval aResult)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mDone, "Already fired success/error");
|
||||
NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
|
||||
NS_ASSERTION(!mError, "mError shouldn't have been set!");
|
||||
NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
|
||||
|
||||
mDone = true;
|
||||
RootResultVal();
|
||||
if (JSVAL_IS_GCTHING(aResult)) {
|
||||
RootResultVal();
|
||||
}
|
||||
mResult = aResult;
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("success"));
|
||||
FireEvent(NS_LITERAL_STRING("success"), false, false);
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::FireError(const nsAString& aError)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mDone, "Already fired success/error");
|
||||
NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
|
||||
NS_ASSERTION(!mError, "mError shouldn't have been set!");
|
||||
NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
|
||||
|
||||
mDone = true;
|
||||
mError = DOMError::CreateWithName(aError);
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"));
|
||||
FireEvent(NS_LITERAL_STRING("error"), true, true);
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::FireEvent(const nsAString& aType)
|
||||
DOMRequest::FireError(nsresult aError)
|
||||
{
|
||||
NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
|
||||
NS_ASSERTION(!mError, "mError shouldn't have been set!");
|
||||
NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
|
||||
|
||||
mDone = true;
|
||||
mError = DOMError::CreateForNSResult(aError);
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"), true, true);
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable)
|
||||
{
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
|
||||
nsresult rv = event->InitEvent(aType, false, false);
|
||||
nsresult rv = event->InitEvent(aType, aBubble, aCancelable);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
@ -140,6 +163,22 @@ DOMRequest::FireEvent(const nsAString& aType)
|
||||
DispatchEvent(event, &dummy);
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::RootResultVal()
|
||||
{
|
||||
NS_ASSERTION(!mRooted, "Don't call me if already rooted!");
|
||||
NS_HOLD_JS_OBJECTS(this, DOMRequest);
|
||||
mRooted = true;
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::UnrootResultVal()
|
||||
{
|
||||
NS_ASSERTION(mRooted, "Don't call me if not rooted!");
|
||||
NS_DROP_JS_OBJECTS(this, DOMRequest);
|
||||
mRooted = false;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DOMRequestService, nsIDOMRequestService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -20,6 +20,12 @@ namespace dom {
|
||||
class DOMRequest : public nsDOMEventTargetHelper,
|
||||
public nsIDOMDOMRequest
|
||||
{
|
||||
protected:
|
||||
jsval mResult;
|
||||
nsCOMPtr<nsIDOMDOMError> mError;
|
||||
bool mDone;
|
||||
bool mRooted;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(success)
|
||||
NS_DECL_EVENT_HANDLER(error)
|
||||
|
||||
@ -33,37 +39,22 @@ public:
|
||||
|
||||
void FireSuccess(jsval aResult);
|
||||
void FireError(const nsAString& aError);
|
||||
void FireError(nsresult aError);
|
||||
|
||||
DOMRequest(nsIDOMWindow* aWindow);
|
||||
|
||||
virtual ~DOMRequest()
|
||||
{
|
||||
UnrootResultVal();
|
||||
}
|
||||
|
||||
bool mDone;
|
||||
jsval mResult;
|
||||
nsCOMPtr<nsIDOMDOMError> mError;
|
||||
bool mRooted;
|
||||
|
||||
private:
|
||||
void FireEvent(const nsAString& aType);
|
||||
|
||||
void RootResultVal()
|
||||
{
|
||||
if (!mRooted) {
|
||||
NS_HOLD_JS_OBJECTS(this, DOMRequest);
|
||||
mRooted = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UnrootResultVal()
|
||||
{
|
||||
if (mRooted) {
|
||||
NS_DROP_JS_OBJECTS(this, DOMRequest);
|
||||
mRooted = false;
|
||||
UnrootResultVal();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void FireEvent(const nsAString& aType, bool aBubble, bool aCancelable);
|
||||
|
||||
virtual void RootResultVal();
|
||||
virtual void UnrootResultVal();
|
||||
};
|
||||
|
||||
class DOMRequestService : public nsIDOMRequestService
|
||||
|
@ -17,6 +17,7 @@ enum StructuredCloneTags {
|
||||
SCTAG_DOM_BLOB,
|
||||
SCTAG_DOM_FILE,
|
||||
SCTAG_DOM_FILELIST,
|
||||
SCTAG_DOM_FILEHANDLE,
|
||||
|
||||
// These tags are used for both main thread and workers.
|
||||
SCTAG_DOM_IMAGEDATA,
|
||||
|
@ -107,3 +107,10 @@ DOM_MSG_DEF(NS_ERROR_FACTORY_NOT_REGISTERED , "Factory not registered")
|
||||
DOM_MSG_DEF(NS_ERROR_FACTORY_NOT_LOADED , "Factory not loaded")
|
||||
DOM_MSG_DEF(NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT , "Factory does not support signatures")
|
||||
DOM_MSG_DEF(NS_ERROR_FACTORY_EXISTS , "Factory already exists")
|
||||
|
||||
DOM4_MSG_DEF(UnknownError, "The operation failed for reasons unrelated to the file storage itself and not covered by any other error code.", NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR)
|
||||
DOM4_MSG_DEF(LockedFileInactiveError, "A request was placed against a locked file which is currently not active, or which is finished.", NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR)
|
||||
DOM4_MSG_DEF(ReadOnlyError, "A mutation operation was attempted in a READ_ONLY locked file.", NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR)
|
||||
|
||||
DOM4_MSG_DEF(InvalidStateError, "A mutation operation was attempted on a file storage that did not allow mutations.", NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR)
|
||||
DOM4_MSG_DEF(AbortError, "A request was aborted, for example through a call to LockedFile.abort.", NS_ERROR_DOM_FILEHANDLE_ABORT_ERR)
|
||||
|
@ -464,6 +464,7 @@
|
||||
|
||||
#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFileHandle.h"
|
||||
#include "mozilla/dom/indexedDB/IDBRequest.h"
|
||||
#include "mozilla/dom/indexedDB/IDBDatabase.h"
|
||||
#include "mozilla/dom/indexedDB/IDBEvents.h"
|
||||
@ -513,6 +514,10 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
|
||||
#include "DOMError.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
#include "DOMFileHandle.h"
|
||||
#include "FileRequest.h"
|
||||
#include "LockedFile.h"
|
||||
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
#undef None // something included above defines this preprocessor symbol, maybe Xlib headers
|
||||
@ -1573,6 +1578,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(IDBFactory, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA_WITH_NAME(IDBFileHandle, FileHandle, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(IDBRequest, IDBEventTargetSH,
|
||||
IDBEVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(IDBDatabase, IDBEventTargetSH,
|
||||
@ -1638,6 +1645,13 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA_WITH_NAME(DOMFileHandle, FileHandle, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(FileRequest, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
};
|
||||
|
||||
// Objects that should be constructable through |new Name();|
|
||||
@ -4330,6 +4344,11 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIIDBFactory)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(IDBFileHandle, nsIDOMFileHandle)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileHandle)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIIDBFileHandle)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(IDBRequest, nsIIDBRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
@ -4459,6 +4478,20 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DOMFileHandle, nsIDOMFileHandle)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileHandle)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(FileRequest, nsIDOMFileRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(LockedFile, nsIDOMLockedFile)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLockedFile)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
{
|
||||
PRUint32 i = ArrayLength(sClassInfoData);
|
||||
|
@ -487,6 +487,7 @@ DOMCI_CLASS(WebSocket)
|
||||
DOMCI_CLASS(CloseEvent)
|
||||
|
||||
DOMCI_CLASS(IDBFactory)
|
||||
DOMCI_CLASS(IDBFileHandle)
|
||||
DOMCI_CLASS(IDBRequest)
|
||||
DOMCI_CLASS(IDBDatabase)
|
||||
DOMCI_CLASS(IDBObjectStore)
|
||||
@ -526,3 +527,7 @@ DOMCI_CLASS(BluetoothAdapter)
|
||||
|
||||
DOMCI_CLASS(DOMError)
|
||||
DOMCI_CLASS(DOMRequest)
|
||||
|
||||
DOMCI_CLASS(DOMFileHandle)
|
||||
DOMCI_CLASS(FileRequest)
|
||||
DOMCI_CLASS(LockedFile)
|
||||
|
@ -89,4 +89,11 @@
|
||||
#define NS_ERROR_DOM_FILE_NOT_READABLE_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILE, 1)
|
||||
#define NS_ERROR_DOM_FILE_ABORT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILE, 2)
|
||||
|
||||
#define NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILEHANDLE,1)
|
||||
#define NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILEHANDLE,2)
|
||||
#define NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILEHANDLE,3)
|
||||
#define NS_ERROR_DOM_FILEHANDLE_ABORT_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILEHANDLE,4)
|
||||
#define NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_FILEHANDLE,5)
|
||||
|
||||
#endif // nsDOMError_h__
|
||||
|
@ -96,6 +96,9 @@ enum DOM4ErrorTypeCodeMap {
|
||||
|
||||
/* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */
|
||||
NotReadableError = 0,
|
||||
|
||||
/* FileHandle API errors */
|
||||
LockedFileInactiveError = 0,
|
||||
};
|
||||
|
||||
#define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message},
|
||||
|
@ -55,8 +55,9 @@ nsDOMScriptObjectFactory::nsDOMScriptObjectFactory()
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM);
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_SVG);
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_XPATH);
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_INDEXEDDB);
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_XPCONNECT);
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_INDEXEDDB);
|
||||
xs->RegisterExceptionProvider(provider, NS_ERROR_MODULE_DOM_FILEHANDLE);
|
||||
}
|
||||
|
||||
NS_ASSERTION(!gExceptionProvider, "Registered twice?!");
|
||||
@ -142,6 +143,10 @@ nsDOMScriptObjectFactory::Observe(nsISupports *aSubject,
|
||||
NS_ERROR_MODULE_DOM_XPATH);
|
||||
xs->UnregisterExceptionProvider(gExceptionProvider,
|
||||
NS_ERROR_MODULE_XPCONNECT);
|
||||
xs->UnregisterExceptionProvider(gExceptionProvider,
|
||||
NS_ERROR_MODULE_DOM_INDEXEDDB);
|
||||
xs->UnregisterExceptionProvider(gExceptionProvider,
|
||||
NS_ERROR_MODULE_DOM_FILEHANDLE);
|
||||
}
|
||||
|
||||
NS_RELEASE(gExceptionProvider);
|
||||
@ -251,7 +256,8 @@ nsDOMExceptionProvider::GetException(nsresult result,
|
||||
default:
|
||||
MOZ_ASSERT(NS_ERROR_GET_MODULE(result) == NS_ERROR_MODULE_DOM ||
|
||||
NS_ERROR_GET_MODULE(result) == NS_ERROR_MODULE_DOM_FILE ||
|
||||
NS_ERROR_GET_MODULE(result) == NS_ERROR_MODULE_DOM_INDEXEDDB,
|
||||
NS_ERROR_GET_MODULE(result) == NS_ERROR_MODULE_DOM_INDEXEDDB ||
|
||||
NS_ERROR_GET_MODULE(result) == NS_ERROR_MODULE_DOM_FILEHANDLE,
|
||||
"Trying to create an exception for the wrong error module.");
|
||||
return NS_NewDOMException(result, aDefaultException, _retval);
|
||||
}
|
||||
|
@ -63,6 +63,8 @@
|
||||
#include "mozilla/dom/indexedDB/FileInfo.h"
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
|
||||
#include "sampler.h"
|
||||
#include "nsDOMBlobBuilder.h"
|
||||
#include "nsIDOMFileHandle.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -2270,14 +2272,99 @@ nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResu
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetFileId(nsIDOMBlob* aBlob, PRInt64* aResult)
|
||||
static nsresult
|
||||
GetFileOrBlob(const nsAString& aName, const jsval& aBlobParts,
|
||||
const jsval& aParameters, JSContext* aCx,
|
||||
PRUint8 aOptionalArgCount, nsISupports** aResult)
|
||||
{
|
||||
if (!IsUniversalXPConnectCapable()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
*aResult = aBlob->GetFileId();
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> file;
|
||||
|
||||
if (aName.IsVoid()) {
|
||||
rv = nsDOMMultipartFile::NewBlob(getter_AddRefs(file));
|
||||
}
|
||||
else {
|
||||
rv = nsDOMMultipartFile::NewFile(aName, getter_AddRefs(file));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIJSNativeInitializer> initializer = do_QueryInterface(file);
|
||||
NS_ASSERTION(initializer, "what?");
|
||||
|
||||
jsval args[2] = { aBlobParts, aParameters };
|
||||
|
||||
rv = initializer->Initialize(nsnull, aCx, nsnull, aOptionalArgCount, args);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
file.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetFile(const nsAString& aName, const jsval& aBlobParts,
|
||||
const jsval& aParameters, JSContext* aCx,
|
||||
PRUint8 aOptionalArgCount, nsIDOMFile** aResult)
|
||||
{
|
||||
nsCOMPtr<nsISupports> file;
|
||||
nsresult rv = GetFileOrBlob(aName, aBlobParts, aParameters, aCx,
|
||||
aOptionalArgCount, getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> result = do_QueryInterface(file);
|
||||
result.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetBlob(const jsval& aBlobParts, const jsval& aParameters,
|
||||
JSContext* aCx, PRUint8 aOptionalArgCount,
|
||||
nsIDOMBlob** aResult)
|
||||
{
|
||||
nsAutoString name;
|
||||
name.SetIsVoid(true);
|
||||
|
||||
nsCOMPtr<nsISupports> blob;
|
||||
nsresult rv = GetFileOrBlob(name, aBlobParts, aParameters, aCx,
|
||||
aOptionalArgCount, getter_AddRefs(blob));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> result = do_QueryInterface(blob);
|
||||
result.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetFileId(const jsval& aFile, JSContext* aCx,
|
||||
PRInt64* aResult)
|
||||
{
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(aFile)) {
|
||||
JSObject* obj = JSVAL_TO_OBJECT(aFile);
|
||||
|
||||
nsISupports* nativeObj =
|
||||
nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(nativeObj);
|
||||
if (blob) {
|
||||
*aResult = blob->GetFileId();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMFileHandle> fileHandle = do_QueryInterface(nativeObj);
|
||||
if (fileHandle) {
|
||||
*aResult = fileHandle->GetFileId();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
*aResult = -1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ interface nsIDOMDOMRequest : nsIDOMEventTarget
|
||||
readonly attribute jsval result;
|
||||
readonly attribute nsIDOMDOMError error;
|
||||
|
||||
attribute nsIDOMEventListener onsuccess;
|
||||
attribute nsIDOMEventListener onerror;
|
||||
attribute nsIDOMEventListener onsuccess;
|
||||
attribute nsIDOMEventListener onerror;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(eebcdf29-f8fa-4c36-bbc7-2146b1cbaf7b)]
|
||||
|
@ -5,6 +5,7 @@
|
||||
DOM_SRCDIRS = \
|
||||
dom/base \
|
||||
dom/battery \
|
||||
dom/file \
|
||||
dom/power \
|
||||
dom/network/src \
|
||||
dom/settings \
|
||||
|
128
dom/file/AsyncHelper.cpp
Normal file
128
dom/file/AsyncHelper.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "AsyncHelper.h"
|
||||
|
||||
#include "nsIRequestObserver.h"
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "FileService.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(AsyncHelper, nsIRunnable, nsIRequest)
|
||||
|
||||
nsresult
|
||||
AsyncHelper::AsyncWork(nsIRequestObserver* aObserver, nsISupports* aCtxt)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (aObserver) {
|
||||
// build proxy for observer events
|
||||
rv = NS_NewRequestObserverProxy(getter_AddRefs(mObserver), aObserver);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mCtxt = aCtxt;
|
||||
|
||||
FileService* service = FileService::GetOrCreate();
|
||||
NS_ENSURE_TRUE(service, NS_ERROR_FAILURE);
|
||||
|
||||
nsIEventTarget* target = service->StreamTransportTarget();
|
||||
|
||||
rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::Run()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (mObserver) {
|
||||
mObserver->OnStartRequest(this, mCtxt);
|
||||
}
|
||||
|
||||
mStatus = DoStreamWork(mStream);
|
||||
|
||||
if (mObserver) {
|
||||
mObserver->OnStopRequest(this, mCtxt, mStatus);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::GetName(nsACString& aName)
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::IsPending(bool* _retval)
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::GetStatus(nsresult* aStatus)
|
||||
{
|
||||
*aStatus = mStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::Cancel(nsresult aStatus)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::Suspend()
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::Resume()
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::GetLoadGroup(nsILoadGroup** aLoadGroup)
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::GetLoadFlags(nsLoadFlags* aLoadFlags)
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncHelper::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
NS_WARNING("Shouldn't be called!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
57
dom/file/AsyncHelper.h
Normal file
57
dom/file/AsyncHelper.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_asynchelper_h__
|
||||
#define mozilla_dom_file_asynchelper_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIRequest.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
class nsIRequestObserver;
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
/**
|
||||
* Must be subclassed. The subclass must implement DoStreamWork.
|
||||
* Async operations that are not supported in necko (truncate, flush, etc.)
|
||||
* should use this helper. Call AsyncWork to invoke the operation.
|
||||
*/
|
||||
class AsyncHelper : public nsIRunnable,
|
||||
public nsIRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
nsresult
|
||||
AsyncWork(nsIRequestObserver* aObserver, nsISupports* aCtxt);
|
||||
|
||||
protected:
|
||||
AsyncHelper(nsISupports* aStream)
|
||||
: mStream(aStream),
|
||||
mStatus(NS_OK)
|
||||
{ }
|
||||
|
||||
virtual ~AsyncHelper()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
DoStreamWork(nsISupports* aStream) = 0;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mStream;
|
||||
nsCOMPtr<nsIRequestObserver> mObserver;
|
||||
nsCOMPtr<nsISupports> mCtxt;
|
||||
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_asynchelper_h__
|
77
dom/file/DOMFileHandle.cpp
Normal file
77
dom/file/DOMFileHandle.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "DOMFileHandle.h"
|
||||
|
||||
#include "nsIFileStreams.h"
|
||||
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "LockedFile.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
// static
|
||||
already_AddRefed<DOMFileHandle>
|
||||
DOMFileHandle::Create(nsPIDOMWindow* aWindow,
|
||||
nsIFileStorage* aFileStorage,
|
||||
nsIFile* aFile)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsRefPtr<DOMFileHandle> newFile(new DOMFileHandle);
|
||||
|
||||
newFile->BindToOwner(aWindow);
|
||||
|
||||
newFile->mFileStorage = aFileStorage;
|
||||
nsresult rv = aFile->GetLeafName(newFile->mName);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
newFile->mFile = aFile;
|
||||
newFile->mFileName = newFile->mName;
|
||||
|
||||
return newFile.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
DOMFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (aReadOnly) {
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), aFile, -1, -1,
|
||||
nsIFileInputStream::DEFER_OPEN);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileStream> stream;
|
||||
rv = NS_NewLocalFileStream(getter_AddRefs(stream), aFile, -1, -1,
|
||||
nsIFileStream::DEFER_OPEN);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMFile>
|
||||
DOMFileHandle::CreateFileObject(LockedFile* aLockedFile, PRUint32 aFileSize)
|
||||
{
|
||||
nsCOMPtr<nsIDOMFile> file =
|
||||
new File(mName, mType, aFileSize, mFile, aLockedFile);
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMFileHandle)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMFileHandle)
|
||||
NS_INTERFACE_MAP_END_INHERITING(FileHandle)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(DOMFileHandle, FileHandle)
|
||||
NS_IMPL_RELEASE_INHERITED(DOMFileHandle, FileHandle)
|
||||
|
||||
DOMCI_DATA(DOMFileHandle, DOMFileHandle)
|
42
dom/file/DOMFileHandle.h
Normal file
42
dom/file/DOMFileHandle.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_domfilehandle_h__
|
||||
#define mozilla_dom_file_domfilehandle_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "FileHandle.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class DOMFileHandle : public FileHandle
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<DOMFileHandle>
|
||||
Create(nsPIDOMWindow* aWindow,
|
||||
nsIFileStorage* aFileStorage,
|
||||
nsIFile* aFile);
|
||||
|
||||
virtual already_AddRefed<nsISupports>
|
||||
CreateStream(nsIFile* aFile, bool aReadOnly);
|
||||
|
||||
virtual already_AddRefed<nsIDOMFile>
|
||||
CreateFileObject(LockedFile* aLockedFile, PRUint32 aFileSize);
|
||||
|
||||
protected:
|
||||
DOMFileHandle()
|
||||
{ }
|
||||
|
||||
~DOMFileHandle()
|
||||
{ }
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_domfilehandle_h__
|
86
dom/file/File.cpp
Normal file
86
dom/file/File.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "File.h"
|
||||
|
||||
#include "LockedFile.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
using mozilla::dom::indexedDB::IndexedDatabaseManager;
|
||||
|
||||
// Create slice
|
||||
File::File(const File* aOther, PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType)
|
||||
: nsDOMFileCC(aContentType, aOther->mStart + aStart, aLength),
|
||||
mFile(aOther->mFile), mLockedFile(aOther->mLockedFile),
|
||||
mWholeFile(false), mStoredFile(aOther->mStoredFile)
|
||||
{
|
||||
NS_ASSERTION(mFile, "Null file!");
|
||||
NS_ASSERTION(mLockedFile, "Null locked file!");
|
||||
|
||||
if (mStoredFile) {
|
||||
FileInfo* fileInfo;
|
||||
|
||||
if (IndexedDatabaseManager::IsClosed()) {
|
||||
fileInfo = aOther->GetFileInfo();
|
||||
}
|
||||
else {
|
||||
MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
|
||||
fileInfo = aOther->GetFileInfo();
|
||||
}
|
||||
|
||||
mFileInfos.AppendElement(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(File)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(File, nsDOMFileCC)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mLockedFile,
|
||||
nsIDOMLockedFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(File, nsDOMFileCC)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLockedFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(File)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMFileCC)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(File, nsDOMFileCC)
|
||||
NS_IMPL_RELEASE_INHERITED(File, nsDOMFileCC)
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetInternalStream(nsIInputStream **aStream)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv = mLockedFile->OpenInputStream(mWholeFile, mStart, mLength,
|
||||
aStream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
File::CreateSlice(PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> t =
|
||||
new File(this, aStart, aLength, aContentType);
|
||||
return t.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetMozFullPathInternal(nsAString &aFilename)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(mIsFile, "Should only be called on files");
|
||||
|
||||
return mFile->GetPath(aFilename);
|
||||
}
|
96
dom/file/File.h
Normal file
96
dom/file/File.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_file_h__
|
||||
#define mozilla_dom_file_file_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsDOMFile.h"
|
||||
|
||||
#include "LockedFile.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class File : public nsDOMFileCC
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(File, nsDOMFileCC)
|
||||
|
||||
// Create as a file
|
||||
File(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength, nsIFile* aFile, LockedFile* aLockedFile)
|
||||
: nsDOMFileCC(aName, aContentType, aLength),
|
||||
mFile(aFile), mLockedFile(aLockedFile),
|
||||
mWholeFile(true), mStoredFile(false)
|
||||
{
|
||||
NS_ASSERTION(mFile, "Null file!");
|
||||
NS_ASSERTION(mLockedFile, "Null locked file!");
|
||||
}
|
||||
|
||||
// Create as a stored file
|
||||
File(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength, nsIFile* aFile, LockedFile* aLockedFile,
|
||||
FileInfo* aFileInfo)
|
||||
: nsDOMFileCC(aName, aContentType, aLength),
|
||||
mFile(aFile), mLockedFile(aLockedFile),
|
||||
mWholeFile(true), mStoredFile(true)
|
||||
{
|
||||
NS_ASSERTION(mFile, "Null file!");
|
||||
NS_ASSERTION(mLockedFile, "Null locked file!");
|
||||
mFileInfos.AppendElement(aFileInfo);
|
||||
}
|
||||
|
||||
// Overrides
|
||||
NS_IMETHOD
|
||||
GetMozFullPathInternal(nsAString& aFullPath);
|
||||
|
||||
NS_IMETHOD
|
||||
GetInternalStream(nsIInputStream** aStream);
|
||||
|
||||
protected:
|
||||
// Create slice
|
||||
File(const File* aOther, PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
virtual ~File()
|
||||
{ }
|
||||
|
||||
virtual already_AddRefed<nsIDOMBlob>
|
||||
CreateSlice(PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
virtual bool
|
||||
IsStoredFile() const
|
||||
{
|
||||
return mStoredFile;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsWholeFile() const
|
||||
{
|
||||
return mWholeFile;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsSnapshot() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsRefPtr<LockedFile> mLockedFile;
|
||||
|
||||
bool mWholeFile;
|
||||
bool mStoredFile;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_file_h__
|
25
dom/file/FileCommon.h
Normal file
25
dom/file/FileCommon.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_filecommon_h__
|
||||
#define mozilla_dom_file_filecommon_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define BEGIN_FILE_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace file {
|
||||
#define END_FILE_NAMESPACE \
|
||||
} /* namespace file */ } /* namespace dom */ } /* namespace mozilla */
|
||||
#define USING_FILE_NAMESPACE \
|
||||
using namespace mozilla::dom::file;
|
||||
|
||||
#endif // mozilla_dom_file_filecommon_h__
|
180
dom/file/FileHandle.cpp
Normal file
180
dom/file/FileHandle.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "FileHandle.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIFileStorage.h"
|
||||
|
||||
#include "FileRequest.h"
|
||||
#include "FileService.h"
|
||||
#include "LockedFile.h"
|
||||
#include "MetadataHelper.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
class GetFileHelper : public MetadataHelper
|
||||
{
|
||||
public:
|
||||
GetFileHelper(LockedFile* aLockedFile,
|
||||
FileRequest* aFileRequest,
|
||||
MetadataParameters* aParams,
|
||||
FileHandle* aFileHandle)
|
||||
: MetadataHelper(aLockedFile, aFileRequest, aParams),
|
||||
mFileHandle(aFileHandle)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
GetSuccessResult(JSContext* aCx, jsval* aVal);
|
||||
|
||||
void
|
||||
ReleaseObjects()
|
||||
{
|
||||
mFileHandle = nsnull;
|
||||
|
||||
MetadataHelper::ReleaseObjects();
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<FileHandle> mFileHandle;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(FileHandle)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileHandle,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFileStorage)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileHandle,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFileStorage)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileHandle)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFileHandle)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FileHandle, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(FileHandle, nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(FileHandle, abort);
|
||||
NS_IMPL_EVENT_HANDLER(FileHandle, error);
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileHandle::GetName(nsAString& aName)
|
||||
{
|
||||
aName = mName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileHandle::GetType(nsAString& aType)
|
||||
{
|
||||
aType = mType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileHandle::Open(const nsAString& aMode,
|
||||
PRUint8 aOptionalArgCount,
|
||||
nsIDOMLockedFile** _retval)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (FileService::IsShuttingDown() || mFileStorage->IsStorageShuttingDown()) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
LockedFile::Mode mode;
|
||||
if (aOptionalArgCount) {
|
||||
if (aMode.EqualsLiteral("readwrite")) {
|
||||
mode = LockedFile::READ_WRITE;
|
||||
}
|
||||
else if (aMode.EqualsLiteral("readonly")) {
|
||||
mode = LockedFile::READ_ONLY;
|
||||
}
|
||||
else {
|
||||
return NS_ERROR_TYPE_ERR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mode = LockedFile::READ_ONLY;
|
||||
}
|
||||
|
||||
nsRefPtr<LockedFile> lockedFile = LockedFile::Create(this, mode);
|
||||
NS_ENSURE_TRUE(lockedFile, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
|
||||
lockedFile.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileHandle::GetFile(nsIDOMFileRequest** _retval)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!GetOwner()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<LockedFile> lockedFile =
|
||||
LockedFile::Create(this, LockedFile::READ_ONLY, LockedFile::PARALLEL);
|
||||
NS_ENSURE_TRUE(lockedFile, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
|
||||
nsRefPtr<FileRequest> fileRequest =
|
||||
FileRequest::Create(GetOwner(), lockedFile);
|
||||
|
||||
nsRefPtr<MetadataParameters> params = new MetadataParameters();
|
||||
params->Init(true, false);
|
||||
|
||||
nsRefPtr<GetFileHelper> helper =
|
||||
new GetFileHelper(lockedFile, fileRequest, params, this);
|
||||
|
||||
nsresult rv = helper->Enqueue();
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
|
||||
fileRequest.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt64)
|
||||
FileHandle::GetFileId()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(mozilla::dom::indexedDB::FileInfo*)
|
||||
FileHandle::GetFileInfo()
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetFileHelper::GetSuccessResult(JSContext* aCx, jsval* aVal)
|
||||
{
|
||||
nsCOMPtr<nsIDOMFile> domFile =
|
||||
mFileHandle->CreateFileObject(mLockedFile, mParams->Size());
|
||||
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
|
||||
&NS_GET_IID(nsIDOMFile), aVal);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
86
dom/file/FileHandle.h
Normal file
86
dom/file/FileHandle.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_filehandle_h__
|
||||
#define mozilla_dom_file_filehandle_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIDOMFileHandle.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
|
||||
class nsIDOMFile;
|
||||
class nsIFileStorage;
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class FileService;
|
||||
class LockedFile;
|
||||
class FinishHelper;
|
||||
class FileHelper;
|
||||
|
||||
/**
|
||||
* Must be subclassed. The subclass must implement CreateStream and
|
||||
* CreateFileObject. Basically, every file storage implementation provides its
|
||||
* own FileHandle implementation (for example IDBFileHandle provides IndexedDB
|
||||
* specific implementation).
|
||||
*/
|
||||
class FileHandle : public nsDOMEventTargetHelper,
|
||||
public nsIDOMFileHandle
|
||||
{
|
||||
friend class FileService;
|
||||
friend class LockedFile;
|
||||
friend class FinishHelper;
|
||||
friend class FileHelper;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMFILEHANDLE
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileHandle, nsDOMEventTargetHelper)
|
||||
|
||||
const nsAString&
|
||||
Name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
const nsAString&
|
||||
Type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsISupports>
|
||||
CreateStream(nsIFile* aFile, bool aReadOnly) = 0;
|
||||
|
||||
virtual already_AddRefed<nsIDOMFile>
|
||||
CreateFileObject(LockedFile* aLockedFile, PRUint32 aFileSize) = 0;
|
||||
|
||||
protected:
|
||||
FileHandle()
|
||||
{ }
|
||||
|
||||
~FileHandle()
|
||||
{ }
|
||||
|
||||
nsCOMPtr<nsIFileStorage> mFileStorage;
|
||||
|
||||
nsString mName;
|
||||
nsString mType;
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsString mFileName;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(abort)
|
||||
NS_DECL_EVENT_HANDLER(error)
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_filehandle_h__
|
209
dom/file/FileHelper.cpp
Normal file
209
dom/file/FileHelper.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "FileHelper.h"
|
||||
|
||||
#include "nsIFileStorage.h"
|
||||
|
||||
#include "nsNetError.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
#include "FileHandle.h"
|
||||
#include "FileRequest.h"
|
||||
#include "FileService.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
LockedFile* gCurrentLockedFile = nsnull;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
FileHelper::FileHelper(LockedFile* aLockedFile,
|
||||
FileRequest* aFileRequest)
|
||||
: mFileStorage(aLockedFile->mFileHandle->mFileStorage),
|
||||
mLockedFile(aLockedFile),
|
||||
mFileRequest(aFileRequest),
|
||||
mResultCode(NS_OK),
|
||||
mFinished(false)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
FileHelper::~FileHelper()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(FileHelper, nsIRequestObserver)
|
||||
|
||||
nsresult
|
||||
FileHelper::Enqueue()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
FileService* service = FileService::GetOrCreate();
|
||||
NS_ENSURE_TRUE(service, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = service->Enqueue(mLockedFile, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mLockedFile) {
|
||||
mLockedFile->OnNewRequest();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileHelper::AsyncRun(FileHelperListener* aListener)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
// Assign the listener early, so we can use it synchronously if the code
|
||||
// below fails.
|
||||
mListener = aListener;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> stream;
|
||||
if (mLockedFile->mRequestMode == LockedFile::PARALLEL) {
|
||||
rv = mLockedFile->CreateParallelStream(getter_AddRefs(stream));
|
||||
}
|
||||
else {
|
||||
rv = mLockedFile->GetOrCreateStream(getter_AddRefs(stream));
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(stream, "This should never be null!");
|
||||
|
||||
rv = DoAsyncRun(stream);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
Finish();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileHelper::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileHelper::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt,
|
||||
nsresult aStatus)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
Finish();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileHelper::OnStreamProgress(PRUint64 aProgress, PRUint64 aProgressMax)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (mLockedFile->IsAborted()) {
|
||||
NS_ASSERTION(mRequest, "Should have a request!\n");
|
||||
|
||||
nsresult rv = mRequest->Cancel(NS_BINDING_ABORTED);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to cancel the request!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFileRequest) {
|
||||
mFileRequest->OnProgress(aProgress, aProgressMax);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
LockedFile*
|
||||
FileHelper::GetCurrentLockedFile()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
return gCurrentLockedFile;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
*aVal = JSVAL_VOID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileHelper::ReleaseObjects()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
mFileStorage = nsnull;
|
||||
mLockedFile = nsnull;
|
||||
mFileRequest = nsnull;
|
||||
mListener = nsnull;
|
||||
mRequest = nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
FileHelper::Finish()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (mFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFinished = true;
|
||||
|
||||
if (mLockedFile->IsAborted()) {
|
||||
// Always fire a "error" event with ABORT_ERR if the transaction was
|
||||
// aborted, even if the request succeeded or failed with another error.
|
||||
mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR;
|
||||
}
|
||||
|
||||
LockedFile* oldLockedFile = gCurrentLockedFile;
|
||||
gCurrentLockedFile = mLockedFile;
|
||||
|
||||
if (mFileRequest) {
|
||||
nsresult rv = mFileRequest->NotifyHelperCompleted(this);
|
||||
if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
|
||||
mResultCode = rv;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(gCurrentLockedFile == mLockedFile, "Should be unchanged!");
|
||||
gCurrentLockedFile = oldLockedFile;
|
||||
|
||||
mLockedFile->OnRequestFinished();
|
||||
|
||||
mListener->OnFileHelperComplete(this);
|
||||
|
||||
ReleaseObjects();
|
||||
|
||||
NS_ASSERTION(!(mFileStorage || mLockedFile || mFileRequest || mListener ||
|
||||
mRequest), "Subclass didn't call FileHelper::ReleaseObjects!");
|
||||
|
||||
}
|
107
dom/file/FileHelper.h
Normal file
107
dom/file/FileHelper.h
Normal file
@ -0,0 +1,107 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_filehelper_h__
|
||||
#define mozilla_dom_file_filehelper_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIRequestObserver.h"
|
||||
|
||||
class nsIFileStorage;
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class FileHelper;
|
||||
class FileRequest;
|
||||
class FileOutputStreamWrapper;
|
||||
class LockedFile;
|
||||
|
||||
class FileHelperListener
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(nsrefcnt)
|
||||
AddRef() = 0;
|
||||
|
||||
NS_IMETHOD_(nsrefcnt)
|
||||
Release() = 0;
|
||||
|
||||
virtual void
|
||||
OnFileHelperComplete(FileHelper* aFileHelper) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Must be subclassed. The subclass must implement DoAsyncRun. It may then
|
||||
* choose to implement GetSuccessResult to properly set the result of the
|
||||
* success event. Call Enqueue to start the file operation.
|
||||
*/
|
||||
class FileHelper : public nsIRequestObserver
|
||||
{
|
||||
friend class FileRequest;
|
||||
friend class FileOutputStreamWrapper;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
nsresult
|
||||
Enqueue();
|
||||
|
||||
nsresult
|
||||
AsyncRun(FileHelperListener* aListener);
|
||||
|
||||
void
|
||||
OnStreamProgress(PRUint64 aProgress, PRUint64 aProgressMax);
|
||||
|
||||
void
|
||||
OnStreamClose()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
Finish();
|
||||
}
|
||||
|
||||
void
|
||||
OnStreamDestroy()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
Finish();
|
||||
}
|
||||
|
||||
static LockedFile*
|
||||
GetCurrentLockedFile();
|
||||
|
||||
protected:
|
||||
FileHelper(LockedFile* aLockedFile, FileRequest* aRequest);
|
||||
|
||||
virtual ~FileHelper();
|
||||
|
||||
virtual nsresult
|
||||
DoAsyncRun(nsISupports* aStream) = 0;
|
||||
|
||||
virtual nsresult
|
||||
GetSuccessResult(JSContext* aCx, jsval* aVal);
|
||||
|
||||
virtual void
|
||||
ReleaseObjects();
|
||||
|
||||
void
|
||||
Finish();
|
||||
|
||||
nsCOMPtr<nsIFileStorage> mFileStorage;
|
||||
nsRefPtr<LockedFile> mLockedFile;
|
||||
nsRefPtr<FileRequest> mFileRequest;
|
||||
|
||||
nsRefPtr<FileHelperListener> mListener;
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
|
||||
private:
|
||||
nsresult mResultCode;
|
||||
bool mFinished;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_filehelper_h__
|
169
dom/file/FileRequest.cpp
Normal file
169
dom/file/FileRequest.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "FileRequest.h"
|
||||
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsDOMProgressEvent.h"
|
||||
|
||||
#include "FileHelper.h"
|
||||
#include "LockedFile.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
FileRequest::FileRequest(nsIDOMWindow* aWindow)
|
||||
: DOMRequest(aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
FileRequest::~FileRequest()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<FileRequest>
|
||||
FileRequest::Create(nsIDOMWindow* aOwner,
|
||||
LockedFile* aLockedFile)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsRefPtr<FileRequest> request = new FileRequest(aOwner);
|
||||
request->mLockedFile = aLockedFile;
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = mLockedFile;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileRequest::NotifyHelperCompleted(FileHelper* aFileHelper)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv = aFileHelper->mResultCode;
|
||||
|
||||
// If the request failed then fire error event and return.
|
||||
if (NS_FAILED(rv)) {
|
||||
FireError(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise we need to get the result from the helper.
|
||||
jsval result;
|
||||
|
||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||
NS_ENSURE_STATE(sc);
|
||||
|
||||
JSContext* cx = sc->GetNativeContext();
|
||||
NS_ASSERTION(cx, "Failed to get a context!");
|
||||
|
||||
JSObject* global = sc->GetNativeGlobal();
|
||||
NS_ASSERTION(global, "Failed to get global object!");
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoEnterCompartment ac;
|
||||
if (ac.enter(cx, global)) {
|
||||
rv = aFileHelper->GetSuccessResult(cx, &result);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("GetSuccessResult failed!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_WARNING("Failed to enter correct compartment!");
|
||||
rv = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
FireSuccess(result);
|
||||
}
|
||||
else {
|
||||
FireError(rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileRequest::GetLockedFile(nsIDOMLockedFile** aLockedFile)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIDOMLockedFile> lockedFile(mLockedFile);
|
||||
lockedFile.forget(aLockedFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(FileRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileRequest, DOMRequest)
|
||||
// Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
|
||||
// nsDOMEventTargetHelper does it for us.
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(progress)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mLockedFile,
|
||||
nsIDOMLockedFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileRequest, DOMRequest)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(progress)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLockedFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFileRequest)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FileRequest, DOMRequest)
|
||||
NS_IMPL_RELEASE_INHERITED(FileRequest, DOMRequest)
|
||||
|
||||
DOMCI_DATA(FileRequest, FileRequest)
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(FileRequest, progress);
|
||||
|
||||
void
|
||||
FileRequest::FireProgressEvent(PRUint64 aLoaded, PRUint64 aTotal)
|
||||
{
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMProgressEvent> event = new nsDOMProgressEvent(nsnull, nsnull);
|
||||
nsresult rv = event->InitProgressEvent(NS_LITERAL_STRING("progress"),
|
||||
false, false, false, aLoaded, aTotal);
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
|
||||
rv = event->SetTrusted(true);
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
|
||||
bool dummy;
|
||||
rv = DispatchEvent(static_cast<nsIDOMProgressEvent*>(event), &dummy);
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
}
|
||||
|
||||
void
|
||||
FileRequest::RootResultVal()
|
||||
{
|
||||
NS_ASSERTION(!mRooted, "Don't call me if already rooted!");
|
||||
nsXPCOMCycleCollectionParticipant *participant;
|
||||
CallQueryInterface(this, &participant);
|
||||
nsContentUtils::HoldJSObjects(NS_CYCLE_COLLECTION_UPCAST(this, DOMRequest),
|
||||
participant);
|
||||
mRooted = true;
|
||||
}
|
64
dom/file/FileRequest.h
Normal file
64
dom/file/FileRequest.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_filerequest_h__
|
||||
#define mozilla_dom_file_filerequest_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIDOMFileRequest.h"
|
||||
|
||||
#include "DOMRequest.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class FileHelper;
|
||||
class LockedFile;
|
||||
|
||||
class FileRequest : public mozilla::dom::DOMRequest,
|
||||
public nsIDOMFileRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMFILEREQUEST
|
||||
NS_FORWARD_NSIDOMDOMREQUEST(DOMRequest::)
|
||||
NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(DOMRequest::)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileRequest, DOMRequest)
|
||||
|
||||
static already_AddRefed<FileRequest>
|
||||
Create(nsIDOMWindow* aOwner, LockedFile* aLockedFile);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult
|
||||
PreHandleEvent(nsEventChainPreVisitor& aVisitor);
|
||||
|
||||
void
|
||||
OnProgress(PRUint64 aProgress, PRUint64 aProgressMax)
|
||||
{
|
||||
FireProgressEvent(aProgress, aProgressMax);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NotifyHelperCompleted(FileHelper* aFileHelper);
|
||||
|
||||
private:
|
||||
FileRequest(nsIDOMWindow* aWindow);
|
||||
~FileRequest();
|
||||
|
||||
void
|
||||
FireProgressEvent(PRUint64 aLoaded, PRUint64 aTotal);
|
||||
|
||||
virtual void
|
||||
RootResultVal();
|
||||
|
||||
nsRefPtr<LockedFile> mLockedFile;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(progress)
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_filerequest_h__
|
528
dom/file/FileService.cpp
Normal file
528
dom/file/FileService.cpp
Normal file
@ -0,0 +1,528 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "FileService.h"
|
||||
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStorage.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIStreamTransportService.h"
|
||||
|
||||
#include "nsNetCID.h"
|
||||
|
||||
#include "FileHandle.h"
|
||||
#include "FileRequest.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
FileService* gInstance = nsnull;
|
||||
bool gShutdown = false;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
FileService::FileService()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!gInstance, "More than one instance!");
|
||||
}
|
||||
|
||||
FileService::~FileService()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!gInstance, "More than one instance!");
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileService::Init()
|
||||
{
|
||||
mFileStorageInfos.Init();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
mStreamTransportTarget =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIStreamTransportService> sts =
|
||||
do_QueryInterface(mStreamTransportTarget);
|
||||
|
||||
rv = sts->RaiseThreadLimit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileService::Cleanup()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsIThread* thread = NS_GetCurrentThread();
|
||||
while (mFileStorageInfos.Count()) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
NS_ERROR("Failed to process next event!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the service is still accessible while any generated callbacks
|
||||
// are processed.
|
||||
nsresult rv = NS_ProcessPendingEvents(thread);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mCompleteCallbacks.IsEmpty()) {
|
||||
// Run all callbacks manually now.
|
||||
for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) {
|
||||
mCompleteCallbacks[index].mCallback->Run();
|
||||
}
|
||||
mCompleteCallbacks.Clear();
|
||||
|
||||
// And make sure they get processed.
|
||||
rv = NS_ProcessPendingEvents(thread);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
FileService*
|
||||
FileService::GetOrCreate()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (gShutdown) {
|
||||
NS_WARNING("Calling GetOrCreate() after shutdown!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!gInstance) {
|
||||
nsRefPtr<FileService> service(new FileService);
|
||||
|
||||
nsresult rv = service->Init();
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs =
|
||||
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
rv = obs->AddObserver(service, "profile-before-change", false);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
// The observer service now owns us.
|
||||
gInstance = service;
|
||||
}
|
||||
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
// static
|
||||
FileService*
|
||||
FileService::Get()
|
||||
{
|
||||
// Does not return an owning reference.
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
FileService::Shutdown()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
gShutdown = true;
|
||||
|
||||
if (gInstance) {
|
||||
if (NS_FAILED(gInstance->Cleanup())) {
|
||||
NS_WARNING("Failed to shutdown file service!");
|
||||
}
|
||||
gInstance = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
FileService::IsShuttingDown()
|
||||
{
|
||||
return gShutdown;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileService::Enqueue(LockedFile* aLockedFile, FileHelper* aFileHelper)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aLockedFile, "Null pointer!");
|
||||
|
||||
FileHandle* fileHandle = aLockedFile->mFileHandle;
|
||||
|
||||
if (fileHandle->mFileStorage->IsStorageInvalidated()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsISupports* storageId = fileHandle->mFileStorage->StorageId();
|
||||
const nsAString& fileName = fileHandle->mFileName;
|
||||
bool modeIsWrite = aLockedFile->mMode == LockedFile::READ_WRITE;
|
||||
|
||||
FileStorageInfo* fileStorageInfo;
|
||||
if (!mFileStorageInfos.Get(storageId, &fileStorageInfo)) {
|
||||
nsAutoPtr<FileStorageInfo> newFileStorageInfo(new FileStorageInfo());
|
||||
|
||||
mFileStorageInfos.Put(storageId, newFileStorageInfo);
|
||||
|
||||
fileStorageInfo = newFileStorageInfo.forget();
|
||||
}
|
||||
|
||||
LockedFileQueue* existingLockedFileQueue =
|
||||
fileStorageInfo->GetLockedFileQueue(aLockedFile);
|
||||
|
||||
if (existingLockedFileQueue) {
|
||||
existingLockedFileQueue->Enqueue(aFileHelper);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool lockedForReading = fileStorageInfo->IsFileLockedForReading(fileName);
|
||||
bool lockedForWriting = fileStorageInfo->IsFileLockedForWriting(fileName);
|
||||
|
||||
if (modeIsWrite) {
|
||||
if (!lockedForWriting) {
|
||||
fileStorageInfo->LockFileForWriting(fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!lockedForReading) {
|
||||
fileStorageInfo->LockFileForReading(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (lockedForWriting || (lockedForReading && modeIsWrite)) {
|
||||
fileStorageInfo->CreateDelayedEnqueueInfo(aLockedFile, aFileHelper);
|
||||
}
|
||||
else {
|
||||
LockedFileQueue* lockedFileQueue =
|
||||
fileStorageInfo->CreateLockedFileQueue(aLockedFile);
|
||||
|
||||
if (aFileHelper) {
|
||||
// Enqueue() will queue the file helper if there's already something
|
||||
// running. That can't fail, so no need to eventually remove
|
||||
// fileStorageInfo from the hash table.
|
||||
//
|
||||
// If the file helper is free to run then AsyncRun() is called on the
|
||||
// file helper. AsyncRun() is responsible for calling all necessary
|
||||
// callbacks when something fails. We're propagating the error here,
|
||||
// however there's no need to eventually remove fileStorageInfo from
|
||||
// the hash table. Code behind AsyncRun() will take care of it. The last
|
||||
// item in the code path is NotifyLockedFileCompleted() which removes
|
||||
// fileStorageInfo from the hash table if there are no locked files for
|
||||
// the file storage.
|
||||
nsresult rv = lockedFileQueue->Enqueue(aFileHelper);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileService::NotifyLockedFileCompleted(LockedFile* aLockedFile)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aLockedFile, "Null pointer!");
|
||||
|
||||
FileHandle* fileHandle = aLockedFile->mFileHandle;
|
||||
nsISupports* storageId = fileHandle->mFileStorage->StorageId();
|
||||
|
||||
FileStorageInfo* fileStorageInfo;
|
||||
if (!mFileStorageInfos.Get(storageId, &fileStorageInfo)) {
|
||||
NS_ERROR("We don't know anyting about this locked file?!");
|
||||
return;
|
||||
}
|
||||
|
||||
fileStorageInfo->RemoveLockedFileQueue(aLockedFile);
|
||||
|
||||
if (!fileStorageInfo->HasRunningLockedFiles()) {
|
||||
mFileStorageInfos.Remove(storageId);
|
||||
|
||||
#ifdef DEBUG
|
||||
storageId = nsnull;
|
||||
#endif
|
||||
|
||||
// See if we need to fire any complete callbacks.
|
||||
PRUint32 index = 0;
|
||||
while (index < mCompleteCallbacks.Length()) {
|
||||
if (MaybeFireCallback(mCompleteCallbacks[index])) {
|
||||
mCompleteCallbacks.RemoveElementAt(index);
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileService::WaitForAllStoragesToComplete(
|
||||
nsTArray<nsCOMPtr<nsIFileStorage> >& aStorages,
|
||||
nsIRunnable* aCallback)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!aStorages.IsEmpty(), "No databases to wait on!");
|
||||
NS_ASSERTION(aCallback, "Null pointer!");
|
||||
|
||||
StoragesCompleteCallback* callback = mCompleteCallbacks.AppendElement();
|
||||
callback->mCallback = aCallback;
|
||||
callback->mStorages.SwapElements(aStorages);
|
||||
|
||||
if (MaybeFireCallback(*callback)) {
|
||||
mCompleteCallbacks.RemoveElementAt(mCompleteCallbacks.Length() - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FileService::AbortLockedFilesForStorage(nsIFileStorage* aFileStorage)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aFileStorage, "Null pointer!");
|
||||
|
||||
FileStorageInfo* fileStorageInfo;
|
||||
if (!mFileStorageInfos.Get(aFileStorage->StorageId(), &fileStorageInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoTArray<nsRefPtr<LockedFile>, 10> lockedFiles;
|
||||
fileStorageInfo->CollectRunningAndDelayedLockedFiles(aFileStorage,
|
||||
lockedFiles);
|
||||
|
||||
for (PRUint32 index = 0; index < lockedFiles.Length(); index++) {
|
||||
lockedFiles[index]->Abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileService::HasLockedFilesForStorage(nsIFileStorage* aFileStorage)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aFileStorage, "Null pointer!");
|
||||
|
||||
FileStorageInfo* fileStorageInfo;
|
||||
if (!mFileStorageInfos.Get(aFileStorage->StorageId(), &fileStorageInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fileStorageInfo->HasRunningLockedFiles(aFileStorage);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(FileService, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!strcmp(aTopic, "profile-before-change"), "Wrong topic!");
|
||||
|
||||
Shutdown();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
FileService::MaybeFireCallback(StoragesCompleteCallback& aCallback)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
for (PRUint32 index = 0; index < aCallback.mStorages.Length(); index++) {
|
||||
if (mFileStorageInfos.Get(aCallback.mStorages[index]->StorageId(),
|
||||
nsnull)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
aCallback.mCallback->Run();
|
||||
return true;
|
||||
}
|
||||
|
||||
FileService::LockedFileQueue::LockedFileQueue(LockedFile* aLockedFile)
|
||||
: mLockedFile(aLockedFile)
|
||||
{
|
||||
NS_ASSERTION(aLockedFile, "Null pointer!");
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(FileService::LockedFileQueue)
|
||||
NS_IMPL_THREADSAFE_RELEASE(FileService::LockedFileQueue)
|
||||
|
||||
nsresult
|
||||
FileService::LockedFileQueue::Enqueue(FileHelper* aFileHelper)
|
||||
{
|
||||
mQueue.AppendElement(aFileHelper);
|
||||
|
||||
nsresult rv;
|
||||
if (mLockedFile->mRequestMode == LockedFile::PARALLEL) {
|
||||
rv = aFileHelper->AsyncRun(this);
|
||||
}
|
||||
else {
|
||||
rv = ProcessQueue();
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileService::LockedFileQueue::OnFileHelperComplete(FileHelper* aFileHelper)
|
||||
{
|
||||
if (mLockedFile->mRequestMode == LockedFile::PARALLEL) {
|
||||
PRInt32 index = mQueue.IndexOf(aFileHelper);
|
||||
NS_ASSERTION(index != -1, "We don't know anything about this helper!");
|
||||
|
||||
mQueue.RemoveElementAt(index);
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(mCurrentHelper == aFileHelper, "How can this happen?!");
|
||||
|
||||
mCurrentHelper = nsnull;
|
||||
|
||||
nsresult rv = ProcessQueue();
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileService::LockedFileQueue::ProcessQueue()
|
||||
{
|
||||
if (mQueue.IsEmpty() || mCurrentHelper) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCurrentHelper = mQueue[0];
|
||||
mQueue.RemoveElementAt(0);
|
||||
|
||||
nsresult rv = mCurrentHelper->AsyncRun(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FileService::LockedFileQueue*
|
||||
FileService::FileStorageInfo::CreateLockedFileQueue(LockedFile* aLockedFile)
|
||||
{
|
||||
nsRefPtr<LockedFileQueue>* lockedFileQueue =
|
||||
mLockedFileQueues.AppendElement();
|
||||
*lockedFileQueue = new LockedFileQueue(aLockedFile);
|
||||
return lockedFileQueue->get();
|
||||
}
|
||||
|
||||
FileService::LockedFileQueue*
|
||||
FileService::FileStorageInfo::GetLockedFileQueue(LockedFile* aLockedFile)
|
||||
{
|
||||
PRUint32 count = mLockedFileQueues.Length();
|
||||
for (PRUint32 index = 0; index < count; index++) {
|
||||
nsRefPtr<LockedFileQueue>& lockedFileQueue = mLockedFileQueues[index];
|
||||
if (lockedFileQueue->mLockedFile == aLockedFile) {
|
||||
return lockedFileQueue;
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
FileService::FileStorageInfo::RemoveLockedFileQueue(LockedFile* aLockedFile)
|
||||
{
|
||||
PRUint32 lockedFileCount = mLockedFileQueues.Length();
|
||||
|
||||
// We can't just remove entries from lock hash tables, we have to rebuild
|
||||
// them instead. Multiple LockedFile objects may lock the same file
|
||||
// (one entry can represent multiple locks).
|
||||
|
||||
mFilesReading.Clear();
|
||||
mFilesWriting.Clear();
|
||||
|
||||
for (PRUint32 index = 0, count = lockedFileCount; index < count; index++) {
|
||||
LockedFile* lockedFile = mLockedFileQueues[index]->mLockedFile;
|
||||
if (lockedFile == aLockedFile) {
|
||||
NS_ASSERTION(count == lockedFileCount, "More than one match?!");
|
||||
|
||||
mLockedFileQueues.RemoveElementAt(index);
|
||||
index--;
|
||||
count--;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const nsAString& fileName = lockedFile->mFileHandle->mFileName;
|
||||
|
||||
if (lockedFile->mMode == LockedFile::READ_WRITE) {
|
||||
if (!IsFileLockedForWriting(fileName)) {
|
||||
LockFileForWriting(fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!IsFileLockedForReading(fileName)) {
|
||||
LockFileForReading(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(mLockedFileQueues.Length() == lockedFileCount - 1,
|
||||
"Didn't find the locked file we were looking for!");
|
||||
|
||||
nsTArray<DelayedEnqueueInfo> delayedEnqueueInfos;
|
||||
delayedEnqueueInfos.SwapElements(mDelayedEnqueueInfos);
|
||||
|
||||
for (PRUint32 index = 0; index < delayedEnqueueInfos.Length(); index++) {
|
||||
DelayedEnqueueInfo& delayedEnqueueInfo = delayedEnqueueInfos[index];
|
||||
if (NS_FAILED(gInstance->Enqueue(delayedEnqueueInfo.mLockedFile,
|
||||
delayedEnqueueInfo.mFileHelper))) {
|
||||
NS_WARNING("Enqueue failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileService::FileStorageInfo::HasRunningLockedFiles(
|
||||
nsIFileStorage* aFileStorage)
|
||||
{
|
||||
for (PRUint32 index = 0; index < mLockedFileQueues.Length(); index++) {
|
||||
LockedFile* lockedFile = mLockedFileQueues[index]->mLockedFile;
|
||||
if (lockedFile->mFileHandle->mFileStorage == aFileStorage) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FileService::DelayedEnqueueInfo*
|
||||
FileService::FileStorageInfo::CreateDelayedEnqueueInfo(LockedFile* aLockedFile,
|
||||
FileHelper* aFileHelper)
|
||||
{
|
||||
DelayedEnqueueInfo* info = mDelayedEnqueueInfos.AppendElement();
|
||||
info->mLockedFile = aLockedFile;
|
||||
info->mFileHelper = aFileHelper;
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
FileService::FileStorageInfo::CollectRunningAndDelayedLockedFiles(
|
||||
nsIFileStorage* aFileStorage,
|
||||
nsTArray<nsRefPtr<LockedFile> >& aLockedFiles)
|
||||
{
|
||||
for (PRUint32 index = 0; index < mLockedFileQueues.Length(); index++) {
|
||||
LockedFile* lockedFile = mLockedFileQueues[index]->mLockedFile;
|
||||
if (lockedFile->mFileHandle->mFileStorage == aFileStorage) {
|
||||
aLockedFiles.AppendElement(lockedFile);
|
||||
}
|
||||
}
|
||||
|
||||
for (PRUint32 index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
|
||||
LockedFile* lockedFile = mDelayedEnqueueInfos[index].mLockedFile;
|
||||
if (lockedFile->mFileHandle->mFileStorage == aFileStorage) {
|
||||
aLockedFiles.AppendElement(lockedFile);
|
||||
}
|
||||
}
|
||||
}
|
196
dom/file/FileService.h
Normal file
196
dom/file/FileService.h
Normal file
@ -0,0 +1,196 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_fileservice_h__
|
||||
#define mozilla_dom_file_fileservice_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
#include "mozilla/dom/file/FileHelper.h"
|
||||
#include "mozilla/dom/file/LockedFile.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class FileService : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// Returns a non-owning reference!
|
||||
static FileService*
|
||||
GetOrCreate();
|
||||
|
||||
// Returns a non-owning reference!
|
||||
static FileService*
|
||||
Get();
|
||||
|
||||
static void
|
||||
Shutdown();
|
||||
|
||||
// Returns true if we've begun the shutdown process.
|
||||
static bool
|
||||
IsShuttingDown();
|
||||
|
||||
nsresult
|
||||
Enqueue(LockedFile* aLockedFile, FileHelper* aFileHelper);
|
||||
|
||||
void
|
||||
NotifyLockedFileCompleted(LockedFile* aLockedFile);
|
||||
|
||||
bool
|
||||
WaitForAllStoragesToComplete(nsTArray<nsCOMPtr<nsIFileStorage> >& aStorages,
|
||||
nsIRunnable* aCallback);
|
||||
|
||||
void
|
||||
AbortLockedFilesForStorage(nsIFileStorage* aFileStorage);
|
||||
|
||||
bool
|
||||
HasLockedFilesForStorage(nsIFileStorage* aFileStorage);
|
||||
|
||||
nsIEventTarget*
|
||||
StreamTransportTarget()
|
||||
{
|
||||
NS_ASSERTION(mStreamTransportTarget, "This should never be null!");
|
||||
return mStreamTransportTarget;
|
||||
}
|
||||
|
||||
private:
|
||||
class LockedFileQueue : public FileHelperListener
|
||||
{
|
||||
friend class FileService;
|
||||
|
||||
public:
|
||||
NS_IMETHOD_(nsrefcnt)
|
||||
AddRef();
|
||||
|
||||
NS_IMETHOD_(nsrefcnt)
|
||||
Release();
|
||||
|
||||
inline nsresult
|
||||
Enqueue(FileHelper* aFileHelper);
|
||||
|
||||
virtual void
|
||||
OnFileHelperComplete(FileHelper* aFileHelper);
|
||||
|
||||
private:
|
||||
inline
|
||||
LockedFileQueue(LockedFile* aLockedFile);
|
||||
|
||||
nsresult
|
||||
ProcessQueue();
|
||||
|
||||
nsAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
nsRefPtr<LockedFile> mLockedFile;
|
||||
nsTArray<nsRefPtr<FileHelper> > mQueue;
|
||||
nsRefPtr<FileHelper> mCurrentHelper;
|
||||
};
|
||||
|
||||
struct DelayedEnqueueInfo
|
||||
{
|
||||
nsRefPtr<LockedFile> mLockedFile;
|
||||
nsRefPtr<FileHelper> mFileHelper;
|
||||
};
|
||||
|
||||
class FileStorageInfo
|
||||
{
|
||||
friend class FileService;
|
||||
|
||||
public:
|
||||
inline LockedFileQueue*
|
||||
CreateLockedFileQueue(LockedFile* aLockedFile);
|
||||
|
||||
inline LockedFileQueue*
|
||||
GetLockedFileQueue(LockedFile* aLockedFile);
|
||||
|
||||
void
|
||||
RemoveLockedFileQueue(LockedFile* aLockedFile);
|
||||
|
||||
bool
|
||||
HasRunningLockedFiles()
|
||||
{
|
||||
return !mLockedFileQueues.IsEmpty();
|
||||
}
|
||||
|
||||
inline bool
|
||||
HasRunningLockedFiles(nsIFileStorage* aFileStorage);
|
||||
|
||||
inline DelayedEnqueueInfo*
|
||||
CreateDelayedEnqueueInfo(LockedFile* aLockedFile, FileHelper* aFileHelper);
|
||||
|
||||
inline void
|
||||
CollectRunningAndDelayedLockedFiles(
|
||||
nsIFileStorage* aFileStorage,
|
||||
nsTArray<nsRefPtr<LockedFile> >& aLockedFiles);
|
||||
|
||||
void
|
||||
LockFileForReading(const nsAString& aFileName)
|
||||
{
|
||||
mFilesReading.PutEntry(aFileName);
|
||||
}
|
||||
|
||||
void
|
||||
LockFileForWriting(const nsAString& aFileName)
|
||||
{
|
||||
mFilesWriting.PutEntry(aFileName);
|
||||
}
|
||||
|
||||
bool
|
||||
IsFileLockedForReading(const nsAString& aFileName)
|
||||
{
|
||||
return mFilesReading.Contains(aFileName);
|
||||
}
|
||||
|
||||
bool
|
||||
IsFileLockedForWriting(const nsAString& aFileName)
|
||||
{
|
||||
return mFilesWriting.Contains(aFileName);
|
||||
}
|
||||
|
||||
private:
|
||||
FileStorageInfo()
|
||||
{
|
||||
mFilesReading.Init();
|
||||
mFilesWriting.Init();
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<LockedFileQueue> > mLockedFileQueues;
|
||||
nsTArray<DelayedEnqueueInfo> mDelayedEnqueueInfos;
|
||||
nsTHashtable<nsStringHashKey> mFilesReading;
|
||||
nsTHashtable<nsStringHashKey> mFilesWriting;
|
||||
};
|
||||
|
||||
struct StoragesCompleteCallback
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIFileStorage> > mStorages;
|
||||
nsCOMPtr<nsIRunnable> mCallback;
|
||||
};
|
||||
|
||||
FileService();
|
||||
~FileService();
|
||||
|
||||
nsresult
|
||||
Init();
|
||||
|
||||
nsresult
|
||||
Cleanup();
|
||||
|
||||
bool
|
||||
MaybeFireCallback(StoragesCompleteCallback& aCallback);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mStreamTransportTarget;
|
||||
nsClassHashtable<nsISupportsHashKey, FileStorageInfo> mFileStorageInfos;
|
||||
nsTArray<StoragesCompleteCallback> mCompleteCallbacks;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif /* mozilla_dom_file_fileservice_h__ */
|
397
dom/file/FileStreamWrappers.cpp
Normal file
397
dom/file/FileStreamWrappers.cpp
Normal file
@ -0,0 +1,397 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "FileStreamWrappers.h"
|
||||
|
||||
#include "nsIFileStorage.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIStandardFileStream.h"
|
||||
|
||||
#include "FileHelper.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
class ProgressRunnable : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
ProgressRunnable(FileHelper* aFileHelper,
|
||||
PRUint64 aProgress,
|
||||
PRUint64 aProgressMax)
|
||||
: mFileHelper(aFileHelper),
|
||||
mProgress(aProgress),
|
||||
mProgressMax(aProgressMax)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<FileHelper> mFileHelper;
|
||||
PRUint64 mProgress;
|
||||
PRUint64 mProgressMax;
|
||||
};
|
||||
|
||||
class CloseRunnable : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
CloseRunnable(FileHelper* aFileHelper)
|
||||
: mFileHelper(aFileHelper)
|
||||
{ }
|
||||
|
||||
private:
|
||||
nsRefPtr<FileHelper> mFileHelper;
|
||||
};
|
||||
|
||||
class DestroyRunnable : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
DestroyRunnable(FileHelper* aFileHelper)
|
||||
: mFileHelper(aFileHelper)
|
||||
{ }
|
||||
|
||||
private:
|
||||
nsRefPtr<FileHelper> mFileHelper;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
FileStreamWrapper::FileStreamWrapper(nsISupports* aFileStream,
|
||||
FileHelper* aFileHelper,
|
||||
PRUint64 aOffset,
|
||||
PRUint64 aLimit,
|
||||
PRUint32 aFlags)
|
||||
: mFileStream(aFileStream),
|
||||
mFileHelper(aFileHelper),
|
||||
mOffset(aOffset),
|
||||
mLimit(aLimit),
|
||||
mFlags(aFlags),
|
||||
mFirstTime(true)
|
||||
{
|
||||
NS_ASSERTION(mFileStream, "Must have a file stream!");
|
||||
NS_ASSERTION(mFileHelper, "Must have a file helper!");
|
||||
}
|
||||
|
||||
FileStreamWrapper::~FileStreamWrapper()
|
||||
{
|
||||
if (mFlags & NOTIFY_DESTROY) {
|
||||
if (NS_IsMainThread()) {
|
||||
mFileHelper->OnStreamDestroy();
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new DestroyRunnable(mFileHelper);
|
||||
|
||||
nsresult rv = NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch to the main thread!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS0(FileStreamWrapper)
|
||||
|
||||
FileInputStreamWrapper::FileInputStreamWrapper(nsISupports* aFileStream,
|
||||
FileHelper* aFileHelper,
|
||||
PRUint64 aOffset,
|
||||
PRUint64 aLimit,
|
||||
PRUint32 aFlags)
|
||||
: FileStreamWrapper(aFileStream, aFileHelper, aOffset, aLimit, aFlags)
|
||||
{
|
||||
mInputStream = do_QueryInterface(mFileStream);
|
||||
NS_ASSERTION(mInputStream, "This should always succeed!");
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(FileInputStreamWrapper,
|
||||
FileStreamWrapper,
|
||||
nsIInputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileInputStreamWrapper::Close()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (mFlags & NOTIFY_CLOSE) {
|
||||
nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
|
||||
NS_WARNING("Failed to dispatch to the main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
mLimit = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileInputStreamWrapper::Available(PRUint32* _retval)
|
||||
{
|
||||
// Performing sync IO on the main thread is generally not allowed.
|
||||
// However, the input stream wrapper is also used to track reads performed by
|
||||
// other APIs like FileReader, XHR, etc.
|
||||
// In that case nsInputStreamChannel::OpenContentStream() calls Available()
|
||||
// before setting the content length property. This property is not important
|
||||
// to perform reads properly, so we can just return NS_BASE_STREAM_CLOSED
|
||||
// here. It causes OpenContentStream() to set the content length property to
|
||||
// zero.
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
return mInputStream->Available(_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileInputStreamWrapper::Read(char* aBuf, PRUint32 aCount, PRUint32* _retval)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mFirstTime) {
|
||||
mFirstTime = false;
|
||||
|
||||
if (mOffset != LL_MAXUINT) {
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
|
||||
if (seekable) {
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
}
|
||||
|
||||
PRUint64 max = mLimit - mOffset;
|
||||
if (max == 0) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aCount > max) {
|
||||
aCount = max;
|
||||
}
|
||||
|
||||
rv = mInputStream->Read(aBuf, aCount, _retval);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mOffset += *_retval;
|
||||
|
||||
if (mFlags & NOTIFY_PROGRESS) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new ProgressRunnable(mFileHelper, mOffset, mLimit);
|
||||
|
||||
rv = NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch to the main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileInputStreamWrapper::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
PRUint32 aCount, PRUint32* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileInputStreamWrapper::IsNonBlocking(bool* _retval)
|
||||
{
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FileOutputStreamWrapper::FileOutputStreamWrapper(nsISupports* aFileStream,
|
||||
FileHelper* aFileHelper,
|
||||
PRUint64 aOffset,
|
||||
PRUint64 aLimit,
|
||||
PRUint32 aFlags)
|
||||
: FileStreamWrapper(aFileStream, aFileHelper, aOffset, aLimit, aFlags)
|
||||
#ifdef DEBUG
|
||||
, mWriteThread(nsnull)
|
||||
#endif
|
||||
{
|
||||
mOutputStream = do_QueryInterface(mFileStream);
|
||||
NS_ASSERTION(mOutputStream, "This should always succeed!");
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(FileOutputStreamWrapper,
|
||||
FileStreamWrapper,
|
||||
nsIOutputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileOutputStreamWrapper::Close()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mFirstTime) {
|
||||
// We must flush buffers of the stream on the same thread on which we wrote
|
||||
// some data.
|
||||
nsCOMPtr<nsIStandardFileStream> sstream = do_QueryInterface(mFileStream);
|
||||
if (sstream) {
|
||||
rv = sstream->FlushBuffers();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to flush buffers of the stream!");
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == mWriteThread,
|
||||
"Unsetting thread locals on wrong thread!");
|
||||
mFileHelper->mFileStorage->UnsetThreadLocals();
|
||||
}
|
||||
|
||||
if (mFlags & NOTIFY_CLOSE) {
|
||||
nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
|
||||
NS_WARNING("Failed to dispatch to the main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
mLimit = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileOutputStreamWrapper::Write(const char* aBuf, PRUint32 aCount,
|
||||
PRUint32* _retval)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mFirstTime) {
|
||||
mFirstTime = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
mWriteThread = PR_GetCurrentThread();
|
||||
#endif
|
||||
mFileHelper->mFileStorage->SetThreadLocals();
|
||||
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mOutputStream);
|
||||
if (seekable) {
|
||||
if (mOffset == LL_MAXUINT) {
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0);
|
||||
}
|
||||
else {
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mOffset = 0;
|
||||
}
|
||||
|
||||
PRUint64 max = mLimit - mOffset;
|
||||
if (max == 0) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aCount > max) {
|
||||
aCount = max;
|
||||
}
|
||||
|
||||
rv = mOutputStream->Write(aBuf, aCount, _retval);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mOffset += *_retval;
|
||||
|
||||
if (mFlags & NOTIFY_PROGRESS) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new ProgressRunnable(mFileHelper, mOffset, mLimit);
|
||||
|
||||
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileOutputStreamWrapper::Flush()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileOutputStreamWrapper::WriteFrom(nsIInputStream* aFromStream,
|
||||
PRUint32 aCount, PRUint32* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileOutputStreamWrapper::WriteSegments(nsReadSegmentFun aReader,
|
||||
void* aClosure, PRUint32 aCount,
|
||||
PRUint32* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileOutputStreamWrapper::IsNonBlocking(bool* _retval)
|
||||
{
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(ProgressRunnable, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ProgressRunnable::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
mFileHelper->OnStreamProgress(mProgress, mProgressMax);
|
||||
mFileHelper = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(CloseRunnable, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CloseRunnable::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
mFileHelper->OnStreamClose();
|
||||
mFileHelper = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(DestroyRunnable, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DestroyRunnable::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
mFileHelper->OnStreamDestroy();
|
||||
mFileHelper = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
94
dom/file/FileStreamWrappers.h
Normal file
94
dom/file/FileStreamWrappers.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_filestreamwrappers_h__
|
||||
#define mozilla_dom_file_filestreamwrappers_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class FileHelper;
|
||||
|
||||
class FileStreamWrapper : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
FileStreamWrapper(nsISupports* aFileStream,
|
||||
FileHelper* aFileHelper,
|
||||
PRUint64 aOffset,
|
||||
PRUint64 aLimit,
|
||||
PRUint32 aFlags);
|
||||
|
||||
virtual ~FileStreamWrapper();
|
||||
|
||||
enum {
|
||||
NOTIFY_PROGRESS = 1 << 0,
|
||||
NOTIFY_CLOSE = 1 << 1,
|
||||
NOTIFY_DESTROY = 1 << 2
|
||||
};
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsISupports> mFileStream;
|
||||
nsRefPtr<FileHelper> mFileHelper;
|
||||
PRUint64 mOffset;
|
||||
PRUint64 mLimit;
|
||||
PRUint32 mFlags;
|
||||
bool mFirstTime;
|
||||
};
|
||||
|
||||
class FileInputStreamWrapper : public FileStreamWrapper,
|
||||
public nsIInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
FileInputStreamWrapper(nsISupports* aFileStream,
|
||||
FileHelper* aFileHelper,
|
||||
PRUint64 aOffset,
|
||||
PRUint64 aLimit,
|
||||
PRUint32 aFlags);
|
||||
|
||||
protected:
|
||||
virtual ~FileInputStreamWrapper()
|
||||
{ }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
class FileOutputStreamWrapper : public FileStreamWrapper,
|
||||
public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
FileOutputStreamWrapper(nsISupports* aFileStream,
|
||||
FileHelper* aFileHelper,
|
||||
PRUint64 aOffset,
|
||||
PRUint64 aLimit,
|
||||
PRUint32 aFlags);
|
||||
|
||||
protected:
|
||||
virtual ~FileOutputStreamWrapper()
|
||||
{ }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
#ifdef DEBUG
|
||||
void* mWriteThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_filestreamwrappers_h__
|
1119
dom/file/LockedFile.cpp
Normal file
1119
dom/file/LockedFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
155
dom/file/LockedFile.h
Normal file
155
dom/file/LockedFile.h
Normal file
@ -0,0 +1,155 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_lockedfile_h__
|
||||
#define mozilla_dom_file_lockedfile_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIDOMLockedFile.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class FileHandle;
|
||||
class FileRequest;
|
||||
class MetadataHelper;
|
||||
|
||||
class LockedFile : public nsDOMEventTargetHelper,
|
||||
public nsIDOMLockedFile,
|
||||
public nsIRunnable
|
||||
{
|
||||
friend class FinishHelper;
|
||||
friend class FileService;
|
||||
friend class FileHelper;
|
||||
friend class MetadataHelper;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMLOCKEDFILE
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(LockedFile, nsDOMEventTargetHelper)
|
||||
|
||||
enum Mode
|
||||
{
|
||||
READ_ONLY = 0,
|
||||
READ_WRITE
|
||||
};
|
||||
|
||||
enum RequestMode
|
||||
{
|
||||
NORMAL = 0, // Sequential
|
||||
PARALLEL
|
||||
};
|
||||
|
||||
enum ReadyState
|
||||
{
|
||||
INITIAL = 0,
|
||||
LOADING,
|
||||
FINISHING,
|
||||
DONE
|
||||
};
|
||||
|
||||
static already_AddRefed<LockedFile>
|
||||
Create(FileHandle* aFileHandle,
|
||||
Mode aMode,
|
||||
RequestMode aRequestMode = NORMAL);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult
|
||||
PreHandleEvent(nsEventChainPreVisitor& aVisitor);
|
||||
|
||||
nsresult
|
||||
CreateParallelStream(nsISupports** aStream);
|
||||
|
||||
nsresult
|
||||
GetOrCreateStream(nsISupports** aStream);
|
||||
|
||||
bool
|
||||
IsOpen() const;
|
||||
|
||||
bool
|
||||
IsAborted() const
|
||||
{
|
||||
return mAborted;
|
||||
}
|
||||
|
||||
FileHandle*
|
||||
Handle() const
|
||||
{
|
||||
return mFileHandle;
|
||||
}
|
||||
|
||||
nsresult
|
||||
OpenInputStream(bool aWholeFile, PRUint64 aStart, PRUint64 aLength,
|
||||
nsIInputStream** aResult);
|
||||
|
||||
private:
|
||||
LockedFile();
|
||||
~LockedFile();
|
||||
|
||||
void
|
||||
OnNewRequest();
|
||||
|
||||
void
|
||||
OnRequestFinished();
|
||||
|
||||
inline already_AddRefed<FileRequest>
|
||||
GenerateFileRequest();
|
||||
|
||||
nsresult
|
||||
WriteOrAppend(const jsval& aValue, JSContext* aCx,
|
||||
nsIDOMFileRequest** _retval, bool aAppend);
|
||||
|
||||
nsresult
|
||||
Finish();
|
||||
|
||||
nsRefPtr<FileHandle> mFileHandle;
|
||||
ReadyState mReadyState;
|
||||
Mode mMode;
|
||||
RequestMode mRequestMode;
|
||||
PRUint64 mLocation;
|
||||
PRUint32 mPendingRequests;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(complete)
|
||||
NS_DECL_EVENT_HANDLER(abort)
|
||||
NS_DECL_EVENT_HANDLER(error)
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports> > mParallelStreams;
|
||||
nsCOMPtr<nsISupports> mStream;
|
||||
|
||||
bool mAborted;
|
||||
bool mCreating;
|
||||
};
|
||||
|
||||
class FinishHelper : public nsIRunnable
|
||||
{
|
||||
friend class LockedFile;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
FinishHelper(LockedFile* aLockedFile);
|
||||
~FinishHelper()
|
||||
{ }
|
||||
|
||||
nsRefPtr<LockedFile> mLockedFile;
|
||||
nsTArray<nsCOMPtr<nsISupports> > mParallelStreams;
|
||||
nsCOMPtr<nsISupports> mStream;
|
||||
|
||||
bool mAborted;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_lockedfile_h__
|
58
dom/file/Makefile.in
Normal file
58
dom/file/Makefile.in
Normal file
@ -0,0 +1,58 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = dom
|
||||
LIBRARY_NAME = domfile_s
|
||||
XPIDL_MODULE = dom_file
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/dom/dom-config.mk
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/dom/file
|
||||
|
||||
CPPSRCS = \
|
||||
AsyncHelper.cpp \
|
||||
DOMFileHandle.cpp \
|
||||
File.cpp \
|
||||
FileHandle.cpp \
|
||||
FileHelper.cpp \
|
||||
FileRequest.cpp \
|
||||
FileService.cpp \
|
||||
FileStreamWrappers.cpp \
|
||||
LockedFile.cpp \
|
||||
MemoryStreams.cpp \
|
||||
MetadataHelper.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
nsIFileStorage.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla/dom/file = \
|
||||
DOMFileHandle.h \
|
||||
File.h \
|
||||
FileCommon.h \
|
||||
FileHandle.h \
|
||||
FileHelper.h \
|
||||
FileService.h \
|
||||
LockedFile.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIDOMFileHandle.idl \
|
||||
nsIDOMFileRequest.idl \
|
||||
nsIDOMLockedFile.idl \
|
||||
$(NULL)
|
||||
|
||||
TEST_DIRS += test
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
90
dom/file/MemoryStreams.cpp
Normal file
90
dom/file/MemoryStreams.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "MemoryStreams.h"
|
||||
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
// static
|
||||
already_AddRefed<MemoryOutputStream>
|
||||
MemoryOutputStream::Create(PRUint64 aSize)
|
||||
{
|
||||
NS_ASSERTION(aSize, "Passed zero size!");
|
||||
|
||||
NS_ENSURE_TRUE(aSize <= PR_UINT32_MAX, nsnull);
|
||||
|
||||
nsRefPtr<MemoryOutputStream> stream = new MemoryOutputStream();
|
||||
|
||||
char* dummy;
|
||||
PRUint32 length = stream->mData.GetMutableData(&dummy, aSize, fallible_t());
|
||||
NS_ENSURE_TRUE(length == aSize, nsnull);
|
||||
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(MemoryOutputStream, nsIOutputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryOutputStream::Close()
|
||||
{
|
||||
mData.Truncate(mOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32* _retval)
|
||||
{
|
||||
return WriteSegments(NS_CopySegmentToBuffer, (char*)aBuf, aCount, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryOutputStream::Flush()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryOutputStream::WriteFrom(nsIInputStream* aFromStream, PRUint32 aCount,
|
||||
PRUint32* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryOutputStream::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
|
||||
PRUint32 aCount, PRUint32* _retval)
|
||||
{
|
||||
NS_ASSERTION(mData.Length() >= mOffset, "Bad stream state!");
|
||||
|
||||
PRUint32 maxCount = mData.Length() - mOffset;
|
||||
if (maxCount == 0) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aCount > maxCount) {
|
||||
aCount = maxCount;
|
||||
}
|
||||
|
||||
nsresult rv = aReader(this, aClosure, mData.BeginWriting() + mOffset, 0,
|
||||
aCount, _retval);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(*_retval <= aCount,
|
||||
"Reader should not read more than we asked it to read!");
|
||||
mOffset += *_retval;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryOutputStream::IsNonBlocking(bool* _retval)
|
||||
{
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
46
dom/file/MemoryStreams.h
Normal file
46
dom/file/MemoryStreams.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_memorystreams_h__
|
||||
#define mozilla_dom_file_memorystreams_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class MemoryOutputStream : public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
static already_AddRefed<MemoryOutputStream>
|
||||
Create(PRUint64 aSize);
|
||||
|
||||
|
||||
const nsCString&
|
||||
Data() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
private:
|
||||
MemoryOutputStream()
|
||||
: mOffset(0)
|
||||
{ }
|
||||
|
||||
virtual ~MemoryOutputStream()
|
||||
{ }
|
||||
|
||||
nsCString mData;
|
||||
PRUint64 mOffset;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_memorystreams_h__
|
106
dom/file/MetadataHelper.cpp
Normal file
106
dom/file/MetadataHelper.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "MetadataHelper.h"
|
||||
|
||||
#include "LockedFile.h"
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
nsresult
|
||||
MetadataHelper::DoAsyncRun(nsISupports* aStream)
|
||||
{
|
||||
bool readWrite = mLockedFile->mMode == LockedFile::READ_WRITE;
|
||||
|
||||
nsRefPtr<AsyncMetadataGetter> getter =
|
||||
new AsyncMetadataGetter(aStream, mParams, readWrite);
|
||||
|
||||
nsresult rv = getter->AsyncWork(this, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MetadataHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(aCx, nsnull, nsnull, nsnull);
|
||||
NS_ENSURE_TRUE(obj, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (mParams->SizeRequested()) {
|
||||
jsval val;
|
||||
|
||||
if (mParams->Size() <= JSVAL_INT_MAX) {
|
||||
val = INT_TO_JSVAL(mParams->Size());
|
||||
}
|
||||
else {
|
||||
double size = mParams->Size();
|
||||
if (!JS_NewNumberValue(aCx, size, &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JS_DefineProperty(aCx, obj, "size", val, nsnull, nsnull,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (mParams->LastModifiedRequested()) {
|
||||
double msec = mParams->LastModified();
|
||||
JSObject *date = JS_NewDateObjectMsec(aCx, msec);
|
||||
NS_ENSURE_TRUE(date, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (!JS_DefineProperty(aCx, obj, "lastModified", OBJECT_TO_JSVAL(date),
|
||||
nsnull, nsnull, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
*aVal = OBJECT_TO_JSVAL(obj);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MetadataHelper::AsyncMetadataGetter::DoStreamWork(nsISupports* aStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (mReadWrite) {
|
||||
// Force a flush (so all pending writes are flushed to the disk and file
|
||||
// metadata is updated too).
|
||||
|
||||
nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(aStream);
|
||||
NS_ASSERTION(ostream, "This should always succeed!");
|
||||
|
||||
rv = ostream->Flush();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileMetadata> metadata = do_QueryInterface(aStream);
|
||||
|
||||
if (mParams->SizeRequested()) {
|
||||
PRInt64 size;
|
||||
rv = metadata->GetSize(&size);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_TRUE(size >= 0, NS_ERROR_FAILURE);
|
||||
|
||||
mParams->mSize = PRUint64(size);
|
||||
}
|
||||
|
||||
if (mParams->LastModifiedRequested()) {
|
||||
PRInt64 lastModified;
|
||||
rv = metadata->GetLastModified(&lastModified);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mParams->mLastModified = lastModified;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
122
dom/file/MetadataHelper.h
Normal file
122
dom/file/MetadataHelper.h
Normal file
@ -0,0 +1,122 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_file_metadatahelper_h__
|
||||
#define mozilla_dom_file_metadatahelper_h__
|
||||
|
||||
#include "FileCommon.h"
|
||||
|
||||
#include "nsIFileStreams.h"
|
||||
|
||||
#include "DictionaryHelpers.h"
|
||||
|
||||
#include "AsyncHelper.h"
|
||||
#include "FileHelper.h"
|
||||
|
||||
class nsIFileStream;
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class MetadataHelper;
|
||||
|
||||
class MetadataParameters
|
||||
{
|
||||
friend class MetadataHelper;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MetadataParameters)
|
||||
|
||||
nsresult
|
||||
Init(JSContext* aCx, const jsval* aVal)
|
||||
{
|
||||
return mConfig.Init(aCx, aVal);
|
||||
}
|
||||
|
||||
void
|
||||
Init(bool aRequestSize, bool aRequestLastModified)
|
||||
{
|
||||
mConfig.size = aRequestSize;
|
||||
mConfig.lastModified = aRequestLastModified;
|
||||
}
|
||||
|
||||
bool
|
||||
IsConfigured() const
|
||||
{
|
||||
return mConfig.size || mConfig.lastModified;
|
||||
}
|
||||
|
||||
bool
|
||||
SizeRequested() const
|
||||
{
|
||||
return mConfig.size;
|
||||
}
|
||||
|
||||
bool
|
||||
LastModifiedRequested() const
|
||||
{
|
||||
return mConfig.lastModified;
|
||||
}
|
||||
|
||||
PRUint64
|
||||
Size() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
PRInt64
|
||||
LastModified() const
|
||||
{
|
||||
return mLastModified;
|
||||
}
|
||||
|
||||
private:
|
||||
DOMFileMetadataParameters mConfig;
|
||||
|
||||
PRUint64 mSize;
|
||||
PRInt64 mLastModified;
|
||||
};
|
||||
|
||||
class MetadataHelper : public FileHelper
|
||||
{
|
||||
public:
|
||||
MetadataHelper(LockedFile* aLockedFile,
|
||||
FileRequest* aFileRequest,
|
||||
MetadataParameters* aParams)
|
||||
: FileHelper(aLockedFile, aFileRequest),
|
||||
mParams(aParams)
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
DoAsyncRun(nsISupports* aStream);
|
||||
|
||||
nsresult
|
||||
GetSuccessResult(JSContext* aCx, jsval* aVal);
|
||||
|
||||
protected:
|
||||
class AsyncMetadataGetter : public AsyncHelper
|
||||
{
|
||||
public:
|
||||
AsyncMetadataGetter(nsISupports* aStream, MetadataParameters* aParams,
|
||||
bool aReadWrite)
|
||||
: AsyncHelper(aStream),
|
||||
mParams(aParams), mReadWrite(aReadWrite)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
nsresult
|
||||
DoStreamWork(nsISupports* aStream);
|
||||
|
||||
private:
|
||||
nsRefPtr<MetadataParameters> mParams;
|
||||
bool mReadWrite;
|
||||
};
|
||||
|
||||
nsRefPtr<MetadataParameters> mParams;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_file_metadatahelper_h__
|
51
dom/file/nsIDOMFileHandle.idl
Normal file
51
dom/file/nsIDOMFileHandle.idl
Normal file
@ -0,0 +1,51 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
class FileInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native FileInfo(mozilla::dom::indexedDB::FileInfo);
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMFileRequest;
|
||||
interface nsIDOMLockedFile;
|
||||
|
||||
[scriptable, builtinclass, uuid(0dc9c73c-4e44-4430-8898-85f61a70b1d2)]
|
||||
interface nsIDOMFileHandle : nsISupports
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
|
||||
readonly attribute DOMString type;
|
||||
|
||||
// mode can be either "readonly" or "readwrite"
|
||||
[optional_argc]
|
||||
nsIDOMLockedFile
|
||||
open([optional /* "readonly" */] in DOMString mode);
|
||||
|
||||
nsIDOMFileRequest
|
||||
getFile();
|
||||
|
||||
[notxpcom]
|
||||
long long
|
||||
getFileId();
|
||||
|
||||
[notxpcom]
|
||||
FileInfo
|
||||
getFileInfo();
|
||||
|
||||
attribute nsIDOMEventListener onabort;
|
||||
|
||||
attribute nsIDOMEventListener onerror;
|
||||
};
|
18
dom/file/nsIDOMFileRequest.idl
Normal file
18
dom/file/nsIDOMFileRequest.idl
Normal file
@ -0,0 +1,18 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsIDOMDOMRequest.idl"
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMLockedFile;
|
||||
|
||||
[scriptable, builtinclass, uuid(fe06b66e-fede-4d44-ab3a-403f60d6b593)]
|
||||
interface nsIDOMFileRequest : nsIDOMDOMRequest
|
||||
{
|
||||
readonly attribute nsIDOMLockedFile lockedFile;
|
||||
|
||||
attribute nsIDOMEventListener onprogress;
|
||||
};
|
66
dom/file/nsIDOMLockedFile.idl
Normal file
66
dom/file/nsIDOMLockedFile.idl
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMFileHandle;
|
||||
interface nsIDOMFileRequest;
|
||||
|
||||
dictionary DOMFileMetadataParameters
|
||||
{
|
||||
boolean size;
|
||||
boolean lastModified;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(63055eeb-cc19-468b-bafa-7b7961796340)]
|
||||
interface nsIDOMLockedFile : nsISupports
|
||||
{
|
||||
readonly attribute nsIDOMFileHandle fileHandle;
|
||||
|
||||
// "readonly" or "readwrite"
|
||||
readonly attribute DOMString mode;
|
||||
|
||||
readonly attribute boolean active;
|
||||
|
||||
attribute unsigned long long location;
|
||||
|
||||
[implicit_jscontext]
|
||||
nsIDOMFileRequest
|
||||
getMetadata(/* DOMFileMetadataParameters */
|
||||
[optional /* all */] in jsval parameters);
|
||||
|
||||
[implicit_jscontext]
|
||||
nsIDOMFileRequest
|
||||
readAsArrayBuffer(in unsigned long long size);
|
||||
|
||||
nsIDOMFileRequest
|
||||
readAsText(in unsigned long long size,
|
||||
[optional] in DOMString encoding);
|
||||
|
||||
[implicit_jscontext]
|
||||
nsIDOMFileRequest
|
||||
write(in jsval value);
|
||||
|
||||
[implicit_jscontext]
|
||||
nsIDOMFileRequest
|
||||
append(in jsval value);
|
||||
|
||||
nsIDOMFileRequest
|
||||
truncate();
|
||||
|
||||
nsIDOMFileRequest
|
||||
flush();
|
||||
|
||||
void
|
||||
abort();
|
||||
|
||||
attribute nsIDOMEventListener oncomplete;
|
||||
|
||||
attribute nsIDOMEventListener onabort;
|
||||
|
||||
attribute nsIDOMEventListener onerror;
|
||||
};
|
55
dom/file/nsIFileStorage.h
Normal file
55
dom/file/nsIFileStorage.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsIFileStorage_h__
|
||||
#define nsIFileStorage_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
#define NS_FILESTORAGE_IID \
|
||||
{0xbba9c2ff, 0x85c9, 0x47c1, \
|
||||
{ 0xaf, 0xce, 0x0a, 0x7e, 0x6f, 0x21, 0x50, 0x95 } }
|
||||
|
||||
class nsIFileStorage : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_FILESTORAGE_IID)
|
||||
|
||||
virtual nsISupports*
|
||||
StorageId() = 0;
|
||||
|
||||
virtual bool
|
||||
IsStorageInvalidated() = 0;
|
||||
|
||||
virtual bool
|
||||
IsStorageShuttingDown() = 0;
|
||||
|
||||
virtual void
|
||||
SetThreadLocals() = 0;
|
||||
|
||||
virtual void
|
||||
UnsetThreadLocals() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileStorage, NS_FILESTORAGE_IID)
|
||||
|
||||
#define NS_DECL_NSIFILESTORAGE \
|
||||
virtual nsISupports* \
|
||||
StorageId(); \
|
||||
\
|
||||
virtual bool \
|
||||
IsStorageInvalidated(); \
|
||||
\
|
||||
virtual bool \
|
||||
IsStorageShuttingDown(); \
|
||||
\
|
||||
virtual void \
|
||||
SetThreadLocals(); \
|
||||
\
|
||||
virtual void \
|
||||
UnsetThreadLocals();
|
||||
|
||||
#endif // nsIFileStorage_h__
|
33
dom/file/test/Makefile.in
Normal file
33
dom/file/test/Makefile.in
Normal file
@ -0,0 +1,33 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = dom/file/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
TEST_FILES = \
|
||||
helpers.js \
|
||||
test_append_read_data.html \
|
||||
test_getFileId.html \
|
||||
test_lockedfile_lifetimes.html \
|
||||
test_lockedfile_lifetimes_nested.html \
|
||||
test_lockedfile_ordering.html \
|
||||
test_overlapping_lockedfiles.html \
|
||||
test_progress_events.html \
|
||||
test_readonly_lockedfiles.html \
|
||||
test_request_readyState.html \
|
||||
test_stream_tracking.html \
|
||||
test_success_events_after_abort.html \
|
||||
test_truncate.html \
|
||||
test_write_read_data.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
|
220
dom/file/test/helpers.js
Normal file
220
dom/file/test/helpers.js
Normal file
@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const IndexedDatabaseKey = "IDB";
|
||||
const DeviceStorageKey = "DS";
|
||||
|
||||
var fileStorages = [
|
||||
{ key: IndexedDatabaseKey }
|
||||
// { key: DeviceStorageKey }
|
||||
];
|
||||
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function runTest()
|
||||
{
|
||||
allowIndexedDB();
|
||||
allowUnlimitedQuota();
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
testGenerator.next();
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
resetUnlimitedQuota();
|
||||
resetIndexedDB();
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
testGenerator.close();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
function grabEventAndContinueHandler(event)
|
||||
{
|
||||
testGenerator.send(event);
|
||||
}
|
||||
|
||||
function continueToNextStep()
|
||||
{
|
||||
SimpleTest.executeSoon(function() {
|
||||
testGenerator.next();
|
||||
});
|
||||
}
|
||||
|
||||
function errorHandler(event)
|
||||
{
|
||||
ok(false, "indexedDB error, code " + event.target.errorCode);
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function unexpectedSuccessHandler()
|
||||
{
|
||||
ok(false, "Got success, but did not expect it!");
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function ExpectError(name)
|
||||
{
|
||||
this._name = name;
|
||||
}
|
||||
ExpectError.prototype = {
|
||||
handleEvent: function(event)
|
||||
{
|
||||
is(event.type, "error", "Got an error event");
|
||||
is(event.target.error.name, this._name, "Expected error was thrown.");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
grabEventAndContinueHandler(event);
|
||||
}
|
||||
};
|
||||
|
||||
function addPermission(type, allow, url)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
let uri;
|
||||
if (url) {
|
||||
uri = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService)
|
||||
.newURI(url, null, null);
|
||||
}
|
||||
else {
|
||||
uri = SpecialPowers.getDocumentURIObject(window.document);
|
||||
}
|
||||
|
||||
let permission;
|
||||
if (allow) {
|
||||
permission = Components.interfaces.nsIPermissionManager.ALLOW_ACTION;
|
||||
}
|
||||
else {
|
||||
permission = Components.interfaces.nsIPermissionManager.DENY_ACTION;
|
||||
}
|
||||
|
||||
Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager)
|
||||
.add(uri, type, permission);
|
||||
}
|
||||
|
||||
function removePermission(permission, url)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
let uri;
|
||||
if (url) {
|
||||
uri = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService)
|
||||
.newURI(url, null, null);
|
||||
}
|
||||
else {
|
||||
uri = SpecialPowers.getDocumentURIObject(window.document);
|
||||
}
|
||||
|
||||
Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager)
|
||||
.remove(uri.host, permission);
|
||||
}
|
||||
|
||||
function allowIndexedDB(url)
|
||||
{
|
||||
addPermission("indexedDB", true, url);
|
||||
}
|
||||
|
||||
function resetIndexedDB(url)
|
||||
{
|
||||
removePermission("indexedDB", url);
|
||||
}
|
||||
|
||||
function allowUnlimitedQuota(url)
|
||||
{
|
||||
addPermission("indexedDB-unlimited", true, url);
|
||||
}
|
||||
|
||||
function resetUnlimitedQuota(url)
|
||||
{
|
||||
removePermission("indexedDB-unlimited", url);
|
||||
}
|
||||
|
||||
function getFileHandle(fileStorageKey, name)
|
||||
{
|
||||
var requestService = SpecialPowers.getDOMRequestService();
|
||||
var request = requestService.createRequest(window);
|
||||
|
||||
switch (fileStorageKey) {
|
||||
case IndexedDatabaseKey:
|
||||
var dbname = window.location.pathname;
|
||||
mozIndexedDB.open(dbname, 1).onsuccess = function(event) {
|
||||
var db = event.target.result;
|
||||
db.mozCreateFileHandle(name).onsuccess = function(event) {
|
||||
var fileHandle = event.target.result;
|
||||
requestService.fireSuccess(request, fileHandle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DeviceStorageKey:
|
||||
var dbname = window.location.pathname;
|
||||
mozIndexedDB.open(dbname, 1).onsuccess = function(event) {
|
||||
var db = event.target.result;
|
||||
db.mozCreateFileHandle(name).onsuccess = function(event) {
|
||||
var fileHandle = event.target.result;
|
||||
requestService.fireSuccess(request, fileHandle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
function getBuffer(size)
|
||||
{
|
||||
let buffer = new ArrayBuffer(size);
|
||||
is(buffer.byteLength, size, "Correct byte length");
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function getRandomBuffer(size)
|
||||
{
|
||||
let buffer = getBuffer(size);
|
||||
let view = new Uint8Array(buffer);
|
||||
for (let i = 0; i < size; i++) {
|
||||
view[i] = parseInt(Math.random() * 255)
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function compareBuffers(buffer1, buffer2)
|
||||
{
|
||||
if (buffer1.byteLength != buffer2.byteLength) {
|
||||
return false;
|
||||
}
|
||||
let view1 = new Uint8Array(buffer1);
|
||||
let view2 = new Uint8Array(buffer2);
|
||||
for (let i = 0; i < buffer1.byteLength; i++) {
|
||||
if (view1[i] != view2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getBlob(type, buffer)
|
||||
{
|
||||
return utils.getBlob([buffer], {type: type});
|
||||
}
|
||||
|
||||
function getRandomBlob(size)
|
||||
{
|
||||
return getBlob("binary/random", getRandomBuffer(size));
|
||||
}
|
||||
|
||||
function getFileId(blob)
|
||||
{
|
||||
return utils.getFileId(blob);
|
||||
}
|
103
dom/file/test/test_append_read_data.html
Normal file
103
dom/file/test/test_append_read_data.html
Normal file
@ -0,0 +1,103 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const maxLocation = 18446744073709552000;
|
||||
|
||||
var testString = "Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix. Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.";
|
||||
for (let i = 0; i < 5; i++) {
|
||||
testString += testString;
|
||||
}
|
||||
|
||||
var testBuffer = getRandomBuffer(100000);
|
||||
|
||||
var testBlob = getBlob("binary/random", testBuffer);
|
||||
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let location = 0;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
|
||||
request = lockedFile.append(testString);
|
||||
is(lockedFile.location, maxLocation, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.location = 0;
|
||||
request = lockedFile.readAsText(testString.length);
|
||||
location += testString.length
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let resultString = event.target.result;
|
||||
ok(resultString == testString, "Correct string data");
|
||||
|
||||
request = lockedFile.append(testBuffer);
|
||||
is(lockedFile.location, maxLocation, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.location = location;
|
||||
request = lockedFile.readAsArrayBuffer(testBuffer.byteLength);
|
||||
location += testBuffer.byteLength;
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let resultBuffer = event.target.result;
|
||||
ok(compareBuffers(resultBuffer, testBuffer), "Correct array buffer data");
|
||||
|
||||
request = lockedFile.append(testBlob);
|
||||
is(lockedFile.location, maxLocation, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.location = location;
|
||||
request = lockedFile.readAsArrayBuffer(testBlob.size);
|
||||
location += testBlob.size;
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
resultBuffer = event.target.result;
|
||||
ok(compareBuffers(resultBuffer, testBuffer), "Correct blob data");
|
||||
|
||||
request = lockedFile.getMetadata({ size: true });
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let result = event.target.result;
|
||||
is(result.size, location, "Correct size");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
31
dom/file/test/test_getFileId.html
Normal file
31
dom/file/test/test_getFileId.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
let id = getFileId(null);
|
||||
ok(id == -1, "Correct id");
|
||||
|
||||
id = getFileId(getRandomBlob(100));
|
||||
ok(id == -1, "Correct id");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
49
dom/file/test/test_lockedfile_lifetimes.html
Normal file
49
dom/file/test/test_lockedfile_lifetimes.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open();
|
||||
continueToNextStep();
|
||||
yield;
|
||||
|
||||
try {
|
||||
lockedFile.getMetadata({ size: true });
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof DOMException, "Got exception.");
|
||||
is(e.name, "LockedFileInactiveError", "Good error.");
|
||||
is(e.code, 0, "Good error code.");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
61
dom/file/test/test_lockedfile_lifetimes_nested.html
Normal file
61
dom/file/test/test_lockedfile_lifetimes_nested.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open();
|
||||
|
||||
let lockedFile2;
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
let thread = Components.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService()
|
||||
.currentThread;
|
||||
|
||||
let eventHasRun;
|
||||
|
||||
thread.dispatch(function() {
|
||||
eventHasRun = true;
|
||||
|
||||
lockedFile2 = fileHandle.open();
|
||||
}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
|
||||
|
||||
while (!eventHasRun) {
|
||||
thread.processNextEvent(false);
|
||||
}
|
||||
|
||||
ok(lockedFile2, "Non-null lockedFile2");
|
||||
|
||||
continueToNextStep();
|
||||
yield;
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
54
dom/file/test/test_lockedfile_ordering.html
Normal file
54
dom/file/test/test_lockedfile_ordering.html
Normal file
@ -0,0 +1,54 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile1 = fileHandle.open("readwrite");
|
||||
let lockedFile2 = fileHandle.open("readwrite");
|
||||
|
||||
let request1 = lockedFile2.write("2");
|
||||
let request2 = lockedFile1.write("1");
|
||||
|
||||
lockedFile1.oncomplete = grabEventAndContinueHandler;
|
||||
lockedFile2.oncomplete = grabEventAndContinueHandler;
|
||||
|
||||
yield;
|
||||
yield;
|
||||
|
||||
let lockedFile3 = fileHandle.open("readonly");
|
||||
let request3 = lockedFile3.readAsText(1);
|
||||
request3.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
event = yield;
|
||||
is(event.target.result, "2", "Locked files were ordered properly.");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
65
dom/file/test/test_overlapping_lockedfiles.html
Normal file
65
dom/file/test/test_overlapping_lockedfiles.html
Normal file
@ -0,0 +1,65 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let stepNumber = 0;
|
||||
|
||||
request = fileHandle.open("readwrite").append("string1");
|
||||
request.onsuccess = function(event) {
|
||||
is(stepNumber, 1, "This callback came first");
|
||||
stepNumber++;
|
||||
event.target.lockedFile.oncomplete = grabEventAndContinueHandler;
|
||||
}
|
||||
|
||||
request = fileHandle.open("readwrite").append("string2");
|
||||
request.onsuccess = function(event) {
|
||||
is(stepNumber, 2, "This callback came second");
|
||||
stepNumber++;
|
||||
event.target.lockedFile.oncomplete = grabEventAndContinueHandler;
|
||||
}
|
||||
|
||||
request = fileHandle.open("readwrite").append("string3");
|
||||
request.onsuccess = function(event) {
|
||||
is(stepNumber, 3, "This callback came third");
|
||||
stepNumber++;
|
||||
event.target.lockedFile.oncomplete = grabEventAndContinueHandler;
|
||||
}
|
||||
|
||||
stepNumber++;
|
||||
yield; yield; yield;;
|
||||
|
||||
is(stepNumber, 4, "All callbacks received");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
70
dom/file/test/test_progress_events.html
Normal file
70
dom/file/test/test_progress_events.html
Normal file
@ -0,0 +1,70 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
var testBuffer = getRandomBuffer(100000);
|
||||
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
|
||||
let sum = 0;
|
||||
|
||||
request = lockedFile.write(testBuffer);
|
||||
request.onprogress = function(event) {
|
||||
let loaded = event.loaded;
|
||||
let total = event.total;
|
||||
ok(loaded >= 0 && loaded <= total, "Correct loaded progress");
|
||||
is(total, testBuffer.byteLength, "Correct total progress");
|
||||
sum += event.loaded - sum;
|
||||
}
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(sum, testBuffer.byteLength, "Correct loaded progress sum");
|
||||
|
||||
sum = 0;
|
||||
|
||||
lockedFile.location = 0;
|
||||
request = lockedFile.readAsArrayBuffer(testBuffer.byteLength);
|
||||
request.onprogress = function(event) {
|
||||
let loaded = event.loaded;
|
||||
let total = event.total;
|
||||
ok(loaded >= 0 && loaded <= total, "Correct loaded progress");
|
||||
is(total, testBuffer.byteLength, "Correct total progress");
|
||||
sum += event.loaded - sum;
|
||||
}
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(sum, testBuffer.byteLength, "Correct loaded progress sum");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
73
dom/file/test/test_readonly_lockedfiles.html
Normal file
73
dom/file/test/test_readonly_lockedfiles.html
Normal file
@ -0,0 +1,73 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
request = fileHandle.open("readwrite").write({});
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(event.target.lockedFile.mode, "readwrite", "Correct mode");
|
||||
|
||||
try {
|
||||
fileHandle.open().write({});
|
||||
ok(false, "Writing to a readonly locked file should fail!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Writing to a readonly locked file failed");
|
||||
}
|
||||
|
||||
try {
|
||||
fileHandle.open().append({});
|
||||
ok(false, "Appending to a readonly locked file should fail!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Appending to a readonly locked file failed");
|
||||
}
|
||||
|
||||
try {
|
||||
fileHandle.open().truncate({});
|
||||
ok(false, "Truncating a readonly locked file should fail!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Truncating a readonly locked file failed");
|
||||
}
|
||||
|
||||
try {
|
||||
fileHandle.open().flush({});
|
||||
ok(false, "Flushing a readonly locked file should fail!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Flushing a readonly locked file failed");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
57
dom/file/test/test_request_readyState.html
Normal file
57
dom/file/test/test_request_readyState.html
Normal file
@ -0,0 +1,57 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
is(request.readyState, "pending", "Correct readyState");
|
||||
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
is(request.readyState, "done", "Correct readyState");
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
request = lockedFile.write("string");
|
||||
is(request.readyState, "pending", "Correct readyState");
|
||||
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(request.readyState, "done", "Correct readyState");
|
||||
|
||||
lockedFile.location = 0;
|
||||
request = lockedFile.readAsText(6);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
is(request.readyState, "pending", "Correct readyState");
|
||||
event = yield;
|
||||
|
||||
ok(event.target.result, "Got something");
|
||||
is(request.readyState, "done", "Correct readyState");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
86
dom/file/test/test_stream_tracking.html
Normal file
86
dom/file/test/test_stream_tracking.html
Normal file
@ -0,0 +1,86 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
var testBuffer = getRandomBuffer(100000);
|
||||
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
|
||||
request = lockedFile.write(testBuffer);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
request = fileHandle.getFile();
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let file = event.target.result;
|
||||
|
||||
let resultBuffer1;
|
||||
let resultBuffer2;
|
||||
|
||||
let reader1 = new FileReader();
|
||||
reader1.readAsArrayBuffer(file);
|
||||
reader1.onerror = errorHandler;
|
||||
reader1.onload = function(event)
|
||||
{
|
||||
resultBuffer1 = event.target.result;
|
||||
|
||||
let reader = new FileReader();
|
||||
try {
|
||||
reader.readAsArrayBuffer(file);
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof DOMException, "Got exception.");
|
||||
is(e.name, "LockedFileInactiveError", "Good error.");
|
||||
is(e.code, 0, "Good error code.");
|
||||
}
|
||||
}
|
||||
|
||||
let reader2 = new FileReader();
|
||||
reader2.readAsArrayBuffer(file);
|
||||
reader2.onerror = errorHandler;
|
||||
reader2.onload = function(event)
|
||||
{
|
||||
resultBuffer2 = event.target.result;
|
||||
}
|
||||
|
||||
lockedFile = event.target.lockedFile;
|
||||
lockedFile.oncomplete = grabEventAndContinueHandler;
|
||||
yield;
|
||||
|
||||
ok(compareBuffers(resultBuffer1, testBuffer), "Correct data");
|
||||
ok(compareBuffers(resultBuffer2, testBuffer), "Correct data");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
66
dom/file/test/test_success_events_after_abort.html
Normal file
66
dom/file/test/test_success_events_after_abort.html
Normal file
@ -0,0 +1,66 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open();
|
||||
|
||||
lockedFile.oncomplete = unexpectedSuccessHandler;
|
||||
lockedFile.onabort = grabEventAndContinueHandler;
|
||||
|
||||
let sawError = false;
|
||||
|
||||
request = lockedFile.getMetadata({ size: true });
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
request.onerror = function(event) {
|
||||
is(event.target.error.name, "AbortError", "Good error");
|
||||
sawError = true;
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
lockedFile.abort();
|
||||
|
||||
event = yield;
|
||||
|
||||
is(event.type, "abort", "Got abort event");
|
||||
is(sawError, true, "Saw getMetadata() error");
|
||||
|
||||
// Make sure the success event isn't queued somehow.
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var thread = Components.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService(Components.interfaces.nsIThreadManager)
|
||||
.currentThread;
|
||||
while (thread.hasPendingEvents()) {
|
||||
thread.processNextEvent(false);
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
61
dom/file/test/test_truncate.html
Normal file
61
dom/file/test/test_truncate.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
var testBuffer = getRandomBuffer(100000);
|
||||
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.bin");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
request = lockedFile.write(testBuffer);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(lockedFile.location, 100000, "Correct location");
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
let location = lockedFile.location - 10000
|
||||
lockedFile.location = location;
|
||||
|
||||
request = lockedFile.truncate();
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
|
||||
request = lockedFile.getMetadata({ size: true });
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(event.target.result.size, location, "Correct size");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
101
dom/file/test/test_write_read_data.html
Normal file
101
dom/file/test/test_write_read_data.html
Normal file
@ -0,0 +1,101 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>File Handle Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
var testString = "Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix. Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.";
|
||||
for (let i = 0; i < 5; i++) {
|
||||
testString += testString;
|
||||
}
|
||||
|
||||
var testBuffer = getRandomBuffer(100000);
|
||||
|
||||
var testBlob = getBlob("binary/random", testBuffer);
|
||||
|
||||
for each (let fileStorage in fileStorages) {
|
||||
let request = getFileHandle(fileStorage.key, "test.txt");
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let location = 0;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
|
||||
request = lockedFile.write(testString);
|
||||
location += testString.length;
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.location = 0;
|
||||
request = lockedFile.readAsText(testString.length);
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let resultString = event.target.result;
|
||||
ok(resultString == testString, "Correct string data");
|
||||
|
||||
request = lockedFile.write(testBuffer);
|
||||
location += testBuffer.byteLength;
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.location -= testBuffer.byteLength;
|
||||
request = lockedFile.readAsArrayBuffer(testBuffer.byteLength);
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let resultBuffer = event.target.result;
|
||||
ok(compareBuffers(resultBuffer, testBuffer), "Correct array buffer data");
|
||||
|
||||
request = lockedFile.write(testBlob);
|
||||
location += testBlob.size;
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.location -= testBlob.size;
|
||||
request = lockedFile.readAsArrayBuffer(testBlob.size);
|
||||
is(lockedFile.location, location, "Correct location");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
resultBuffer = event.target.result;
|
||||
ok(compareBuffers(resultBuffer, testBuffer), "Correct blob data");
|
||||
|
||||
request = lockedFile.getMetadata({ size: true });
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let result = event.target.result;
|
||||
is(result.size, location, "Correct size");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
321
dom/indexedDB/FileStream.cpp
Normal file
321
dom/indexedDB/FileStream.cpp
Normal file
@ -0,0 +1,321 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "FileStream.h"
|
||||
|
||||
#include "nsIFile.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "test_quota.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(FileStream)
|
||||
NS_IMPL_THREADSAFE_RELEASE(FileStream)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(FileStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardFileStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStandardFileStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFileMetadata)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
||||
{
|
||||
// TODO: Add support for 64 bit file sizes, bug 752431
|
||||
NS_ENSURE_TRUE(aOffset <= PR_INT32_MAX, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
int whence;
|
||||
switch (aWhence) {
|
||||
case nsISeekableStream::NS_SEEK_SET:
|
||||
whence = SEEK_SET;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_CUR:
|
||||
whence = SEEK_CUR;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_END:
|
||||
whence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fseek(mQuotaFile, aOffset, whence);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Tell(PRInt64* aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
long rc = sqlite3_quota_ftell(mQuotaFile);
|
||||
NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
*aResult = rc;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::SetEOF()
|
||||
{
|
||||
PRInt64 pos;
|
||||
nsresult rv = Tell(&pos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_ftruncate(mQuotaFile, pos);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Close()
|
||||
{
|
||||
CleanUpOpen();
|
||||
|
||||
if (mQuotaFile) {
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fclose(mQuotaFile);
|
||||
mQuotaFile = nsnull;
|
||||
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Available(PRUint32* aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
long rc = sqlite3_quota_file_available(mQuotaFile);
|
||||
NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
*aResult = rc;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
size_t bytesRead = sqlite3_quota_fread(aBuf, 1, aCount, mQuotaFile);
|
||||
if (bytesRead < aCount && sqlite3_quota_ferror(mQuotaFile)) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
*aResult = bytesRead;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
PRUint32 aCount, PRUint32* aResult)
|
||||
{
|
||||
NS_NOTREACHED("Don't call me!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
size_t bytesWritten = sqlite3_quota_fwrite(aBuf, 1, aCount, mQuotaFile);
|
||||
if (bytesWritten < aCount) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
*aResult = bytesWritten;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Flush()
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fflush(mQuotaFile, 1);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
|
||||
{
|
||||
NS_NOTREACHED("Don't call me!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Init(nsIFile* aFile, const nsAString& aMode, PRInt32 aFlags)
|
||||
{
|
||||
NS_ASSERTION(!mQuotaFile && !mDeferredOpen, "Already initialized!");
|
||||
|
||||
nsresult rv = aFile->GetPath(mFilePath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mMode = aMode;
|
||||
mFlags = aFlags;
|
||||
|
||||
if (mFlags & nsIStandardFileStream::FLAGS_DEFER_OPEN) {
|
||||
mDeferredOpen = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoOpen();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::GetSize(PRInt64* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
// TODO: Use sqlite3_quota_file_size() here, bug 760783
|
||||
PRInt64 rc = sqlite3_quota_file_truesize(mQuotaFile);
|
||||
|
||||
NS_ASSERTION(rc >= 0, "The file is not under quota management!");
|
||||
|
||||
*_retval = rc;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::GetLastModified(PRInt64* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
time_t mtime;
|
||||
int rc = sqlite3_quota_file_mtime(mQuotaFile, &mtime);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
*_retval = mtime * PR_MSEC_PER_SEC;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::FlushBuffers()
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fflush(mQuotaFile, 0);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileStream::DoOpen()
|
||||
{
|
||||
NS_ASSERTION(!mFilePath.IsEmpty(), "Must have a file path");
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
quota_FILE* quotaFile =
|
||||
sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(mFilePath).get(),
|
||||
NS_ConvertUTF16toUTF8(mMode).get());
|
||||
|
||||
CleanUpOpen();
|
||||
|
||||
if (!quotaFile) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
mQuotaFile = quotaFile;
|
||||
|
||||
return NS_OK;
|
||||
}
|
140
dom/indexedDB/FileStream.h
Normal file
140
dom/indexedDB/FileStream.h
Normal file
@ -0,0 +1,140 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_indexeddb_filestream_h__
|
||||
#define mozilla_dom_indexeddb_filestream_h__
|
||||
|
||||
#include "IndexedDatabase.h"
|
||||
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIStandardFileStream.h"
|
||||
|
||||
class nsIFile;
|
||||
struct quota_FILE;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class FileStream : public nsISeekableStream,
|
||||
public nsIInputStream,
|
||||
public nsIOutputStream,
|
||||
public nsIStandardFileStream,
|
||||
public nsIFileMetadata
|
||||
{
|
||||
public:
|
||||
FileStream()
|
||||
: mFlags(0),
|
||||
mDeferredOpen(false),
|
||||
mQuotaFile(nsnull)
|
||||
{ }
|
||||
|
||||
virtual ~FileStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSISTANDARDFILESTREAM
|
||||
NS_DECL_NSIFILEMETADATA
|
||||
|
||||
// nsIInputStream
|
||||
NS_IMETHOD
|
||||
Close();
|
||||
|
||||
NS_IMETHOD
|
||||
Available(PRUint32* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuf, PRUint32 aCount, PRUint32* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, PRUint32 aCount,
|
||||
PRUint32* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* _retval);
|
||||
|
||||
// nsIOutputStream
|
||||
|
||||
// Close() already declared
|
||||
|
||||
NS_IMETHOD
|
||||
Flush();
|
||||
|
||||
NS_IMETHOD
|
||||
Write(const char* aBuf, PRUint32 aCount, PRUint32* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
WriteFrom(nsIInputStream* aFromStream, PRUint32 aCount, PRUint32* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
WriteSegments(nsReadSegmentFun aReader, void* aClosure, PRUint32 aCount,
|
||||
PRUint32* _retval);
|
||||
|
||||
// IsNonBlocking() already declared
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Cleans up data prepared in Init.
|
||||
*/
|
||||
void
|
||||
CleanUpOpen()
|
||||
{
|
||||
mFilePath.Truncate();
|
||||
mDeferredOpen = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the file. This is called either from Init
|
||||
* or from DoPendingOpen (if FLAGS_DEFER_OPEN is used when initializing this
|
||||
* stream). The default behavior of DoOpen is to open the file and save the
|
||||
* file descriptor.
|
||||
*/
|
||||
virtual nsresult
|
||||
DoOpen();
|
||||
|
||||
/**
|
||||
* If there is a pending open, do it now. It's important for this to be
|
||||
* inlined since we do it in almost every stream API call.
|
||||
*/
|
||||
nsresult
|
||||
DoPendingOpen()
|
||||
{
|
||||
if (!mDeferredOpen) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Data we need to do an open.
|
||||
*/
|
||||
nsString mFilePath;
|
||||
nsString mMode;
|
||||
|
||||
/**
|
||||
* Flags describing our behavior. See the IDL file for possible values.
|
||||
*/
|
||||
PRInt32 mFlags;
|
||||
|
||||
/**
|
||||
* Whether we have a pending open (see FLAGS_DEFER_OPEN in the IDL file).
|
||||
*/
|
||||
bool mDeferredOpen;
|
||||
|
||||
/**
|
||||
* File descriptor for opened file.
|
||||
*/
|
||||
quota_FILE* mQuotaFile;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_indexeddb_filestream_h__
|
@ -1001,7 +1001,7 @@ ContinueObjectStoreHelper::GatherResultsFromStatement(
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 1, 2,
|
||||
mDatabase->Manager(), mCloneReadInfo);
|
||||
mDatabase, mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@ -1071,7 +1071,7 @@ ContinueIndexObjectHelper::GatherResultsFromStatement(
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 2, 3,
|
||||
mDatabase->Manager(), mCloneReadInfo);
|
||||
mDatabase, mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "CheckQuotaHelper.h"
|
||||
#include "DatabaseInfo.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBFileHandle.h"
|
||||
#include "IDBIndex.h"
|
||||
#include "IDBObjectStore.h"
|
||||
#include "IDBTransaction.h"
|
||||
@ -90,6 +91,53 @@ private:
|
||||
PRInt64 mObjectStoreId;
|
||||
};
|
||||
|
||||
class CreateFileHelper : public AsyncConnectionHelper
|
||||
{
|
||||
public:
|
||||
CreateFileHelper(IDBDatabase* aDatabase,
|
||||
IDBRequest* aRequest,
|
||||
const nsAString& aName,
|
||||
const nsAString& aType)
|
||||
: AsyncConnectionHelper(aDatabase, aRequest),
|
||||
mName(aName), mType(aType)
|
||||
{ }
|
||||
|
||||
~CreateFileHelper()
|
||||
{ }
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
nsresult GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal);
|
||||
void ReleaseMainThreadObjects()
|
||||
{
|
||||
mFileInfo = nsnull;
|
||||
AsyncConnectionHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
virtual ChildProcessSendResult MaybeSendResponseToChildProcess(
|
||||
nsresult aResultCode)
|
||||
MOZ_OVERRIDE
|
||||
{
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
virtual nsresult UnpackResponseFromParentProcess(
|
||||
const ResponseValue& aResponseValue)
|
||||
MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_NOT_REACHED("Should never get here!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
private:
|
||||
// In-params.
|
||||
nsString mName;
|
||||
nsString mType;
|
||||
|
||||
// Out-params.
|
||||
nsRefPtr<FileInfo> mFileInfo;
|
||||
};
|
||||
|
||||
NS_STACK_CLASS
|
||||
class AutoRemoveObjectStore
|
||||
{
|
||||
@ -349,6 +397,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIDBDatabase)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFileStorage)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBDatabase)
|
||||
NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
|
||||
|
||||
@ -692,6 +741,36 @@ IDBDatabase::Transaction(const jsval& aStoreNames,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBDatabase::MozCreateFileHandle(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIIDBRequest** _retval)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (IndexedDatabaseManager::IsShuttingDown()) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (mClosed) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBRequest> request = IDBRequest::Create(nsnull, this, nsnull);
|
||||
|
||||
nsRefPtr<CreateFileHelper> helper =
|
||||
new CreateFileHelper(this, request, aName, aType);
|
||||
|
||||
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(manager, "We should definitely have a manager here");
|
||||
|
||||
nsresult rv = helper->Dispatch(manager->IOThread());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
request.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBDatabase::Close()
|
||||
{
|
||||
@ -703,6 +782,37 @@ IDBDatabase::Close()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
IDBDatabase::StorageId()
|
||||
{
|
||||
return Id();
|
||||
}
|
||||
|
||||
bool
|
||||
IDBDatabase::IsStorageInvalidated()
|
||||
{
|
||||
return IsInvalidated();
|
||||
}
|
||||
|
||||
bool
|
||||
IDBDatabase::IsStorageShuttingDown()
|
||||
{
|
||||
return IndexedDatabaseManager::IsShuttingDown();
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::SetThreadLocals()
|
||||
{
|
||||
NS_ASSERTION(GetOwner(), "Should have owner!");
|
||||
IndexedDatabaseManager::SetCurrentWindow(GetOwner());
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::UnsetThreadLocals()
|
||||
{
|
||||
IndexedDatabaseManager::SetCurrentWindow(nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
IDBDatabase::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
||||
{
|
||||
@ -846,3 +956,35 @@ DeleteObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateFileHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
FileManager* fileManager = mDatabase->Manager();
|
||||
|
||||
mFileInfo = fileManager->GetNewFileInfo();
|
||||
NS_ENSURE_TRUE(mFileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
NS_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory, mFileInfo->Id());
|
||||
NS_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsresult rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateFileHelper::GetSuccessResult(JSContext* aCx,
|
||||
jsval* aVal)
|
||||
{
|
||||
nsRefPtr<IDBFileHandle> fileHandle =
|
||||
IDBFileHandle::Create(mDatabase, mName, mType, mFileInfo.forget());
|
||||
NS_ENSURE_TRUE(fileHandle, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMFileHandle*, fileHandle),
|
||||
aVal);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabase.h"
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIFileStorage.h"
|
||||
#include "nsIIDBDatabase.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
|
||||
@ -31,7 +32,8 @@ class IndexedDBDatabaseParent;
|
||||
struct ObjectStoreInfoGuts;
|
||||
|
||||
class IDBDatabase : public IDBWrapperCache,
|
||||
public nsIIDBDatabase
|
||||
public nsIIDBDatabase,
|
||||
public nsIFileStorage
|
||||
{
|
||||
friend class AsyncConnectionHelper;
|
||||
friend class IndexedDatabaseManager;
|
||||
@ -39,6 +41,7 @@ class IDBDatabase : public IDBWrapperCache,
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIIDBDATABASE
|
||||
NS_DECL_NSIFILESTORAGE
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase, IDBWrapperCache)
|
||||
|
||||
|
119
dom/indexedDB/IDBFileHandle.cpp
Normal file
119
dom/indexedDB/IDBFileHandle.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "IDBFileHandle.h"
|
||||
|
||||
#include "nsIStandardFileStream.h"
|
||||
|
||||
#include "nsDOMClassInfoID.h"
|
||||
|
||||
#include "FileStream.h"
|
||||
#include "mozilla/dom/file/File.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
inline
|
||||
already_AddRefed<nsIFile>
|
||||
GetFileFor(FileInfo* aFileInfo)
|
||||
|
||||
{
|
||||
FileManager* fileManager = aFileInfo->Manager();
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
NS_ENSURE_TRUE(directory, nsnull);
|
||||
|
||||
nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory,
|
||||
aFileInfo->Id());
|
||||
NS_ENSURE_TRUE(file, nsnull);
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
already_AddRefed<IDBFileHandle>
|
||||
IDBFileHandle::Create(IDBDatabase* aDatabase,
|
||||
const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
already_AddRefed<FileInfo> aFileInfo)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo(aFileInfo);
|
||||
NS_ASSERTION(fileInfo, "Null pointer!");
|
||||
|
||||
nsRefPtr<IDBFileHandle> newFile = new IDBFileHandle();
|
||||
|
||||
newFile->BindToOwner(aDatabase);
|
||||
|
||||
newFile->mFileStorage = aDatabase;
|
||||
newFile->mName = aName;
|
||||
newFile->mType = aType;
|
||||
|
||||
newFile->mFile = GetFileFor(fileInfo);
|
||||
NS_ENSURE_TRUE(newFile->mFile, nsnull);
|
||||
newFile->mFileName.AppendInt(fileInfo->Id());
|
||||
|
||||
fileInfo.swap(newFile->mFileInfo);
|
||||
|
||||
return newFile.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
|
||||
{
|
||||
nsRefPtr<FileStream> stream = new FileStream();
|
||||
|
||||
nsString streamMode;
|
||||
if (aReadOnly) {
|
||||
streamMode.AssignLiteral("rb");
|
||||
}
|
||||
else {
|
||||
streamMode.AssignLiteral("r+b");
|
||||
}
|
||||
|
||||
nsresult rv = stream->Init(aFile, streamMode,
|
||||
nsIStandardFileStream::FLAGS_DEFER_OPEN);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
nsCOMPtr<nsISupports> result =
|
||||
NS_ISUPPORTS_CAST(nsIStandardFileStream*, stream);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMFile>
|
||||
IDBFileHandle::CreateFileObject(mozilla::dom::file::LockedFile* aLockedFile,
|
||||
PRUint32 aFileSize)
|
||||
{
|
||||
nsCOMPtr<nsIDOMFile> file = new mozilla::dom::file::File(
|
||||
mName, mType, aFileSize, mFile, aLockedFile, mFileInfo);
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBFileHandle)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIDBFileHandle)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBFileHandle)
|
||||
NS_INTERFACE_MAP_END_INHERITING(FileHandle)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(IDBFileHandle, FileHandle)
|
||||
NS_IMPL_RELEASE_INHERITED(IDBFileHandle, FileHandle)
|
||||
|
||||
DOMCI_DATA(IDBFileHandle, IDBFileHandle)
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBFileHandle::GetDatabase(nsIIDBDatabase** aDatabase)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIIDBDatabase> database = do_QueryInterface(mFileStorage);
|
||||
NS_ASSERTION(database, "This should always succeed!");
|
||||
|
||||
database.forget(aDatabase);
|
||||
return NS_OK;
|
||||
}
|
61
dom/indexedDB/IDBFileHandle.h
Normal file
61
dom/indexedDB/IDBFileHandle.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_indexeddb_idbfilehandle_h__
|
||||
#define mozilla_dom_indexeddb_idbfilehandle_h__
|
||||
|
||||
#include "IndexedDatabase.h"
|
||||
|
||||
#include "nsIIDBFileHandle.h"
|
||||
|
||||
#include "mozilla/dom/file/FileHandle.h"
|
||||
#include "mozilla/dom/indexedDB/FileInfo.h"
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class IDBFileHandle : public mozilla::dom::file::FileHandle,
|
||||
public nsIIDBFileHandle
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIIDBFILEHANDLE
|
||||
|
||||
NS_IMETHOD_(PRInt64)
|
||||
GetFileId()
|
||||
{
|
||||
return mFileInfo->Id();
|
||||
}
|
||||
|
||||
NS_IMETHOD_(FileInfo*)
|
||||
GetFileInfo()
|
||||
{
|
||||
return mFileInfo;
|
||||
}
|
||||
|
||||
static already_AddRefed<IDBFileHandle>
|
||||
Create(IDBDatabase* aDatabase, const nsAString& aName,
|
||||
const nsAString& aType, already_AddRefed<FileInfo> aFileInfo);
|
||||
|
||||
virtual already_AddRefed<nsISupports>
|
||||
CreateStream(nsIFile* aFile, bool aReadOnly);
|
||||
|
||||
virtual already_AddRefed<nsIDOMFile>
|
||||
CreateFileObject(mozilla::dom::file::LockedFile* aLockedFile,
|
||||
PRUint32 aFileSize);
|
||||
|
||||
private:
|
||||
IDBFileHandle()
|
||||
{ }
|
||||
|
||||
~IDBFileHandle()
|
||||
{ }
|
||||
|
||||
nsRefPtr<FileInfo> mFileInfo;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_indexeddb_idbfilehandle_h__
|
@ -1172,7 +1172,7 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
|
||||
|
||||
if (hasResult) {
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
|
||||
mDatabase->Manager(), mCloneReadInfo);
|
||||
mDatabase, mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -1488,7 +1488,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
|
||||
NS_ASSERTION(readInfo, "This shouldn't fail!");
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
|
||||
mDatabase->Manager(), *readInfo);
|
||||
mDatabase, *readInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
@ -2023,7 +2023,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 2, 3,
|
||||
mDatabase->Manager(), mCloneReadInfo);
|
||||
mDatabase, mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now we need to make the query to get the next match.
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "IDBObjectStore.h"
|
||||
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
@ -27,8 +28,10 @@
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
#include "FileStream.h"
|
||||
#include "IDBCursor.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBFileHandle.h"
|
||||
#include "IDBIndex.h"
|
||||
#include "IDBKeyRange.h"
|
||||
#include "IDBTransaction.h"
|
||||
@ -910,7 +913,7 @@ IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
|
||||
mozIStorageStatement* aStatement,
|
||||
PRUint32 aDataIndex,
|
||||
PRUint32 aFileIdsIndex,
|
||||
FileManager* aFileManager,
|
||||
IDBDatabase* aDatabase,
|
||||
StructuredCloneReadInfo& aInfo)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -956,26 +959,28 @@ IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
|
||||
rv = aStatement->GetIsNull(aFileIdsIndex, &isNull);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (isNull) {
|
||||
return NS_OK;
|
||||
if (!isNull) {
|
||||
nsString ids;
|
||||
rv = aStatement->GetString(aFileIdsIndex, ids);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsAutoTArray<PRInt64, 10> array;
|
||||
rv = ConvertFileIdsToArray(ids, array);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
FileManager* fileManager = aDatabase->Manager();
|
||||
|
||||
for (PRUint32 i = 0; i < array.Length(); i++) {
|
||||
const PRInt64& id = array[i];
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id);
|
||||
NS_ASSERTION(fileInfo, "Null file info!");
|
||||
|
||||
aInfo.mFileInfos.AppendElement(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
nsString ids;
|
||||
rv = aStatement->GetString(aFileIdsIndex, ids);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsAutoTArray<PRInt64, 10> array;
|
||||
rv = ConvertFileIdsToArray(ids, array);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
for (PRUint32 i = 0; i < array.Length(); i++) {
|
||||
const PRInt64& id = array.ElementAt(i);
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = aFileManager->GetFileInfo(id);
|
||||
NS_ASSERTION(fileInfo, "Null file info!");
|
||||
|
||||
aInfo.mFileInfos.AppendElement(fileInfo);
|
||||
}
|
||||
aInfo.mDatabase = aDatabase;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1102,7 +1107,8 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
uint32_t aData,
|
||||
void* aClosure)
|
||||
{
|
||||
if (aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE) {
|
||||
if (aTag == SCTAG_DOM_FILEHANDLE || aTag == SCTAG_DOM_BLOB ||
|
||||
aTag == SCTAG_DOM_FILE) {
|
||||
StructuredCloneReadInfo* cloneReadInfo =
|
||||
reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
|
||||
|
||||
@ -1112,15 +1118,50 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
}
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = cloneReadInfo->mFileInfos[aData];
|
||||
nsRefPtr<FileManager> fileManager = fileInfo->Manager();
|
||||
IDBDatabase* database = cloneReadInfo->mDatabase;
|
||||
|
||||
if (aTag == SCTAG_DOM_FILEHANDLE) {
|
||||
nsCString type;
|
||||
if (!StructuredCloneReadString(aReader, type)) {
|
||||
return nsnull;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convType(type);
|
||||
|
||||
nsCString name;
|
||||
if (!StructuredCloneReadString(aReader, name)) {
|
||||
return nsnull;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convName(name);
|
||||
|
||||
nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(database,
|
||||
convName, convType, fileInfo.forget());
|
||||
|
||||
jsval wrappedFileHandle;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
|
||||
static_cast<nsIDOMFileHandle*>(fileHandle),
|
||||
&NS_GET_IID(nsIDOMFileHandle),
|
||||
&wrappedFileHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return JSVAL_TO_OBJECT(wrappedFileHandle);
|
||||
}
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
if (!directory) {
|
||||
NS_WARNING("Failed to get directory!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile =
|
||||
fileManager->GetFileForId(directory, fileInfo->Id());
|
||||
if (!nativeFile) {
|
||||
NS_WARNING("Failed to get file!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
@ -1209,25 +1250,55 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
if (wrappedNative) {
|
||||
nsISupports* supports = wrappedNative->Native();
|
||||
|
||||
IDBTransaction* transaction = cloneWriteInfo->mTransaction;
|
||||
FileManager* fileManager = transaction->Database()->Manager();
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
|
||||
if (blob) {
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
|
||||
// Check if it is a blob created from this db or the blob was already
|
||||
// stored in this db
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
||||
if (!fileInfo) {
|
||||
fileInfo = blob->GetFileInfo(fileManager);
|
||||
}
|
||||
|
||||
if (!fileInfo) {
|
||||
fileInfo = fileManager->GetNewFileInfo();
|
||||
if (!fileInfo) {
|
||||
NS_WARNING("Failed to get new file info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
|
||||
NS_WARNING("Failed to get internal steam!");
|
||||
return false;
|
||||
}
|
||||
|
||||
transaction->AddFileInfo(blob, fileInfo);
|
||||
}
|
||||
|
||||
PRUint64 size;
|
||||
if (NS_FAILED(blob->GetSize(&size))) {
|
||||
NS_WARNING("Failed to get size!");
|
||||
return false;
|
||||
}
|
||||
size = SwapBytes(size);
|
||||
|
||||
nsString type;
|
||||
if (NS_FAILED(blob->GetType(type))) {
|
||||
NS_WARNING("Failed to get type!");
|
||||
return false;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 convType(type);
|
||||
PRUint32 convTypeLength = SwapBytes(convType.Length());
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
|
||||
cloneWriteInfo->mBlobs.Length()) ||
|
||||
cloneWriteInfo->mFiles.Length()) ||
|
||||
!JS_WriteBytes(aWriter, &size, sizeof(PRUint64)) ||
|
||||
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(PRUint32)) ||
|
||||
!JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
|
||||
@ -1237,6 +1308,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
if (file) {
|
||||
nsString name;
|
||||
if (NS_FAILED(file->GetName(name))) {
|
||||
NS_WARNING("Failed to get name!");
|
||||
return false;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 convName(name);
|
||||
@ -1248,7 +1320,51 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
cloneWriteInfo->mBlobs.AppendElement(blob);
|
||||
StructuredCloneFile* cloneFile = cloneWriteInfo->mFiles.AppendElement();
|
||||
cloneFile->mFile = blob.forget();
|
||||
cloneFile->mFileInfo = fileInfo.forget();
|
||||
cloneFile->mInputStream = inputStream.forget();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMFileHandle> fileHandle = do_QueryInterface(supports);
|
||||
if (fileHandle) {
|
||||
nsRefPtr<FileInfo> fileInfo = fileHandle->GetFileInfo();
|
||||
|
||||
// Throw when trying to store non IDB file handles or IDB file handles
|
||||
// across databases.
|
||||
if (!fileInfo || fileInfo->Manager() != fileManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsString type;
|
||||
if (NS_FAILED(fileHandle->GetType(type))) {
|
||||
NS_WARNING("Failed to get type!");
|
||||
return false;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 convType(type);
|
||||
PRUint32 convTypeLength = SwapBytes(convType.Length());
|
||||
|
||||
nsString name;
|
||||
if (NS_FAILED(fileHandle->GetName(name))) {
|
||||
NS_WARNING("Failed to get name!");
|
||||
return false;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 convName(name);
|
||||
PRUint32 convNameLength = SwapBytes(convName.Length());
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILEHANDLE,
|
||||
cloneWriteInfo->mFiles.Length()) ||
|
||||
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(PRUint32)) ||
|
||||
!JS_WriteBytes(aWriter, convType.get(), convType.Length()) ||
|
||||
!JS_WriteBytes(aWriter, &convNameLength, sizeof(PRUint32)) ||
|
||||
!JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StructuredCloneFile* file = cloneWriteInfo->mFiles.AppendElement();
|
||||
file->mFileInfo = fileInfo.forget();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1465,6 +1581,7 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
|
||||
}
|
||||
|
||||
aCloneWriteInfo.mOffsetToKeyProp = 0;
|
||||
aCloneWriteInfo.mTransaction = mTransaction;
|
||||
|
||||
// We guard on rv being a success because we need to run the property
|
||||
// deletion code below even if we should not be serializing the value
|
||||
@ -2379,26 +2496,30 @@ IDBObjectStore::Count(const jsval& aKey,
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
CopyData(nsIInputStream* aStream, quota_FILE* aFile)
|
||||
CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
do {
|
||||
char copyBuffer[FILE_COPY_BUFFER_SIZE];
|
||||
|
||||
PRUint32 numRead;
|
||||
nsresult rv = aStream->Read(copyBuffer, FILE_COPY_BUFFER_SIZE, &numRead);
|
||||
rv = aInputStream->Read(copyBuffer, FILE_COPY_BUFFER_SIZE, &numRead);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (numRead <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
size_t numWrite = sqlite3_quota_fwrite(copyBuffer, 1, numRead, aFile);
|
||||
PRUint32 numWrite;
|
||||
rv = aOutputStream->Write(copyBuffer, numRead, &numWrite);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE);
|
||||
} while (true);
|
||||
|
||||
// Flush and sync
|
||||
NS_ENSURE_TRUE(sqlite3_quota_fflush(aFile, 1) == 0,
|
||||
NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
rv = aOutputStream->Flush();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2570,50 +2691,28 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
|
||||
nsAutoString fileIds;
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneWriteInfo.mBlobs.Length(); index++) {
|
||||
nsCOMPtr<nsIDOMBlob>& domBlob = mCloneWriteInfo.mBlobs[index];
|
||||
PRUint32 length = mCloneWriteInfo.mFiles.Length();
|
||||
for (PRUint32 index = 0; index < length; index++) {
|
||||
StructuredCloneFile& cloneFile = mCloneWriteInfo.mFiles[index];
|
||||
|
||||
PRInt64 id = -1;
|
||||
|
||||
// Check if it is a blob created from this db or the blob was already
|
||||
// stored in this db
|
||||
nsRefPtr<FileInfo> fileInfo = domBlob->GetFileInfo(fileManager);
|
||||
if (fileInfo) {
|
||||
id = fileInfo->Id();
|
||||
}
|
||||
|
||||
if (id == -1) {
|
||||
fileInfo = fileManager->GetNewFileInfo();
|
||||
NS_ENSURE_TRUE(fileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
id = fileInfo->Id();
|
||||
|
||||
mTransaction->OnNewFileInfo(fileInfo);
|
||||
FileInfo* fileInfo = cloneFile.mFileInfo;
|
||||
nsIInputStream* inputStream = cloneFile.mInputStream;
|
||||
|
||||
PRInt64 id = fileInfo->Id();
|
||||
if (inputStream) {
|
||||
// Copy it
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = domBlob->GetInternalStream(getter_AddRefs(inputStream));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile = fileManager->GetFileForId(directory, id);
|
||||
nsCOMPtr<nsIFile> nativeFile =
|
||||
fileManager->GetFileForId(directory, id);
|
||||
NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsString nativeFilePath;
|
||||
rv = nativeFile->GetPath(nativeFilePath);
|
||||
nsRefPtr<FileStream> outputStream = new FileStream();
|
||||
rv = outputStream->Init(nativeFile, NS_LITERAL_STRING("wb"), 0);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
quota_FILE* file =
|
||||
sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(nativeFilePath).get(), "wb");
|
||||
NS_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = CopyData(inputStream, file);
|
||||
|
||||
NS_ENSURE_TRUE(sqlite3_quota_fclose(file) == 0,
|
||||
NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = CopyData(inputStream, outputStream);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
domBlob->AddFileInfo(fileInfo);
|
||||
cloneFile.mFile->AddFileInfo(fileInfo);
|
||||
}
|
||||
|
||||
if (index) {
|
||||
@ -2777,7 +2876,7 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
|
||||
|
||||
if (hasResult) {
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
|
||||
mDatabase->Manager(), mCloneReadInfo);
|
||||
mDatabase, mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@ -3087,7 +3186,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2,
|
||||
mDatabase->Manager(), mCloneReadInfo);
|
||||
mDatabase, mCloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now we need to make the query to get the next match.
|
||||
@ -3461,7 +3560,7 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
|
||||
do {
|
||||
StructuredCloneReadInfo cloneReadInfo;
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2,
|
||||
mDatabase->Manager(), cloneReadInfo);
|
||||
mDatabase, cloneReadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer;
|
||||
@ -3612,7 +3711,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
NS_ASSERTION(readInfo, "Shouldn't fail if SetCapacity succeeded!");
|
||||
|
||||
rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
|
||||
mDatabase->Manager(), *readInfo);
|
||||
mDatabase, *readInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
GetStructuredCloneReadInfoFromStatement(mozIStorageStatement* aStatement,
|
||||
PRUint32 aDataIndex,
|
||||
PRUint32 aFileIdsIndex,
|
||||
FileManager* aFileManager,
|
||||
IDBDatabase* aDatabase,
|
||||
StructuredCloneReadInfo& aInfo);
|
||||
|
||||
static void
|
||||
|
@ -113,6 +113,8 @@ IDBTransaction::CreateInternal(IDBDatabase* aDatabase,
|
||||
|
||||
IndexedDBTransactionChild* actor = nsnull;
|
||||
|
||||
transaction->mCreatedFileInfos.Init();
|
||||
|
||||
if (IndexedDatabaseManager::IsMainProcess()) {
|
||||
transaction->mCachedStatements.Init();
|
||||
|
||||
@ -470,10 +472,18 @@ IDBTransaction::GetOrCreateObjectStore(const nsAString& aName,
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::OnNewFileInfo(FileInfo* aFileInfo)
|
||||
already_AddRefed<FileInfo>
|
||||
IDBTransaction::GetFileInfo(nsIDOMBlob* aBlob)
|
||||
{
|
||||
mCreatedFileInfos.AppendElement(aFileInfo);
|
||||
nsRefPtr<FileInfo> fileInfo;
|
||||
mCreatedFileInfos.Get(aBlob, getter_AddRefs(fileInfo));
|
||||
return fileInfo.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::AddFileInfo(nsIDOMBlob* aBlob, FileInfo* aFileInfo)
|
||||
{
|
||||
mCreatedFileInfos.Put(aBlob, aFileInfo);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -152,7 +152,8 @@ public:
|
||||
ObjectStoreInfo* aObjectStoreInfo,
|
||||
bool aCreating);
|
||||
|
||||
void OnNewFileInfo(FileInfo* aFileInfo);
|
||||
already_AddRefed<FileInfo> GetFileInfo(nsIDOMBlob* aBlob);
|
||||
void AddFileInfo(nsIDOMBlob* aBlob, FileInfo* aFileInfo);
|
||||
|
||||
void ClearCreatedFileInfos();
|
||||
|
||||
@ -230,7 +231,7 @@ private:
|
||||
nsTArray<nsRefPtr<IDBObjectStore> > mCreatedObjectStores;
|
||||
|
||||
nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
|
||||
nsTArray<nsRefPtr<FileInfo> > mCreatedFileInfos;
|
||||
nsRefPtrHashtable<nsISupportsHashKey, FileInfo> mCreatedFileInfos;
|
||||
|
||||
IndexedDBTransactionChild* mActorChild;
|
||||
IndexedDBTransactionParent* mActorParent;
|
||||
|
@ -28,19 +28,34 @@
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIInputStream;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class FileInfo;
|
||||
class IDBDatabase;
|
||||
class IDBTransaction;
|
||||
|
||||
template <class T>
|
||||
void SwapData(T& aData1, T& aData2)
|
||||
{
|
||||
T temp = aData2;
|
||||
aData2 = aData1;
|
||||
aData1 = temp;
|
||||
}
|
||||
|
||||
struct SerializedStructuredCloneReadInfo;
|
||||
|
||||
struct StructuredCloneReadInfo
|
||||
{
|
||||
// In IndexedDatabaseInlines.h
|
||||
inline StructuredCloneReadInfo();
|
||||
|
||||
void Swap(StructuredCloneReadInfo& aCloneReadInfo)
|
||||
{
|
||||
mCloneBuffer.swap(aCloneReadInfo.mCloneBuffer);
|
||||
mFileInfos.SwapElements(aCloneReadInfo.mFileInfos);
|
||||
SwapData(mDatabase, aCloneReadInfo.mDatabase);
|
||||
}
|
||||
|
||||
// In IndexedDatabaseInlines.h
|
||||
@ -49,6 +64,7 @@ struct StructuredCloneReadInfo
|
||||
|
||||
JSAutoStructuredCloneBuffer mCloneBuffer;
|
||||
nsTArray<nsRefPtr<FileInfo> > mFileInfos;
|
||||
IDBDatabase* mDatabase;
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneReadInfo
|
||||
@ -77,22 +93,41 @@ struct SerializedStructuredCloneReadInfo
|
||||
size_t dataLength;
|
||||
};
|
||||
|
||||
struct StructuredCloneFile
|
||||
{
|
||||
bool operator==(const StructuredCloneFile& aOther) const
|
||||
{
|
||||
return this->mFile == aOther.mFile &&
|
||||
this->mFileInfo == aOther.mFileInfo &&
|
||||
this->mInputStream == aOther.mInputStream;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> mFile;
|
||||
nsRefPtr<FileInfo> mFileInfo;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneWriteInfo;
|
||||
|
||||
struct StructuredCloneWriteInfo
|
||||
{
|
||||
// In IndexedDatabaseInlines.h
|
||||
inline StructuredCloneWriteInfo();
|
||||
|
||||
void Swap(StructuredCloneWriteInfo& aCloneWriteInfo)
|
||||
{
|
||||
mCloneBuffer.swap(aCloneWriteInfo.mCloneBuffer);
|
||||
mBlobs.SwapElements(aCloneWriteInfo.mBlobs);
|
||||
mOffsetToKeyProp = aCloneWriteInfo.mOffsetToKeyProp;
|
||||
mFiles.SwapElements(aCloneWriteInfo.mFiles);
|
||||
SwapData(mTransaction, aCloneWriteInfo.mTransaction);
|
||||
SwapData(mOffsetToKeyProp, aCloneWriteInfo.mOffsetToKeyProp);
|
||||
}
|
||||
|
||||
bool operator==(const StructuredCloneWriteInfo& aOther) const
|
||||
{
|
||||
return this->mCloneBuffer.nbytes() == aOther.mCloneBuffer.nbytes() &&
|
||||
this->mCloneBuffer.data() == aOther.mCloneBuffer.data() &&
|
||||
this->mBlobs == aOther.mBlobs &&
|
||||
this->mFiles == aOther.mFiles &&
|
||||
this->mTransaction == aOther.mTransaction &&
|
||||
this->mOffsetToKeyProp == aOther.mOffsetToKeyProp;
|
||||
}
|
||||
|
||||
@ -101,7 +136,8 @@ struct StructuredCloneWriteInfo
|
||||
SetFromSerialized(const SerializedStructuredCloneWriteInfo& aOther);
|
||||
|
||||
JSAutoStructuredCloneBuffer mCloneBuffer;
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
|
||||
nsTArray<StructuredCloneFile> mFiles;
|
||||
IDBTransaction* mTransaction;
|
||||
PRUint64 mOffsetToKeyProp;
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,13 @@
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
inline
|
||||
StructuredCloneWriteInfo::StructuredCloneWriteInfo()
|
||||
: mTransaction(nsnull),
|
||||
mOffsetToKeyProp(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
StructuredCloneWriteInfo::SetFromSerialized(
|
||||
@ -22,11 +29,17 @@ StructuredCloneWriteInfo::SetFromSerialized(
|
||||
return false;
|
||||
}
|
||||
|
||||
mBlobs.Clear();
|
||||
mFiles.Clear();
|
||||
mOffsetToKeyProp = aOther.offsetToKeyProp;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
StructuredCloneReadInfo::StructuredCloneReadInfo()
|
||||
: mDatabase(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
StructuredCloneReadInfo::SetFromSerialized(
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "nsIDOMScriptObjectFactory.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStorage.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
@ -17,6 +18,7 @@
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "mozilla/dom/file/FileService.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
@ -56,6 +58,7 @@
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::services;
|
||||
using mozilla::Preferences;
|
||||
using mozilla::dom::file::FileService;
|
||||
|
||||
static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
||||
|
||||
@ -113,6 +116,7 @@ public:
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(QuotaCallback, mozIStorageQuotaCallback)
|
||||
|
||||
// Adds all databases in the hash to the given array.
|
||||
template <class T>
|
||||
PLDHashOperator
|
||||
EnumerateToTArray(const nsACString& aKey,
|
||||
nsTArray<IDBDatabase*>* aValue,
|
||||
@ -123,8 +127,8 @@ EnumerateToTArray(const nsACString& aKey,
|
||||
NS_ASSERTION(aValue, "Null pointer!");
|
||||
NS_ASSERTION(aUserArg, "Null pointer!");
|
||||
|
||||
nsTArray<IDBDatabase*>* array =
|
||||
static_cast<nsTArray<IDBDatabase*>*>(aUserArg);
|
||||
nsTArray<T>* array =
|
||||
static_cast<nsTArray<T>*>(aUserArg);
|
||||
|
||||
if (!array->AppendElements(*aValue)) {
|
||||
NS_WARNING("Out of memory!");
|
||||
@ -518,8 +522,10 @@ IndexedDatabaseManager::AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow)
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
|
||||
nsAutoTArray<IDBDatabase*, 50> liveDatabases;
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray<IDBDatabase*>,
|
||||
&liveDatabases);
|
||||
|
||||
FileService* service = FileService::Get();
|
||||
TransactionThreadPool* pool = TransactionThreadPool::Get();
|
||||
|
||||
for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
|
||||
@ -529,6 +535,10 @@ IndexedDatabaseManager::AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow)
|
||||
NS_WARNING("Failed to close database for dying window!");
|
||||
}
|
||||
|
||||
if (service) {
|
||||
service->AbortLockedFilesForStorage(database);
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
pool->AbortTransactionsForDatabase(database);
|
||||
}
|
||||
@ -543,17 +553,20 @@ IndexedDatabaseManager::HasOpenTransactions(nsPIDOMWindow* aWindow)
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
|
||||
nsAutoTArray<IDBDatabase*, 50> liveDatabases;
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
|
||||
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray<IDBDatabase*>,
|
||||
&liveDatabases);
|
||||
|
||||
FileService* service = FileService::Get();
|
||||
TransactionThreadPool* pool = TransactionThreadPool::Get();
|
||||
if (!pool) {
|
||||
if (!service && !pool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
|
||||
IDBDatabase*& database = liveDatabases[index];
|
||||
if (database->GetOwner() == aWindow &&
|
||||
pool->HasTransactionsForDatabase(database)) {
|
||||
((service && service->HasLockedFilesForStorage(database)) ||
|
||||
(pool && pool->HasTransactionsForDatabase(database)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -587,21 +600,38 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
|
||||
// transactions that have not completed. We need to wait for those
|
||||
// before we dispatch the helper.
|
||||
|
||||
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
|
||||
if (!pool) {
|
||||
NS_ERROR("IndexedDB is totally broken.");
|
||||
return;
|
||||
FileService* service = FileService::Get();
|
||||
TransactionThreadPool* pool = TransactionThreadPool::Get();
|
||||
|
||||
PRUint32 count = !!service + !!pool;
|
||||
|
||||
nsRefPtr<WaitForTransactionsToFinishRunnable> runnable =
|
||||
new WaitForTransactionsToFinishRunnable(op,
|
||||
NS_MAX<PRUint32>(count, 1));
|
||||
|
||||
if (!count) {
|
||||
runnable->Run();
|
||||
}
|
||||
else {
|
||||
// Use the WaitForTransactionsToxFinishRunnable as the callback.
|
||||
|
||||
nsRefPtr<WaitForTransactionsToFinishRunnable> waitRunnable =
|
||||
new WaitForTransactionsToFinishRunnable(op);
|
||||
if (service) {
|
||||
nsTArray<nsCOMPtr<nsIFileStorage> > array;
|
||||
array.AppendElement(aDatabase);
|
||||
|
||||
nsAutoTArray<nsRefPtr<IDBDatabase>, 1> array;
|
||||
array.AppendElement(aDatabase);
|
||||
if (!service->WaitForAllStoragesToComplete(array, runnable)) {
|
||||
NS_WARNING("Failed to wait for storages to complete!");
|
||||
}
|
||||
}
|
||||
|
||||
// Use the WaitForTransactionsToFinishRunnable as the callback.
|
||||
if (!pool->WaitForAllDatabasesToComplete(array, waitRunnable)) {
|
||||
NS_WARNING("Failed to wait for transaction to complete!");
|
||||
if (pool) {
|
||||
nsTArray<nsRefPtr<IDBDatabase> > array;
|
||||
array.AppendElement(aDatabase);
|
||||
|
||||
if (!pool->WaitForAllDatabasesToComplete(array, runnable)) {
|
||||
NS_WARNING("Failed to wait for databases to complete!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1249,6 +1279,39 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
|
||||
}
|
||||
|
||||
if (sIsMainProcess) {
|
||||
FileService* service = FileService::Get();
|
||||
if (service) {
|
||||
// This should only wait for IDB databases (file storages) to complete.
|
||||
// Other file storages may still have running locked files.
|
||||
// If the necko service (thread pool) gets the shutdown notification
|
||||
// first then the sync loop won't be processed at all, otherwise it will
|
||||
// lock the main thread until all IDB file storages are finished.
|
||||
|
||||
nsTArray<nsCOMPtr<nsIFileStorage> >
|
||||
liveDatabases(mLiveDatabases.Count());
|
||||
mLiveDatabases.EnumerateRead(
|
||||
EnumerateToTArray<nsCOMPtr<nsIFileStorage> >,
|
||||
&liveDatabases);
|
||||
|
||||
if (!liveDatabases.IsEmpty()) {
|
||||
nsRefPtr<WaitForLockedFilesToFinishRunnable> runnable =
|
||||
new WaitForLockedFilesToFinishRunnable();
|
||||
|
||||
if (!service->WaitForAllStoragesToComplete(liveDatabases,
|
||||
runnable)) {
|
||||
NS_WARNING("Failed to wait for databases to complete!");
|
||||
}
|
||||
|
||||
nsIThread* thread = NS_GetCurrentThread();
|
||||
while (runnable->IsBusy()) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
NS_ERROR("Failed to process next event!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to join with our IO thread.
|
||||
if (NS_FAILED(mIOThread->Shutdown())) {
|
||||
NS_WARNING("Failed to shutdown IO thread!");
|
||||
@ -1287,7 +1350,8 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
|
||||
|
||||
// Grab all live databases, for all origins.
|
||||
nsAutoTArray<IDBDatabase*, 50> liveDatabases;
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
|
||||
mLiveDatabases.EnumerateRead(EnumerateToTArray<IDBDatabase*>,
|
||||
&liveDatabases);
|
||||
|
||||
// Invalidate them all.
|
||||
if (!liveDatabases.IsEmpty()) {
|
||||
@ -1493,7 +1557,7 @@ IndexedDatabaseManager::AsyncUsageRunnable::GetUsageForDirectory(
|
||||
rv = file->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(fileSize > 0, "Negative size?!");
|
||||
NS_ASSERTION(fileSize >= 0, "Negative size?!");
|
||||
|
||||
IncrementUsage(aUsage, PRUint64(fileSize));
|
||||
}
|
||||
@ -1532,6 +1596,11 @@ IndexedDatabaseManager::WaitForTransactionsToFinishRunnable::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(mOp && mOp->mHelper, "What?");
|
||||
NS_ASSERTION(mCountdown, "Wrong countdown!");
|
||||
|
||||
if (--mCountdown) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Don't hold the callback alive longer than necessary.
|
||||
nsRefPtr<AsyncConnectionHelper> helper;
|
||||
@ -1547,6 +1616,18 @@ IndexedDatabaseManager::WaitForTransactionsToFinishRunnable::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::WaitForLockedFilesToFinishRunnable,
|
||||
nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
IndexedDatabaseManager::WaitForLockedFilesToFinishRunnable::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
mBusy = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IndexedDatabaseManager::SynchronizedOp::SynchronizedOp(const nsACString& aOrigin,
|
||||
nsIAtom* aId)
|
||||
|
@ -310,12 +310,14 @@ private:
|
||||
class WaitForTransactionsToFinishRunnable MOZ_FINAL : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
WaitForTransactionsToFinishRunnable(SynchronizedOp* aOp)
|
||||
: mOp(aOp)
|
||||
WaitForTransactionsToFinishRunnable(SynchronizedOp* aOp,
|
||||
PRUint32 aCountdown)
|
||||
: mOp(aOp), mCountdown(aCountdown)
|
||||
{
|
||||
NS_ASSERTION(mOp, "Why don't we have a runnable?");
|
||||
NS_ASSERTION(mOp->mDatabases.IsEmpty(), "We're here too early!");
|
||||
NS_ASSERTION(mOp->mHelper, "What are we supposed to do when we're done?");
|
||||
NS_ASSERTION(mCountdown, "Wrong countdown!");
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -324,6 +326,26 @@ private:
|
||||
private:
|
||||
// The IndexedDatabaseManager holds this alive.
|
||||
SynchronizedOp* mOp;
|
||||
PRUint32 mCountdown;
|
||||
};
|
||||
|
||||
class WaitForLockedFilesToFinishRunnable MOZ_FINAL : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
WaitForLockedFilesToFinishRunnable()
|
||||
: mBusy(true)
|
||||
{ }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
bool IsBusy() const
|
||||
{
|
||||
return mBusy;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mBusy;
|
||||
};
|
||||
|
||||
class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
|
||||
|
@ -24,10 +24,12 @@ CPPSRCS = \
|
||||
DatabaseInfo.cpp \
|
||||
FileInfo.cpp \
|
||||
FileManager.cpp \
|
||||
FileStream.cpp \
|
||||
IDBCursor.cpp \
|
||||
IDBDatabase.cpp \
|
||||
IDBEvents.cpp \
|
||||
IDBFactory.cpp \
|
||||
IDBFileHandle.cpp \
|
||||
IDBIndex.cpp \
|
||||
IDBKeyRange.cpp \
|
||||
IDBObjectStore.cpp \
|
||||
@ -45,6 +47,8 @@ EXPORTS_mozilla/dom/indexedDB = \
|
||||
IDBCursor.h \
|
||||
IDBDatabase.h \
|
||||
IDBEvents.h \
|
||||
IDBFactory.h \
|
||||
IDBFileHandle.h \
|
||||
IDBIndex.h \
|
||||
IDBKeyRange.h \
|
||||
IDBObjectStore.h \
|
||||
@ -53,7 +57,6 @@ EXPORTS_mozilla/dom/indexedDB = \
|
||||
IDBWrapperCache.h \
|
||||
IndexedDatabase.h \
|
||||
IndexedDatabaseManager.h \
|
||||
IDBFactory.h \
|
||||
Key.h \
|
||||
FileManager.h \
|
||||
FileInfo.h \
|
||||
@ -77,6 +80,7 @@ XPIDLSRCS = \
|
||||
nsIIDBCursorWithValue.idl \
|
||||
nsIIDBDatabase.idl \
|
||||
nsIIDBFactory.idl \
|
||||
nsIIDBFileHandle.idl \
|
||||
nsIIDBIndex.idl \
|
||||
nsIIDBKeyRange.idl \
|
||||
nsIIDBObjectStore.idl \
|
||||
@ -85,6 +89,7 @@ XPIDLSRCS = \
|
||||
nsIIDBVersionChangeEvent.idl \
|
||||
nsIIDBOpenDBRequest.idl \
|
||||
nsIIndexedDatabaseManager.idl \
|
||||
nsIStandardFileStream.idl \
|
||||
$(NULL)
|
||||
|
||||
DIRS += ipc
|
||||
|
@ -216,8 +216,14 @@ TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
|
||||
mTransactionsInProgress.Remove(databaseId);
|
||||
|
||||
// See if we need to fire any complete callbacks.
|
||||
for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) {
|
||||
MaybeFireCallback(index);
|
||||
PRUint32 index = 0;
|
||||
while (index < mCompleteCallbacks.Length()) {
|
||||
if (MaybeFireCallback(mCompleteCallbacks[index])) {
|
||||
mCompleteCallbacks.RemoveElementAt(index);
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -459,7 +465,10 @@ TransactionThreadPool::WaitForAllDatabasesToComplete(
|
||||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
MaybeFireCallback(mCompleteCallbacks.Length() - 1);
|
||||
if (MaybeFireCallback(*callback)) {
|
||||
mCompleteCallbacks.RemoveElementAt(mCompleteCallbacks.Length() - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -540,25 +549,20 @@ TransactionThreadPool::HasTransactionsForDatabase(IDBDatabase* aDatabase)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TransactionThreadPool::MaybeFireCallback(PRUint32 aCallbackIndex)
|
||||
bool
|
||||
TransactionThreadPool::MaybeFireCallback(DatabasesCompleteCallback& aCallback)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
DatabasesCompleteCallback& callback = mCompleteCallbacks[aCallbackIndex];
|
||||
|
||||
bool freeToRun = true;
|
||||
for (PRUint32 index = 0; index < callback.mDatabases.Length(); index++) {
|
||||
if (mTransactionsInProgress.Get(callback.mDatabases[index]->Id(), nsnull)) {
|
||||
freeToRun = false;
|
||||
break;
|
||||
for (PRUint32 index = 0; index < aCallback.mDatabases.Length(); index++) {
|
||||
if (mTransactionsInProgress.Get(aCallback.mDatabases[index]->Id(),
|
||||
nsnull)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (freeToRun) {
|
||||
callback.mCallback->Run();
|
||||
mCompleteCallbacks.RemoveElementAt(aCallbackIndex);
|
||||
}
|
||||
aCallback.mCallback->Run();
|
||||
return true;
|
||||
}
|
||||
|
||||
TransactionThreadPool::
|
||||
|
@ -129,7 +129,7 @@ protected:
|
||||
aInfo.finishRunnable);
|
||||
}
|
||||
|
||||
void MaybeFireCallback(PRUint32 aCallbackIndex);
|
||||
bool MaybeFireCallback(DatabasesCompleteCallback& aCallback);
|
||||
|
||||
nsCOMPtr<nsIThreadPool> mThreadPool;
|
||||
|
||||
|
@ -23,7 +23,7 @@ dictionary IDBObjectStoreParameters
|
||||
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
|
||||
* for more information.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(bedee48a-f47f-44f2-ba1e-d8fe595bbfee)]
|
||||
[scriptable, builtinclass, uuid(4543dbad-2b37-4741-8729-73b08b7ee37e)]
|
||||
interface nsIIDBDatabase : nsISupports
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
@ -35,7 +35,7 @@ interface nsIIDBDatabase : nsISupports
|
||||
[implicit_jscontext]
|
||||
nsIIDBObjectStore
|
||||
createObjectStore([Null(Stringify)] in DOMString name,
|
||||
/* nsIIDBObjectStoreParameters */
|
||||
/* IDBObjectStoreParameters */
|
||||
[optional /* none */] in jsval options);
|
||||
|
||||
void
|
||||
@ -47,6 +47,10 @@ interface nsIIDBDatabase : nsISupports
|
||||
transaction(in jsval storeNames, // js array of strings
|
||||
[optional /* "readonly" */] in DOMString mode);
|
||||
|
||||
nsIIDBRequest
|
||||
mozCreateFileHandle(in DOMString name,
|
||||
[optional] in DOMString type);
|
||||
|
||||
void
|
||||
close();
|
||||
|
||||
|
15
dom/indexedDB/nsIIDBFileHandle.idl
Normal file
15
dom/indexedDB/nsIIDBFileHandle.idl
Normal file
@ -0,0 +1,15 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIIDBDatabase;
|
||||
|
||||
[scriptable, builtinclass, uuid(7b05f6bb-26b0-4c12-a9a1-e31dd933deb8)]
|
||||
interface nsIIDBFileHandle : nsISupports
|
||||
{
|
||||
readonly attribute nsIIDBDatabase database;
|
||||
};
|
60
dom/indexedDB/nsIStandardFileStream.idl
Normal file
60
dom/indexedDB/nsIStandardFileStream.idl
Normal file
@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIFile;
|
||||
|
||||
/**
|
||||
* A stream that allows you to read from a file or stream to a file
|
||||
* using standard file APIs.
|
||||
*/
|
||||
[scriptable, uuid(ebbbb779-92a3-4b2a-b7cf-6efbe904c453)]
|
||||
interface nsIStandardFileStream : nsISupports
|
||||
{
|
||||
/**
|
||||
* If this is set, the file will be opened (i.e., a call to
|
||||
* fopen done) only when we do an actual operation on the stream,
|
||||
* or more specifically, when one of the following is called:
|
||||
* - Seek
|
||||
* - Tell
|
||||
* - SetEOF
|
||||
* - Available
|
||||
* - Read
|
||||
* - Write
|
||||
* - Flush
|
||||
* - GetSize
|
||||
* - GetLastModified
|
||||
* - Sync
|
||||
*
|
||||
* FLAGS_DEFER_OPEN is useful if we use the stream on a background
|
||||
* thread, so that the opening and possible |stat|ing of the file
|
||||
* happens there as well.
|
||||
*
|
||||
* @note Using this flag results in the file not being opened
|
||||
* during the call to Init. This means that any errors that might
|
||||
* happen when this flag is not set would happen during the
|
||||
* first read. Also, the file is not locked when Init is called,
|
||||
* so it might be deleted before we try to read from it.
|
||||
*/
|
||||
const long FLAGS_DEFER_OPEN = 1 << 0;
|
||||
|
||||
/**
|
||||
* @param file file to read from or stream to
|
||||
* @param mode file open mode (see fopen documentation)
|
||||
* @param flags flags specifying various behaviors of the class
|
||||
* (see enumerations in the class)
|
||||
*/
|
||||
void init(in nsIFile file,
|
||||
in AString mode,
|
||||
in long flags);
|
||||
|
||||
/**
|
||||
* Flush all written content held in memory buffers out to disk.
|
||||
* This is the equivalent of fflush()
|
||||
*/
|
||||
void flushBuffers();
|
||||
};
|
@ -56,6 +56,8 @@ TEST_FILES = \
|
||||
test_file_resurrection_transaction_abort.html \
|
||||
test_file_sharing.html \
|
||||
test_file_transaction_abort.html \
|
||||
test_filehandle_serialization.html \
|
||||
test_filehandle_store_snapshot.html \
|
||||
test_getAll.html \
|
||||
test_global_data.html \
|
||||
test_index_empty_keyPath.html \
|
||||
|
@ -48,12 +48,12 @@ function compareBuffers(buffer1, buffer2)
|
||||
|
||||
function getBlob(type, view)
|
||||
{
|
||||
return new Blob([view], {type: type});
|
||||
return utils.getBlob([view], {type: type});
|
||||
}
|
||||
|
||||
function getFile(name, type, view)
|
||||
{
|
||||
return new Blob([view], {type: type});
|
||||
return utils.getFile(name, [view], {type: type});
|
||||
}
|
||||
|
||||
function getRandomBlob(size)
|
||||
@ -212,6 +212,11 @@ function scheduleGC()
|
||||
SpecialPowers.exactGC(window, continueToNextStep);
|
||||
}
|
||||
|
||||
function getFileId(file)
|
||||
{
|
||||
return utils.getFileId(file);
|
||||
}
|
||||
|
||||
function hasFileInfo(name, id)
|
||||
{
|
||||
return utils.getFileReferences(name, id);
|
||||
|
@ -11,10 +11,15 @@ function executeSoon(aFun)
|
||||
}
|
||||
|
||||
if (!window.runTest) {
|
||||
window.runTest = function()
|
||||
window.runTest = function(limitedQuota)
|
||||
{
|
||||
allowIndexedDB();
|
||||
allowUnlimitedQuota();
|
||||
if (limitedQuota) {
|
||||
denyUnlimitedQuota();
|
||||
}
|
||||
else {
|
||||
allowUnlimitedQuota();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
testGenerator.next();
|
||||
|
@ -61,6 +61,9 @@
|
||||
refResult = result;
|
||||
continue;
|
||||
}
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
isnot(result.mozFullPath, refResult.mozFullPath, "Different os files");
|
||||
}
|
||||
|
||||
for (let i = 1; i < databases.length; i++) {
|
||||
@ -82,6 +85,9 @@
|
||||
let result = event.target.result;
|
||||
verifyBlob(result, refResult, 2);
|
||||
yield;
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
isnot(result.mozFullPath, refResult.mozFullPath, "Different os files");
|
||||
}
|
||||
|
||||
is(bufferCache.length, 2, "Correct length");
|
||||
|
@ -12,8 +12,6 @@
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
denyUnlimitedQuota();
|
||||
|
||||
const READ_WRITE = IDBTransaction.READ_WRITE;
|
||||
const DEFAULT_QUOTA_MB = 50;
|
||||
|
||||
@ -32,16 +30,13 @@
|
||||
let event = yield;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
|
||||
let db = event.target.result;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { });
|
||||
objectStore.add(testData.value, testData.key);
|
||||
|
||||
let usage = getUsageSync();
|
||||
|
||||
let size = (DEFAULT_QUOTA_MB + 1) * 1024 * 1024 - usage;
|
||||
|
||||
let size = (DEFAULT_QUOTA_MB + 1) * 1024 * 1024 - getUsageSync();
|
||||
fileData.file = getNullFile("random.bin", size);
|
||||
|
||||
event = yield;
|
||||
@ -70,6 +65,6 @@
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
<body onload="runTest(true);"></body>
|
||||
|
||||
</html>
|
||||
|
66
dom/indexedDB/test/test_filehandle_quota.html
Normal file
66
dom/indexedDB/test/test_filehandle_quota.html
Normal file
@ -0,0 +1,66 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const READ_WRITE = IDBTransaction.READ_WRITE;
|
||||
const DEFAULT_QUOTA_MB = 50;
|
||||
|
||||
const name = window.location.pathname;
|
||||
const description = "My Test Database";
|
||||
|
||||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
event = yield;
|
||||
|
||||
request = db.mozCreateFileHandle("test.bin", "binary");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
|
||||
let blob = getNullBlob((50 + 1) * 1024 * 1024 - getUsageSync());
|
||||
|
||||
request = lockedFile.write(blob);
|
||||
request.onerror = new ExpectError("UnknownError");
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield;
|
||||
|
||||
lockedFile.oncomplete = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(event.type, "complete", "Got correct event type");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="file.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest(true);"></body>
|
||||
|
||||
</html>
|
101
dom/indexedDB/test/test_filehandle_serialization.html
Normal file
101
dom/indexedDB/test/test_filehandle_serialization.html
Normal file
@ -0,0 +1,101 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const READ_WRITE = IDBTransaction.READ_WRITE;
|
||||
|
||||
const databaseInfo = [
|
||||
{ name: window.location.pathname + "1", description: "Test Database 1" },
|
||||
{ name: window.location.pathname + "2", description: "Test Database 2" }
|
||||
];
|
||||
|
||||
const objectStoreName = "Blobs";
|
||||
|
||||
const testFile = getRandomFile("random.bin", 100000);
|
||||
|
||||
let databases = [];
|
||||
for each (let info in databaseInfo) {
|
||||
let request = mozIndexedDB.open(info.name, 1, info.description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
db.createObjectStore(objectStoreName, { });
|
||||
|
||||
event = yield;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
databases.push(db);
|
||||
}
|
||||
|
||||
let db1 = databases[0];
|
||||
|
||||
let request = db1.mozCreateFileHandle("random.bin", "binary/random");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
is(getFileId(fileHandle), 1, "Correct file id");
|
||||
is(fileHandle.name, "random.bin", "Correct name");
|
||||
is(fileHandle.type, "binary/random", "Correct type");
|
||||
|
||||
let trans = db1.transaction([objectStoreName], READ_WRITE);
|
||||
let objectStore = trans.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.add(fileHandle, 42);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
request = objectStore.get(42);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let result = event.target.result;
|
||||
is(getFileId(result), 1, "Correct file id");
|
||||
is(result.name, fileHandle.name, "Correct name");
|
||||
is(result.type, fileHandle.type, "Correct type");
|
||||
|
||||
let db2 = databases[1];
|
||||
|
||||
trans = db2.transaction([objectStoreName], READ_WRITE);
|
||||
objectStore = trans.objectStore(objectStoreName);
|
||||
|
||||
try {
|
||||
objectStore.add(fileHandle, 42);
|
||||
ok(false, "Should have thrown!");
|
||||
}
|
||||
catch (e) {
|
||||
ok(e instanceof DOMException, "Got exception.");
|
||||
is(e.name, "DataCloneError", "Good error.");
|
||||
is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="file.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
92
dom/indexedDB/test/test_filehandle_store_snapshot.html
Normal file
92
dom/indexedDB/test/test_filehandle_store_snapshot.html
Normal file
@ -0,0 +1,92 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const READ_WRITE = IDBTransaction.READ_WRITE;
|
||||
|
||||
const name = window.location.pathname;
|
||||
const description = "My Test Database";
|
||||
|
||||
const objectStoreName = "Blobs";
|
||||
|
||||
const testFile = getRandomFile("random.bin", 100000);
|
||||
|
||||
let request = mozIndexedDB.open(name, 1, description);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield;
|
||||
|
||||
is(event.type, "upgradeneeded", "Got correct event type");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { });
|
||||
|
||||
event = yield;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
request = db.mozCreateFileHandle("random.bin", "binary/random");
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let fileHandle = event.target.result;
|
||||
fileHandle.onerror = errorHandler;
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
|
||||
is(getFileId(fileHandle), 1, "Correct file id");
|
||||
|
||||
request = lockedFile.write(testFile);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
request = fileHandle.getFile();
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let file = event.target.result;
|
||||
|
||||
lockedFile = event.target.lockedFile;
|
||||
is(lockedFile.active, true, "Correct active state");
|
||||
|
||||
let trans = db.transaction([objectStoreName], READ_WRITE);
|
||||
let objectStore = trans.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.add(file, 42);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(lockedFile.active, false, "Correct open state");
|
||||
|
||||
request = objectStore.get(42);
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
verifyBlob(event.target.result, testFile, 2);
|
||||
yield;
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="file.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user