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