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"
12 #include "nsContentUtils.h"
14 // first we need a simple class which wraps a nsIPropertyElement and
15 // cuts out the leading URL from the key
16 class URLPropertyElement
: public nsIPropertyElement
19 URLPropertyElement(nsIPropertyElement
*aRealElement
, uint32_t aURLLength
) :
20 mRealElement(aRealElement
),
21 mURLLength(aURLLength
)
25 NS_DECL_NSIPROPERTYELEMENT
28 nsCOMPtr
<nsIPropertyElement
> mRealElement
;
31 virtual ~URLPropertyElement() {}
34 NS_IMPL_ISUPPORTS(URLPropertyElement
, nsIPropertyElement
)
36 // we'll tweak the key on the way through, and remove the url prefix
38 URLPropertyElement::GetKey(nsACString
& aKey
)
40 nsresult rv
= mRealElement
->GetKey(aKey
);
41 if (NS_FAILED(rv
)) return rv
;
44 aKey
.Cut(0, mURLLength
);
49 // values are unaffected
51 URLPropertyElement::GetValue(nsAString
& aValue
)
53 return mRealElement
->GetValue(aValue
);
56 // setters are kind of strange, hopefully we'll never be called
58 URLPropertyElement::SetKey(const nsACString
& aKey
)
60 // this is just wrong - ideally you'd take the key, append it to
61 // the url, and set that as the key. However, that would require
62 // us to hold onto a copy of the string, and that's a waste,
63 // considering nobody should ever be calling this.
64 NS_ERROR("This makes no sense!");
65 return NS_ERROR_NOT_IMPLEMENTED
;
69 URLPropertyElement::SetValue(const nsAString
& aValue
)
71 return mRealElement
->SetValue(aValue
);
75 // this is a special enumerator which returns only the elements which
76 // are prefixed with a particular url
77 class nsPropertyEnumeratorByURL
: public nsISimpleEnumerator
80 nsPropertyEnumeratorByURL(const nsACString
& aURL
,
81 nsISimpleEnumerator
* aOuter
) :
85 // prepare the url once so we can use its value later
86 // persistent properties uses ":" as a delimiter, so escape
88 mURL
.ReplaceSubstring(":", "%3A");
89 // there is always a # between the url and the real key
94 NS_DECL_NSISIMPLEENUMERATOR
98 // actual enumerator of all strings from nsIProperties
99 nsCOMPtr
<nsISimpleEnumerator
> mOuter
;
101 // the current element that is valid for this url
102 nsCOMPtr
<nsIPropertyElement
> mCurrent
;
104 // the url in question, pre-escaped and with the # already in it
107 virtual ~nsPropertyEnumeratorByURL() {}
111 // nsStringBundleTextOverride implementation
113 NS_IMPL_ISUPPORTS(nsStringBundleTextOverride
,
114 nsIStringBundleOverride
)
117 nsStringBundleTextOverride::Init()
121 // check for existence of custom-strings.txt
123 nsCOMPtr
<nsIFile
> customStringsFile
;
124 rv
= NS_GetSpecialDirectory(NS_APP_CHROME_DIR
,
125 getter_AddRefs(customStringsFile
));
127 if (NS_FAILED(rv
)) return rv
;
129 // bail if not found - this will cause the service creation to
130 // bail as well, and cause this object to go away
132 customStringsFile
->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt"));
135 rv
= customStringsFile
->Exists(&exists
);
136 if (NS_FAILED(rv
) || !exists
)
137 return NS_ERROR_FAILURE
;
139 NS_WARNING("Using custom-strings.txt to override string bundles.");
140 // read in the custom bundle. Keys are in the form
141 // chrome://package/locale/foo.properties:keyname
143 nsAutoCString customStringsURLSpec
;
144 rv
= NS_GetURLSpecFromFile(customStringsFile
, customStringsURLSpec
);
145 if (NS_FAILED(rv
)) return rv
;
147 nsCOMPtr
<nsIURI
> uri
;
148 rv
= NS_NewURI(getter_AddRefs(uri
), customStringsURLSpec
);
149 NS_ENSURE_SUCCESS(rv
, rv
);
151 nsCOMPtr
<nsIChannel
> channel
;
152 rv
= NS_NewChannel(getter_AddRefs(channel
),
154 nsContentUtils::GetSystemPrincipal(),
155 nsILoadInfo::SEC_NORMAL
,
156 nsIContentPolicy::TYPE_OTHER
);
158 NS_ENSURE_SUCCESS(rv
, rv
);
159 nsCOMPtr
<nsIInputStream
> in
;
160 rv
= channel
->Open(getter_AddRefs(in
));
161 NS_ENSURE_SUCCESS(rv
, rv
);
163 static NS_DEFINE_CID(kPersistentPropertiesCID
, NS_IPERSISTENTPROPERTIES_CID
);
164 mValues
= do_CreateInstance(kPersistentPropertiesCID
, &rv
);
165 if (NS_FAILED(rv
)) return rv
;
167 rv
= mValues
->Load(in
);
169 // turn this on to see the contents of custom-strings.txt
171 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
172 mValues
->Enumerate(getter_AddRefs(enumerator
));
173 NS_ASSERTION(enumerator
, "no enumerator!\n");
175 printf("custom-strings.txt contains:\n");
176 printf("----------------------------\n");
179 enumerator
->HasMoreElements(&hasMore
);
181 nsCOMPtr
<nsISupports
> sup
;
182 enumerator
->GetNext(getter_AddRefs(sup
));
184 nsCOMPtr
<nsIPropertyElement
> prop
= do_QueryInterface(sup
);
189 prop
->GetValue(value
);
191 printf("%s = '%s'\n", key
.get(), NS_ConvertUTF16toUTF8(value
).get());
193 enumerator
->HasMoreElements(&hasMore
);
201 nsStringBundleTextOverride::GetStringFromName(const nsACString
& aURL
,
202 const nsACString
& key
,
205 // concatenate url#key to get the key to read
206 nsAutoCString
combinedURL(aURL
+ NS_LITERAL_CSTRING("#") + key
);
208 // persistent properties uses ":" as a delimiter, so escape that character
209 combinedURL
.ReplaceSubstring(":", "%3A");
211 return mValues
->GetStringProperty(combinedURL
, aResult
);
215 nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString
& aURL
,
216 nsISimpleEnumerator
** aResult
)
218 // enumerate all strings, and let the enumerator know
219 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
220 mValues
->Enumerate(getter_AddRefs(enumerator
));
222 // make the enumerator wrapper and pass it off
223 nsPropertyEnumeratorByURL
* propEnum
=
224 new nsPropertyEnumeratorByURL(aURL
, enumerator
);
226 if (!propEnum
) return NS_ERROR_OUT_OF_MEMORY
;
228 NS_ADDREF(*aResult
= propEnum
);
235 // nsPropertyEnumeratorByURL implementation
239 NS_IMPL_ISUPPORTS(nsPropertyEnumeratorByURL
, nsISimpleEnumerator
)
242 nsPropertyEnumeratorByURL::GetNext(nsISupports
**aResult
)
244 if (!mCurrent
) return NS_ERROR_UNEXPECTED
;
246 // wrap mCurrent instead of returning it
247 *aResult
= new URLPropertyElement(mCurrent
, mURL
.Length());
250 // release it so we don't return it twice
257 nsPropertyEnumeratorByURL::HasMoreElements(bool * aResult
)
260 mOuter
->HasMoreElements(&hasMore
);
263 nsCOMPtr
<nsISupports
> supports
;
264 mOuter
->GetNext(getter_AddRefs(supports
));
266 mCurrent
= do_QueryInterface(supports
);
269 nsAutoCString curKey
;
270 mCurrent
->GetKey(curKey
);
272 if (StringBeginsWith(curKey
, mURL
))
276 mOuter
->HasMoreElements(&hasMore
);
282 *aResult
= mCurrent
? true : false;