Back to index

lightning-sunbird  0.9+nobinonly
nsStringBundleTextOverride.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the string bundle override service.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corp.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Alec Flett <alecf@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "nsStringBundleTextOverride.h"
00041 #include "nsString.h"
00042 #include "nsEscape.h"
00043 
00044 #include "nsNetUtil.h"
00045 #include "nsAppDirectoryServiceDefs.h"
00046 
00047 static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID);
00048 
00049 
00050 // first we need a simple class which wraps a nsIPropertyElement and
00051 // cuts out the leading URL from the key
00052 class URLPropertyElement : public nsIPropertyElement
00053 {
00054 public:
00055     URLPropertyElement(nsIPropertyElement *aRealElement, PRUint32 aURLLength) :
00056         mRealElement(aRealElement),
00057         mURLLength(aURLLength)
00058     { }
00059     virtual ~URLPropertyElement() {}
00060 
00061     NS_DECL_ISUPPORTS
00062     NS_DECL_NSIPROPERTYELEMENT
00063     
00064 private:
00065     nsCOMPtr<nsIPropertyElement> mRealElement;
00066     PRUint32 mURLLength;
00067 };
00068 
00069 NS_IMPL_ISUPPORTS1(URLPropertyElement, nsIPropertyElement)
00070 
00071 // we'll tweak the key on the way through, and remove the url prefix
00072 NS_IMETHODIMP
00073 URLPropertyElement::GetKey(nsACString& aKey)
00074 {
00075     nsresult rv =  mRealElement->GetKey(aKey);
00076     if (NS_FAILED(rv)) return rv;
00077 
00078     // chop off the url
00079     aKey.Cut(0, mURLLength);
00080     
00081     return NS_OK;
00082 }
00083 
00084 // values are unaffected
00085 NS_IMETHODIMP
00086 URLPropertyElement::GetValue(nsAString& aValue)
00087 {
00088     return mRealElement->GetValue(aValue);
00089 }
00090 
00091 // setters are kind of strange, hopefully we'll never be called
00092 NS_IMETHODIMP
00093 URLPropertyElement::SetKey(const nsACString& aKey)
00094 {
00095     // this is just wrong - ideally you'd take the key, append it to
00096     // the url, and set that as the key. However, that would require
00097     // us to hold onto a copy of the string, and thats a waste,
00098     // considering nobody should ever be calling this.
00099     NS_ASSERTION(0, "This makes no sense!");
00100     return NS_ERROR_NOT_IMPLEMENTED;
00101 }
00102 
00103 NS_IMETHODIMP
00104 URLPropertyElement::SetValue(const nsAString& aValue)
00105 {
00106     return mRealElement->SetValue(aValue);
00107 }
00108 
00109 
00110 // this is a special enumerator which returns only the elements which
00111 // are prefixed with a particular url
00112 class nsPropertyEnumeratorByURL : public nsISimpleEnumerator
00113 {
00114 public:
00115     nsPropertyEnumeratorByURL(const nsACString& aURL,
00116                               nsISimpleEnumerator* aOuter) :
00117         mOuter(aOuter),
00118         mURL(aURL)
00119     {
00120         // prepare the url once so we can use its value later
00121         // persistent properties uses ":" as a delimiter, so escape
00122         // that character
00123         mURL.ReplaceSubstring(":", "%3A");
00124         // there is always a # between the url and the real key
00125         mURL.Append('#');
00126     }
00127 
00128     NS_DECL_ISUPPORTS
00129     NS_DECL_NSISIMPLEENUMERATOR
00130     
00131     virtual ~nsPropertyEnumeratorByURL() {}
00132 private:
00133 
00134     // actual enumerator of all strings from nsIProperties
00135     nsCOMPtr<nsISimpleEnumerator> mOuter;
00136 
00137     // the current element that is valid for this url
00138     nsCOMPtr<nsIPropertyElement> mCurrent;
00139 
00140     // the url in question, pre-escaped and with the # already in it
00141     nsCString mURL;
00142 };
00143 
00144 //
00145 // nsStringBundleTextOverride implementation
00146 //
00147 NS_IMPL_ISUPPORTS1(nsStringBundleTextOverride,
00148                    nsIStringBundleOverride)
00149 
00150 nsresult
00151 nsStringBundleTextOverride::Init()
00152 {
00153     nsresult rv;
00154 
00155     // check for existence of custom-strings.txt
00156 
00157     nsCOMPtr<nsIFile> customStringsFile;
00158     rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR,
00159                                 getter_AddRefs(customStringsFile));
00160 
00161     if (NS_FAILED(rv)) return rv;
00162 
00163     // bail if not found - this will cause the service creation to
00164     // bail as well, and cause this object to go away
00165 
00166     customStringsFile->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt"));
00167 
00168     PRBool exists;
00169     rv = customStringsFile->Exists(&exists);
00170     if (NS_FAILED(rv) || !exists)
00171         return NS_ERROR_FAILURE;
00172 
00173     NS_WARNING("Using custom-strings.txt to override string bundles.");
00174     // read in the custom bundle. Keys are in the form
00175     // chrome://package/locale/foo.properties:keyname
00176 
00177     nsCAutoString customStringsURLSpec;
00178     rv = NS_GetURLSpecFromFile(customStringsFile, customStringsURLSpec);
00179     if (NS_FAILED(rv)) return rv;
00180     
00181     nsCOMPtr<nsIURI> uri;
00182     rv = NS_NewURI(getter_AddRefs(uri), customStringsURLSpec);
00183     if (NS_FAILED(rv)) return rv;
00184 
00185     nsCOMPtr<nsIInputStream> in;
00186     rv = NS_OpenURI(getter_AddRefs(in), uri);
00187     if (NS_FAILED(rv)) return rv;
00188 
00189     mValues = do_CreateInstance(kPersistentPropertiesCID, &rv);
00190     if (NS_FAILED(rv)) return rv;
00191 
00192     rv = mValues->Load(in);
00193 
00194     // turn this on to see the contents of custom-strings.txt
00195 #ifdef DEBUG_alecf
00196     nsCOMPtr<nsISimpleEnumerator> enumerator;
00197     mValues->Enumerate(getter_AddRefs(enumerator));
00198     NS_ASSERTION(enumerator, "no enumerator!\n");
00199     
00200     printf("custom-strings.txt contains:\n");
00201     printf("----------------------------\n");
00202 
00203     PRBool hasMore;
00204     enumerator->HasMoreElements(&hasMore);
00205     do {
00206         nsCOMPtr<nsISupports> sup;
00207         enumerator->GetNext(getter_AddRefs(sup));
00208 
00209         nsCOMPtr<nsIPropertyElement> prop = do_QueryInterface(sup);
00210 
00211         nsCAutoString key;
00212         nsAutoString value;
00213         prop->GetKey(key);
00214         prop->GetValue(value);
00215 
00216         printf("%s = '%s'\n", key.get(), NS_ConvertUCS2toUTF8(value).get());
00217 
00218         enumerator->HasMoreElements(&hasMore);
00219     } while (hasMore);
00220 #endif
00221     
00222     return rv;
00223 }
00224 
00225 NS_IMETHODIMP
00226 nsStringBundleTextOverride::GetStringFromName(const nsACString& aURL,
00227                                               const nsACString& key,
00228                                               nsAString& aResult)
00229 {
00230     // concatenate url#key to get the key to read
00231     nsCAutoString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key);
00232 
00233     // persistent properties uses ":" as a delimiter, so escape that character
00234     combinedURL.ReplaceSubstring(":", "%3A");
00235 
00236     return mValues->GetStringProperty(combinedURL, aResult);
00237 }
00238 
00239 NS_IMETHODIMP
00240 nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL,
00241                                                   nsISimpleEnumerator** aResult)
00242 {
00243     // enumerate all strings, and let the enumerator know
00244     nsCOMPtr<nsISimpleEnumerator> enumerator;
00245     mValues->Enumerate(getter_AddRefs(enumerator));
00246 
00247     // make the enumerator wrapper and pass it off
00248     nsPropertyEnumeratorByURL* propEnum =
00249         new nsPropertyEnumeratorByURL(aURL, enumerator);
00250 
00251     if (!propEnum) return NS_ERROR_OUT_OF_MEMORY;
00252     
00253     NS_ADDREF(*aResult = propEnum);
00254     
00255     return NS_OK;
00256 }
00257 
00258 
00259 //
00260 // nsPropertyEnumeratorByURL implementation
00261 //
00262 
00263 
00264 NS_IMPL_ISUPPORTS1(nsPropertyEnumeratorByURL, nsISimpleEnumerator)
00265 
00266 NS_IMETHODIMP
00267 nsPropertyEnumeratorByURL::GetNext(nsISupports **aResult)
00268 {
00269     if (!mCurrent) return NS_ERROR_UNEXPECTED;
00270 
00271     // wrap mCurrent instead of returning it
00272     *aResult = new URLPropertyElement(mCurrent, mURL.Length());
00273     NS_ADDREF(*aResult);
00274 
00275     // release it so we don't return it twice
00276     mCurrent = nsnull;
00277     
00278     return NS_OK;
00279 }
00280 
00281 NS_IMETHODIMP
00282 nsPropertyEnumeratorByURL::HasMoreElements(PRBool * aResult)
00283 {
00284     PRBool hasMore;
00285     mOuter->HasMoreElements(&hasMore);
00286     while (hasMore) {
00287 
00288         nsCOMPtr<nsISupports> supports;
00289         mOuter->GetNext(getter_AddRefs(supports));
00290 
00291         mCurrent = do_QueryInterface(supports);
00292 
00293         if (mCurrent) {
00294             nsCAutoString curKey;
00295             mCurrent->GetKey(curKey);
00296         
00297             if (StringBeginsWith(curKey, mURL))
00298                 break;
00299         }
00300         
00301         mOuter->HasMoreElements(&hasMore);
00302     }
00303 
00304     if (!hasMore)
00305         mCurrent = PR_FALSE;
00306     
00307     *aResult = mCurrent ? PR_TRUE : PR_FALSE;
00308     
00309     return NS_OK;
00310 }