Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLEntities.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Communicator client 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 "nsHTMLEntities.h"
00039 
00040 
00041 
00042 #include "nsString.h"
00043 #include "nsCRT.h"
00044 #include "prtypes.h"
00045 #include "pldhash.h"
00046 
00047 struct EntityNode {
00048   const char* mStr; // never owns buffer
00049   PRInt32       mUnicode;
00050 };
00051 
00052 struct EntityNodeEntry : public PLDHashEntryHdr
00053 {
00054   const EntityNode* node;
00055 }; 
00056 
00057 PR_STATIC_CALLBACK(const void*)
00058   getStringKey(PLDHashTable*, PLDHashEntryHdr* aHdr)
00059 {
00060   const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
00061   return entry->node->mStr;
00062 }
00063 
00064 PR_STATIC_CALLBACK(const void*)
00065   getUnicodeKey(PLDHashTable*, PLDHashEntryHdr* aHdr)
00066 {
00067   const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
00068   return NS_INT32_TO_PTR(entry->node->mUnicode);
00069 }
00070 
00071 PR_STATIC_CALLBACK(PRBool)
00072   matchNodeString(PLDHashTable*, const PLDHashEntryHdr* aHdr,
00073                   const void* key)
00074 {
00075   const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
00076   const char* str = NS_STATIC_CAST(const char*, key);
00077   return (nsCRT::strcmp(entry->node->mStr, str) == 0);
00078 }
00079 
00080 PR_STATIC_CALLBACK(PRBool)
00081   matchNodeUnicode(PLDHashTable*, const PLDHashEntryHdr* aHdr,
00082                    const void* key)
00083 {
00084   const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
00085   const PRInt32 ucode = NS_PTR_TO_INT32(key);
00086   return (entry->node->mUnicode == ucode);
00087 }
00088 
00089 PR_STATIC_CALLBACK(PLDHashNumber)
00090   hashUnicodeValue(PLDHashTable*, const void* key)
00091 {
00092   // key is actually the unicode value
00093   return PLDHashNumber(NS_PTR_TO_INT32(key));
00094   }
00095 
00096 
00097 static const PLDHashTableOps EntityToUnicodeOps = {
00098   PL_DHashAllocTable,
00099   PL_DHashFreeTable,
00100   getStringKey,
00101   PL_DHashStringKey,
00102   matchNodeString,
00103   PL_DHashMoveEntryStub,
00104   PL_DHashClearEntryStub,
00105   PL_DHashFinalizeStub,
00106   nsnull,
00107 }; 
00108 
00109 static const PLDHashTableOps UnicodeToEntityOps = {
00110   PL_DHashAllocTable,
00111   PL_DHashFreeTable,
00112   getUnicodeKey,
00113   hashUnicodeValue,
00114   matchNodeUnicode,
00115   PL_DHashMoveEntryStub,
00116   PL_DHashClearEntryStub,
00117   PL_DHashFinalizeStub,
00118   nsnull,
00119 };
00120 
00121 static PLDHashTable gEntityToUnicode = { 0 };
00122 static PLDHashTable gUnicodeToEntity = { 0 };
00123 static nsrefcnt gTableRefCnt = 0;
00124 
00125 #define HTML_ENTITY(_name, _value) { #_name, _value },
00126 static const EntityNode gEntityArray[] = {
00127 #include "nsHTMLEntityList.h"
00128 };
00129 #undef HTML_ENTITY
00130 
00131 #define NS_HTML_ENTITY_COUNT ((PRInt32)NS_ARRAY_LENGTH(gEntityArray))
00132 
00133 nsresult
00134 nsHTMLEntities::AddRefTable(void) 
00135 {
00136   if (!gTableRefCnt) {
00137     if (!PL_DHashTableInit(&gEntityToUnicode, &EntityToUnicodeOps,
00138                            nsnull, sizeof(EntityNodeEntry),
00139                            PRUint32(NS_HTML_ENTITY_COUNT / 0.75))) {
00140       gEntityToUnicode.ops = nsnull;
00141       return NS_ERROR_OUT_OF_MEMORY;
00142     }
00143     if (!PL_DHashTableInit(&gUnicodeToEntity, &UnicodeToEntityOps,
00144                            nsnull, sizeof(EntityNodeEntry),
00145                            PRUint32(NS_HTML_ENTITY_COUNT / 0.75))) {
00146       PL_DHashTableFinish(&gEntityToUnicode);
00147       gEntityToUnicode.ops = gUnicodeToEntity.ops = nsnull;
00148       return NS_ERROR_OUT_OF_MEMORY;
00149     }
00150     for (const EntityNode *node = gEntityArray,
00151                  *node_end = gEntityArray + NS_ARRAY_LENGTH(gEntityArray);
00152          node < node_end; ++node) {
00153 
00154       // add to Entity->Unicode table
00155       EntityNodeEntry* entry =
00156         NS_STATIC_CAST(EntityNodeEntry*,
00157                        PL_DHashTableOperate(&gEntityToUnicode,
00158                                             node->mStr,
00159                                             PL_DHASH_ADD));
00160       NS_ASSERTION(entry, "Error adding an entry");
00161       // Prefer earlier entries when we have duplication.
00162       if (!entry->node)
00163         entry->node = node;
00164 
00165       // add to Unicode->Entity table
00166       entry = NS_STATIC_CAST(EntityNodeEntry*,
00167                              PL_DHashTableOperate(&gUnicodeToEntity,
00168                                                   NS_INT32_TO_PTR(node->mUnicode),
00169                                                   PL_DHASH_ADD));
00170       NS_ASSERTION(entry, "Error adding an entry");
00171       // Prefer earlier entries when we have duplication.
00172       if (!entry->node)
00173         entry->node = node;
00174     }
00175   }
00176   ++gTableRefCnt;
00177   return NS_OK;
00178 }
00179 
00180 void
00181 nsHTMLEntities::ReleaseTable(void) 
00182 {
00183   if (--gTableRefCnt != 0)
00184     return;
00185 
00186   if (gEntityToUnicode.ops) {
00187     PL_DHashTableFinish(&gEntityToUnicode);
00188     gEntityToUnicode.ops = nsnull;
00189   }
00190   if (gUnicodeToEntity.ops) {
00191     PL_DHashTableFinish(&gUnicodeToEntity);
00192     gUnicodeToEntity.ops = nsnull;
00193   }
00194 
00195 }
00196 
00197 PRInt32 
00198 nsHTMLEntities::EntityToUnicode(const nsCString& aEntity)
00199 {
00200   NS_ASSERTION(gEntityToUnicode.ops, "no lookup table, needs addref");
00201   if (!gEntityToUnicode.ops)
00202     return -1;
00203 
00204     //this little piece of code exists because entities may or may not have the terminating ';'.
00205     //if we see it, strip if off for this test...
00206 
00207     if(';'==aEntity.Last()) {
00208       nsCAutoString temp(aEntity);
00209       temp.Truncate(aEntity.Length()-1);
00210       return EntityToUnicode(temp);
00211     }
00212       
00213   EntityNodeEntry* entry = 
00214     NS_STATIC_CAST(EntityNodeEntry*,
00215                    PL_DHashTableOperate(&gEntityToUnicode, aEntity.get(), PL_DHASH_LOOKUP));
00216 
00217   if (!entry || PL_DHASH_ENTRY_IS_FREE(entry))
00218   return -1;
00219         
00220   return entry->node->mUnicode;
00221 }
00222 
00223 
00224 PRInt32 
00225 nsHTMLEntities::EntityToUnicode(const nsAString& aEntity) {
00226   nsCAutoString theEntity; theEntity.AssignWithConversion(aEntity);
00227   if(';'==theEntity.Last()) {
00228     theEntity.Truncate(theEntity.Length()-1);
00229   }
00230 
00231   return EntityToUnicode(theEntity);
00232 }
00233 
00234 
00235 const char*
00236 nsHTMLEntities::UnicodeToEntity(PRInt32 aUnicode)
00237 {
00238   NS_ASSERTION(gUnicodeToEntity.ops, "no lookup table, needs addref");
00239   EntityNodeEntry* entry =
00240     NS_STATIC_CAST(EntityNodeEntry*,
00241                    PL_DHashTableOperate(&gUnicodeToEntity, NS_INT32_TO_PTR(aUnicode), PL_DHASH_LOOKUP));
00242                    
00243   if (!entry || PL_DHASH_ENTRY_IS_FREE(entry))
00244   return nsnull;
00245     
00246   return entry->node->mStr;
00247 }
00248 
00249 #ifdef NS_DEBUG
00250 #include <stdio.h>
00251 
00252 class nsTestEntityTable {
00253 public:
00254    nsTestEntityTable() {
00255      PRInt32 value;
00256      nsHTMLEntities::AddRefTable();
00257 
00258      // Make sure we can find everything we are supposed to
00259      for (int i = 0; i < NS_HTML_ENTITY_COUNT; ++i) {
00260        nsAutoString entity; entity.AssignWithConversion(gEntityArray[i].mStr);
00261 
00262        value = nsHTMLEntities::EntityToUnicode(entity);
00263        NS_ASSERTION(value != -1, "can't find entity");
00264        NS_ASSERTION(value == gEntityArray[i].mUnicode, "bad unicode value");
00265 
00266        entity.AssignWithConversion(nsHTMLEntities::UnicodeToEntity(value));
00267        NS_ASSERTION(entity.EqualsASCII(gEntityArray[i].mStr), "bad entity name");
00268      }
00269 
00270      // Make sure we don't find things that aren't there
00271      value = nsHTMLEntities::EntityToUnicode(nsCAutoString("@"));
00272      NS_ASSERTION(value == -1, "found @");
00273      value = nsHTMLEntities::EntityToUnicode(nsCAutoString("zzzzz"));
00274      NS_ASSERTION(value == -1, "found zzzzz");
00275      nsHTMLEntities::ReleaseTable();
00276    }
00277 };
00278 //nsTestEntityTable validateEntityTable;
00279 #endif
00280