Back to index

lightning-sunbird  0.9+nobinonly
nsUnicharUtils.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 Unicode case conversion helpers.
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 #include "nsString.h"
00040 #include "nsUnicharUtils.h"
00041 #include "nsUnicharUtilCIID.h"
00042 #include "nsICaseConversion.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsCRT.h"
00045 
00046 #include "nsIObserver.h"
00047 #include "nsIObserverService.h"
00048 
00049 // global cache of the case conversion service
00050 static nsICaseConversion *gCaseConv = nsnull;
00051 
00052 class nsShutdownObserver : public nsIObserver
00053 {
00054 public:
00055     nsShutdownObserver() { }
00056     virtual ~nsShutdownObserver() {}
00057     NS_DECL_ISUPPORTS
00058     
00059     NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
00060                        const PRUnichar *aData)
00061     {
00062         if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0) {
00063             NS_IF_RELEASE(gCaseConv);
00064         }
00065 
00066         return NS_OK;
00067     }
00068 
00069 };
00070 
00071 NS_IMPL_ISUPPORTS1(nsShutdownObserver, nsIObserver)
00072 
00073 static nsresult NS_InitCaseConversion() {
00074     if (gCaseConv) return NS_OK;
00075 
00076     nsresult rv;
00077     
00078     rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &gCaseConv);
00079 
00080     if (NS_SUCCEEDED(rv)) {
00081         nsCOMPtr<nsIObserverService> obs =
00082             do_GetService("@mozilla.org/observer-service;1", &rv);
00083         if (NS_SUCCEEDED(rv)) {
00084             nsShutdownObserver *observer = new nsShutdownObserver();
00085             if (observer)
00086                 obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
00087         }
00088     }
00089     
00090     return NS_OK;
00091 }
00092 
00093 class ConvertToLowerCase
00094 {
00095 public:
00096     typedef PRUnichar value_type;
00097     
00098     ConvertToLowerCase()
00099     {
00100         NS_InitCaseConversion();
00101     }
00102 
00103     PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength)
00104     {
00105         if (gCaseConv)
00106             gCaseConv->ToLower(aSource, NS_CONST_CAST(PRUnichar*,aSource), aSourceLength);
00107         else
00108             NS_WARNING("No case converter: no conversion done");
00109 
00110         return aSourceLength;
00111     }
00112 };
00113 
00114 #ifdef MOZ_V1_STRING_ABI
00115 void
00116 ToLowerCase( nsAString& aString )
00117   {
00118     nsAString::iterator fromBegin, fromEnd;
00119     ConvertToLowerCase converter;
00120     copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter);
00121   }
00122 #endif
00123 
00124 void
00125 ToLowerCase( nsASingleFragmentString& aString )
00126   {
00127     ConvertToLowerCase converter;
00128     PRUnichar* start;
00129     converter.write(aString.BeginWriting(start), aString.Length());
00130   }
00131 
00132 void
00133 ToLowerCase( nsString& aString )
00134   {
00135     ConvertToLowerCase converter;
00136     PRUnichar* start;
00137     converter.write(aString.BeginWriting(start), aString.Length());
00138   }
00139 
00140 class CopyToLowerCase
00141   {
00142     public:
00143       typedef PRUnichar value_type;
00144     
00145       CopyToLowerCase( nsAString::iterator& aDestIter )
00146         : mIter(aDestIter)
00147         {
00148           NS_InitCaseConversion();
00149         }
00150 
00151       PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength )
00152         {
00153           PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength);
00154           PRUnichar* dest = mIter.get();
00155           if (gCaseConv)
00156               gCaseConv->ToLower(aSource, dest, len);
00157           else {
00158               NS_WARNING("No case converter: only copying");
00159               memcpy(dest, aSource, len * sizeof(*aSource));
00160           }
00161           mIter.advance(len);
00162           return len;
00163         }
00164 
00165     protected:
00166       nsAString::iterator& mIter;
00167   };
00168 
00169 void
00170 ToLowerCase( const nsAString& aSource, nsAString& aDest )
00171   {
00172     nsAString::const_iterator fromBegin, fromEnd;
00173     nsAString::iterator toBegin;
00174     // FIXME: need way to return error
00175     if (!EnsureStringLength(aDest, aSource.Length())) {
00176       aDest.Truncate();
00177       return; // out of memory
00178     }
00179     CopyToLowerCase converter(aDest.BeginWriting(toBegin));
00180     copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
00181   }
00182 
00183 class ConvertToUpperCase
00184 {
00185 public:
00186     typedef PRUnichar value_type;
00187     
00188     ConvertToUpperCase()
00189     {
00190         NS_InitCaseConversion();
00191     }
00192     
00193     PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength)
00194     {
00195         if (gCaseConv)
00196             gCaseConv->ToUpper(aSource, NS_CONST_CAST(PRUnichar*,aSource), aSourceLength);
00197         else
00198             NS_WARNING("No case converter: no conversion done");
00199         
00200         return aSourceLength;
00201     }
00202 };
00203 
00204 #ifdef MOZ_V1_STRING_ABI
00205 void
00206 ToUpperCase( nsAString& aString )
00207   {
00208     nsAString::iterator fromBegin, fromEnd;
00209     ConvertToUpperCase converter;
00210     copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter);
00211   }
00212 #endif
00213 
00214 void
00215 ToUpperCase( nsASingleFragmentString& aString )
00216   {
00217     ConvertToUpperCase converter;
00218     PRUnichar* start;
00219     converter.write(aString.BeginWriting(start), aString.Length());
00220   }
00221 
00222 void
00223 ToUpperCase( nsString& aString )
00224   {
00225     ConvertToUpperCase converter;
00226     PRUnichar* start;
00227     converter.write(aString.BeginWriting(start), aString.Length());
00228   }
00229 
00230 class CopyToUpperCase
00231   {
00232     public:
00233       typedef PRUnichar value_type;
00234     
00235       CopyToUpperCase( nsAString::iterator& aDestIter )
00236         : mIter(aDestIter)
00237         {
00238           NS_InitCaseConversion();
00239         }
00240 
00241       PRUint32 write( const PRUnichar* aSource, PRUint32 aSourceLength )
00242         {
00243           PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength);
00244           PRUnichar* dest = mIter.get();
00245           if (gCaseConv)
00246               gCaseConv->ToUpper(aSource, dest, len);
00247           else {
00248               NS_WARNING("No case converter: only copying");
00249               memcpy(dest, aSource, len * sizeof(*aSource));
00250           }
00251           mIter.advance(len);
00252           return len;
00253         }
00254 
00255     protected:
00256       nsAString::iterator& mIter;
00257   };
00258 
00259 void
00260 ToUpperCase( const nsAString& aSource, nsAString& aDest )
00261   {
00262     nsAString::const_iterator fromBegin, fromEnd;
00263     nsAString::iterator toBegin;
00264     // FIXME: need way to return error
00265     if (!EnsureStringLength(aDest, aSource.Length())) {
00266       aDest.Truncate();
00267       return; // out of memory
00268     }
00269     CopyToUpperCase converter(aDest.BeginWriting(toBegin));
00270     copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter);
00271   }
00272 
00273 int
00274 nsCaseInsensitiveStringComparator::operator()( const PRUnichar* lhs, const PRUnichar* rhs, PRUint32 aLength ) const
00275   {
00276       NS_InitCaseConversion();
00277       PRInt32 result;
00278       if (gCaseConv) {
00279           gCaseConv->CaseInsensitiveCompare(lhs, rhs, aLength, &result);
00280       }
00281       else {
00282           NS_WARNING("No case converter: using default");
00283           nsDefaultStringComparator comparator;
00284           result = comparator(lhs, rhs, aLength);
00285       }
00286       return result;
00287   }
00288 
00289 int
00290 nsCaseInsensitiveStringComparator::operator()( PRUnichar lhs, PRUnichar rhs ) const
00291   {
00292       // see if they're an exact match first
00293       if (lhs == rhs) return 0;
00294       
00295       NS_InitCaseConversion();
00296 
00297       if (gCaseConv) {
00298           gCaseConv->ToLower(lhs, &lhs);
00299           gCaseConv->ToLower(rhs, &rhs);
00300       } else {
00301           if (lhs < 256)
00302               lhs = tolower(char(lhs));
00303           if (rhs < 256)
00304               rhs = tolower(char(rhs));
00305           NS_WARNING("No case converter: no conversion done");
00306       }
00307       
00308       if (lhs == rhs) return 0;
00309       if (lhs < rhs) return -1;
00310       return 1;
00311   }
00312 
00313 PRUnichar
00314 ToLowerCase(PRUnichar aChar)
00315 {
00316     PRUnichar result;
00317     if (NS_FAILED(NS_InitCaseConversion()))
00318         return aChar;
00319 
00320     if (gCaseConv)
00321         gCaseConv->ToLower(aChar, &result);
00322     else {
00323         NS_WARNING("No case converter: no conversion done");
00324         if (aChar < 256)
00325             result = tolower(char(aChar));
00326         else
00327             result = aChar;
00328     }
00329     return result;
00330 }
00331 
00332 PRUnichar
00333 ToUpperCase(PRUnichar aChar)
00334 {
00335     PRUnichar result;
00336     if (NS_FAILED(NS_InitCaseConversion()))
00337         return aChar;
00338 
00339     if (gCaseConv)
00340         gCaseConv->ToUpper(aChar, &result);
00341     else {
00342         NS_WARNING("No case converter: no conversion done");
00343         if (aChar < 256)
00344             result = toupper(char(aChar));
00345         else
00346             result = aChar;
00347     }
00348     return result;
00349 }
00350