source: trunk/third/mozilla/htmlparser/src/nsHTMLEntities.cpp @ 20192

Revision 20192, 8.6 KB checked in by rbasch, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20191, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is Mozilla Communicator client code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the NPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the NPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39#include "nsHTMLEntities.h"
40
41
42
43#include "nsString.h"
44#include "nsCRT.h"
45#include "prtypes.h"
46#include "pldhash.h"
47
48struct EntityNode {
49  const char* mStr; // never owns buffer
50  PRInt32       mUnicode;
51};
52
53struct EntityNodeEntry : public PLDHashEntryHdr
54{
55  const EntityNode* node;
56};
57
58PR_STATIC_CALLBACK(const void*)
59  getStringKey(PLDHashTable*, PLDHashEntryHdr* aHdr)
60{
61  const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
62  return entry->node->mStr;
63}
64
65PR_STATIC_CALLBACK(const void*)
66  getUnicodeKey(PLDHashTable*, PLDHashEntryHdr* aHdr)
67{
68  const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
69  return NS_INT32_TO_PTR(entry->node->mUnicode);
70}
71
72PR_STATIC_CALLBACK(PRBool)
73  matchNodeString(PLDHashTable*, const PLDHashEntryHdr* aHdr,
74                  const void* key)
75{
76  const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
77  const char* str = NS_STATIC_CAST(const char*, key);
78  return (nsCRT::strcmp(entry->node->mStr, str) == 0);
79}
80
81PR_STATIC_CALLBACK(PRBool)
82  matchNodeUnicode(PLDHashTable*, const PLDHashEntryHdr* aHdr,
83                   const void* key)
84{
85  const EntityNodeEntry* entry = NS_STATIC_CAST(const EntityNodeEntry*, aHdr);
86  const PRInt32 ucode = NS_PTR_TO_INT32(key);
87  return (entry->node->mUnicode == ucode);
88}
89
90PR_STATIC_CALLBACK(PLDHashNumber)
91  hashUnicodeValue(PLDHashTable*, const void* key)
92{
93  // key is actually the unicode value
94  return PLDHashNumber(NS_PTR_TO_INT32(key));
95  }
96
97
98static const PLDHashTableOps EntityToUnicodeOps = {
99  PL_DHashAllocTable,
100  PL_DHashFreeTable,
101  getStringKey,
102  PL_DHashStringKey,
103  matchNodeString,
104  PL_DHashMoveEntryStub,
105  PL_DHashClearEntryStub,
106  PL_DHashFinalizeStub,
107  nsnull,
108};
109
110static const PLDHashTableOps UnicodeToEntityOps = {
111  PL_DHashAllocTable,
112  PL_DHashFreeTable,
113  getUnicodeKey,
114  hashUnicodeValue,
115  matchNodeUnicode,
116  PL_DHashMoveEntryStub,
117  PL_DHashClearEntryStub,
118  PL_DHashFinalizeStub,
119  nsnull,
120};
121
122static PLDHashTable gEntityToUnicode = { 0 };
123static PLDHashTable gUnicodeToEntity = { 0 };
124static nsrefcnt gTableRefCnt = 0;
125
126#define HTML_ENTITY(_name, _value) { #_name, _value },
127static const EntityNode gEntityArray[] = {
128#include "nsHTMLEntityList.h"
129};
130#undef HTML_ENTITY
131
132#define NS_HTML_ENTITY_COUNT ((PRInt32)NS_ARRAY_LENGTH(gEntityArray))
133
134nsresult
135nsHTMLEntities::AddRefTable(void)
136{
137  if (!gTableRefCnt) {
138    if (!PL_DHashTableInit(&gEntityToUnicode, &EntityToUnicodeOps,
139                           nsnull, sizeof(EntityNodeEntry),
140                           PRUint32(NS_HTML_ENTITY_COUNT / 0.75))) {
141      gEntityToUnicode.ops = nsnull;
142      return NS_ERROR_OUT_OF_MEMORY;
143    }
144    if (!PL_DHashTableInit(&gUnicodeToEntity, &UnicodeToEntityOps,
145                           nsnull, sizeof(EntityNodeEntry),
146                           PRUint32(NS_HTML_ENTITY_COUNT / 0.75))) {
147      PL_DHashTableFinish(&gEntityToUnicode);
148      gEntityToUnicode.ops = gUnicodeToEntity.ops = nsnull;
149      return NS_ERROR_OUT_OF_MEMORY;
150    }
151    for (const EntityNode *node = gEntityArray,
152                 *node_end = gEntityArray + NS_ARRAY_LENGTH(gEntityArray);
153         node < node_end; ++node) {
154
155      // add to Entity->Unicode table
156      EntityNodeEntry* entry =
157        NS_STATIC_CAST(EntityNodeEntry*,
158                       PL_DHashTableOperate(&gEntityToUnicode,
159                                            node->mStr,
160                                            PL_DHASH_ADD));
161      NS_ASSERTION(entry, "Error adding an entry");
162      // Prefer earlier entries when we have duplication.
163      if (!entry->node)
164        entry->node = node;
165
166      // add to Unicode->Entity table
167      entry = NS_STATIC_CAST(EntityNodeEntry*,
168                             PL_DHashTableOperate(&gUnicodeToEntity,
169                                                  NS_INT32_TO_PTR(node->mUnicode),
170                                                  PL_DHASH_ADD));
171      NS_ASSERTION(entry, "Error adding an entry");
172      // Prefer earlier entries when we have duplication.
173      if (!entry->node)
174        entry->node = node;
175    }
176  }
177  ++gTableRefCnt;
178  return NS_OK;
179}
180
181void
182nsHTMLEntities::ReleaseTable(void)
183{
184  if (--gTableRefCnt != 0)
185    return;
186
187  if (gEntityToUnicode.ops) {
188    PL_DHashTableFinish(&gEntityToUnicode);
189    gEntityToUnicode.ops = nsnull;
190  }
191  if (gUnicodeToEntity.ops) {
192    PL_DHashTableFinish(&gUnicodeToEntity);
193    gUnicodeToEntity.ops = nsnull;
194  }
195
196}
197
198PRInt32
199nsHTMLEntities::EntityToUnicode(const nsCString& aEntity)
200{
201  NS_ASSERTION(gEntityToUnicode.ops, "no lookup table, needs addref");
202  if (!gEntityToUnicode.ops)
203    return -1;
204
205    //this little piece of code exists because entities may or may not have the terminating ';'.
206    //if we see it, strip if off for this test...
207
208    if(';'==aEntity.Last()) {
209      nsCAutoString temp(aEntity);
210      temp.Truncate(aEntity.Length()-1);
211      return EntityToUnicode(temp);
212    }
213     
214  EntityNodeEntry* entry =
215    NS_STATIC_CAST(EntityNodeEntry*,
216                   PL_DHashTableOperate(&gEntityToUnicode, aEntity.get(), PL_DHASH_LOOKUP));
217
218  if (!entry || PL_DHASH_ENTRY_IS_FREE(entry))
219  return -1;
220       
221  return entry->node->mUnicode;
222}
223
224
225PRInt32
226nsHTMLEntities::EntityToUnicode(const nsAString& aEntity) {
227  nsCAutoString theEntity; theEntity.AssignWithConversion(aEntity);
228  if(';'==theEntity.Last()) {
229    theEntity.Truncate(theEntity.Length()-1);
230  }
231
232  return EntityToUnicode(theEntity);
233}
234
235
236const char*
237nsHTMLEntities::UnicodeToEntity(PRInt32 aUnicode)
238{
239  NS_ASSERTION(gUnicodeToEntity.ops, "no lookup table, needs addref");
240  EntityNodeEntry* entry =
241    NS_STATIC_CAST(EntityNodeEntry*,
242                   PL_DHashTableOperate(&gUnicodeToEntity, NS_INT32_TO_PTR(aUnicode), PL_DHASH_LOOKUP));
243                   
244  if (!entry || PL_DHASH_ENTRY_IS_FREE(entry))
245  return nsnull;
246   
247  return entry->node->mStr;
248}
249
250#ifdef NS_DEBUG
251#include <stdio.h>
252
253class nsTestEntityTable {
254public:
255   nsTestEntityTable() {
256     PRInt32 value;
257     nsHTMLEntities::AddRefTable();
258
259     // Make sure we can find everything we are supposed to
260     for (int i = 0; i < NS_HTML_ENTITY_COUNT; ++i) {
261       nsAutoString entity; entity.AssignWithConversion(gEntityArray[i].mStr);
262
263       value = nsHTMLEntities::EntityToUnicode(entity);
264       NS_ASSERTION(value != -1, "can't find entity");
265       NS_ASSERTION(value == gEntityArray[i].mUnicode, "bad unicode value");
266
267       entity.AssignWithConversion(nsHTMLEntities::UnicodeToEntity(value));
268       NS_ASSERTION(entity.EqualsWithConversion(gEntityArray[i].mStr), "bad entity name");
269     }
270
271     // Make sure we don't find things that aren't there
272     value = nsHTMLEntities::EntityToUnicode(nsCAutoString("@"));
273     NS_ASSERTION(value == -1, "found @");
274     value = nsHTMLEntities::EntityToUnicode(nsCAutoString("zzzzz"));
275     NS_ASSERTION(value == -1, "found zzzzz");
276     nsHTMLEntities::ReleaseTable();
277   }
278};
279//nsTestEntityTable validateEntityTable;
280#endif
281
Note: See TracBrowser for help on using the repository browser.