summaryrefslogtreecommitdiffstats
path: root/intl/strres/nsStringBundleTextOverride.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'intl/strres/nsStringBundleTextOverride.cpp')
-rw-r--r--intl/strres/nsStringBundleTextOverride.cpp286
1 files changed, 286 insertions, 0 deletions
diff --git a/intl/strres/nsStringBundleTextOverride.cpp b/intl/strres/nsStringBundleTextOverride.cpp
new file mode 100644
index 000000000..ec21726d6
--- /dev/null
+++ b/intl/strres/nsStringBundleTextOverride.cpp
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsStringBundleTextOverride.h"
+#include "nsString.h"
+
+#include "nsNetUtil.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsContentUtils.h"
+#include "nsDirectoryServiceUtils.h"
+
+// first we need a simple class which wraps a nsIPropertyElement and
+// cuts out the leading URL from the key
+class URLPropertyElement : public nsIPropertyElement
+{
+public:
+ URLPropertyElement(nsIPropertyElement *aRealElement, uint32_t aURLLength) :
+ mRealElement(aRealElement),
+ mURLLength(aURLLength)
+ { }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROPERTYELEMENT
+
+private:
+ nsCOMPtr<nsIPropertyElement> mRealElement;
+ uint32_t mURLLength;
+
+ virtual ~URLPropertyElement() {}
+};
+
+NS_IMPL_ISUPPORTS(URLPropertyElement, nsIPropertyElement)
+
+// we'll tweak the key on the way through, and remove the url prefix
+NS_IMETHODIMP
+URLPropertyElement::GetKey(nsACString& aKey)
+{
+ nsresult rv = mRealElement->GetKey(aKey);
+ if (NS_FAILED(rv)) return rv;
+
+ // chop off the url
+ aKey.Cut(0, mURLLength);
+
+ return NS_OK;
+}
+
+// values are unaffected
+NS_IMETHODIMP
+URLPropertyElement::GetValue(nsAString& aValue)
+{
+ return mRealElement->GetValue(aValue);
+}
+
+// setters are kind of strange, hopefully we'll never be called
+NS_IMETHODIMP
+URLPropertyElement::SetKey(const nsACString& aKey)
+{
+ // this is just wrong - ideally you'd take the key, append it to
+ // the url, and set that as the key. However, that would require
+ // us to hold onto a copy of the string, and that's a waste,
+ // considering nobody should ever be calling this.
+ NS_ERROR("This makes no sense!");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+URLPropertyElement::SetValue(const nsAString& aValue)
+{
+ return mRealElement->SetValue(aValue);
+}
+
+
+// this is a special enumerator which returns only the elements which
+// are prefixed with a particular url
+class nsPropertyEnumeratorByURL : public nsISimpleEnumerator
+{
+public:
+ nsPropertyEnumeratorByURL(const nsACString& aURL,
+ nsISimpleEnumerator* aOuter) :
+ mOuter(aOuter),
+ mURL(aURL)
+ {
+ // prepare the url once so we can use its value later
+ // persistent properties uses ":" as a delimiter, so escape
+ // that character
+ mURL.ReplaceSubstring(":", "%3A");
+ // there is always a # between the url and the real key
+ mURL.Append('#');
+ }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISIMPLEENUMERATOR
+
+private:
+
+ // actual enumerator of all strings from nsIProperties
+ nsCOMPtr<nsISimpleEnumerator> mOuter;
+
+ // the current element that is valid for this url
+ nsCOMPtr<nsIPropertyElement> mCurrent;
+
+ // the url in question, pre-escaped and with the # already in it
+ nsCString mURL;
+
+ virtual ~nsPropertyEnumeratorByURL() {}
+};
+
+//
+// nsStringBundleTextOverride implementation
+//
+NS_IMPL_ISUPPORTS(nsStringBundleTextOverride,
+ nsIStringBundleOverride)
+
+nsresult
+nsStringBundleTextOverride::Init()
+{
+ nsresult rv;
+
+ // check for existence of custom-strings.txt
+
+ nsCOMPtr<nsIFile> customStringsFile;
+ rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR,
+ getter_AddRefs(customStringsFile));
+
+ if (NS_FAILED(rv)) return rv;
+
+ // bail if not found - this will cause the service creation to
+ // bail as well, and cause this object to go away
+
+ customStringsFile->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt"));
+
+ bool exists;
+ rv = customStringsFile->Exists(&exists);
+ if (NS_FAILED(rv) || !exists)
+ return NS_ERROR_FAILURE;
+
+ NS_WARNING("Using custom-strings.txt to override string bundles.");
+ // read in the custom bundle. Keys are in the form
+ // chrome://package/locale/foo.properties:keyname
+
+ nsAutoCString customStringsURLSpec;
+ rv = NS_GetURLSpecFromFile(customStringsFile, customStringsURLSpec);
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI(getter_AddRefs(uri), customStringsURLSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIChannel> channel;
+ rv = NS_NewChannel(getter_AddRefs(channel),
+ uri,
+ nsContentUtils::GetSystemPrincipal(),
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
+ nsIContentPolicy::TYPE_OTHER);
+
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIInputStream> in;
+ rv = channel->Open2(getter_AddRefs(in));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID);
+ mValues = do_CreateInstance(kPersistentPropertiesCID, &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = mValues->Load(in);
+
+ // turn this on to see the contents of custom-strings.txt
+#ifdef DEBUG_alecf
+ nsCOMPtr<nsISimpleEnumerator> enumerator;
+ mValues->Enumerate(getter_AddRefs(enumerator));
+ NS_ASSERTION(enumerator, "no enumerator!\n");
+
+ printf("custom-strings.txt contains:\n");
+ printf("----------------------------\n");
+
+ bool hasMore;
+ enumerator->HasMoreElements(&hasMore);
+ do {
+ nsCOMPtr<nsISupports> sup;
+ enumerator->GetNext(getter_AddRefs(sup));
+
+ nsCOMPtr<nsIPropertyElement> prop = do_QueryInterface(sup);
+
+ nsAutoCString key;
+ nsAutoString value;
+ prop->GetKey(key);
+ prop->GetValue(value);
+
+ printf("%s = '%s'\n", key.get(), NS_ConvertUTF16toUTF8(value).get());
+
+ enumerator->HasMoreElements(&hasMore);
+ } while (hasMore);
+#endif
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsStringBundleTextOverride::GetStringFromName(const nsACString& aURL,
+ const nsACString& key,
+ nsAString& aResult)
+{
+ // concatenate url#key to get the key to read
+ nsAutoCString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key);
+
+ // persistent properties uses ":" as a delimiter, so escape that character
+ combinedURL.ReplaceSubstring(":", "%3A");
+
+ return mValues->GetStringProperty(combinedURL, aResult);
+}
+
+NS_IMETHODIMP
+nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL,
+ nsISimpleEnumerator** aResult)
+{
+ // enumerate all strings, and let the enumerator know
+ nsCOMPtr<nsISimpleEnumerator> enumerator;
+ mValues->Enumerate(getter_AddRefs(enumerator));
+
+ // make the enumerator wrapper and pass it off
+ nsPropertyEnumeratorByURL* propEnum =
+ new nsPropertyEnumeratorByURL(aURL, enumerator);
+
+ if (!propEnum) return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(*aResult = propEnum);
+
+ return NS_OK;
+}
+
+
+//
+// nsPropertyEnumeratorByURL implementation
+//
+
+
+NS_IMPL_ISUPPORTS(nsPropertyEnumeratorByURL, nsISimpleEnumerator)
+
+NS_IMETHODIMP
+nsPropertyEnumeratorByURL::GetNext(nsISupports **aResult)
+{
+ if (!mCurrent) return NS_ERROR_UNEXPECTED;
+
+ // wrap mCurrent instead of returning it
+ *aResult = new URLPropertyElement(mCurrent, mURL.Length());
+ NS_ADDREF(*aResult);
+
+ // release it so we don't return it twice
+ mCurrent = nullptr;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPropertyEnumeratorByURL::HasMoreElements(bool * aResult)
+{
+ bool hasMore;
+ mOuter->HasMoreElements(&hasMore);
+ while (hasMore) {
+
+ nsCOMPtr<nsISupports> supports;
+ mOuter->GetNext(getter_AddRefs(supports));
+
+ mCurrent = do_QueryInterface(supports);
+
+ if (mCurrent) {
+ nsAutoCString curKey;
+ mCurrent->GetKey(curKey);
+
+ if (StringBeginsWith(curKey, mURL))
+ break;
+ }
+
+ mOuter->HasMoreElements(&hasMore);
+ }
+
+ if (!hasMore)
+ mCurrent = nullptr;
+
+ *aResult = mCurrent ? true : false;
+
+ return NS_OK;
+}