blob: 5facf3b7a202fa1eb41aa6a7135709a39236babe [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * entities.c : implementation for the XML entities handking
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00007 */
8
Daniel Veillard3c558c31999-12-22 11:30:41 +00009#ifdef WIN32
10#include "win32config.h"
11#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#include "config.h"
13#endif
14
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000016#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000017#ifdef HAVE_STDLIB_H
18#include <stdlib.h>
19#endif
Daniel Veillard361d8452000-04-03 19:48:13 +000020#include <libxml/xmlmemory.h>
21#include <libxml/entities.h>
22#include <libxml/parser.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000023
Daniel Veillardcf461992000-03-14 18:30:20 +000024#define DEBUG_ENT_REF /* debugging of cross entities dependancies */
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +000025#define ENTITY_HASH_SIZE 256 /* modify xmlEntityComputeHash accordingly */
26
27/*
28 * xmlEntityComputeHash:
29 *
30 * Computes the hash value for this given entity
31 */
32int
33xmlEntityComputeHash(const xmlChar *name) {
34 register const unsigned char *cur = (const unsigned char *) name;
35 register unsigned char val = 0;
36
37 if (name == NULL)
38 return(val);
39 while (*cur) val += *cur++;
40 return(val);
41}
Daniel Veillardcf461992000-03-14 18:30:20 +000042
Daniel Veillard260a68f1998-08-13 03:39:55 +000043/*
44 * The XML predefined entities.
45 */
46
47struct xmlPredefinedEntityValue {
48 const char *name;
49 const char *value;
50};
51struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
52 { "lt", "<" },
53 { "gt", ">" },
54 { "apos", "'" },
55 { "quot", "\"" },
56 { "amp", "&" }
57};
58
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +000059/*
60 * TODO: !!!!!!! This is GROSS, allocation of a 256 entry hash for
61 * a fixed number of 4 elements !
62 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000063xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
64
65/*
Daniel Veillard260a68f1998-08-13 03:39:55 +000066 * xmlFreeEntity : clean-up an entity record.
67 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000068void xmlFreeEntity(xmlEntityPtr entity) {
69 if (entity == NULL) return;
70
Daniel Veillardcf461992000-03-14 18:30:20 +000071 if (entity->children)
72 xmlFreeNodeList(entity->children);
Daniel Veillard260a68f1998-08-13 03:39:55 +000073 if (entity->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000074 xmlFree((char *) entity->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +000075 if (entity->ExternalID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000076 xmlFree((char *) entity->ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000077 if (entity->SystemID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000078 xmlFree((char *) entity->SystemID);
Daniel Veillard39c7d712000-09-10 16:14:55 +000079 if (entity->URI != NULL)
80 xmlFree((char *) entity->URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +000081 if (entity->content != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000082 xmlFree((char *) entity->content);
Daniel Veillard011b63c1999-06-02 17:44:04 +000083 if (entity->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000084 xmlFree((char *) entity->orig);
Daniel Veillardcf461992000-03-14 18:30:20 +000085#ifdef WITH_EXTRA_ENT_DETECT
86 if (entity->entTab != NULL) {
87 int i;
88
89 for (i = 0; i < entity->entNr; i++)
90 xmlFree(entity->entTab[i]);
91 xmlFree(entity->entTab);
92 }
93#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +000094 memset(entity, -1, sizeof(xmlEntity));
Daniel Veillardcf461992000-03-14 18:30:20 +000095 xmlFree(entity);
Daniel Veillard260a68f1998-08-13 03:39:55 +000096}
97
98/*
Daniel Veillardbe36afe1998-11-27 06:39:50 +000099 * xmlAddEntity : register a new entity for an entities table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000100 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000101static xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000102xmlAddEntity(xmlEntitiesTablePtr table, const xmlChar *name, int type,
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000103 const xmlChar *ExternalID, const xmlChar *SystemID,
104 const xmlChar *content) {
105#ifndef ENTITY_HASH_SIZE
Daniel Veillard260a68f1998-08-13 03:39:55 +0000106 int i;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000107#endif
108 int hash;
Daniel Veillardcf461992000-03-14 18:30:20 +0000109 xmlEntityPtr ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000110
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000111 if (name == NULL)
112 return(NULL);
113#ifdef ENTITY_HASH_SIZE
114 hash = xmlEntityComputeHash(name);
115 ret = table->table[hash];
116 while (ret != NULL) {
117 if (!xmlStrcmp(ret->name, name)) {
118 /*
119 * The entity is already defined in this Dtd, the spec says to NOT
120 * override it ... Is it worth a Warning ??? !!!
121 * Not having a cprinting context this seems hard ...
122 */
123 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
124 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
125 ((ret->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
126 (ret->etype == XML_EXTERNAL_PARAMETER_ENTITY)))
127 return(NULL);
128 else
129 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
130 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
131 ((ret->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
132 (ret->etype != XML_EXTERNAL_PARAMETER_ENTITY)))
133 return(NULL);
134 }
135 ret = ret->nexte;
136 }
137#else
Daniel Veillard260a68f1998-08-13 03:39:55 +0000138 for (i = 0;i < table->nb_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000139 ret = table->table[i];
140 if (!xmlStrcmp(ret->name, name)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000141 /*
142 * The entity is already defined in this Dtd, the spec says to NOT
143 * override it ... Is it worth a Warning ??? !!!
Daniel Veillardb96e6431999-08-29 21:02:19 +0000144 * Not having a cprinting context this seems hard ...
Daniel Veillard260a68f1998-08-13 03:39:55 +0000145 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000146 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
147 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000148 ((ret->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
149 (ret->etype == XML_EXTERNAL_PARAMETER_ENTITY)))
150 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000151 else
152 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
153 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
Daniel Veillardcf461992000-03-14 18:30:20 +0000154 ((ret->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
155 (ret->etype != XML_EXTERNAL_PARAMETER_ENTITY)))
156 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000157 }
158 }
159 if (table->nb_entities >= table->max_entities) {
160 /*
161 * need more elements.
162 */
163 table->max_entities *= 2;
Daniel Veillardcf461992000-03-14 18:30:20 +0000164 table->table = (xmlEntityPtr *)
165 xmlRealloc(table->table,
166 table->max_entities * sizeof(xmlEntityPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000167 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000168 perror("realloc failed");
Daniel Veillardcf461992000-03-14 18:30:20 +0000169 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000170 }
171 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000172#endif
Daniel Veillardcf461992000-03-14 18:30:20 +0000173 ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
174 if (ret == NULL) {
175 fprintf(stderr, "xmlAddEntity: out of memory\n");
176 return(NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000177 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000178 memset(ret, 0, sizeof(xmlEntity));
179 ret->type = XML_ENTITY_DECL;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000180#ifdef ENTITY_HASH_SIZE
181 ret->nexte = table->table[hash];
182 table->table[hash] = ret;
183#else
Daniel Veillardcf461992000-03-14 18:30:20 +0000184 table->table[table->nb_entities] = ret;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000185#endif
Daniel Veillardcf461992000-03-14 18:30:20 +0000186
187 /*
188 * fill the structure.
189 */
190 ret->name = xmlStrdup(name);
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000191 ret->etype = (xmlEntityType) type;
Daniel Veillardcf461992000-03-14 18:30:20 +0000192 if (ExternalID != NULL)
193 ret->ExternalID = xmlStrdup(ExternalID);
194 if (SystemID != NULL)
195 ret->SystemID = xmlStrdup(SystemID);
196 if (content != NULL) {
197 ret->length = xmlStrlen(content);
198 ret->content = xmlStrndup(content, ret->length);
199 } else {
200 ret->length = 0;
201 ret->content = NULL;
202 }
Daniel Veillard39c7d712000-09-10 16:14:55 +0000203 ret->URI = NULL; /* to be computed by the layer knowing
204 the defining entity */
Daniel Veillardcf461992000-03-14 18:30:20 +0000205 ret->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000206 table->nb_entities++;
Daniel Veillardcf461992000-03-14 18:30:20 +0000207
208 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000209}
210
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000211/**
212 * xmlInitializePredefinedEntities:
213 *
214 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000215 */
216void xmlInitializePredefinedEntities(void) {
217 int i;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000218 xmlChar name[50];
219 xmlChar value[50];
Daniel Veillard260a68f1998-08-13 03:39:55 +0000220 const char *in;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000221 xmlChar *out;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000222
223 if (xmlPredefinedEntities != NULL) return;
224
225 xmlPredefinedEntities = xmlCreateEntitiesTable();
226 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
227 sizeof(xmlPredefinedEntityValues[0]);i++) {
228 in = xmlPredefinedEntityValues[i].name;
229 out = &name[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000230 for (;(*out++ = (xmlChar) *in);)in++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000231 in = xmlPredefinedEntityValues[i].value;
232 out = &value[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000233 for (;(*out++ = (xmlChar) *in);)in++;
234 xmlAddEntity(xmlPredefinedEntities, (const xmlChar *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000235 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000236 &value[0]);
237 }
238}
239
Daniel Veillardccb09631998-10-27 06:21:04 +0000240/**
Daniel Veillarda594bf41999-12-01 09:51:45 +0000241 * xmlCleanupPredefinedEntities:
242 *
243 * Cleanup up the predefined entities table.
244 */
245void xmlCleanupPredefinedEntities(void) {
246 if (xmlPredefinedEntities == NULL) return;
247
248 xmlFreeEntitiesTable(xmlPredefinedEntities);
249 xmlPredefinedEntities = NULL;
250}
251
252/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000253 * xmlGetPredefinedEntity:
254 * @name: the entity name
255 *
256 * Check whether this name is an predefined entity.
257 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000258 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000259 */
260xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000261xmlGetPredefinedEntity(const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000262 int i;
263 xmlEntityPtr cur;
264
265 if (xmlPredefinedEntities == NULL)
266 xmlInitializePredefinedEntities();
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000267#ifdef ENTITY_HASH_SIZE
268 i = xmlEntityComputeHash(name);
269 cur = xmlPredefinedEntities->table[i];
270 while (cur != NULL) {
271 if (!xmlStrcmp(cur->name, name))
272 return(cur);
273 cur = cur->nexte;
274 }
275#else
Daniel Veillardccb09631998-10-27 06:21:04 +0000276 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000277 cur = xmlPredefinedEntities->table[i];
Daniel Veillardccb09631998-10-27 06:21:04 +0000278 if (!xmlStrcmp(cur->name, name)) return(cur);
279 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000280#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000281 return(NULL);
282}
283
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000284/**
285 * xmlAddDtdEntity:
286 * @doc: the document
287 * @name: the entity name
288 * @type: the entity type XML_xxx_yyy_ENTITY
289 * @ExternalID: the entity external ID if available
290 * @SystemID: the entity system ID if available
291 * @content: the entity content
292 *
Daniel Veillardcf461992000-03-14 18:30:20 +0000293 * Register a new entity for this document DTD external subset.
294 *
295 * Returns a pointer to the entity or NULL in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +0000296 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000297xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000298xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
Daniel Veillardcf461992000-03-14 18:30:20 +0000299 const xmlChar *ExternalID, const xmlChar *SystemID,
300 const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000301 xmlEntitiesTablePtr table;
Daniel Veillardcf461992000-03-14 18:30:20 +0000302 xmlEntityPtr ret;
303 xmlDtdPtr dtd;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000304
Daniel Veillardcf461992000-03-14 18:30:20 +0000305 if (doc == NULL) {
306 fprintf(stderr,
307 "xmlAddDtdEntity: doc == NULL !\n");
308 return(NULL);
309 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000310 if (doc->extSubset == NULL) {
311 fprintf(stderr,
312 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000313 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000314 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000315 dtd = doc->extSubset;
316 table = (xmlEntitiesTablePtr) dtd->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000317 if (table == NULL) {
318 table = xmlCreateEntitiesTable();
Daniel Veillardcf461992000-03-14 18:30:20 +0000319 dtd->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000320 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000321 ret = xmlAddEntity(table, name, type, ExternalID, SystemID, content);
322 if (ret == NULL) return(NULL);
323
324 /*
325 * Link it to the Dtd
326 */
327 ret->parent = dtd;
328 ret->doc = dtd->doc;
329 if (dtd->last == NULL) {
330 dtd->children = dtd->last = (xmlNodePtr) ret;
331 } else {
332 dtd->last->next = (xmlNodePtr) ret;
333 ret->prev = dtd->last;
334 dtd->last = (xmlNodePtr) ret;
335 }
336 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000337}
338
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000339/**
340 * xmlAddDocEntity:
341 * @doc: the document
342 * @name: the entity name
343 * @type: the entity type XML_xxx_yyy_ENTITY
344 * @ExternalID: the entity external ID if available
345 * @SystemID: the entity system ID if available
346 * @content: the entity content
347 *
348 * Register a new entity for this document.
Daniel Veillardcf461992000-03-14 18:30:20 +0000349 *
350 * Returns a pointer to the entity or NULL in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +0000351 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000352xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000353xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
Daniel Veillardcf461992000-03-14 18:30:20 +0000354 const xmlChar *ExternalID, const xmlChar *SystemID,
355 const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000356 xmlEntitiesTablePtr table;
Daniel Veillardcf461992000-03-14 18:30:20 +0000357 xmlEntityPtr ret;
358 xmlDtdPtr dtd;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000359
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000360 if (doc == NULL) {
361 fprintf(stderr,
362 "xmlAddDocEntity: document is NULL !\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000363 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000364 }
365 if (doc->intSubset == NULL) {
366 fprintf(stderr,
367 "xmlAddDtdEntity: document without internal subset !\n");
Daniel Veillardcf461992000-03-14 18:30:20 +0000368 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000369 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000370 dtd = doc->intSubset;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000371 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000372 if (table == NULL) {
373 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000374 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000375 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000376 ret = xmlAddEntity(table, name, type, ExternalID, SystemID, content);
377 if (ret == NULL) return(NULL);
378
379 /*
380 * Link it to the Dtd
381 */
382 ret->parent = dtd;
383 ret->doc = dtd->doc;
384 if (dtd->last == NULL) {
385 dtd->children = dtd->last = (xmlNodePtr) ret;
386 } else {
387 dtd->last->next = (xmlNodePtr) ret;
388 ret->prev = dtd->last;
389 dtd->last = (xmlNodePtr) ret;
390 }
391 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000392}
393
Daniel Veillardcf461992000-03-14 18:30:20 +0000394#ifdef WITH_EXTRA_ENT_DETECT
395/**
396 * xmlEntityCheckReference:
397 * @ent: an existing entity
398 * @to: the entity name it's referencing
399 *
400 * Function to keep track of references and detect cycles (well formedness
401 * errors !).
402 *
403 * Returns: 0 if Okay, -1 in case of general error, 1 in case of loop
404 * detection.
405 */
406int
407xmlEntityCheckReference(xmlEntityPtr ent, const xmlChar *to) {
408 int i;
409 xmlDocPtr doc;
410
411 if (ent == NULL) return(-1);
412 if (to == NULL) return(-1);
413
414 doc = ent->doc;
415 if (doc == NULL) return(-1);
416
417#ifdef DEBUG_ENT_REF
418 printf("xmlEntityCheckReference(%s to %s)\n", ent->name, to);
419#endif
420
421
422 /*
423 * Do a recursive checking
424 */
425 for (i = 0;i < ent->entNr;i++) {
426 xmlEntityPtr indir = NULL;
427
428 if (!xmlStrcmp(to, ent->entTab[i]))
429 return(1);
430
431 switch (ent->etype) {
432 case XML_INTERNAL_GENERAL_ENTITY:
433 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
434 indir = xmlGetDocEntity(doc, ent->entTab[i]);
435 break;
436 case XML_INTERNAL_PARAMETER_ENTITY:
437 case XML_EXTERNAL_PARAMETER_ENTITY:
438 indir = xmlGetDtdEntity(doc, ent->entTab[i]);
439 break;
440 case XML_INTERNAL_PREDEFINED_ENTITY:
441 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
442 break;
443 }
444 if (xmlEntityCheckReference(indir, to) == 1)
445 return(1);
446 }
447 return(0);
448}
449
450/**
451 * xmlEntityAddReference:
452 * @ent: an existing entity
453 * @to: the entity name it's referencing
454 *
455 * Function to register reuse of an existing entity from a (new) one
456 * Used to keep track of references and detect cycles (well formedness
457 * errors !).
458 *
459 * Returns: 0 if Okay, -1 in case of general error, 1 in case of loop
460 * detection.
461 */
462int
463xmlEntityAddReference(xmlEntityPtr ent, const xmlChar *to) {
464 int i;
465 xmlDocPtr doc;
466 xmlEntityPtr indir = NULL;
467
468 if (ent == NULL) return(-1);
469 if (to == NULL) return(-1);
470
471 doc = ent->doc;
472 if (doc == NULL) return(-1);
473
474#ifdef DEBUG_ENT_REF
475 printf("xmlEntityAddReference(%s to %s)\n", ent->name, to);
476#endif
477 if (ent->entTab == NULL) {
478 ent->entNr = 0;
479 ent->entMax = 5;
480 ent->entTab = (xmlChar **) xmlMalloc(ent->entMax * sizeof(xmlChar *));
481 if (ent->entTab == NULL) {
482 fprintf(stderr, "xmlEntityAddReference: out of memory !\n");
483 return(-1);
484 }
485 }
486
487 for (i = 0;i < ent->entNr;i++) {
488 if (!xmlStrcmp(to, ent->entTab[i]))
489 return(0);
490 }
491
492 /*
493 * Do a recursive checking
494 */
495
496 switch (ent->etype) {
497 case XML_INTERNAL_GENERAL_ENTITY:
498 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
499 indir = xmlGetDocEntity(doc, to);
500 break;
501 case XML_INTERNAL_PARAMETER_ENTITY:
502 case XML_EXTERNAL_PARAMETER_ENTITY:
503 indir = xmlGetDtdEntity(doc, to);
504 break;
505 case XML_INTERNAL_PREDEFINED_ENTITY:
506 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
507 break;
508 }
509 if ((indir != NULL) &&
510 (xmlEntityCheckReference(indir, ent->name) == 1))
511 return(1);
512
513 /*
514 * Add this to the list
515 */
516 if (ent->entMax <= ent->entNr) {
517 ent->entMax *= 2;
518 ent->entTab = (xmlChar **) xmlRealloc(ent->entTab,
519 ent->entMax * sizeof(xmlChar *));
520 if (ent->entTab == NULL) {
521 fprintf(stderr, "xmlEntityAddReference: out of memory !\n");
522 return(-1);
523 }
524 }
525 ent->entTab[ent->entNr++] = xmlStrdup(to);
526 return(0);
527}
528#endif
529
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000530
531/**
532 * xmlGetEntityFromTable:
533 * @table: an entity table
534 * @name: the entity name
535 * @parameter: look for parameter entities
536 *
537 * Do an entity lookup in the table.
538 * returns the corresponding parameter entity, if found.
539 *
540 * Returns A pointer to the entity structure or NULL if not found.
541 */
542xmlEntityPtr
543xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name,
544 int parameter) {
545 xmlEntityPtr cur;
546#ifdef ENTITY_HASH_SIZE
547 int hash;
548
549 hash = xmlEntityComputeHash(name);
550 cur = table->table[hash];
551 while (cur != NULL) {
552 switch (cur->etype) {
553 case XML_INTERNAL_PARAMETER_ENTITY:
554 case XML_EXTERNAL_PARAMETER_ENTITY:
555 if ((parameter) && (!xmlStrcmp(cur->name, name)))
556 return(cur);
557 default:
558 if ((!parameter) && (!xmlStrcmp(cur->name, name)))
559 return(cur);
560 }
561 cur = cur->nexte;
562 }
563#else
564 int i;
565
566 for (i = 0;i < table->nb_entities;i++) {
567 cur = table->table[i];
568 switch (cur->etype) {
569 case XML_INTERNAL_PARAMETER_ENTITY:
570 case XML_EXTERNAL_PARAMETER_ENTITY:
571 if ((parameter) && (!xmlStrcmp(cur->name, name)))
572 return(cur);
573 default:
574 if ((!parameter) && (!xmlStrcmp(cur->name, name)))
575 return(cur);
576 }
577 }
578#endif
579 return(NULL);
580}
581
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000582/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000583 * xmlGetParameterEntity:
584 * @doc: the document referencing the entity
585 * @name: the entity name
586 *
587 * Do an entity lookup in the internal and external subsets and
588 * returns the corresponding parameter entity, if found.
589 *
590 * Returns A pointer to the entity structure or NULL if not found.
591 */
592xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000593xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000594 xmlEntitiesTablePtr table;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000595 xmlEntityPtr ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000596
597 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
598 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000599 ret = xmlGetEntityFromTable(table, name, 1);
600 if (ret != NULL)
601 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000602 }
603 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
604 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000605 return(xmlGetEntityFromTable(table, name, 1));
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000606 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000607 return(NULL);
608}
609
610/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000611 * xmlGetDtdEntity:
612 * @doc: the document referencing the entity
613 * @name: the entity name
614 *
615 * Do an entity lookup in the Dtd entity hash table and
616 * returns the corresponding entity, if found.
617 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000618 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000619 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000620xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000621xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000622 xmlEntitiesTablePtr table;
623
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000624 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
625 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000626 return(xmlGetEntityFromTable(table, name, 0));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000627 }
628 return(NULL);
629}
630
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000631/**
632 * xmlGetDocEntity:
633 * @doc: the document referencing the entity
634 * @name: the entity name
635 *
636 * Do an entity lookup in the document entity hash table and
637 * returns the corrsponding entity, otherwise a lookup is done
638 * in the predefined entities too.
639 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000640 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000641 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000642xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000643xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000644 xmlEntityPtr cur;
645 xmlEntitiesTablePtr table;
646
Daniel Veillard4b5b80c2000-09-08 18:54:41 +0000647 if (doc != NULL) {
648 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
649 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
650 cur = xmlGetEntityFromTable(table, name, 0);
651 if (cur != NULL)
652 return(cur);
653 }
654 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
655 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
656 cur = xmlGetEntityFromTable(table, name, 0);
657 if (cur != NULL)
658 return(cur);
659 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000660 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000661 if (xmlPredefinedEntities == NULL)
662 xmlInitializePredefinedEntities();
663 table = xmlPredefinedEntities;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000664 return(xmlGetEntityFromTable(table, name, 0));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000665}
666
667/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000668 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
669 * | [#x10000-#x10FFFF]
670 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
671 */
672#define IS_CHAR(c) \
673 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
674 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
675
Daniel Veillard14fff061999-06-22 21:49:07 +0000676/*
677 * A buffer used for converting entities to their equivalent and back.
Daniel Veillard14fff061999-06-22 21:49:07 +0000678 */
679static int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000680static xmlChar *buffer = NULL;
Daniel Veillard14fff061999-06-22 21:49:07 +0000681
Daniel Veillard0142b842000-01-14 14:45:24 +0000682int growBuffer(void) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000683 buffer_size *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000684 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000685 if (buffer == NULL) {
686 perror("realloc failed");
Daniel Veillard0142b842000-01-14 14:45:24 +0000687 return(-1);
Daniel Veillard14fff061999-06-22 21:49:07 +0000688 }
Daniel Veillard0142b842000-01-14 14:45:24 +0000689 return(0);
Daniel Veillard14fff061999-06-22 21:49:07 +0000690}
691
692
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000693/**
694 * xmlEncodeEntities:
695 * @doc: the document containing the string
696 * @input: A string to convert to XML.
697 *
698 * Do a global encoding of a string, replacing the predefined entities
699 * and non ASCII values with their entities and CharRef counterparts.
700 *
Daniel Veillardb96e6431999-08-29 21:02:19 +0000701 * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
702 * compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000703 *
704 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000705 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000706 *
707 * Returns A newly allocated string with the substitution done.
708 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000709const xmlChar *
710xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
711 const xmlChar *cur = input;
712 xmlChar *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000713 static int warning = 1;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000714 int html = 0;
715
Daniel Veillardb05deb71999-08-10 19:04:08 +0000716
717 if (warning) {
718 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
719 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
720 warning = 0;
721 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000722
723 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000724 if (doc != NULL)
725 html = (doc->type == XML_HTML_DOCUMENT_NODE);
726
Daniel Veillard14fff061999-06-22 21:49:07 +0000727 if (buffer == NULL) {
728 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000729 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000730 if (buffer == NULL) {
731 perror("malloc failed");
Daniel Veillard0142b842000-01-14 14:45:24 +0000732 return(NULL);
Daniel Veillard14fff061999-06-22 21:49:07 +0000733 }
734 out = buffer;
735 }
736 while (*cur != '\0') {
737 if (out - buffer > buffer_size - 100) {
738 int index = out - buffer;
739
740 growBuffer();
741 out = &buffer[index];
742 }
743
744 /*
745 * By default one have to encode at least '<', '>', '"' and '&' !
746 */
747 if (*cur == '<') {
748 *out++ = '&';
749 *out++ = 'l';
750 *out++ = 't';
751 *out++ = ';';
752 } else if (*cur == '>') {
753 *out++ = '&';
754 *out++ = 'g';
755 *out++ = 't';
756 *out++ = ';';
757 } else if (*cur == '&') {
758 *out++ = '&';
759 *out++ = 'a';
760 *out++ = 'm';
761 *out++ = 'p';
762 *out++ = ';';
763 } else if (*cur == '"') {
764 *out++ = '&';
765 *out++ = 'q';
766 *out++ = 'u';
767 *out++ = 'o';
768 *out++ = 't';
769 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000770 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000771 *out++ = '&';
772 *out++ = 'a';
773 *out++ = 'p';
774 *out++ = 'o';
775 *out++ = 's';
776 *out++ = ';';
777 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
778 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
779 /*
780 * default case, just copy !
781 */
782 *out++ = *cur;
783#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000784 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000785 char buf[10], *ptr;
Daniel Veillard39c7d712000-09-10 16:14:55 +0000786
Daniel Veillard14fff061999-06-22 21:49:07 +0000787#ifdef HAVE_SNPRINTF
Daniel Veillard39c7d712000-09-10 16:14:55 +0000788 snprintf(buf, sizeof(buf), "&#%d;", *cur);
Daniel Veillard14fff061999-06-22 21:49:07 +0000789#else
790 sprintf(buf, "&#%d;", *cur);
791#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +0000792 buf[sizeof(buf) - 1] = 0;
Daniel Veillard14fff061999-06-22 21:49:07 +0000793 ptr = buf;
794 while (*ptr != 0) *out++ = *ptr++;
795#endif
796 } else if (IS_CHAR(*cur)) {
797 char buf[10], *ptr;
798
799#ifdef HAVE_SNPRINTF
Daniel Veillard39c7d712000-09-10 16:14:55 +0000800 snprintf(buf, sizeof(buf), "&#%d;", *cur);
Daniel Veillard14fff061999-06-22 21:49:07 +0000801#else
802 sprintf(buf, "&#%d;", *cur);
803#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +0000804 buf[sizeof(buf) - 1] = 0;
Daniel Veillard14fff061999-06-22 21:49:07 +0000805 ptr = buf;
806 while (*ptr != 0) *out++ = *ptr++;
807 }
808#if 0
809 else {
810 /*
811 * default case, this is not a valid char !
812 * Skip it...
813 */
814 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
815 }
816#endif
817 cur++;
818 }
819 *out++ = 0;
820 return(buffer);
821}
822
823/*
824 * Macro used to grow the current buffer.
825 */
826#define growBufferReentrant() { \
827 buffer_size *= 2; \
Daniel Veillard0142b842000-01-14 14:45:24 +0000828 buffer = (xmlChar *) \
829 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000830 if (buffer == NULL) { \
831 perror("realloc failed"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000832 return(NULL); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000833 } \
834}
835
836
837/**
838 * xmlEncodeEntitiesReentrant:
839 * @doc: the document containing the string
840 * @input: A string to convert to XML.
841 *
842 * Do a global encoding of a string, replacing the predefined entities
843 * and non ASCII values with their entities and CharRef counterparts.
844 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
845 * must be deallocated.
846 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000847 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000848 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000849xmlChar *
850xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
851 const xmlChar *cur = input;
852 xmlChar *buffer = NULL;
853 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000854 int buffer_size = 0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000855 int html = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000856
Daniel Veillard242590e1998-11-13 18:04:35 +0000857 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000858 if (doc != NULL)
859 html = (doc->type == XML_HTML_DOCUMENT_NODE);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000860
861 /*
862 * allocate an translation buffer.
863 */
864 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000865 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000866 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000867 perror("malloc failed");
Daniel Veillard0142b842000-01-14 14:45:24 +0000868 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000869 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000870 out = buffer;
871
Daniel Veillard260a68f1998-08-13 03:39:55 +0000872 while (*cur != '\0') {
873 if (out - buffer > buffer_size - 100) {
874 int index = out - buffer;
875
Daniel Veillard14fff061999-06-22 21:49:07 +0000876 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000877 out = &buffer[index];
878 }
879
880 /*
881 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000882 */
883 if (*cur == '<') {
884 *out++ = '&';
885 *out++ = 'l';
886 *out++ = 't';
887 *out++ = ';';
888 } else if (*cur == '>') {
889 *out++ = '&';
890 *out++ = 'g';
891 *out++ = 't';
892 *out++ = ';';
893 } else if (*cur == '&') {
894 *out++ = '&';
895 *out++ = 'a';
896 *out++ = 'm';
897 *out++ = 'p';
898 *out++ = ';';
899 } else if (*cur == '"') {
900 *out++ = '&';
901 *out++ = 'q';
902 *out++ = 'u';
903 *out++ = 'o';
904 *out++ = 't';
905 *out++ = ';';
Daniel Veillardcf461992000-03-14 18:30:20 +0000906#if 0
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000907 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000908 *out++ = '&';
909 *out++ = 'a';
910 *out++ = 'p';
911 *out++ = 'o';
912 *out++ = 's';
913 *out++ = ';';
Daniel Veillardcf461992000-03-14 18:30:20 +0000914#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000915 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
916 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
917 /*
918 * default case, just copy !
919 */
920 *out++ = *cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000921 } else if (*cur >= 0x80) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000922 if ((doc->encoding != NULL) || (html)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000923 /*
Daniel Veillard39c7d712000-09-10 16:14:55 +0000924 * Bjørn Reese <br@sseusa.com> provided the patch
925 xmlChar xc;
926 xc = (*cur & 0x3F) << 6;
927 if (cur[1] != 0) {
928 xc += *(++cur) & 0x3F;
929 *out++ = xc;
930 } else
Daniel Veillardcf461992000-03-14 18:30:20 +0000931 */
Daniel Veillard39c7d712000-09-10 16:14:55 +0000932 *out++ = *cur;
Daniel Veillardcf461992000-03-14 18:30:20 +0000933 } else {
934 /*
935 * We assume we have UTF-8 input.
936 */
937 char buf[10], *ptr;
938 int val = 0, l = 1;
939
940 if (*cur < 0xC0) {
941 fprintf(stderr,
942 "xmlEncodeEntitiesReentrant : input not UTF-8\n");
943 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
944#ifdef HAVE_SNPRINTF
Daniel Veillard39c7d712000-09-10 16:14:55 +0000945 snprintf(buf, sizeof(buf), "&#%d;", *cur);
Daniel Veillardcf461992000-03-14 18:30:20 +0000946#else
947 sprintf(buf, "&#%d;", *cur);
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000948#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +0000949 buf[sizeof(buf) - 1] = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +0000950 ptr = buf;
951 while (*ptr != 0) *out++ = *ptr++;
952 continue;
953 } else if (*cur < 0xE0) {
954 val = (cur[0]) & 0x1F;
955 val <<= 6;
956 val |= (cur[1]) & 0x3F;
957 l = 2;
958 } else if (*cur < 0xF0) {
959 val = (cur[0]) & 0x0F;
960 val <<= 6;
961 val |= (cur[1]) & 0x3F;
962 val <<= 6;
963 val |= (cur[2]) & 0x3F;
964 l = 3;
965 } else if (*cur < 0xF8) {
966 val = (cur[0]) & 0x07;
967 val <<= 6;
968 val |= (cur[1]) & 0x3F;
969 val <<= 6;
970 val |= (cur[2]) & 0x3F;
971 val <<= 6;
972 val |= (cur[3]) & 0x3F;
973 l = 4;
974 }
975 if ((l == 1) || (!IS_CHAR(val))) {
976 fprintf(stderr,
977 "xmlEncodeEntitiesReentrant : char out of range\n");
978 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
979#ifdef HAVE_SNPRINTF
Daniel Veillard39c7d712000-09-10 16:14:55 +0000980 snprintf(buf, sizeof(buf), "&#%d;", *cur);
Daniel Veillardcf461992000-03-14 18:30:20 +0000981#else
982 sprintf(buf, "&#%d;", *cur);
983#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +0000984 buf[sizeof(buf) - 1] = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +0000985 ptr = buf;
986 while (*ptr != 0) *out++ = *ptr++;
987 cur++;
988 continue;
989 }
990 /*
991 * We could do multiple things here. Just save as a char ref
992 */
993#ifdef HAVE_SNPRINTF
Daniel Veillard39c7d712000-09-10 16:14:55 +0000994 snprintf(buf, sizeof(buf), "&#x%X;", val);
Daniel Veillardcf461992000-03-14 18:30:20 +0000995#else
996 sprintf(buf, "&#x%X;", val);
997#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +0000998 buf[sizeof(buf) - 1] = 0;
Daniel Veillardcf461992000-03-14 18:30:20 +0000999 ptr = buf;
1000 while (*ptr != 0) *out++ = *ptr++;
1001 cur += l;
1002 continue;
1003 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00001004 } else if (IS_CHAR(*cur)) {
1005 char buf[10], *ptr;
1006
1007#ifdef HAVE_SNPRINTF
Daniel Veillard39c7d712000-09-10 16:14:55 +00001008 snprintf(buf, sizeof(buf), "&#%d;", *cur);
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00001009#else
1010 sprintf(buf, "&#%d;", *cur);
1011#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00001012 buf[sizeof(buf) - 1] = 0;
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00001013 ptr = buf;
1014 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001015 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00001016#if 0
1017 else {
1018 /*
1019 * default case, this is not a valid char !
1020 * Skip it...
1021 */
1022 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
1023 }
1024#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001025 cur++;
1026 }
1027 *out++ = 0;
1028 return(buffer);
1029}
1030
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001031/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001032 * xmlEncodeSpecialChars:
1033 * @doc: the document containing the string
1034 * @input: A string to convert to XML.
1035 *
1036 * Do a global encoding of a string, replacing the predefined entities
1037 * this routine is reentrant, and result must be deallocated.
1038 *
1039 * Returns A newly allocated string with the substitution done.
1040 */
1041xmlChar *
1042xmlEncodeSpecialChars(xmlDocPtr doc, const xmlChar *input) {
1043 const xmlChar *cur = input;
1044 xmlChar *buffer = NULL;
1045 xmlChar *out = NULL;
1046 int buffer_size = 0;
1047 int html = 0;
1048
1049 if (input == NULL) return(NULL);
1050 if (doc != NULL)
1051 html = (doc->type == XML_HTML_DOCUMENT_NODE);
1052
1053 /*
1054 * allocate an translation buffer.
1055 */
1056 buffer_size = 1000;
1057 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1058 if (buffer == NULL) {
1059 perror("malloc failed");
1060 return(NULL);
1061 }
1062 out = buffer;
1063
1064 while (*cur != '\0') {
1065 if (out - buffer > buffer_size - 10) {
1066 int index = out - buffer;
1067
1068 growBufferReentrant();
1069 out = &buffer[index];
1070 }
1071
1072 /*
1073 * By default one have to encode at least '<', '>', '"' and '&' !
1074 */
1075 if (*cur == '<') {
1076 *out++ = '&';
1077 *out++ = 'l';
1078 *out++ = 't';
1079 *out++ = ';';
1080 } else if (*cur == '>') {
1081 *out++ = '&';
1082 *out++ = 'g';
1083 *out++ = 't';
1084 *out++ = ';';
1085 } else if (*cur == '&') {
1086 *out++ = '&';
1087 *out++ = 'a';
1088 *out++ = 'm';
1089 *out++ = 'p';
1090 *out++ = ';';
1091 } else if (*cur == '"') {
1092 *out++ = '&';
1093 *out++ = 'q';
1094 *out++ = 'u';
1095 *out++ = 'o';
1096 *out++ = 't';
1097 *out++ = ';';
1098 } else {
1099 /*
1100 * Works because on UTF-8, all extended sequences cannot
1101 * result in bytes in the ASCII range.
1102 */
1103 *out++ = *cur;
1104 }
1105 cur++;
1106 }
1107 *out++ = 0;
1108 return(buffer);
1109}
1110
1111/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001112 * xmlCreateEntitiesTable:
1113 *
1114 * create and initialize an empty entities hash table.
1115 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001116 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001117 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001118xmlEntitiesTablePtr
1119xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001120 xmlEntitiesTablePtr ret;
1121
1122 ret = (xmlEntitiesTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001123 xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001124 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001125 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001126 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001127 return(NULL);
1128 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001129 ret->nb_entities = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001130#ifdef ENTITY_HASH_SIZE
1131 ret->max_entities = ENTITY_HASH_SIZE;
Daniel Veillardcf461992000-03-14 18:30:20 +00001132 ret->table = (xmlEntityPtr *)
1133 xmlMalloc(ret->max_entities * sizeof(xmlEntityPtr));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001134 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001135 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardcf461992000-03-14 18:30:20 +00001136 ret->max_entities * (long)sizeof(xmlEntityPtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001137 xmlFree(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001138 return(NULL);
1139 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001140 memset(ret->table, 0, ret->max_entities * sizeof(xmlEntityPtr));
1141#else
1142 ret->max_entities = XML_MIN_ENTITIES_TABLE;
1143 ret->table = (xmlEntityPtr *)
1144 xmlMalloc(ret->max_entities * sizeof(xmlEntityPtr));
1145 if (ret == NULL) {
1146 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
1147 ret->max_entities * (long)sizeof(xmlEntityPtr));
1148 xmlFree(ret);
1149 return(NULL);
1150 }
1151#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001152 return(ret);
1153}
1154
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001155/**
1156 * xmlFreeEntitiesTable:
1157 * @table: An entity table
1158 *
1159 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001160 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001161void
1162xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001163 int i;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001164#ifdef ENTITY_HASH_SIZE
1165 xmlEntityPtr cur, next;
1166#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001167
1168 if (table == NULL) return;
1169
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001170#ifdef ENTITY_HASH_SIZE
1171 for (i = 0;i < ENTITY_HASH_SIZE;i++) {
1172 cur = table->table[i];
1173 while (cur != NULL) {
1174 next = cur->nexte;
1175 xmlFreeEntity(cur);
1176 cur = next;
1177 }
1178 }
1179#else
Daniel Veillard260a68f1998-08-13 03:39:55 +00001180 for (i = 0;i < table->nb_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001181 xmlFreeEntity(table->table[i]);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001182 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001183#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001184 xmlFree(table->table);
1185 xmlFree(table);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001186}
1187
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001188/**
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001189 * xmlCopyEntity:
1190 * @ent: An entity
1191 *
1192 * Build a copy of an entity
1193 *
1194 * Returns the new xmlEntitiesPtr or NULL in case of error.
1195 */
1196xmlEntityPtr
1197xmlCopyEntity(xmlEntityPtr ent) {
1198 xmlEntityPtr cur;
1199
1200 cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
1201 if (cur == NULL) {
1202 fprintf(stderr, "xmlCopyEntity: out of memory !\n");
1203 return(NULL);
1204 }
1205 memset(cur, 0, sizeof(xmlEntity));
1206 cur->type = XML_ELEMENT_DECL;
1207
1208 cur->etype = ent->etype;
1209 if (ent->name != NULL)
1210 cur->name = xmlStrdup(ent->name);
1211 if (ent->ExternalID != NULL)
1212 cur->ExternalID = xmlStrdup(ent->ExternalID);
1213 if (ent->SystemID != NULL)
1214 cur->SystemID = xmlStrdup(ent->SystemID);
1215 if (ent->content != NULL)
1216 cur->content = xmlStrdup(ent->content);
1217 if (ent->orig != NULL)
1218 cur->orig = xmlStrdup(ent->orig);
1219 return(cur);
1220}
1221
1222/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001223 * xmlCopyEntitiesTable:
1224 * @table: An entity table
1225 *
1226 * Build a copy of an entity table.
1227 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001228 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001229 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001230xmlEntitiesTablePtr
1231xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
1232 xmlEntitiesTablePtr ret;
1233 xmlEntityPtr cur, ent;
1234 int i;
1235
Daniel Veillard6454aec1999-09-02 22:04:43 +00001236 ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001237 if (ret == NULL) {
1238 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
1239 return(NULL);
1240 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001241#ifdef ENTITY_HASH_SIZE
1242 ret->table = (xmlEntityPtr *) xmlMalloc(ENTITY_HASH_SIZE *
1243 sizeof(xmlEntityPtr));
1244 if (ret->table == NULL) {
1245 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
1246 xmlFree(ret);
1247 return(NULL);
1248 }
1249#else
Daniel Veillardcf461992000-03-14 18:30:20 +00001250 ret->table = (xmlEntityPtr *) xmlMalloc(table->max_entities *
1251 sizeof(xmlEntityPtr));
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001252 if (ret->table == NULL) {
1253 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001254 xmlFree(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001255 return(NULL);
1256 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001257#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001258 ret->max_entities = table->max_entities;
1259 ret->nb_entities = table->nb_entities;
1260 for (i = 0;i < ret->nb_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001261 ent = table->table[i];
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001262 if (ent == NULL)
1263 cur = NULL;
1264 else
1265 cur = xmlCopyEntity(ent);
1266 ret->table[i] = cur;
1267#ifdef ENTITY_HASH_SIZE
1268 ent = ent->nexte;
1269 while ((ent != NULL) && (cur != NULL)) {
1270 cur->nexte = xmlCopyEntity(ent);
1271 cur = cur->nexte;
1272 }
1273#endif
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001274 }
1275 return(ret);
1276}
1277
1278/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001279 * xmlDumpEntityDecl:
1280 * @buf: An XML buffer.
1281 * @ent: An entity table
1282 *
1283 * This will dump the content of the entity table as an XML DTD definition
1284 */
1285void
1286xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
1287 switch (ent->etype) {
1288 case XML_INTERNAL_GENERAL_ENTITY:
1289 xmlBufferWriteChar(buf, "<!ENTITY ");
1290 xmlBufferWriteCHAR(buf, ent->name);
1291 xmlBufferWriteChar(buf, " ");
1292 if (ent->orig != NULL)
1293 xmlBufferWriteQuotedString(buf, ent->orig);
1294 else
1295 xmlBufferWriteQuotedString(buf, ent->content);
1296 xmlBufferWriteChar(buf, ">\n");
1297 break;
1298 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1299 xmlBufferWriteChar(buf, "<!ENTITY ");
1300 xmlBufferWriteCHAR(buf, ent->name);
1301 if (ent->ExternalID != NULL) {
1302 xmlBufferWriteChar(buf, " PUBLIC ");
1303 xmlBufferWriteQuotedString(buf, ent->ExternalID);
1304 xmlBufferWriteChar(buf, " ");
1305 xmlBufferWriteQuotedString(buf, ent->SystemID);
1306 } else {
1307 xmlBufferWriteChar(buf, " SYSTEM ");
1308 xmlBufferWriteQuotedString(buf, ent->SystemID);
1309 }
1310 xmlBufferWriteChar(buf, ">\n");
1311 break;
1312 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1313 xmlBufferWriteChar(buf, "<!ENTITY ");
1314 xmlBufferWriteCHAR(buf, ent->name);
1315 if (ent->ExternalID != NULL) {
1316 xmlBufferWriteChar(buf, " PUBLIC ");
1317 xmlBufferWriteQuotedString(buf, ent->ExternalID);
1318 xmlBufferWriteChar(buf, " ");
1319 xmlBufferWriteQuotedString(buf, ent->SystemID);
1320 } else {
1321 xmlBufferWriteChar(buf, " SYSTEM ");
1322 xmlBufferWriteQuotedString(buf, ent->SystemID);
1323 }
1324 if (ent->content != NULL) { /* Should be true ! */
1325 xmlBufferWriteChar(buf, " NDATA ");
1326 if (ent->orig != NULL)
1327 xmlBufferWriteCHAR(buf, ent->orig);
1328 else
1329 xmlBufferWriteCHAR(buf, ent->content);
1330 }
1331 xmlBufferWriteChar(buf, ">\n");
1332 break;
1333 case XML_INTERNAL_PARAMETER_ENTITY:
1334 xmlBufferWriteChar(buf, "<!ENTITY % ");
1335 xmlBufferWriteCHAR(buf, ent->name);
1336 xmlBufferWriteChar(buf, " ");
1337 if (ent->orig == NULL)
1338 xmlBufferWriteQuotedString(buf, ent->content);
1339 else
1340 xmlBufferWriteQuotedString(buf, ent->orig);
1341 xmlBufferWriteChar(buf, ">\n");
1342 break;
1343 case XML_EXTERNAL_PARAMETER_ENTITY:
1344 xmlBufferWriteChar(buf, "<!ENTITY % ");
1345 xmlBufferWriteCHAR(buf, ent->name);
1346 if (ent->ExternalID != NULL) {
1347 xmlBufferWriteChar(buf, " PUBLIC ");
1348 xmlBufferWriteQuotedString(buf, ent->ExternalID);
1349 xmlBufferWriteChar(buf, " ");
1350 xmlBufferWriteQuotedString(buf, ent->SystemID);
1351 } else {
1352 xmlBufferWriteChar(buf, " SYSTEM ");
1353 xmlBufferWriteQuotedString(buf, ent->SystemID);
1354 }
1355 xmlBufferWriteChar(buf, ">\n");
1356 break;
1357 default:
1358 fprintf(stderr,
1359 "xmlDumpEntitiesTable: internal: unknown type %d\n",
1360 ent->etype);
1361 }
1362}
1363
1364/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001365 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001366 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001367 * @table: An entity table
1368 *
1369 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +00001370 */
1371void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001372xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001373 int i;
1374 xmlEntityPtr cur;
1375
1376 if (table == NULL) return;
1377
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001378#ifdef ENTITY_HASH_SIZE
1379 for (i = 0;i < ENTITY_HASH_SIZE;i++) {
1380 cur = table->table[i];
1381 while (cur != NULL) {
1382 xmlDumpEntityDecl(buf, cur);
1383 cur = cur->nexte;
1384 }
1385 }
1386#else
Daniel Veillard260a68f1998-08-13 03:39:55 +00001387 for (i = 0;i < table->nb_entities;i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00001388 cur = table->table[i];
1389 xmlDumpEntityDecl(buf, cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001390 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001391#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00001392}