1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/strres/src/nsStringBundleTextOverride.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,274 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#include "nsStringBundleTextOverride.h" 1.11 +#include "nsString.h" 1.12 + 1.13 +#include "nsNetUtil.h" 1.14 +#include "nsAppDirectoryServiceDefs.h" 1.15 + 1.16 +// first we need a simple class which wraps a nsIPropertyElement and 1.17 +// cuts out the leading URL from the key 1.18 +class URLPropertyElement : public nsIPropertyElement 1.19 +{ 1.20 +public: 1.21 + URLPropertyElement(nsIPropertyElement *aRealElement, uint32_t aURLLength) : 1.22 + mRealElement(aRealElement), 1.23 + mURLLength(aURLLength) 1.24 + { } 1.25 + virtual ~URLPropertyElement() {} 1.26 + 1.27 + NS_DECL_ISUPPORTS 1.28 + NS_DECL_NSIPROPERTYELEMENT 1.29 + 1.30 +private: 1.31 + nsCOMPtr<nsIPropertyElement> mRealElement; 1.32 + uint32_t mURLLength; 1.33 +}; 1.34 + 1.35 +NS_IMPL_ISUPPORTS(URLPropertyElement, nsIPropertyElement) 1.36 + 1.37 +// we'll tweak the key on the way through, and remove the url prefix 1.38 +NS_IMETHODIMP 1.39 +URLPropertyElement::GetKey(nsACString& aKey) 1.40 +{ 1.41 + nsresult rv = mRealElement->GetKey(aKey); 1.42 + if (NS_FAILED(rv)) return rv; 1.43 + 1.44 + // chop off the url 1.45 + aKey.Cut(0, mURLLength); 1.46 + 1.47 + return NS_OK; 1.48 +} 1.49 + 1.50 +// values are unaffected 1.51 +NS_IMETHODIMP 1.52 +URLPropertyElement::GetValue(nsAString& aValue) 1.53 +{ 1.54 + return mRealElement->GetValue(aValue); 1.55 +} 1.56 + 1.57 +// setters are kind of strange, hopefully we'll never be called 1.58 +NS_IMETHODIMP 1.59 +URLPropertyElement::SetKey(const nsACString& aKey) 1.60 +{ 1.61 + // this is just wrong - ideally you'd take the key, append it to 1.62 + // the url, and set that as the key. However, that would require 1.63 + // us to hold onto a copy of the string, and that's a waste, 1.64 + // considering nobody should ever be calling this. 1.65 + NS_ERROR("This makes no sense!"); 1.66 + return NS_ERROR_NOT_IMPLEMENTED; 1.67 +} 1.68 + 1.69 +NS_IMETHODIMP 1.70 +URLPropertyElement::SetValue(const nsAString& aValue) 1.71 +{ 1.72 + return mRealElement->SetValue(aValue); 1.73 +} 1.74 + 1.75 + 1.76 +// this is a special enumerator which returns only the elements which 1.77 +// are prefixed with a particular url 1.78 +class nsPropertyEnumeratorByURL : public nsISimpleEnumerator 1.79 +{ 1.80 +public: 1.81 + nsPropertyEnumeratorByURL(const nsACString& aURL, 1.82 + nsISimpleEnumerator* aOuter) : 1.83 + mOuter(aOuter), 1.84 + mURL(aURL) 1.85 + { 1.86 + // prepare the url once so we can use its value later 1.87 + // persistent properties uses ":" as a delimiter, so escape 1.88 + // that character 1.89 + mURL.ReplaceSubstring(":", "%3A"); 1.90 + // there is always a # between the url and the real key 1.91 + mURL.Append('#'); 1.92 + } 1.93 + 1.94 + NS_DECL_ISUPPORTS 1.95 + NS_DECL_NSISIMPLEENUMERATOR 1.96 + 1.97 + virtual ~nsPropertyEnumeratorByURL() {} 1.98 +private: 1.99 + 1.100 + // actual enumerator of all strings from nsIProperties 1.101 + nsCOMPtr<nsISimpleEnumerator> mOuter; 1.102 + 1.103 + // the current element that is valid for this url 1.104 + nsCOMPtr<nsIPropertyElement> mCurrent; 1.105 + 1.106 + // the url in question, pre-escaped and with the # already in it 1.107 + nsCString mURL; 1.108 +}; 1.109 + 1.110 +// 1.111 +// nsStringBundleTextOverride implementation 1.112 +// 1.113 +NS_IMPL_ISUPPORTS(nsStringBundleTextOverride, 1.114 + nsIStringBundleOverride) 1.115 + 1.116 +nsresult 1.117 +nsStringBundleTextOverride::Init() 1.118 +{ 1.119 + nsresult rv; 1.120 + 1.121 + // check for existence of custom-strings.txt 1.122 + 1.123 + nsCOMPtr<nsIFile> customStringsFile; 1.124 + rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, 1.125 + getter_AddRefs(customStringsFile)); 1.126 + 1.127 + if (NS_FAILED(rv)) return rv; 1.128 + 1.129 + // bail if not found - this will cause the service creation to 1.130 + // bail as well, and cause this object to go away 1.131 + 1.132 + customStringsFile->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt")); 1.133 + 1.134 + bool exists; 1.135 + rv = customStringsFile->Exists(&exists); 1.136 + if (NS_FAILED(rv) || !exists) 1.137 + return NS_ERROR_FAILURE; 1.138 + 1.139 + NS_WARNING("Using custom-strings.txt to override string bundles."); 1.140 + // read in the custom bundle. Keys are in the form 1.141 + // chrome://package/locale/foo.properties:keyname 1.142 + 1.143 + nsAutoCString customStringsURLSpec; 1.144 + rv = NS_GetURLSpecFromFile(customStringsFile, customStringsURLSpec); 1.145 + if (NS_FAILED(rv)) return rv; 1.146 + 1.147 + nsCOMPtr<nsIURI> uri; 1.148 + rv = NS_NewURI(getter_AddRefs(uri), customStringsURLSpec); 1.149 + if (NS_FAILED(rv)) return rv; 1.150 + 1.151 + nsCOMPtr<nsIInputStream> in; 1.152 + rv = NS_OpenURI(getter_AddRefs(in), uri); 1.153 + if (NS_FAILED(rv)) return rv; 1.154 + 1.155 + static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID); 1.156 + mValues = do_CreateInstance(kPersistentPropertiesCID, &rv); 1.157 + if (NS_FAILED(rv)) return rv; 1.158 + 1.159 + rv = mValues->Load(in); 1.160 + 1.161 + // turn this on to see the contents of custom-strings.txt 1.162 +#ifdef DEBUG_alecf 1.163 + nsCOMPtr<nsISimpleEnumerator> enumerator; 1.164 + mValues->Enumerate(getter_AddRefs(enumerator)); 1.165 + NS_ASSERTION(enumerator, "no enumerator!\n"); 1.166 + 1.167 + printf("custom-strings.txt contains:\n"); 1.168 + printf("----------------------------\n"); 1.169 + 1.170 + bool hasMore; 1.171 + enumerator->HasMoreElements(&hasMore); 1.172 + do { 1.173 + nsCOMPtr<nsISupports> sup; 1.174 + enumerator->GetNext(getter_AddRefs(sup)); 1.175 + 1.176 + nsCOMPtr<nsIPropertyElement> prop = do_QueryInterface(sup); 1.177 + 1.178 + nsAutoCString key; 1.179 + nsAutoString value; 1.180 + prop->GetKey(key); 1.181 + prop->GetValue(value); 1.182 + 1.183 + printf("%s = '%s'\n", key.get(), NS_ConvertUTF16toUTF8(value).get()); 1.184 + 1.185 + enumerator->HasMoreElements(&hasMore); 1.186 + } while (hasMore); 1.187 +#endif 1.188 + 1.189 + return rv; 1.190 +} 1.191 + 1.192 +NS_IMETHODIMP 1.193 +nsStringBundleTextOverride::GetStringFromName(const nsACString& aURL, 1.194 + const nsACString& key, 1.195 + nsAString& aResult) 1.196 +{ 1.197 + // concatenate url#key to get the key to read 1.198 + nsAutoCString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key); 1.199 + 1.200 + // persistent properties uses ":" as a delimiter, so escape that character 1.201 + combinedURL.ReplaceSubstring(":", "%3A"); 1.202 + 1.203 + return mValues->GetStringProperty(combinedURL, aResult); 1.204 +} 1.205 + 1.206 +NS_IMETHODIMP 1.207 +nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL, 1.208 + nsISimpleEnumerator** aResult) 1.209 +{ 1.210 + // enumerate all strings, and let the enumerator know 1.211 + nsCOMPtr<nsISimpleEnumerator> enumerator; 1.212 + mValues->Enumerate(getter_AddRefs(enumerator)); 1.213 + 1.214 + // make the enumerator wrapper and pass it off 1.215 + nsPropertyEnumeratorByURL* propEnum = 1.216 + new nsPropertyEnumeratorByURL(aURL, enumerator); 1.217 + 1.218 + if (!propEnum) return NS_ERROR_OUT_OF_MEMORY; 1.219 + 1.220 + NS_ADDREF(*aResult = propEnum); 1.221 + 1.222 + return NS_OK; 1.223 +} 1.224 + 1.225 + 1.226 +// 1.227 +// nsPropertyEnumeratorByURL implementation 1.228 +// 1.229 + 1.230 + 1.231 +NS_IMPL_ISUPPORTS(nsPropertyEnumeratorByURL, nsISimpleEnumerator) 1.232 + 1.233 +NS_IMETHODIMP 1.234 +nsPropertyEnumeratorByURL::GetNext(nsISupports **aResult) 1.235 +{ 1.236 + if (!mCurrent) return NS_ERROR_UNEXPECTED; 1.237 + 1.238 + // wrap mCurrent instead of returning it 1.239 + *aResult = new URLPropertyElement(mCurrent, mURL.Length()); 1.240 + NS_ADDREF(*aResult); 1.241 + 1.242 + // release it so we don't return it twice 1.243 + mCurrent = nullptr; 1.244 + 1.245 + return NS_OK; 1.246 +} 1.247 + 1.248 +NS_IMETHODIMP 1.249 +nsPropertyEnumeratorByURL::HasMoreElements(bool * aResult) 1.250 +{ 1.251 + bool hasMore; 1.252 + mOuter->HasMoreElements(&hasMore); 1.253 + while (hasMore) { 1.254 + 1.255 + nsCOMPtr<nsISupports> supports; 1.256 + mOuter->GetNext(getter_AddRefs(supports)); 1.257 + 1.258 + mCurrent = do_QueryInterface(supports); 1.259 + 1.260 + if (mCurrent) { 1.261 + nsAutoCString curKey; 1.262 + mCurrent->GetKey(curKey); 1.263 + 1.264 + if (StringBeginsWith(curKey, mURL)) 1.265 + break; 1.266 + } 1.267 + 1.268 + mOuter->HasMoreElements(&hasMore); 1.269 + } 1.270 + 1.271 + if (!hasMore) 1.272 + mCurrent = nullptr; 1.273 + 1.274 + *aResult = mCurrent ? true : false; 1.275 + 1.276 + return NS_OK; 1.277 +}