gecko/intl/strres/nsStringBundleTextOverride.cpp

287 lines
7.9 KiB
C++

/* -*- 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;
}