diff options
Diffstat (limited to 'intl/strres/nsStringBundleTextOverride.cpp')
-rw-r--r-- | intl/strres/nsStringBundleTextOverride.cpp | 286 |
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; +} |