Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 :
7 : #include "nsStringBundleTextOverride.h"
8 : #include "nsString.h"
9 :
10 : #include "nsNetUtil.h"
11 : #include "nsAppDirectoryServiceDefs.h"
12 : #include "nsContentUtils.h"
13 : #include "nsDirectoryServiceUtils.h"
14 :
15 : // first we need a simple class which wraps a nsIPropertyElement and
16 : // cuts out the leading URL from the key
17 : class URLPropertyElement : public nsIPropertyElement
18 : {
19 : public:
20 0 : URLPropertyElement(nsIPropertyElement *aRealElement, uint32_t aURLLength) :
21 : mRealElement(aRealElement),
22 0 : mURLLength(aURLLength)
23 0 : { }
24 :
25 : NS_DECL_ISUPPORTS
26 : NS_DECL_NSIPROPERTYELEMENT
27 :
28 : private:
29 : nsCOMPtr<nsIPropertyElement> mRealElement;
30 : uint32_t mURLLength;
31 :
32 0 : virtual ~URLPropertyElement() {}
33 : };
34 :
35 0 : NS_IMPL_ISUPPORTS(URLPropertyElement, nsIPropertyElement)
36 :
37 : // we'll tweak the key on the way through, and remove the url prefix
38 : NS_IMETHODIMP
39 0 : URLPropertyElement::GetKey(nsACString& aKey)
40 : {
41 0 : nsresult rv = mRealElement->GetKey(aKey);
42 0 : if (NS_FAILED(rv)) return rv;
43 :
44 : // chop off the url
45 0 : aKey.Cut(0, mURLLength);
46 :
47 0 : return NS_OK;
48 : }
49 :
50 : // values are unaffected
51 : NS_IMETHODIMP
52 0 : URLPropertyElement::GetValue(nsAString& aValue)
53 : {
54 0 : return mRealElement->GetValue(aValue);
55 : }
56 :
57 : // setters are kind of strange, hopefully we'll never be called
58 : NS_IMETHODIMP
59 0 : URLPropertyElement::SetKey(const nsACString& aKey)
60 : {
61 : // this is just wrong - ideally you'd take the key, append it to
62 : // the url, and set that as the key. However, that would require
63 : // us to hold onto a copy of the string, and that's a waste,
64 : // considering nobody should ever be calling this.
65 0 : NS_ERROR("This makes no sense!");
66 0 : return NS_ERROR_NOT_IMPLEMENTED;
67 : }
68 :
69 : NS_IMETHODIMP
70 0 : URLPropertyElement::SetValue(const nsAString& aValue)
71 : {
72 0 : return mRealElement->SetValue(aValue);
73 : }
74 :
75 :
76 : // this is a special enumerator which returns only the elements which
77 : // are prefixed with a particular url
78 : class nsPropertyEnumeratorByURL : public nsISimpleEnumerator
79 : {
80 : public:
81 0 : nsPropertyEnumeratorByURL(const nsACString& aURL,
82 0 : nsISimpleEnumerator* aOuter) :
83 : mOuter(aOuter),
84 0 : mURL(aURL)
85 : {
86 : // prepare the url once so we can use its value later
87 : // persistent properties uses ":" as a delimiter, so escape
88 : // that character
89 0 : mURL.ReplaceSubstring(":", "%3A");
90 : // there is always a # between the url and the real key
91 0 : mURL.Append('#');
92 0 : }
93 :
94 : NS_DECL_ISUPPORTS
95 : NS_DECL_NSISIMPLEENUMERATOR
96 :
97 : private:
98 :
99 : // actual enumerator of all strings from nsIProperties
100 : nsCOMPtr<nsISimpleEnumerator> mOuter;
101 :
102 : // the current element that is valid for this url
103 : nsCOMPtr<nsIPropertyElement> mCurrent;
104 :
105 : // the url in question, pre-escaped and with the # already in it
106 : nsCString mURL;
107 :
108 0 : virtual ~nsPropertyEnumeratorByURL() {}
109 : };
110 :
111 : //
112 : // nsStringBundleTextOverride implementation
113 : //
114 6 : NS_IMPL_ISUPPORTS(nsStringBundleTextOverride,
115 : nsIStringBundleOverride)
116 :
117 : nsresult
118 3 : nsStringBundleTextOverride::Init()
119 : {
120 : nsresult rv;
121 :
122 : // check for existence of custom-strings.txt
123 :
124 6 : nsCOMPtr<nsIFile> customStringsFile;
125 3 : rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR,
126 6 : getter_AddRefs(customStringsFile));
127 :
128 3 : if (NS_FAILED(rv)) return rv;
129 :
130 : // bail if not found - this will cause the service creation to
131 : // bail as well, and cause this object to go away
132 :
133 3 : customStringsFile->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt"));
134 :
135 : bool exists;
136 3 : rv = customStringsFile->Exists(&exists);
137 3 : if (NS_FAILED(rv) || !exists)
138 3 : return NS_ERROR_FAILURE;
139 :
140 0 : NS_WARNING("Using custom-strings.txt to override string bundles.");
141 : // read in the custom bundle. Keys are in the form
142 : // chrome://package/locale/foo.properties:keyname
143 :
144 0 : nsAutoCString customStringsURLSpec;
145 0 : rv = NS_GetURLSpecFromFile(customStringsFile, customStringsURLSpec);
146 0 : if (NS_FAILED(rv)) return rv;
147 :
148 0 : nsCOMPtr<nsIURI> uri;
149 0 : rv = NS_NewURI(getter_AddRefs(uri), customStringsURLSpec);
150 0 : NS_ENSURE_SUCCESS(rv, rv);
151 :
152 0 : nsCOMPtr<nsIChannel> channel;
153 0 : rv = NS_NewChannel(getter_AddRefs(channel),
154 : uri,
155 : nsContentUtils::GetSystemPrincipal(),
156 : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
157 : nsIContentPolicy::TYPE_OTHER);
158 :
159 0 : NS_ENSURE_SUCCESS(rv, rv);
160 0 : nsCOMPtr<nsIInputStream> in;
161 0 : rv = channel->Open2(getter_AddRefs(in));
162 0 : NS_ENSURE_SUCCESS(rv, rv);
163 :
164 : static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID);
165 0 : mValues = do_CreateInstance(kPersistentPropertiesCID, &rv);
166 0 : if (NS_FAILED(rv)) return rv;
167 :
168 0 : rv = mValues->Load(in);
169 :
170 : // turn this on to see the contents of custom-strings.txt
171 : #ifdef DEBUG_alecf
172 : nsCOMPtr<nsISimpleEnumerator> enumerator;
173 : mValues->Enumerate(getter_AddRefs(enumerator));
174 : NS_ASSERTION(enumerator, "no enumerator!\n");
175 :
176 : printf("custom-strings.txt contains:\n");
177 : printf("----------------------------\n");
178 :
179 : bool hasMore;
180 : enumerator->HasMoreElements(&hasMore);
181 : do {
182 : nsCOMPtr<nsISupports> sup;
183 : enumerator->GetNext(getter_AddRefs(sup));
184 :
185 : nsCOMPtr<nsIPropertyElement> prop = do_QueryInterface(sup);
186 :
187 : nsAutoCString key;
188 : nsAutoString value;
189 : prop->GetKey(key);
190 : prop->GetValue(value);
191 :
192 : printf("%s = '%s'\n", key.get(), NS_ConvertUTF16toUTF8(value).get());
193 :
194 : enumerator->HasMoreElements(&hasMore);
195 : } while (hasMore);
196 : #endif
197 :
198 0 : return rv;
199 : }
200 :
201 : NS_IMETHODIMP
202 0 : nsStringBundleTextOverride::GetStringFromName(const nsACString& aURL,
203 : const nsACString& key,
204 : nsAString& aResult)
205 : {
206 : // concatenate url#key to get the key to read
207 0 : nsAutoCString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key);
208 :
209 : // persistent properties uses ":" as a delimiter, so escape that character
210 0 : combinedURL.ReplaceSubstring(":", "%3A");
211 :
212 0 : return mValues->GetStringProperty(combinedURL, aResult);
213 : }
214 :
215 : NS_IMETHODIMP
216 0 : nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL,
217 : nsISimpleEnumerator** aResult)
218 : {
219 : // enumerate all strings, and let the enumerator know
220 0 : nsCOMPtr<nsISimpleEnumerator> enumerator;
221 0 : mValues->Enumerate(getter_AddRefs(enumerator));
222 :
223 : // make the enumerator wrapper and pass it off
224 : nsPropertyEnumeratorByURL* propEnum =
225 0 : new nsPropertyEnumeratorByURL(aURL, enumerator);
226 :
227 0 : if (!propEnum) return NS_ERROR_OUT_OF_MEMORY;
228 :
229 0 : NS_ADDREF(*aResult = propEnum);
230 :
231 0 : return NS_OK;
232 : }
233 :
234 :
235 : //
236 : // nsPropertyEnumeratorByURL implementation
237 : //
238 :
239 :
240 0 : NS_IMPL_ISUPPORTS(nsPropertyEnumeratorByURL, nsISimpleEnumerator)
241 :
242 : NS_IMETHODIMP
243 0 : nsPropertyEnumeratorByURL::GetNext(nsISupports **aResult)
244 : {
245 0 : if (!mCurrent) return NS_ERROR_UNEXPECTED;
246 :
247 : // wrap mCurrent instead of returning it
248 0 : *aResult = new URLPropertyElement(mCurrent, mURL.Length());
249 0 : NS_ADDREF(*aResult);
250 :
251 : // release it so we don't return it twice
252 0 : mCurrent = nullptr;
253 :
254 0 : return NS_OK;
255 : }
256 :
257 : NS_IMETHODIMP
258 0 : nsPropertyEnumeratorByURL::HasMoreElements(bool * aResult)
259 : {
260 : bool hasMore;
261 0 : mOuter->HasMoreElements(&hasMore);
262 0 : while (hasMore) {
263 :
264 0 : nsCOMPtr<nsISupports> supports;
265 0 : mOuter->GetNext(getter_AddRefs(supports));
266 :
267 0 : mCurrent = do_QueryInterface(supports);
268 :
269 0 : if (mCurrent) {
270 0 : nsAutoCString curKey;
271 0 : mCurrent->GetKey(curKey);
272 :
273 0 : if (StringBeginsWith(curKey, mURL))
274 0 : break;
275 : }
276 :
277 0 : mOuter->HasMoreElements(&hasMore);
278 : }
279 :
280 0 : if (!hasMore)
281 0 : mCurrent = nullptr;
282 :
283 0 : *aResult = mCurrent ? true : false;
284 :
285 0 : return NS_OK;
286 : }
|