Bug 788612 - Move bundle handing into nsDOMDeviceStorage to avoid calls to the nsIStringBundleService. r=bent
authorDoug Turner <dougt@dougt.org>
Thu, 13 Sep 2012 22:37:00 -0700
changeset 107053 7c8b9e22567e4254bd5bf3bc962f52a9ef955d03
parent 107052 089c534af34efe339050b122824cbefd8784a149
child 107054 35807584afe40ebff6e4a74cbab6780062450dcb
push id23466
push userdougt@mozilla.com
push dateFri, 14 Sep 2012 16:33:32 +0000
treeherdermozilla-central@6eec6da1392c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs788612
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 788612 - Move bundle handing into nsDOMDeviceStorage to avoid calls to the nsIStringBundleService. r=bent
dom/devicestorage/DeviceStorage.h
dom/devicestorage/nsDeviceStorage.cpp
dom/devicestorage/nsDeviceStorage.h
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -45,19 +45,16 @@ private:
 
   nsresult EnumerateInternal(const JS::Value & aName,
                              const JS::Value & aOptions,
                              JSContext* aCx,
                              uint8_t aArgc, 
                              bool aEditable, 
                              nsIDOMDeviceStorageCursor** aRetval);
 
-  static bool IsMimeTypeCorrectForStorageType(nsAString& aType,
-					      nsIDOMBlob* aBlob);
-
   nsString mStorageType;
   nsCOMPtr<nsIFile> mRootDirectory;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   bool mIsWatchingFile;
   bool mAllowedToWatchFile;
 
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -3,19 +3,21 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/PContentPermissionRequestChild.h"
+#include "mozilla/ClearOnShutdown.h"
 
 #include "nsDeviceStorage.h"
 
+#include "nsAutoPtr.h"
 #include "nsDOMEvent.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIFile.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h"
@@ -45,22 +47,129 @@
 #undef CreateEvent
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolume.h"
 #include "nsIVolumeService.h"
 #endif
 
 #define DEVICESTORAGE_PROPERTIES "chrome://global/content/devicestorage.properties"
+#define DEVICESTORAGE_PICTURES   "pictures"
+#define DEVICESTORAGE_VIDEOS     "videos"
+#define DEVICESTORAGE_MUSIC      "music"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::devicestorage;
 
 #include "nsDirectoryServiceDefs.h"
 
+nsAutoPtr<DeviceStorageTypeChecker> DeviceStorageTypeChecker::sDeviceStorageTypeChecker;
+
+DeviceStorageTypeChecker::DeviceStorageTypeChecker()
+{
+}
+
+DeviceStorageTypeChecker::~DeviceStorageTypeChecker()
+{
+}
+
+DeviceStorageTypeChecker*
+DeviceStorageTypeChecker::CreateOrGet()
+{
+  if (sDeviceStorageTypeChecker) {
+    return sDeviceStorageTypeChecker;
+  }
+
+  NS_ASSERTION(NS_IsMainThread(), "This can only be created on the main thread!");
+
+  nsCOMPtr<nsIStringBundleService> stringService = mozilla::services::GetStringBundleService();
+  if (!stringService) {
+    return nullptr;
+  }
+  
+  nsCOMPtr<nsIStringBundle> filterBundle;
+  if (NS_FAILED(stringService->CreateBundle(DEVICESTORAGE_PROPERTIES, getter_AddRefs(filterBundle)))) {
+    return nullptr;
+  }
+
+  DeviceStorageTypeChecker* result = new DeviceStorageTypeChecker();
+  result->InitFromBundle(filterBundle);
+
+  sDeviceStorageTypeChecker = result;
+  ClearOnShutdown(&sDeviceStorageTypeChecker);
+  return result;
+}
+
+void
+DeviceStorageTypeChecker::InitFromBundle(nsIStringBundle* aBundle)
+{
+  aBundle->GetStringFromName(NS_ConvertASCIItoUTF16(DEVICESTORAGE_PICTURES).get(), getter_Copies(mPicturesExtensions));
+  aBundle->GetStringFromName(NS_ConvertASCIItoUTF16(DEVICESTORAGE_MUSIC).get(), getter_Copies(mMusicExtensions));
+  aBundle->GetStringFromName(NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS).get(), getter_Copies(mVideosExtensions));
+}
+
+
+bool
+DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* aBlob)
+{
+  NS_ASSERTION(aBlob, "Calling Check without a blob");
+
+  nsString mimeType;
+  if (NS_FAILED(aBlob->GetType(mimeType))) {
+    return false;
+  }
+
+  if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) {
+    return StringBeginsWith(mimeType, NS_LITERAL_STRING("image/"));
+  }
+
+  if (aType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) {
+    return StringBeginsWith(mimeType, NS_LITERAL_STRING("video/"));
+  }
+
+  if (aType.EqualsLiteral(DEVICESTORAGE_MUSIC)) {
+    return StringBeginsWith(mimeType, NS_LITERAL_STRING("audio/"));
+  }
+
+  return false;
+}
+
+bool
+DeviceStorageTypeChecker::Check(const nsAString& aType, nsIFile* aFile)
+{
+  NS_ASSERTION(aFile, "Calling Check without a file");
+
+  nsString path;
+  aFile->GetPath(path);
+
+  int32_t dotIdx = path.RFindChar(PRUnichar('.'));
+  if (dotIdx == kNotFound) {
+    return false;
+  }
+
+  nsAutoString extensionMatch;
+  extensionMatch.AssignLiteral("*");
+  extensionMatch.Append(Substring(path, dotIdx));
+  extensionMatch.AppendLiteral(";");
+
+  if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) {
+    return FindInReadable(extensionMatch, mPicturesExtensions);
+  }
+
+  if (aType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) {
+    return FindInReadable(extensionMatch, mVideosExtensions);
+  }
+
+  if (aType.EqualsLiteral(DEVICESTORAGE_MUSIC)) {
+    return FindInReadable(extensionMatch, mMusicExtensions);
+  }
+
+  return false;
+}
+
 class IOEventComplete : public nsRunnable
 {
 public:
   IOEventComplete(DeviceStorageFile *aFile, const char *aType)
     : mFile(aFile)
     , mType(aType)
   {
   }
@@ -91,26 +200,32 @@ DeviceStorageFile::DeviceStorageFile(con
 {
   NS_ASSERTION(aFile, "Must not create a DeviceStorageFile with a null nsIFile");
   // always take a clone
   nsCOMPtr<nsIFile> file;
   aFile->Clone(getter_AddRefs(mFile));
 
   AppendRelativePath();
   NormalizeFilePath();
+
+  DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
+  NS_ASSERTION(typeChecker, "DeviceStorageTypeChecker is null");
 }
 
 DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, nsIFile* aFile)
   : mStorageType(aStorageType)
   , mEditable(false)
 {
   NS_ASSERTION(aFile, "Must not create a DeviceStorageFile with a null nsIFile");
   // always take a clone
   nsCOMPtr<nsIFile> file;
   aFile->Clone(getter_AddRefs(mFile));
+
+  DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
+  NS_ASSERTION(typeChecker, "DeviceStorageTypeChecker is null");
 }
 
 void
 DeviceStorageFile::SetPath(const nsAString& aPath) {
   mPath.Assign(aPath);
   NormalizeFilePath();
 }
 
@@ -145,53 +260,16 @@ DeviceStorageFile::IsSafePath()
         PL_strcmp(token, ".") == 0 ||
         PL_strcmp(token, "..") == 0 ) {
       return false;
     }
   }
   return true;
 }
 
-bool
-DeviceStorageFile::IsType(nsIFile* aFile, const nsAString& aStorageType)
-{
-  // String bundles are cached by the bundle service.
-  nsCOMPtr<nsIStringBundleService> stringService = mozilla::services::GetStringBundleService();
-  if (!stringService) {
-    return false;
-  }
-
-  nsCOMPtr<nsIStringBundle> filterBundle;
-  if (NS_FAILED(stringService->CreateBundle(DEVICESTORAGE_PROPERTIES,
-					    getter_AddRefs(filterBundle)))) {
-    return false;
-  }
-
-  nsString path;
-  aFile->GetPath(path);
-
-  int32_t dotIdx = path.RFindChar(PRUnichar('.'));
-  if (dotIdx == kNotFound) {
-    return false;
-  }
-
-  nsAutoString extensionMatch;
-  extensionMatch.AssignASCII("*");
-  extensionMatch.Append(Substring(path, dotIdx));
-  extensionMatch.AppendASCII(";");
-
-  nsString extensionListStr;
-  if (NS_FAILED(filterBundle->GetStringFromName(aStorageType.BeginReading(),
-						getter_Copies(extensionListStr)))) {
-    return false;
-  }
-
-  return FindInReadable(extensionMatch, extensionListStr);
-}
-
 void
 DeviceStorageFile::NormalizeFilePath() {
 #if defined(XP_WIN)
   PRUnichar* cur = mPath.BeginWriting();
   PRUnichar* end = mPath.EndWriting();
   for (; cur < end; ++cur) {
     if (PRUnichar('\\') == *cur)
       *cur = PRUnichar('/');
@@ -415,16 +493,21 @@ DeviceStorageFile::DirectoryDiskUsage(ns
 
   if (NS_FAILED(rv) || !e) {
     return;
   }
 
   nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
   NS_ASSERTION(files, "GetDirectoryEntries must return a nsIDirectoryEnumerator");
 
+  DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
+  if (!typeChecker) {
+    return;
+  }
+
   nsCOMPtr<nsIFile> f;
   while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) {
     bool isDir;
     rv = f->IsDirectory(&isDir);
     if (NS_FAILED(rv)) {
       continue;
     }
 
@@ -442,17 +525,17 @@ DeviceStorageFile::DirectoryDiskUsage(ns
 
     if (isLink) {
       // for now, lets just totally ignore symlinks.
       NS_WARNING("DirectoryDiskUsage ignores symlinks");
     } else if (isDir) {
       DirectoryDiskUsage(f, aSoFar, aStorageType);
     } else if (isFile) {
 
-      if (!DeviceStorageFile::IsType(f, aStorageType)) {
+      if (!typeChecker->Check(aStorageType, f)) {
 	continue;
       }
 
       int64_t size;
       rv = f->GetFileSize(&size);
       if (NS_SUCCEEDED(rv)) {
 	*aSoFar += size;
       }
@@ -477,21 +560,21 @@ GetSDCardStatus(nsAString& aState) {
 
   int32_t state;
   nsresult rv = vol->GetState(&state);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
 
   if (state == nsIVolume::STATE_MOUNTED) {
-    aState.AssignASCII("available");
+    aState.AssignLiteral("available");
   } else if (state == nsIVolume::STATE_SHARED || state == nsIVolume::STATE_SHAREDMNT) {
-    aState.AssignASCII("shared");
+    aState.AssignLiteral("shared");
   } else {
-    aState.AssignASCII("unavailable");
+    aState.AssignLiteral("unavailable");
   }
   return NS_OK;
 }
 
 static void
 RegisterForSDCardChanges(nsIObserver* aObserver)
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
@@ -784,20 +867,25 @@ ContinueCursorEvent::Run() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   jsval val = JSVAL_NULL;
 
   nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
   nsString cursorStorageType;
   cursor->GetStorageType(cursorStorageType);
 
+  DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
+  if (!typeChecker) {
+    return NS_ERROR_FAILURE;
+  }
+
   while (cursor->mFiles.Length() > 0) {
     nsRefPtr<DeviceStorageFile> file = cursor->mFiles[0];
     cursor->mFiles.RemoveElementAt(0);
-    if (!DeviceStorageFile::IsType(file->mFile, cursorStorageType)) {
+    if (!typeChecker->Check(cursorStorageType, file->mFile)) {
       continue;
     }
     val = nsIFileToJsval(cursor->GetOwner(), file);
     cursor->mOkToCallContinue = true;
     break;
   }
 
   mRequest->FireSuccess(val);
@@ -1556,41 +1644,16 @@ nsDOMDeviceStorage::CreateDeviceStorages
                                             nsDOMDeviceStorage** aStore)
 {
   nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage();
   if (NS_SUCCEEDED(storage->Init(aWin, aType))) {
     NS_ADDREF(*aStore = storage);
   }
 }
 
-bool
-nsDOMDeviceStorage::IsMimeTypeCorrectForStorageType(nsAString& aType, nsIDOMBlob* aBlob)
-{
-  NS_ASSERTION(aBlob, "Calling IsMimeTypeCorrectForStorageType without a blob");
-
-  nsString mimeType;
-  if (NS_FAILED(aBlob->GetType(mimeType))) {
-    return false;
-  }
-
-  if (aType.Equals(NS_LITERAL_STRING("pictures"))) {
-    return StringBeginsWith(mimeType, NS_LITERAL_STRING("image/"));
-  }
-
-  if (aType.Equals(NS_LITERAL_STRING("videos"))) {
-    return StringBeginsWith(mimeType, NS_LITERAL_STRING("video/"));
-  }
-
-  if (aType.Equals(NS_LITERAL_STRING("music"))) {
-    return StringBeginsWith(mimeType, NS_LITERAL_STRING("audio/"));
-  }
-
-  return false;
-}
-
 NS_IMETHODIMP
 nsDOMDeviceStorage::Add(nsIDOMBlob *aBlob, nsIDOMDOMRequest * *_retval)
 {
   if (!aBlob) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIMIMEService> mimeSvc = do_GetService(NS_MIMESERVICE_CONTRACTID);
@@ -1631,23 +1694,29 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob 
   if (aBlob == nullptr)
     return NS_OK;
 
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     return NS_ERROR_UNEXPECTED;
   }
 
+  DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet();
+  if (!typeChecker) {
+    return NS_ERROR_FAILURE;
+  }
+
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   NS_ADDREF(*_retval = request);
 
   nsCOMPtr<nsIRunnable> r;
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory, aPath);
-  if (!DeviceStorageFile::IsType(dsf->mFile, mStorageType) || !IsMimeTypeCorrectForStorageType(mStorageType, aBlob)) {
+  if (!typeChecker->Check(mStorageType, dsf->mFile) ||
+      !typeChecker->Check(mStorageType, aBlob)) {
     r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE, dsf);
   }
   else if (!dsf->IsSafePath()) {
     r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
   }
   else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_WRITE,
 				 win, mPrincipal, dsf, request, aBlob);
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -20,32 +20,54 @@ class nsPIDOMWindow;
 #include "nsIURI.h"
 #include "nsInterfaceHashtable.h"
 #include "nsIPrincipal.h"
 #include "nsString.h"
 #include "nsWeakPtr.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIObserver.h"
+#include "nsIStringBundle.h"
 #include "mozilla/Mutex.h"
 #include "prtime.h"
 #include "DeviceStorage.h"
 
 
 #define POST_ERROR_EVENT_FILE_DOES_NOT_EXIST         "File location doesn't exists"
 #define POST_ERROR_EVENT_FILE_NOT_ENUMERABLE         "File location is not enumerable"
 #define POST_ERROR_EVENT_PERMISSION_DENIED           "Permission Denied"
 #define POST_ERROR_EVENT_ILLEGAL_FILE_NAME           "Illegal file name"
 #define POST_ERROR_EVENT_ILLEGAL_TYPE                "Illegal content type"
 #define POST_ERROR_EVENT_UNKNOWN                     "Unknown"
 #define POST_ERROR_EVENT_NON_STRING_TYPE_UNSUPPORTED "Non-string type unsupported"
 #define POST_ERROR_EVENT_NOT_IMPLEMENTED             "Not implemented"
 
 using namespace mozilla::dom;
 
+class DeviceStorageTypeChecker MOZ_FINAL
+{
+public:
+  static DeviceStorageTypeChecker* CreateOrGet();
+
+  DeviceStorageTypeChecker();
+  ~DeviceStorageTypeChecker();
+
+  void InitFromBundle(nsIStringBundle* aBundle);
+
+  bool Check(const nsAString& aType, nsIDOMBlob* aBlob);
+  bool Check(const nsAString& aType, nsIFile* aFile);
+
+private:
+  nsString mPicturesExtensions;
+  nsString mVideosExtensions;
+  nsString mMusicExtensions;
+
+  static nsAutoPtr<DeviceStorageTypeChecker> sDeviceStorageTypeChecker;
+};
+
 class DeviceStorageFile MOZ_FINAL
   : public nsISupports {
 public:
   nsCOMPtr<nsIFile> mFile;
   nsString mPath;
   nsString mStorageType;
   bool mEditable;
 
@@ -61,17 +83,16 @@ public:
   bool IsSafePath();
 
   nsresult Remove();
   nsresult Write(nsIInputStream* aInputStream);
   nsresult Write(InfallibleTArray<uint8_t>& bits);
   void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRTime aSince = 0);
   void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRTime aSince, nsAString& aRootPath);
 
-  static bool IsType(nsIFile* aFile, const nsAString& aStorageType);
   static void DirectoryDiskUsage(nsIFile* aFile, uint64_t* aSoFar, const nsAString& aStorageType);
 
 private:
   void NormalizeFilePath();
   void AppendRelativePath();
 };
 
 class ContinueCursorEvent MOZ_FINAL: public nsRunnable