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