blob: d6580cfebe075db67ed0574f0939511f80cfd51e [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 Veillard6454aec1999-09-02 22:04:43 +000020#include "xmlmemory.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include "entities.h"
Daniel Veillarda0555cc1999-12-01 09:51:45 +000022#include "parser.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000023
24/*
25 * The XML predefined entities.
26 */
27
28struct xmlPredefinedEntityValue {
29 const char *name;
30 const char *value;
31};
32struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
33 { "lt", "<" },
34 { "gt", ">" },
35 { "apos", "'" },
36 { "quot", "\"" },
37 { "amp", "&" }
38};
39
40xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
41
42/*
Daniel Veillard260a68f1998-08-13 03:39:55 +000043 * xmlFreeEntity : clean-up an entity record.
44 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000045void xmlFreeEntity(xmlEntityPtr entity) {
46 if (entity == NULL) return;
47
48 if (entity->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000049 xmlFree((char *) entity->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +000050 if (entity->ExternalID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000051 xmlFree((char *) entity->ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000052 if (entity->SystemID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000053 xmlFree((char *) entity->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000054 if (entity->content != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000055 xmlFree((char *) entity->content);
Daniel Veillard011b63c1999-06-02 17:44:04 +000056 if (entity->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000057 xmlFree((char *) entity->orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +000058 memset(entity, -1, sizeof(xmlEntity));
59}
60
61/*
Daniel Veillardbe36afe1998-11-27 06:39:50 +000062 * xmlAddEntity : register a new entity for an entities table.
Daniel Veillard260a68f1998-08-13 03:39:55 +000063 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +000064static void
Daniel Veillarddd6b3671999-09-23 22:19:22 +000065xmlAddEntity(xmlEntitiesTablePtr table, const xmlChar *name, int type,
66 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000067 int i;
68 xmlEntityPtr cur;
69 int len;
70
71 for (i = 0;i < table->nb_entities;i++) {
72 cur = &table->table[i];
73 if (!xmlStrcmp(cur->name, name)) {
74 /*
75 * The entity is already defined in this Dtd, the spec says to NOT
76 * override it ... Is it worth a Warning ??? !!!
Daniel Veillardb96e6431999-08-29 21:02:19 +000077 * Not having a cprinting context this seems hard ...
Daniel Veillard260a68f1998-08-13 03:39:55 +000078 */
Daniel Veillardb05deb71999-08-10 19:04:08 +000079 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
80 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
81 ((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
82 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)))
83 return;
84 else
85 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
86 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
87 ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
88 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY)))
89 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000090 }
91 }
92 if (table->nb_entities >= table->max_entities) {
93 /*
94 * need more elements.
95 */
96 table->max_entities *= 2;
97 table->table = (xmlEntityPtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +000098 xmlRealloc(table->table, table->max_entities * sizeof(xmlEntity));
Daniel Veillardb05deb71999-08-10 19:04:08 +000099 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000100 perror("realloc failed");
Daniel Veillardb05deb71999-08-10 19:04:08 +0000101 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000102 }
103 }
104 cur = &table->table[table->nb_entities];
105 cur->name = xmlStrdup(name);
106 for (len = 0;name[0] != 0;name++)len++;
107 cur->len = len;
108 cur->type = type;
109 if (ExternalID != NULL)
110 cur->ExternalID = xmlStrdup(ExternalID);
111 else
112 cur->ExternalID = NULL;
113 if (SystemID != NULL)
114 cur->SystemID = xmlStrdup(SystemID);
115 else
116 cur->SystemID = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000117 if (content != NULL) {
118 cur->length = xmlStrlen(content);
119 cur->content = xmlStrndup(content, cur->length);
120 } else {
121 cur->length = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000122 cur->content = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000123 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000124 cur->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000125 table->nb_entities++;
126}
127
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000128/**
129 * xmlInitializePredefinedEntities:
130 *
131 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000132 */
133void xmlInitializePredefinedEntities(void) {
134 int i;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000135 xmlChar name[50];
136 xmlChar value[50];
Daniel Veillard260a68f1998-08-13 03:39:55 +0000137 const char *in;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000138 xmlChar *out;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000139
140 if (xmlPredefinedEntities != NULL) return;
141
142 xmlPredefinedEntities = xmlCreateEntitiesTable();
143 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
144 sizeof(xmlPredefinedEntityValues[0]);i++) {
145 in = xmlPredefinedEntityValues[i].name;
146 out = &name[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000147 for (;(*out++ = (xmlChar) *in);)in++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000148 in = xmlPredefinedEntityValues[i].value;
149 out = &value[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000150 for (;(*out++ = (xmlChar) *in);)in++;
151 xmlAddEntity(xmlPredefinedEntities, (const xmlChar *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000152 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000153 &value[0]);
154 }
155}
156
Daniel Veillardccb09631998-10-27 06:21:04 +0000157/**
Daniel Veillarda594bf41999-12-01 09:51:45 +0000158 * xmlCleanupPredefinedEntities:
159 *
160 * Cleanup up the predefined entities table.
161 */
162void xmlCleanupPredefinedEntities(void) {
163 if (xmlPredefinedEntities == NULL) return;
164
165 xmlFreeEntitiesTable(xmlPredefinedEntities);
166 xmlPredefinedEntities = NULL;
167}
168
169/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000170 * xmlGetPredefinedEntity:
171 * @name: the entity name
172 *
173 * Check whether this name is an predefined entity.
174 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000175 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000176 */
177xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000178xmlGetPredefinedEntity(const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000179 int i;
180 xmlEntityPtr cur;
181
182 if (xmlPredefinedEntities == NULL)
183 xmlInitializePredefinedEntities();
184 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
185 cur = &xmlPredefinedEntities->table[i];
186 if (!xmlStrcmp(cur->name, name)) return(cur);
187 }
188 return(NULL);
189}
190
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000191/**
192 * xmlAddDtdEntity:
193 * @doc: the document
194 * @name: the entity name
195 * @type: the entity type XML_xxx_yyy_ENTITY
196 * @ExternalID: the entity external ID if available
197 * @SystemID: the entity system ID if available
198 * @content: the entity content
199 *
200 * Register a new entity for this document DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000201 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000202void
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000203xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
204 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000205 xmlEntitiesTablePtr table;
206
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000207 if (doc->extSubset == NULL) {
208 fprintf(stderr,
209 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210 return;
211 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000212 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000213 if (table == NULL) {
214 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000215 doc->extSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000216 }
217 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
218}
219
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000220/**
221 * xmlAddDocEntity:
222 * @doc: the document
223 * @name: the entity name
224 * @type: the entity type XML_xxx_yyy_ENTITY
225 * @ExternalID: the entity external ID if available
226 * @SystemID: the entity system ID if available
227 * @content: the entity content
228 *
229 * Register a new entity for this document.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000230 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000231void
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
233 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000234 xmlEntitiesTablePtr table;
235
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000236 if (doc == NULL) {
237 fprintf(stderr,
238 "xmlAddDocEntity: document is NULL !\n");
239 return;
240 }
241 if (doc->intSubset == NULL) {
242 fprintf(stderr,
243 "xmlAddDtdEntity: document without internal subset !\n");
244 return;
245 }
246 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000247 if (table == NULL) {
248 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000250 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000251 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000252}
253
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000254/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000255 * xmlGetParameterEntity:
256 * @doc: the document referencing the entity
257 * @name: the entity name
258 *
259 * Do an entity lookup in the internal and external subsets and
260 * returns the corresponding parameter entity, if found.
261 *
262 * Returns A pointer to the entity structure or NULL if not found.
263 */
264xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000265xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000266 int i;
267 xmlEntityPtr cur;
268 xmlEntitiesTablePtr table;
269
270 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
271 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
272 for (i = 0;i < table->nb_entities;i++) {
273 cur = &table->table[i];
274 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
275 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
276 (!xmlStrcmp(cur->name, name))) return(cur);
277 }
278 }
279 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
280 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
281 for (i = 0;i < table->nb_entities;i++) {
282 cur = &table->table[i];
283 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
284 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
285 (!xmlStrcmp(cur->name, name))) return(cur);
286 }
287 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000288 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
289 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
290 for (i = 0;i < table->nb_entities;i++) {
291 cur = &table->table[i];
292 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
293 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
294 (!xmlStrcmp(cur->name, name))) return(cur);
295 }
296 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000297 return(NULL);
298}
299
300/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000301 * xmlGetDtdEntity:
302 * @doc: the document referencing the entity
303 * @name: the entity name
304 *
305 * Do an entity lookup in the Dtd entity hash table and
306 * returns the corresponding entity, if found.
307 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000308 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000309 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000310xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000311xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000312 int i;
313 xmlEntityPtr cur;
314 xmlEntitiesTablePtr table;
315
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000316 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
317 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000318 for (i = 0;i < table->nb_entities;i++) {
319 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000320 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
321 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
322 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000323 }
324 }
325 return(NULL);
326}
327
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000328/**
329 * xmlGetDocEntity:
330 * @doc: the document referencing the entity
331 * @name: the entity name
332 *
333 * Do an entity lookup in the document entity hash table and
334 * returns the corrsponding entity, otherwise a lookup is done
335 * in the predefined entities too.
336 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000337 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000338 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000339xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000340xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000341 int i;
342 xmlEntityPtr cur;
343 xmlEntitiesTablePtr table;
344
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000345 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
346 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000347 for (i = 0;i < table->nb_entities;i++) {
348 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000349 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
350 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
351 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000352 }
353 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000354 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
355 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
356 for (i = 0;i < table->nb_entities;i++) {
357 cur = &table->table[i];
358 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
359 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
360 (!xmlStrcmp(cur->name, name))) return(cur);
361 }
362 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000363 if (xmlPredefinedEntities == NULL)
364 xmlInitializePredefinedEntities();
365 table = xmlPredefinedEntities;
366 for (i = 0;i < table->nb_entities;i++) {
367 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000368 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
369 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
370 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000371 }
372
373 return(NULL);
374}
375
376/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000377 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
378 * | [#x10000-#x10FFFF]
379 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
380 */
381#define IS_CHAR(c) \
382 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
383 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
384
Daniel Veillard14fff061999-06-22 21:49:07 +0000385/*
386 * A buffer used for converting entities to their equivalent and back.
Daniel Veillard14fff061999-06-22 21:49:07 +0000387 */
388static int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000389static xmlChar *buffer = NULL;
Daniel Veillard14fff061999-06-22 21:49:07 +0000390
Daniel Veillard0142b842000-01-14 14:45:24 +0000391int growBuffer(void) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000392 buffer_size *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000393 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000394 if (buffer == NULL) {
395 perror("realloc failed");
Daniel Veillard0142b842000-01-14 14:45:24 +0000396 return(-1);
Daniel Veillard14fff061999-06-22 21:49:07 +0000397 }
Daniel Veillard0142b842000-01-14 14:45:24 +0000398 return(0);
Daniel Veillard14fff061999-06-22 21:49:07 +0000399}
400
401
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000402/**
403 * xmlEncodeEntities:
404 * @doc: the document containing the string
405 * @input: A string to convert to XML.
406 *
407 * Do a global encoding of a string, replacing the predefined entities
408 * and non ASCII values with their entities and CharRef counterparts.
409 *
Daniel Veillardb96e6431999-08-29 21:02:19 +0000410 * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
411 * compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000412 *
413 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000414 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000415 *
416 * Returns A newly allocated string with the substitution done.
417 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000418const xmlChar *
419xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
420 const xmlChar *cur = input;
421 xmlChar *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000422 static int warning = 1;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000423 int html = 0;
424
Daniel Veillardb05deb71999-08-10 19:04:08 +0000425
426 if (warning) {
427 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
428 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
429 warning = 0;
430 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000431
432 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000433 if (doc != NULL)
434 html = (doc->type == XML_HTML_DOCUMENT_NODE);
435
Daniel Veillard14fff061999-06-22 21:49:07 +0000436 if (buffer == NULL) {
437 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000438 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000439 if (buffer == NULL) {
440 perror("malloc failed");
Daniel Veillard0142b842000-01-14 14:45:24 +0000441 return(NULL);
Daniel Veillard14fff061999-06-22 21:49:07 +0000442 }
443 out = buffer;
444 }
445 while (*cur != '\0') {
446 if (out - buffer > buffer_size - 100) {
447 int index = out - buffer;
448
449 growBuffer();
450 out = &buffer[index];
451 }
452
453 /*
454 * By default one have to encode at least '<', '>', '"' and '&' !
455 */
456 if (*cur == '<') {
457 *out++ = '&';
458 *out++ = 'l';
459 *out++ = 't';
460 *out++ = ';';
461 } else if (*cur == '>') {
462 *out++ = '&';
463 *out++ = 'g';
464 *out++ = 't';
465 *out++ = ';';
466 } else if (*cur == '&') {
467 *out++ = '&';
468 *out++ = 'a';
469 *out++ = 'm';
470 *out++ = 'p';
471 *out++ = ';';
472 } else if (*cur == '"') {
473 *out++ = '&';
474 *out++ = 'q';
475 *out++ = 'u';
476 *out++ = 'o';
477 *out++ = 't';
478 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000479 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000480 *out++ = '&';
481 *out++ = 'a';
482 *out++ = 'p';
483 *out++ = 'o';
484 *out++ = 's';
485 *out++ = ';';
486 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
487 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
488 /*
489 * default case, just copy !
490 */
491 *out++ = *cur;
492#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000493 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000494 char buf[10], *ptr;
495#ifdef HAVE_SNPRINTF
496 snprintf(buf, 9, "&#%d;", *cur);
497#else
498 sprintf(buf, "&#%d;", *cur);
499#endif
500 ptr = buf;
501 while (*ptr != 0) *out++ = *ptr++;
502#endif
503 } else if (IS_CHAR(*cur)) {
504 char buf[10], *ptr;
505
506#ifdef HAVE_SNPRINTF
507 snprintf(buf, 9, "&#%d;", *cur);
508#else
509 sprintf(buf, "&#%d;", *cur);
510#endif
511 ptr = buf;
512 while (*ptr != 0) *out++ = *ptr++;
513 }
514#if 0
515 else {
516 /*
517 * default case, this is not a valid char !
518 * Skip it...
519 */
520 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
521 }
522#endif
523 cur++;
524 }
525 *out++ = 0;
526 return(buffer);
527}
528
529/*
530 * Macro used to grow the current buffer.
531 */
532#define growBufferReentrant() { \
533 buffer_size *= 2; \
Daniel Veillard0142b842000-01-14 14:45:24 +0000534 buffer = (xmlChar *) \
535 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000536 if (buffer == NULL) { \
537 perror("realloc failed"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000538 return(NULL); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000539 } \
540}
541
542
543/**
544 * xmlEncodeEntitiesReentrant:
545 * @doc: the document containing the string
546 * @input: A string to convert to XML.
547 *
548 * Do a global encoding of a string, replacing the predefined entities
549 * and non ASCII values with their entities and CharRef counterparts.
550 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
551 * must be deallocated.
552 *
553 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
554 * get erroneous.
555 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000556 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000557 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000558xmlChar *
559xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
560 const xmlChar *cur = input;
561 xmlChar *buffer = NULL;
562 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000563 int buffer_size = 0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000564 int html = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000565
Daniel Veillard242590e1998-11-13 18:04:35 +0000566 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000567 if (doc != NULL)
568 html = (doc->type == XML_HTML_DOCUMENT_NODE);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000569
570 /*
571 * allocate an translation buffer.
572 */
573 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000574 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000575 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000576 perror("malloc failed");
Daniel Veillard0142b842000-01-14 14:45:24 +0000577 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000578 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000579 out = buffer;
580
Daniel Veillard260a68f1998-08-13 03:39:55 +0000581 while (*cur != '\0') {
582 if (out - buffer > buffer_size - 100) {
583 int index = out - buffer;
584
Daniel Veillard14fff061999-06-22 21:49:07 +0000585 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000586 out = &buffer[index];
587 }
588
589 /*
590 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000591 */
592 if (*cur == '<') {
593 *out++ = '&';
594 *out++ = 'l';
595 *out++ = 't';
596 *out++ = ';';
597 } else if (*cur == '>') {
598 *out++ = '&';
599 *out++ = 'g';
600 *out++ = 't';
601 *out++ = ';';
602 } else if (*cur == '&') {
603 *out++ = '&';
604 *out++ = 'a';
605 *out++ = 'm';
606 *out++ = 'p';
607 *out++ = ';';
608 } else if (*cur == '"') {
609 *out++ = '&';
610 *out++ = 'q';
611 *out++ = 'u';
612 *out++ = 'o';
613 *out++ = 't';
614 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000615 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000616 *out++ = '&';
617 *out++ = 'a';
618 *out++ = 'p';
619 *out++ = 'o';
620 *out++ = 's';
621 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000622 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
623 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
624 /*
625 * default case, just copy !
626 */
627 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000628#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000629 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000630 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000631#ifdef HAVE_SNPRINTF
632 snprintf(buf, 9, "&#%d;", *cur);
633#else
634 sprintf(buf, "&#%d;", *cur);
635#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000636 ptr = buf;
637 while (*ptr != 0) *out++ = *ptr++;
638#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000639 } else if (IS_CHAR(*cur)) {
640 char buf[10], *ptr;
641
642#ifdef HAVE_SNPRINTF
643 snprintf(buf, 9, "&#%d;", *cur);
644#else
645 sprintf(buf, "&#%d;", *cur);
646#endif
647 ptr = buf;
648 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000649 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000650#if 0
651 else {
652 /*
653 * default case, this is not a valid char !
654 * Skip it...
655 */
656 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
657 }
658#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000659 cur++;
660 }
661 *out++ = 0;
662 return(buffer);
663}
664
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000665/**
666 * xmlCreateEntitiesTable:
667 *
668 * create and initialize an empty entities hash table.
669 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000670 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000671 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000672xmlEntitiesTablePtr
673xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000674 xmlEntitiesTablePtr ret;
675
676 ret = (xmlEntitiesTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000677 xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000678 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000679 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000680 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000681 return(NULL);
682 }
683 ret->max_entities = XML_MIN_ENTITIES_TABLE;
684 ret->nb_entities = 0;
685 ret->table = (xmlEntityPtr )
Daniel Veillard6454aec1999-09-02 22:04:43 +0000686 xmlMalloc(ret->max_entities * sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000687 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000688 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000689 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000690 xmlFree(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000691 return(NULL);
692 }
693 return(ret);
694}
695
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000696/**
697 * xmlFreeEntitiesTable:
698 * @table: An entity table
699 *
700 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000701 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000702void
703xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000704 int i;
705
706 if (table == NULL) return;
707
708 for (i = 0;i < table->nb_entities;i++) {
709 xmlFreeEntity(&table->table[i]);
710 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000711 xmlFree(table->table);
712 xmlFree(table);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000713}
714
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000715/**
716 * xmlCopyEntitiesTable:
717 * @table: An entity table
718 *
719 * Build a copy of an entity table.
720 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000721 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000722 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000723xmlEntitiesTablePtr
724xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
725 xmlEntitiesTablePtr ret;
726 xmlEntityPtr cur, ent;
727 int i;
728
Daniel Veillard6454aec1999-09-02 22:04:43 +0000729 ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000730 if (ret == NULL) {
731 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
732 return(NULL);
733 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000734 ret->table = (xmlEntityPtr) xmlMalloc(table->max_entities *
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000735 sizeof(xmlEntity));
736 if (ret->table == NULL) {
737 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000738 xmlFree(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000739 return(NULL);
740 }
741 ret->max_entities = table->max_entities;
742 ret->nb_entities = table->nb_entities;
743 for (i = 0;i < ret->nb_entities;i++) {
744 cur = &ret->table[i];
745 ent = &table->table[i];
746 cur->len = ent->len;
747 cur->type = ent->type;
748 if (ent->name != NULL)
749 cur->name = xmlStrdup(ent->name);
750 else
751 cur->name = NULL;
752 if (ent->ExternalID != NULL)
753 cur->ExternalID = xmlStrdup(ent->ExternalID);
754 else
755 cur->ExternalID = NULL;
756 if (ent->SystemID != NULL)
757 cur->SystemID = xmlStrdup(ent->SystemID);
758 else
759 cur->SystemID = NULL;
760 if (ent->content != NULL)
761 cur->content = xmlStrdup(ent->content);
762 else
763 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000764 if (ent->orig != NULL)
765 cur->orig = xmlStrdup(ent->orig);
766 else
767 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000768 }
769 return(ret);
770}
771
772/**
773 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000774 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000775 * @table: An entity table
776 *
777 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000778 */
779void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000780xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000781 int i;
782 xmlEntityPtr cur;
783
784 if (table == NULL) return;
785
786 for (i = 0;i < table->nb_entities;i++) {
787 cur = &table->table[i];
788 switch (cur->type) {
789 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000790 xmlBufferWriteChar(buf, "<!ENTITY ");
791 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000792 xmlBufferWriteChar(buf, " ");
793 if (cur->orig != NULL)
794 xmlBufferWriteQuotedString(buf, cur->orig);
795 else
796 xmlBufferWriteQuotedString(buf, cur->content);
797 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000798 break;
799 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000800 xmlBufferWriteChar(buf, "<!ENTITY ");
801 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000802 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000803 xmlBufferWriteChar(buf, " PUBLIC ");
804 xmlBufferWriteQuotedString(buf, cur->ExternalID);
805 xmlBufferWriteChar(buf, " ");
806 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000807 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000808 xmlBufferWriteChar(buf, " SYSTEM ");
809 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000810 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000811 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000812 break;
813 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000814 xmlBufferWriteChar(buf, "<!ENTITY ");
815 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000816 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000817 xmlBufferWriteChar(buf, " PUBLIC ");
818 xmlBufferWriteQuotedString(buf, cur->ExternalID);
819 xmlBufferWriteChar(buf, " ");
820 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000821 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000822 xmlBufferWriteChar(buf, " SYSTEM ");
823 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000824 }
825 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000826 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000827 if (cur->orig != NULL)
828 xmlBufferWriteCHAR(buf, cur->orig);
829 else
830 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000831 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000832 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000833 break;
834 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000835 xmlBufferWriteChar(buf, "<!ENTITY % ");
836 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000837 xmlBufferWriteChar(buf, " ");
838 if (cur->orig == NULL)
839 xmlBufferWriteQuotedString(buf, cur->content);
840 else
841 xmlBufferWriteQuotedString(buf, cur->orig);
842 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000843 break;
844 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000845 xmlBufferWriteChar(buf, "<!ENTITY % ");
846 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000847 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000848 xmlBufferWriteChar(buf, " PUBLIC ");
849 xmlBufferWriteQuotedString(buf, cur->ExternalID);
850 xmlBufferWriteChar(buf, " ");
851 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000852 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000853 xmlBufferWriteChar(buf, " SYSTEM ");
854 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000855 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000856 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000857 break;
858 default:
859 fprintf(stderr,
860 "xmlDumpEntitiesTable: internal: unknown type %d\n",
861 cur->type);
862 }
863 }
864}