blob: 78571e02d0e38fc89bc1a8d5d67f289c89895f5b [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 Veillard7f7d1111999-09-22 09:46:25 +00009#ifndef WIN32
10#include "config.h"
11#endif
12
Daniel Veillard260a68f1998-08-13 03:39:55 +000013#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000014#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000015#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +000018#include "xmlmemory.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000019#include "entities.h"
20
21/*
22 * The XML predefined entities.
23 */
24
25struct xmlPredefinedEntityValue {
26 const char *name;
27 const char *value;
28};
29struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
30 { "lt", "<" },
31 { "gt", ">" },
32 { "apos", "'" },
33 { "quot", "\"" },
34 { "amp", "&" }
35};
36
37xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
38
39/*
Daniel Veillard260a68f1998-08-13 03:39:55 +000040 * xmlFreeEntity : clean-up an entity record.
41 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000042void xmlFreeEntity(xmlEntityPtr entity) {
43 if (entity == NULL) return;
44
45 if (entity->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000046 xmlFree((char *) entity->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +000047 if (entity->ExternalID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000048 xmlFree((char *) entity->ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000049 if (entity->SystemID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000050 xmlFree((char *) entity->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000051 if (entity->content != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000052 xmlFree((char *) entity->content);
Daniel Veillard011b63c1999-06-02 17:44:04 +000053 if (entity->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000054 xmlFree((char *) entity->orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +000055 memset(entity, -1, sizeof(xmlEntity));
56}
57
58/*
Daniel Veillardbe36afe1998-11-27 06:39:50 +000059 * xmlAddEntity : register a new entity for an entities table.
Daniel Veillard260a68f1998-08-13 03:39:55 +000060 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +000061static void
Daniel Veillarddd6b3671999-09-23 22:19:22 +000062xmlAddEntity(xmlEntitiesTablePtr table, const xmlChar *name, int type,
63 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000064 int i;
65 xmlEntityPtr cur;
66 int len;
67
68 for (i = 0;i < table->nb_entities;i++) {
69 cur = &table->table[i];
70 if (!xmlStrcmp(cur->name, name)) {
71 /*
72 * The entity is already defined in this Dtd, the spec says to NOT
73 * override it ... Is it worth a Warning ??? !!!
Daniel Veillardb96e6431999-08-29 21:02:19 +000074 * Not having a cprinting context this seems hard ...
Daniel Veillard260a68f1998-08-13 03:39:55 +000075 */
Daniel Veillardb05deb71999-08-10 19:04:08 +000076 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
77 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
78 ((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
79 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)))
80 return;
81 else
82 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
83 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
84 ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
85 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY)))
86 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000087 }
88 }
89 if (table->nb_entities >= table->max_entities) {
90 /*
91 * need more elements.
92 */
93 table->max_entities *= 2;
94 table->table = (xmlEntityPtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +000095 xmlRealloc(table->table, table->max_entities * sizeof(xmlEntity));
Daniel Veillardb05deb71999-08-10 19:04:08 +000096 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000097 perror("realloc failed");
Daniel Veillardb05deb71999-08-10 19:04:08 +000098 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000099 }
100 }
101 cur = &table->table[table->nb_entities];
102 cur->name = xmlStrdup(name);
103 for (len = 0;name[0] != 0;name++)len++;
104 cur->len = len;
105 cur->type = type;
106 if (ExternalID != NULL)
107 cur->ExternalID = xmlStrdup(ExternalID);
108 else
109 cur->ExternalID = NULL;
110 if (SystemID != NULL)
111 cur->SystemID = xmlStrdup(SystemID);
112 else
113 cur->SystemID = NULL;
114 if (content != NULL)
115 cur->content = xmlStrdup(content);
116 else
117 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000118 cur->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000119 table->nb_entities++;
120}
121
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000122/**
123 * xmlInitializePredefinedEntities:
124 *
125 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126 */
127void xmlInitializePredefinedEntities(void) {
128 int i;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000129 xmlChar name[50];
130 xmlChar value[50];
Daniel Veillard260a68f1998-08-13 03:39:55 +0000131 const char *in;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000132 xmlChar *out;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000133
134 if (xmlPredefinedEntities != NULL) return;
135
136 xmlPredefinedEntities = xmlCreateEntitiesTable();
137 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
138 sizeof(xmlPredefinedEntityValues[0]);i++) {
139 in = xmlPredefinedEntityValues[i].name;
140 out = &name[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000141 for (;(*out++ = (xmlChar) *in);)in++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000142 in = xmlPredefinedEntityValues[i].value;
143 out = &value[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000144 for (;(*out++ = (xmlChar) *in);)in++;
145 xmlAddEntity(xmlPredefinedEntities, (const xmlChar *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000146 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000147 &value[0]);
148 }
149}
150
Daniel Veillardccb09631998-10-27 06:21:04 +0000151/**
152 * xmlGetPredefinedEntity:
153 * @name: the entity name
154 *
155 * Check whether this name is an predefined entity.
156 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000157 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000158 */
159xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000160xmlGetPredefinedEntity(const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000161 int i;
162 xmlEntityPtr cur;
163
164 if (xmlPredefinedEntities == NULL)
165 xmlInitializePredefinedEntities();
166 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
167 cur = &xmlPredefinedEntities->table[i];
168 if (!xmlStrcmp(cur->name, name)) return(cur);
169 }
170 return(NULL);
171}
172
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000173/**
174 * xmlAddDtdEntity:
175 * @doc: the document
176 * @name: the entity name
177 * @type: the entity type XML_xxx_yyy_ENTITY
178 * @ExternalID: the entity external ID if available
179 * @SystemID: the entity system ID if available
180 * @content: the entity content
181 *
182 * Register a new entity for this document DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000183 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000184void
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000185xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
186 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000187 xmlEntitiesTablePtr table;
188
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000189 if (doc->extSubset == NULL) {
190 fprintf(stderr,
191 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000192 return;
193 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000194 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000195 if (table == NULL) {
196 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000197 doc->extSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000198 }
199 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
200}
201
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000202/**
203 * xmlAddDocEntity:
204 * @doc: the document
205 * @name: the entity name
206 * @type: the entity type XML_xxx_yyy_ENTITY
207 * @ExternalID: the entity external ID if available
208 * @SystemID: the entity system ID if available
209 * @content: the entity content
210 *
211 * Register a new entity for this document.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000212 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000213void
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000214xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
215 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000216 xmlEntitiesTablePtr table;
217
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000218 if (doc == NULL) {
219 fprintf(stderr,
220 "xmlAddDocEntity: document is NULL !\n");
221 return;
222 }
223 if (doc->intSubset == NULL) {
224 fprintf(stderr,
225 "xmlAddDtdEntity: document without internal subset !\n");
226 return;
227 }
228 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000229 if (table == NULL) {
230 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000231 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000232 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000233 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000234}
235
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000236/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000237 * xmlGetParameterEntity:
238 * @doc: the document referencing the entity
239 * @name: the entity name
240 *
241 * Do an entity lookup in the internal and external subsets and
242 * returns the corresponding parameter entity, if found.
243 *
244 * Returns A pointer to the entity structure or NULL if not found.
245 */
246xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000247xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000248 int i;
249 xmlEntityPtr cur;
250 xmlEntitiesTablePtr table;
251
252 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
253 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
254 for (i = 0;i < table->nb_entities;i++) {
255 cur = &table->table[i];
256 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
257 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
258 (!xmlStrcmp(cur->name, name))) return(cur);
259 }
260 }
261 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
262 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
263 for (i = 0;i < table->nb_entities;i++) {
264 cur = &table->table[i];
265 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
266 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
267 (!xmlStrcmp(cur->name, name))) return(cur);
268 }
269 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000270 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
271 table = (xmlEntitiesTablePtr) doc->extSubset->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 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000279 return(NULL);
280}
281
282/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000283 * xmlGetDtdEntity:
284 * @doc: the document referencing the entity
285 * @name: the entity name
286 *
287 * Do an entity lookup in the Dtd entity hash table and
288 * returns the corresponding entity, if found.
289 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000290 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000291 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000292xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000293xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000294 int i;
295 xmlEntityPtr cur;
296 xmlEntitiesTablePtr table;
297
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000298 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
299 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000300 for (i = 0;i < table->nb_entities;i++) {
301 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000302 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
303 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
304 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000305 }
306 }
307 return(NULL);
308}
309
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000310/**
311 * xmlGetDocEntity:
312 * @doc: the document referencing the entity
313 * @name: the entity name
314 *
315 * Do an entity lookup in the document entity hash table and
316 * returns the corrsponding entity, otherwise a lookup is done
317 * in the predefined entities too.
318 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000319 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000320 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000321xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000322xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000323 int i;
324 xmlEntityPtr cur;
325 xmlEntitiesTablePtr table;
326
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000327 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
328 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000329 for (i = 0;i < table->nb_entities;i++) {
330 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000331 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
332 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
333 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000334 }
335 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000336 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
337 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
338 for (i = 0;i < table->nb_entities;i++) {
339 cur = &table->table[i];
340 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
341 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
342 (!xmlStrcmp(cur->name, name))) return(cur);
343 }
344 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000345 if (xmlPredefinedEntities == NULL)
346 xmlInitializePredefinedEntities();
347 table = xmlPredefinedEntities;
348 for (i = 0;i < table->nb_entities;i++) {
349 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000350 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
351 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
352 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000353 }
354
355 return(NULL);
356}
357
358/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000359 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
360 * | [#x10000-#x10FFFF]
361 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
362 */
363#define IS_CHAR(c) \
364 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
365 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
366
Daniel Veillard14fff061999-06-22 21:49:07 +0000367/*
368 * A buffer used for converting entities to their equivalent and back.
Daniel Veillard14fff061999-06-22 21:49:07 +0000369 */
370static int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000371static xmlChar *buffer = NULL;
Daniel Veillard14fff061999-06-22 21:49:07 +0000372
373void growBuffer(void) {
374 buffer_size *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000375 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000376 if (buffer == NULL) {
377 perror("realloc failed");
378 exit(1);
379 }
380}
381
382
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000383/**
384 * xmlEncodeEntities:
385 * @doc: the document containing the string
386 * @input: A string to convert to XML.
387 *
388 * Do a global encoding of a string, replacing the predefined entities
389 * and non ASCII values with their entities and CharRef counterparts.
390 *
Daniel Veillardb96e6431999-08-29 21:02:19 +0000391 * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
392 * compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000393 *
394 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000395 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000396 *
397 * Returns A newly allocated string with the substitution done.
398 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000399const xmlChar *
400xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
401 const xmlChar *cur = input;
402 xmlChar *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000403 static int warning = 1;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000404 int html = 0;
405
Daniel Veillardb05deb71999-08-10 19:04:08 +0000406
407 if (warning) {
408 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
409 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
410 warning = 0;
411 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000412
413 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000414 if (doc != NULL)
415 html = (doc->type == XML_HTML_DOCUMENT_NODE);
416
Daniel Veillard14fff061999-06-22 21:49:07 +0000417 if (buffer == NULL) {
418 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000419 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000420 if (buffer == NULL) {
421 perror("malloc failed");
422 exit(1);
423 }
424 out = buffer;
425 }
426 while (*cur != '\0') {
427 if (out - buffer > buffer_size - 100) {
428 int index = out - buffer;
429
430 growBuffer();
431 out = &buffer[index];
432 }
433
434 /*
435 * By default one have to encode at least '<', '>', '"' and '&' !
436 */
437 if (*cur == '<') {
438 *out++ = '&';
439 *out++ = 'l';
440 *out++ = 't';
441 *out++ = ';';
442 } else if (*cur == '>') {
443 *out++ = '&';
444 *out++ = 'g';
445 *out++ = 't';
446 *out++ = ';';
447 } else if (*cur == '&') {
448 *out++ = '&';
449 *out++ = 'a';
450 *out++ = 'm';
451 *out++ = 'p';
452 *out++ = ';';
453 } else if (*cur == '"') {
454 *out++ = '&';
455 *out++ = 'q';
456 *out++ = 'u';
457 *out++ = 'o';
458 *out++ = 't';
459 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000460 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000461 *out++ = '&';
462 *out++ = 'a';
463 *out++ = 'p';
464 *out++ = 'o';
465 *out++ = 's';
466 *out++ = ';';
467 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
468 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
469 /*
470 * default case, just copy !
471 */
472 *out++ = *cur;
473#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000474 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000475 char buf[10], *ptr;
476#ifdef HAVE_SNPRINTF
477 snprintf(buf, 9, "&#%d;", *cur);
478#else
479 sprintf(buf, "&#%d;", *cur);
480#endif
481 ptr = buf;
482 while (*ptr != 0) *out++ = *ptr++;
483#endif
484 } else if (IS_CHAR(*cur)) {
485 char buf[10], *ptr;
486
487#ifdef HAVE_SNPRINTF
488 snprintf(buf, 9, "&#%d;", *cur);
489#else
490 sprintf(buf, "&#%d;", *cur);
491#endif
492 ptr = buf;
493 while (*ptr != 0) *out++ = *ptr++;
494 }
495#if 0
496 else {
497 /*
498 * default case, this is not a valid char !
499 * Skip it...
500 */
501 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
502 }
503#endif
504 cur++;
505 }
506 *out++ = 0;
507 return(buffer);
508}
509
510/*
511 * Macro used to grow the current buffer.
512 */
513#define growBufferReentrant() { \
514 buffer_size *= 2; \
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000515 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000516 if (buffer == NULL) { \
517 perror("realloc failed"); \
518 exit(1); \
519 } \
520}
521
522
523/**
524 * xmlEncodeEntitiesReentrant:
525 * @doc: the document containing the string
526 * @input: A string to convert to XML.
527 *
528 * Do a global encoding of a string, replacing the predefined entities
529 * and non ASCII values with their entities and CharRef counterparts.
530 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
531 * must be deallocated.
532 *
533 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
534 * get erroneous.
535 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000536 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000537 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000538xmlChar *
539xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
540 const xmlChar *cur = input;
541 xmlChar *buffer = NULL;
542 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000543 int buffer_size = 0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000544 int html = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000545
Daniel Veillard242590e1998-11-13 18:04:35 +0000546 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000547 if (doc != NULL)
548 html = (doc->type == XML_HTML_DOCUMENT_NODE);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000549
550 /*
551 * allocate an translation buffer.
552 */
553 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000554 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000555 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000556 perror("malloc failed");
557 exit(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000558 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000559 out = buffer;
560
Daniel Veillard260a68f1998-08-13 03:39:55 +0000561 while (*cur != '\0') {
562 if (out - buffer > buffer_size - 100) {
563 int index = out - buffer;
564
Daniel Veillard14fff061999-06-22 21:49:07 +0000565 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000566 out = &buffer[index];
567 }
568
569 /*
570 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000571 */
572 if (*cur == '<') {
573 *out++ = '&';
574 *out++ = 'l';
575 *out++ = 't';
576 *out++ = ';';
577 } else if (*cur == '>') {
578 *out++ = '&';
579 *out++ = 'g';
580 *out++ = 't';
581 *out++ = ';';
582 } else if (*cur == '&') {
583 *out++ = '&';
584 *out++ = 'a';
585 *out++ = 'm';
586 *out++ = 'p';
587 *out++ = ';';
588 } else if (*cur == '"') {
589 *out++ = '&';
590 *out++ = 'q';
591 *out++ = 'u';
592 *out++ = 'o';
593 *out++ = 't';
594 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000595 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000596 *out++ = '&';
597 *out++ = 'a';
598 *out++ = 'p';
599 *out++ = 'o';
600 *out++ = 's';
601 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000602 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
603 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
604 /*
605 * default case, just copy !
606 */
607 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000608#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000609 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000610 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000611#ifdef HAVE_SNPRINTF
612 snprintf(buf, 9, "&#%d;", *cur);
613#else
614 sprintf(buf, "&#%d;", *cur);
615#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000616 ptr = buf;
617 while (*ptr != 0) *out++ = *ptr++;
618#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000619 } else if (IS_CHAR(*cur)) {
620 char buf[10], *ptr;
621
622#ifdef HAVE_SNPRINTF
623 snprintf(buf, 9, "&#%d;", *cur);
624#else
625 sprintf(buf, "&#%d;", *cur);
626#endif
627 ptr = buf;
628 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000629 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000630#if 0
631 else {
632 /*
633 * default case, this is not a valid char !
634 * Skip it...
635 */
636 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
637 }
638#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000639 cur++;
640 }
641 *out++ = 0;
642 return(buffer);
643}
644
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000645/**
646 * xmlCreateEntitiesTable:
647 *
648 * create and initialize an empty entities hash table.
649 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000650 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000651 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000652xmlEntitiesTablePtr
653xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000654 xmlEntitiesTablePtr ret;
655
656 ret = (xmlEntitiesTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000657 xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000658 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000659 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000660 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000661 return(NULL);
662 }
663 ret->max_entities = XML_MIN_ENTITIES_TABLE;
664 ret->nb_entities = 0;
665 ret->table = (xmlEntityPtr )
Daniel Veillard6454aec1999-09-02 22:04:43 +0000666 xmlMalloc(ret->max_entities * sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000667 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000668 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000669 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000670 xmlFree(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000671 return(NULL);
672 }
673 return(ret);
674}
675
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000676/**
677 * xmlFreeEntitiesTable:
678 * @table: An entity table
679 *
680 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000681 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000682void
683xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000684 int i;
685
686 if (table == NULL) return;
687
688 for (i = 0;i < table->nb_entities;i++) {
689 xmlFreeEntity(&table->table[i]);
690 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000691 xmlFree(table->table);
692 xmlFree(table);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000693}
694
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000695/**
696 * xmlCopyEntitiesTable:
697 * @table: An entity table
698 *
699 * Build a copy of an entity table.
700 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000701 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000702 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000703xmlEntitiesTablePtr
704xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
705 xmlEntitiesTablePtr ret;
706 xmlEntityPtr cur, ent;
707 int i;
708
Daniel Veillard6454aec1999-09-02 22:04:43 +0000709 ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000710 if (ret == NULL) {
711 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
712 return(NULL);
713 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000714 ret->table = (xmlEntityPtr) xmlMalloc(table->max_entities *
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000715 sizeof(xmlEntity));
716 if (ret->table == NULL) {
717 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000718 xmlFree(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000719 return(NULL);
720 }
721 ret->max_entities = table->max_entities;
722 ret->nb_entities = table->nb_entities;
723 for (i = 0;i < ret->nb_entities;i++) {
724 cur = &ret->table[i];
725 ent = &table->table[i];
726 cur->len = ent->len;
727 cur->type = ent->type;
728 if (ent->name != NULL)
729 cur->name = xmlStrdup(ent->name);
730 else
731 cur->name = NULL;
732 if (ent->ExternalID != NULL)
733 cur->ExternalID = xmlStrdup(ent->ExternalID);
734 else
735 cur->ExternalID = NULL;
736 if (ent->SystemID != NULL)
737 cur->SystemID = xmlStrdup(ent->SystemID);
738 else
739 cur->SystemID = NULL;
740 if (ent->content != NULL)
741 cur->content = xmlStrdup(ent->content);
742 else
743 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000744 if (ent->orig != NULL)
745 cur->orig = xmlStrdup(ent->orig);
746 else
747 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000748 }
749 return(ret);
750}
751
752/**
753 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000754 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000755 * @table: An entity table
756 *
757 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000758 */
759void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000760xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000761 int i;
762 xmlEntityPtr cur;
763
764 if (table == NULL) return;
765
766 for (i = 0;i < table->nb_entities;i++) {
767 cur = &table->table[i];
768 switch (cur->type) {
769 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000770 xmlBufferWriteChar(buf, "<!ENTITY ");
771 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000772 xmlBufferWriteChar(buf, " ");
773 if (cur->orig != NULL)
774 xmlBufferWriteQuotedString(buf, cur->orig);
775 else
776 xmlBufferWriteQuotedString(buf, cur->content);
777 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000778 break;
779 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000780 xmlBufferWriteChar(buf, "<!ENTITY ");
781 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000782 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000783 xmlBufferWriteChar(buf, " PUBLIC ");
784 xmlBufferWriteQuotedString(buf, cur->ExternalID);
785 xmlBufferWriteChar(buf, " ");
786 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000787 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000788 xmlBufferWriteChar(buf, " SYSTEM ");
789 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000790 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000791 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000792 break;
793 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000794 xmlBufferWriteChar(buf, "<!ENTITY ");
795 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000796 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000797 xmlBufferWriteChar(buf, " PUBLIC ");
798 xmlBufferWriteQuotedString(buf, cur->ExternalID);
799 xmlBufferWriteChar(buf, " ");
800 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000801 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000802 xmlBufferWriteChar(buf, " SYSTEM ");
803 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000804 }
805 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000806 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000807 if (cur->orig != NULL)
808 xmlBufferWriteCHAR(buf, cur->orig);
809 else
810 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000811 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000812 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000813 break;
814 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000815 xmlBufferWriteChar(buf, "<!ENTITY % ");
816 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000817 xmlBufferWriteChar(buf, " ");
818 if (cur->orig == NULL)
819 xmlBufferWriteQuotedString(buf, cur->content);
820 else
821 xmlBufferWriteQuotedString(buf, cur->orig);
822 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000823 break;
824 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000825 xmlBufferWriteChar(buf, "<!ENTITY % ");
826 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000827 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000828 xmlBufferWriteChar(buf, " PUBLIC ");
829 xmlBufferWriteQuotedString(buf, cur->ExternalID);
830 xmlBufferWriteChar(buf, " ");
831 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000832 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000833 xmlBufferWriteChar(buf, " SYSTEM ");
834 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000835 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000836 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000837 break;
838 default:
839 fprintf(stderr,
840 "xmlDumpEntitiesTable: internal: unknown type %d\n",
841 cur->type);
842 }
843 }
844}