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/. */
7 #include "nsStringBundleTextOverride.h"
10 #include "nsNetUtil.h"
11 #include "nsAppDirectoryServiceDefs.h"
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
18 URLPropertyElement(nsIPropertyElement
*aRealElement
, uint32_t aURLLength
) :
19 mRealElement(aRealElement
),
20 mURLLength(aURLLength
)
24 NS_DECL_NSIPROPERTYELEMENT
27 nsCOMPtr
<nsIPropertyElement
> mRealElement
;
30 virtual ~URLPropertyElement() {}
33 NS_IMPL_ISUPPORTS(URLPropertyElement
, nsIPropertyElement
)
35 // we'll tweak the key on the way through, and remove the url prefix
37 URLPropertyElement::GetKey(nsACString
& aKey
)
39 nsresult rv
= mRealElement
->GetKey(aKey
);
40 if (NS_FAILED(rv
)) return rv
;
43 aKey
.Cut(0, mURLLength
);
48 // values are unaffected
50 URLPropertyElement::GetValue(nsAString
& aValue
)
52 return mRealElement
->GetValue(aValue
);
55 // setters are kind of strange, hopefully we'll never be called
57 URLPropertyElement::SetKey(const nsACString
& aKey
)
59 // this is just wrong - ideally you'd take the key, append it to
60 // the url, and set that as the key. However, that would require
61 // us to hold onto a copy of the string, and that's a waste,
62 // considering nobody should ever be calling this.
63 NS_ERROR("This makes no sense!");
64 return NS_ERROR_NOT_IMPLEMENTED
;
68 URLPropertyElement::SetValue(const nsAString
& aValue
)
70 return mRealElement
->SetValue(aValue
);
74 // this is a special enumerator which returns only the elements which
75 // are prefixed with a particular url
76 class nsPropertyEnumeratorByURL
: public nsISimpleEnumerator
79 nsPropertyEnumeratorByURL(const nsACString
& aURL
,
80 nsISimpleEnumerator
* aOuter
) :
84 // prepare the url once so we can use its value later
85 // persistent properties uses ":" as a delimiter, so escape
87 mURL
.ReplaceSubstring(":", "%3A");
88 // there is always a # between the url and the real key
93 NS_DECL_NSISIMPLEENUMERATOR
97 // actual enumerator of all strings from nsIProperties
98 nsCOMPtr
<nsISimpleEnumerator
> mOuter
;
100 // the current element that is valid for this url
101 nsCOMPtr
<nsIPropertyElement
> mCurrent
;
103 // the url in question, pre-escaped and with the # already in it
106 virtual ~nsPropertyEnumeratorByURL() {}
110 // nsStringBundleTextOverride implementation
112 NS_IMPL_ISUPPORTS(nsStringBundleTextOverride
,
113 nsIStringBundleOverride
)
116 nsStringBundleTextOverride::Init()
120 // check for existence of custom-strings.txt
122 nsCOMPtr
<nsIFile
> customStringsFile
;
123 rv
= NS_GetSpecialDirectory(NS_APP_CHROME_DIR
,
124 getter_AddRefs(customStringsFile
));
126 if (NS_FAILED(rv
)) return rv
;
128 // bail if not found - this will cause the service creation to
129 // bail as well, and cause this object to go away
131 customStringsFile
->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt"));
134 rv
= customStringsFile
->Exists(&exists
);
135 if (NS_FAILED(rv
) || !exists
)
136 return NS_ERROR_FAILURE
;
138 NS_WARNING("Using custom-strings.txt to override string bundles.");
139 // read in the custom bundle. Keys are in the form
140 // chrome://package/locale/foo.properties:keyname
142 nsAutoCString customStringsURLSpec
;
143 rv
= NS_GetURLSpecFromFile(customStringsFile
, customStringsURLSpec
);
144 if (NS_FAILED(rv
)) return rv
;
146 nsCOMPtr
<nsIURI
> uri
;
147 rv
= NS_NewURI(getter_AddRefs(uri
), customStringsURLSpec
);
148 if (NS_FAILED(rv
)) return rv
;
150 nsCOMPtr
<nsIInputStream
> in
;
151 rv
= NS_OpenURI(getter_AddRefs(in
), uri
);
152 if (NS_FAILED(rv
)) return rv
;
154 static NS_DEFINE_CID(kPersistentPropertiesCID
, NS_IPERSISTENTPROPERTIES_CID
);
155 mValues
= do_CreateInstance(kPersistentPropertiesCID
, &rv
);
156 if (NS_FAILED(rv
)) return rv
;
158 rv
= mValues
->Load(in
);
160 // turn this on to see the contents of custom-strings.txt
162 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
163 mValues
->Enumerate(getter_AddRefs(enumerator
));
164 NS_ASSERTION(enumerator
, "no enumerator!\n");
166 printf("custom-strings.txt contains:\n");
167 printf("----------------------------\n");
170 enumerator
->HasMoreElements(&hasMore
);
172 nsCOMPtr
<nsISupports
> sup
;
173 enumerator
->GetNext(getter_AddRefs(sup
));
175 nsCOMPtr
<nsIPropertyElement
> prop
= do_QueryInterface(sup
);
180 prop
->GetValue(value
);
182 printf("%s = '%s'\n", key
.get(), NS_ConvertUTF16toUTF8(value
).get());
184 enumerator
->HasMoreElements(&hasMore
);
192 nsStringBundleTextOverride::GetStringFromName(const nsACString
& aURL
,
193 const nsACString
& key
,
196 // concatenate url#key to get the key to read
197 nsAutoCString
combinedURL(aURL
+ NS_LITERAL_CSTRING("#") + key
);
199 // persistent properties uses ":" as a delimiter, so escape that character
200 combinedURL
.ReplaceSubstring(":", "%3A");
202 return mValues
->GetStringProperty(combinedURL
, aResult
);
206 nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString
& aURL
,
207 nsISimpleEnumerator
** aResult
)
209 // enumerate all strings, and let the enumerator know
210 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
211 mValues
->Enumerate(getter_AddRefs(enumerator
));
213 // make the enumerator wrapper and pass it off
214 nsPropertyEnumeratorByURL
* propEnum
=
215 new nsPropertyEnumeratorByURL(aURL
, enumerator
);
217 if (!propEnum
) return NS_ERROR_OUT_OF_MEMORY
;
219 NS_ADDREF(*aResult
= propEnum
);
226 // nsPropertyEnumeratorByURL implementation
230 NS_IMPL_ISUPPORTS(nsPropertyEnumeratorByURL
, nsISimpleEnumerator
)
233 nsPropertyEnumeratorByURL::GetNext(nsISupports
**aResult
)
235 if (!mCurrent
) return NS_ERROR_UNEXPECTED
;
237 // wrap mCurrent instead of returning it
238 *aResult
= new URLPropertyElement(mCurrent
, mURL
.Length());
241 // release it so we don't return it twice
248 nsPropertyEnumeratorByURL::HasMoreElements(bool * aResult
)
251 mOuter
->HasMoreElements(&hasMore
);
254 nsCOMPtr
<nsISupports
> supports
;
255 mOuter
->GetNext(getter_AddRefs(supports
));
257 mCurrent
= do_QueryInterface(supports
);
260 nsAutoCString curKey
;
261 mCurrent
->GetKey(curKey
);
263 if (StringBeginsWith(curKey
, mURL
))
267 mOuter
->HasMoreElements(&hasMore
);
273 *aResult
= mCurrent
? true : false;