Back to index

lightning-sunbird  0.9+nobinonly
nsEntityConverter.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 mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsEntityConverter.h"
00039 #include "nsIProperties.h"
00040 #include "nsIServiceManager.h"
00041 #include "nsIComponentManager.h"
00042 #include "nsReadableUtils.h"
00043 #include "nsCRT.h"
00044 #include "nsLiteralString.h"
00045 #include "nsXPIDLString.h"
00046 #include "nsString.h"
00047 #include "nsUnicharUtils.h"
00048 
00049 //
00050 // implementation methods
00051 //
00052 nsEntityConverter::nsEntityConverter()
00053 :      mVersionList(NULL),
00054   mVersionListLength(0)
00055 {
00056 }
00057 
00058 nsEntityConverter::~nsEntityConverter()
00059 {
00060   if (NULL != mVersionList) delete [] mVersionList;
00061 }
00062 
00063 NS_IMETHODIMP 
00064 nsEntityConverter::LoadVersionPropertyFile()
00065 {
00066     NS_NAMED_LITERAL_CSTRING(url, "resource://gre/res/entityTables/htmlEntityVersions.properties");
00067        nsresult rv;
00068     nsCOMPtr<nsIStringBundleService> bundleService =
00069         do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00070 
00071     if (NS_FAILED(rv)) return rv;
00072     
00073     nsCOMPtr<nsIStringBundle> entities;
00074     rv = bundleService->CreateBundle(url.get(), getter_AddRefs(entities));
00075     if (NS_FAILED(rv)) return rv;
00076     
00077     PRInt32   result;
00078 
00079     nsAutoString key;
00080     nsXPIDLString value;
00081     rv = entities->GetStringFromName(NS_LITERAL_STRING("length").get(),
00082                                      getter_Copies(value));
00083     NS_ASSERTION(NS_SUCCEEDED(rv),"nsEntityConverter: malformed entity table\n");
00084     if (NS_FAILED(rv)) return rv;
00085       
00086     mVersionListLength = nsAutoString(value).ToInteger(&result);
00087     NS_ASSERTION(32 >= mVersionListLength,"nsEntityConverter: malformed entity table\n");
00088     if (32 < mVersionListLength) return NS_ERROR_FAILURE;
00089     
00090     mVersionList = new nsEntityVersionList[mVersionListLength];
00091     if (!mVersionList) return NS_ERROR_OUT_OF_MEMORY;
00092 
00093     for (PRUint32 i = 0; i < mVersionListLength && NS_SUCCEEDED(rv); i++) {
00094         key.SetLength(0);
00095         key.AppendInt(i+1, 10);
00096         rv = entities->GetStringFromName(key.get(), getter_Copies(value));
00097         PRUint32 len = value.Length();
00098         if (kVERSION_STRING_LEN < len) return NS_ERROR_UNEXPECTED;
00099         
00100         memcpy(mVersionList[i].mEntityListName, value.get(), len*sizeof(PRUnichar));
00101         mVersionList[i].mEntityListName[len] = 0;
00102         mVersionList[i].mVersion = (1 << i);
00103     }
00104 
00105     return NS_OK;
00106 }
00107 
00108 already_AddRefed<nsIStringBundle>
00109 nsEntityConverter::LoadEntityBundle(PRUint32 version)
00110 {
00111   nsCAutoString url(NS_LITERAL_CSTRING("resource://gre/res/entityTables/"));
00112   const PRUnichar *versionName = NULL;
00113   nsresult rv;
00114 
00115   nsCOMPtr<nsIStringBundleService> bundleService =
00116       do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00117   if (NS_FAILED(rv)) return NULL;
00118   
00119   versionName = GetVersionName(version);
00120   if (NULL == versionName) return NULL;
00121 
00122   // all property file names are ASCII, like "html40Latin1" so this is safe
00123   LossyAppendUTF16toASCII(versionName, url);
00124   url.Append(".properties");
00125 
00126   nsIStringBundle* bundle;
00127   rv = bundleService->CreateBundle(url.get(), &bundle);
00128   if (NS_FAILED(rv)) return NULL;
00129   
00130   // does this addref right?
00131   return bundle;
00132 }
00133 
00134 const PRUnichar*
00135 nsEntityConverter:: GetVersionName(PRUint32 versionNumber)
00136 {
00137   for (PRUint32 i = 0; i < mVersionListLength; i++) {
00138     if (versionNumber == mVersionList[i].mVersion)
00139       return mVersionList[i].mEntityListName;
00140   }
00141 
00142   return NULL;
00143 }
00144 
00145 nsIStringBundle*
00146 nsEntityConverter:: GetVersionBundleInstance(PRUint32 versionNumber)
00147 {
00148   if (NULL == mVersionList) {
00149     // load the property file which contains available version names
00150     // and generate a list of version/name pair
00151     nsresult rv = LoadVersionPropertyFile();
00152     if (NS_FAILED(rv)) return NULL;
00153   }
00154 
00155   PRUint32 i;
00156   for (i = 0; i < mVersionListLength; i++) {
00157     if (versionNumber == mVersionList[i].mVersion) {
00158       if (!mVersionList[i].mEntities)
00159       { // not loaded
00160         // load the property file
00161         mVersionList[i].mEntities = LoadEntityBundle(versionNumber);
00162         NS_ASSERTION(mVersionList[i].mEntities, "LoadEntityBundle failed");
00163       }
00164       return mVersionList[i].mEntities.get();
00165     }
00166   }
00167 
00168   return NULL;
00169 }
00170 
00171 
00172 //
00173 // nsISupports methods
00174 //
00175 NS_IMPL_ISUPPORTS1(nsEntityConverter,nsIEntityConverter)
00176 
00177 
00178 //
00179 // nsIEntityConverter
00180 //
00181 NS_IMETHODIMP
00182 nsEntityConverter::ConvertToEntity(PRUnichar character, PRUint32 entityVersion, char **_retval)
00183 { 
00184   return ConvertUTF32ToEntity((PRUint32)character, entityVersion, _retval);
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsEntityConverter::ConvertUTF32ToEntity(PRUint32 character, PRUint32 entityVersion, char **_retval)
00189 {
00190   NS_ASSERTION(_retval, "null ptr- _retval");
00191   if(nsnull == _retval)
00192     return NS_ERROR_NULL_POINTER;
00193   *_retval = NULL;
00194 
00195   for (PRUint32 mask = 1, mask2 = 0xFFFFFFFFL; (0!=(entityVersion & mask2)); mask<<=1, mask2<<=1) {
00196     if (0 == (entityVersion & mask)) 
00197       continue;
00198     nsIStringBundle* entities = GetVersionBundleInstance(entityVersion & mask);
00199     NS_ASSERTION(entities, "Cannot get the property file");
00200 
00201     if (NULL == entities) 
00202       continue;
00203 
00204     nsAutoString key(NS_LITERAL_STRING("entity."));
00205     key.AppendInt(character,10);
00206 
00207     nsXPIDLString value;
00208     nsresult rv = entities->GetStringFromName(key.get(), getter_Copies(value));
00209     if (NS_SUCCEEDED(rv)) {
00210       *_retval = ToNewCString(value);
00211       if(nsnull == *_retval)
00212         return NS_ERROR_OUT_OF_MEMORY;
00213       else
00214         return NS_OK;
00215     }
00216   }
00217        return NS_ERROR_ILLEGAL_VALUE;
00218 }
00219 
00220 NS_IMETHODIMP
00221 nsEntityConverter::ConvertToEntities(const PRUnichar *inString, PRUint32 entityVersion, PRUnichar **_retval)
00222 {
00223   NS_ASSERTION(inString, "null ptr- inString");
00224   NS_ASSERTION(_retval, "null ptr- _retval");
00225   if((nsnull == inString) || (nsnull == _retval))
00226     return NS_ERROR_NULL_POINTER;
00227   *_retval = NULL;
00228 
00229   const PRUnichar *entity = NULL;
00230   nsString outString;
00231 
00232   // per character look for the entity
00233   PRUint32 len = nsCRT::strlen(inString);
00234   for (PRUint32 i = 0; i < len; i++) {
00235     nsAutoString key(NS_LITERAL_STRING("entity."));
00236     if (IS_HIGH_SURROGATE(inString[i]) &&
00237         i + 2 < len &&
00238         IS_LOW_SURROGATE(inString[i + 1])) {
00239       key.AppendInt(SURROGATE_TO_UCS4(inString[i], inString[++i]), 10);
00240     }
00241     else {
00242       key.AppendInt(inString[i],10);
00243     }
00244     
00245     nsXPIDLString value;
00246     
00247     entity = NULL;
00248     for (PRUint32 mask = 1, mask2 = 0xFFFFFFFFL; (0!=(entityVersion & mask2)); mask<<=1, mask2<<=1) {
00249       if (0 == (entityVersion & mask)) 
00250          continue;
00251       nsIStringBundle* entities = GetVersionBundleInstance(entityVersion & mask);
00252       NS_ASSERTION(entities, "Cannot get the property file");
00253 
00254       if (NULL == entities) 
00255           continue;
00256 
00257       nsresult rv = entities->GetStringFromName(key.get(),
00258                                                 getter_Copies(value));
00259       if (NS_SUCCEEDED(rv)) {
00260         entity = value.get();
00261         break;
00262       }
00263     }
00264     if (NULL != entity) {
00265       outString.Append(entity);
00266     }
00267     else {
00268       outString.Append(&inString[i], 1);
00269     }
00270   }
00271 
00272   *_retval = ToNewUnicode(outString);
00273   if (NULL == *_retval) 
00274     return NS_ERROR_OUT_OF_MEMORY;
00275 
00276   return NS_OK;
00277 }
00278 
00279 
00280 
00281 nsresult NS_NewEntityConverter(nsISupports** oResult)
00282 {
00283    if(!oResult)
00284       return NS_ERROR_NULL_POINTER;
00285    *oResult = new nsEntityConverter();
00286    if(*oResult)
00287       NS_ADDREF(*oResult);
00288    return (*oResult) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00289 }