blob: 78f7ec2cb0155875c6b759f698a69a164c25c36b [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;
404
405 if (warning) {
406 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
407 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
408 warning = 0;
409 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000410
411 if (input == NULL) return(NULL);
412 if (buffer == NULL) {
413 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000414 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000415 if (buffer == NULL) {
416 perror("malloc failed");
417 exit(1);
418 }
419 out = buffer;
420 }
421 while (*cur != '\0') {
422 if (out - buffer > buffer_size - 100) {
423 int index = out - buffer;
424
425 growBuffer();
426 out = &buffer[index];
427 }
428
429 /*
430 * By default one have to encode at least '<', '>', '"' and '&' !
431 */
432 if (*cur == '<') {
433 *out++ = '&';
434 *out++ = 'l';
435 *out++ = 't';
436 *out++ = ';';
437 } else if (*cur == '>') {
438 *out++ = '&';
439 *out++ = 'g';
440 *out++ = 't';
441 *out++ = ';';
442 } else if (*cur == '&') {
443 *out++ = '&';
444 *out++ = 'a';
445 *out++ = 'm';
446 *out++ = 'p';
447 *out++ = ';';
448 } else if (*cur == '"') {
449 *out++ = '&';
450 *out++ = 'q';
451 *out++ = 'u';
452 *out++ = 'o';
453 *out++ = 't';
454 *out++ = ';';
455 } else if (*cur == '\'') {
456 *out++ = '&';
457 *out++ = 'a';
458 *out++ = 'p';
459 *out++ = 'o';
460 *out++ = 's';
461 *out++ = ';';
462 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
463 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
464 /*
465 * default case, just copy !
466 */
467 *out++ = *cur;
468#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000469 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000470 char buf[10], *ptr;
471#ifdef HAVE_SNPRINTF
472 snprintf(buf, 9, "&#%d;", *cur);
473#else
474 sprintf(buf, "&#%d;", *cur);
475#endif
476 ptr = buf;
477 while (*ptr != 0) *out++ = *ptr++;
478#endif
479 } else if (IS_CHAR(*cur)) {
480 char buf[10], *ptr;
481
482#ifdef HAVE_SNPRINTF
483 snprintf(buf, 9, "&#%d;", *cur);
484#else
485 sprintf(buf, "&#%d;", *cur);
486#endif
487 ptr = buf;
488 while (*ptr != 0) *out++ = *ptr++;
489 }
490#if 0
491 else {
492 /*
493 * default case, this is not a valid char !
494 * Skip it...
495 */
496 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
497 }
498#endif
499 cur++;
500 }
501 *out++ = 0;
502 return(buffer);
503}
504
505/*
506 * Macro used to grow the current buffer.
507 */
508#define growBufferReentrant() { \
509 buffer_size *= 2; \
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000510 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000511 if (buffer == NULL) { \
512 perror("realloc failed"); \
513 exit(1); \
514 } \
515}
516
517
518/**
519 * xmlEncodeEntitiesReentrant:
520 * @doc: the document containing the string
521 * @input: A string to convert to XML.
522 *
523 * Do a global encoding of a string, replacing the predefined entities
524 * and non ASCII values with their entities and CharRef counterparts.
525 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
526 * must be deallocated.
527 *
528 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
529 * get erroneous.
530 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000531 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000532 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000533xmlChar *
534xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
535 const xmlChar *cur = input;
536 xmlChar *buffer = NULL;
537 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000538 int buffer_size = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000539
Daniel Veillard242590e1998-11-13 18:04:35 +0000540 if (input == NULL) return(NULL);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000541
542 /*
543 * allocate an translation buffer.
544 */
545 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000546 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000547 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000548 perror("malloc failed");
549 exit(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000550 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000551 out = buffer;
552
Daniel Veillard260a68f1998-08-13 03:39:55 +0000553 while (*cur != '\0') {
554 if (out - buffer > buffer_size - 100) {
555 int index = out - buffer;
556
Daniel Veillard14fff061999-06-22 21:49:07 +0000557 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000558 out = &buffer[index];
559 }
560
561 /*
562 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000563 */
564 if (*cur == '<') {
565 *out++ = '&';
566 *out++ = 'l';
567 *out++ = 't';
568 *out++ = ';';
569 } else if (*cur == '>') {
570 *out++ = '&';
571 *out++ = 'g';
572 *out++ = 't';
573 *out++ = ';';
574 } else if (*cur == '&') {
575 *out++ = '&';
576 *out++ = 'a';
577 *out++ = 'm';
578 *out++ = 'p';
579 *out++ = ';';
580 } else if (*cur == '"') {
581 *out++ = '&';
582 *out++ = 'q';
583 *out++ = 'u';
584 *out++ = 'o';
585 *out++ = 't';
586 *out++ = ';';
587 } else if (*cur == '\'') {
588 *out++ = '&';
589 *out++ = 'a';
590 *out++ = 'p';
591 *out++ = 'o';
592 *out++ = 's';
593 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000594 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
595 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
596 /*
597 * default case, just copy !
598 */
599 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000600#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000601 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000602 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000603#ifdef HAVE_SNPRINTF
604 snprintf(buf, 9, "&#%d;", *cur);
605#else
606 sprintf(buf, "&#%d;", *cur);
607#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000608 ptr = buf;
609 while (*ptr != 0) *out++ = *ptr++;
610#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000611 } else if (IS_CHAR(*cur)) {
612 char buf[10], *ptr;
613
614#ifdef HAVE_SNPRINTF
615 snprintf(buf, 9, "&#%d;", *cur);
616#else
617 sprintf(buf, "&#%d;", *cur);
618#endif
619 ptr = buf;
620 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000621 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000622#if 0
623 else {
624 /*
625 * default case, this is not a valid char !
626 * Skip it...
627 */
628 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
629 }
630#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000631 cur++;
632 }
633 *out++ = 0;
634 return(buffer);
635}
636
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000637/**
638 * xmlCreateEntitiesTable:
639 *
640 * create and initialize an empty entities hash table.
641 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000642 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000643 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000644xmlEntitiesTablePtr
645xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000646 xmlEntitiesTablePtr ret;
647
648 ret = (xmlEntitiesTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000649 xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000650 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000651 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000652 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000653 return(NULL);
654 }
655 ret->max_entities = XML_MIN_ENTITIES_TABLE;
656 ret->nb_entities = 0;
657 ret->table = (xmlEntityPtr )
Daniel Veillard6454aec1999-09-02 22:04:43 +0000658 xmlMalloc(ret->max_entities * sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000659 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000660 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000661 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000662 xmlFree(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000663 return(NULL);
664 }
665 return(ret);
666}
667
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000668/**
669 * xmlFreeEntitiesTable:
670 * @table: An entity table
671 *
672 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000673 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000674void
675xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000676 int i;
677
678 if (table == NULL) return;
679
680 for (i = 0;i < table->nb_entities;i++) {
681 xmlFreeEntity(&table->table[i]);
682 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000683 xmlFree(table->table);
684 xmlFree(table);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000685}
686
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000687/**
688 * xmlCopyEntitiesTable:
689 * @table: An entity table
690 *
691 * Build a copy of an entity table.
692 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000693 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000694 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000695xmlEntitiesTablePtr
696xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
697 xmlEntitiesTablePtr ret;
698 xmlEntityPtr cur, ent;
699 int i;
700
Daniel Veillard6454aec1999-09-02 22:04:43 +0000701 ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000702 if (ret == NULL) {
703 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
704 return(NULL);
705 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000706 ret->table = (xmlEntityPtr) xmlMalloc(table->max_entities *
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000707 sizeof(xmlEntity));
708 if (ret->table == NULL) {
709 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000710 xmlFree(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000711 return(NULL);
712 }
713 ret->max_entities = table->max_entities;
714 ret->nb_entities = table->nb_entities;
715 for (i = 0;i < ret->nb_entities;i++) {
716 cur = &ret->table[i];
717 ent = &table->table[i];
718 cur->len = ent->len;
719 cur->type = ent->type;
720 if (ent->name != NULL)
721 cur->name = xmlStrdup(ent->name);
722 else
723 cur->name = NULL;
724 if (ent->ExternalID != NULL)
725 cur->ExternalID = xmlStrdup(ent->ExternalID);
726 else
727 cur->ExternalID = NULL;
728 if (ent->SystemID != NULL)
729 cur->SystemID = xmlStrdup(ent->SystemID);
730 else
731 cur->SystemID = NULL;
732 if (ent->content != NULL)
733 cur->content = xmlStrdup(ent->content);
734 else
735 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000736 if (ent->orig != NULL)
737 cur->orig = xmlStrdup(ent->orig);
738 else
739 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000740 }
741 return(ret);
742}
743
744/**
745 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000746 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000747 * @table: An entity table
748 *
749 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000750 */
751void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000752xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000753 int i;
754 xmlEntityPtr cur;
755
756 if (table == NULL) return;
757
758 for (i = 0;i < table->nb_entities;i++) {
759 cur = &table->table[i];
760 switch (cur->type) {
761 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000762 xmlBufferWriteChar(buf, "<!ENTITY ");
763 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000764 xmlBufferWriteChar(buf, " ");
765 if (cur->orig != NULL)
766 xmlBufferWriteQuotedString(buf, cur->orig);
767 else
768 xmlBufferWriteQuotedString(buf, cur->content);
769 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000770 break;
771 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000772 xmlBufferWriteChar(buf, "<!ENTITY ");
773 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000774 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000775 xmlBufferWriteChar(buf, " PUBLIC ");
776 xmlBufferWriteQuotedString(buf, cur->ExternalID);
777 xmlBufferWriteChar(buf, " ");
778 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000779 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000780 xmlBufferWriteChar(buf, " SYSTEM ");
781 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000782 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000783 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000784 break;
785 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000786 xmlBufferWriteChar(buf, "<!ENTITY ");
787 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000788 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000789 xmlBufferWriteChar(buf, " PUBLIC ");
790 xmlBufferWriteQuotedString(buf, cur->ExternalID);
791 xmlBufferWriteChar(buf, " ");
792 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000793 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000794 xmlBufferWriteChar(buf, " SYSTEM ");
795 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000796 }
797 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000798 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000799 if (cur->orig != NULL)
800 xmlBufferWriteCHAR(buf, cur->orig);
801 else
802 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000803 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000804 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000805 break;
806 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000807 xmlBufferWriteChar(buf, "<!ENTITY % ");
808 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000809 xmlBufferWriteChar(buf, " ");
810 if (cur->orig == NULL)
811 xmlBufferWriteQuotedString(buf, cur->content);
812 else
813 xmlBufferWriteQuotedString(buf, cur->orig);
814 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000815 break;
816 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000817 xmlBufferWriteChar(buf, "<!ENTITY % ");
818 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000819 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000820 xmlBufferWriteChar(buf, " PUBLIC ");
821 xmlBufferWriteQuotedString(buf, cur->ExternalID);
822 xmlBufferWriteChar(buf, " ");
823 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000824 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000825 xmlBufferWriteChar(buf, " SYSTEM ");
826 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000827 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000828 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000829 break;
830 default:
831 fprintf(stderr,
832 "xmlDumpEntitiesTable: internal: unknown type %d\n",
833 cur->type);
834 }
835 }
836}