blob: 24c770c0a881d6769ca9f9703359a63a21c90652 [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
9#include <stdio.h>
Seth Alvese7f12e61998-10-01 20:51:15 +000010#include <stdlib.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000011#include <string.h>
Daniel Veillard6454aec1999-09-02 22:04:43 +000012#include "xmlmemory.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000013#include "entities.h"
14
15/*
16 * The XML predefined entities.
17 */
18
19struct xmlPredefinedEntityValue {
20 const char *name;
21 const char *value;
22};
23struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
24 { "lt", "<" },
25 { "gt", ">" },
26 { "apos", "'" },
27 { "quot", "\"" },
28 { "amp", "&" }
29};
30
31xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
32
33/*
Daniel Veillard260a68f1998-08-13 03:39:55 +000034 * xmlFreeEntity : clean-up an entity record.
35 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000036void xmlFreeEntity(xmlEntityPtr entity) {
37 if (entity == NULL) return;
38
39 if (entity->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000040 xmlFree((char *) entity->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +000041 if (entity->ExternalID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000042 xmlFree((char *) entity->ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000043 if (entity->SystemID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000044 xmlFree((char *) entity->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000045 if (entity->content != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000046 xmlFree((char *) entity->content);
Daniel Veillard011b63c1999-06-02 17:44:04 +000047 if (entity->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000048 xmlFree((char *) entity->orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +000049 memset(entity, -1, sizeof(xmlEntity));
50}
51
52/*
Daniel Veillardbe36afe1998-11-27 06:39:50 +000053 * xmlAddEntity : register a new entity for an entities table.
Daniel Veillard260a68f1998-08-13 03:39:55 +000054 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +000055static void
56xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
Daniel Veillardb96e6431999-08-29 21:02:19 +000057 const CHAR *ExternalID, const CHAR *SystemID, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000058 int i;
59 xmlEntityPtr cur;
60 int len;
61
62 for (i = 0;i < table->nb_entities;i++) {
63 cur = &table->table[i];
64 if (!xmlStrcmp(cur->name, name)) {
65 /*
66 * The entity is already defined in this Dtd, the spec says to NOT
67 * override it ... Is it worth a Warning ??? !!!
Daniel Veillardb96e6431999-08-29 21:02:19 +000068 * Not having a cprinting context this seems hard ...
Daniel Veillard260a68f1998-08-13 03:39:55 +000069 */
Daniel Veillardb05deb71999-08-10 19:04:08 +000070 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
71 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
72 ((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
73 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)))
74 return;
75 else
76 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;
Daniel Veillard260a68f1998-08-13 03:39:55 +000081 }
82 }
83 if (table->nb_entities >= table->max_entities) {
84 /*
85 * need more elements.
86 */
87 table->max_entities *= 2;
88 table->table = (xmlEntityPtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +000089 xmlRealloc(table->table, table->max_entities * sizeof(xmlEntity));
Daniel Veillardb05deb71999-08-10 19:04:08 +000090 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000091 perror("realloc failed");
Daniel Veillardb05deb71999-08-10 19:04:08 +000092 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000093 }
94 }
95 cur = &table->table[table->nb_entities];
96 cur->name = xmlStrdup(name);
97 for (len = 0;name[0] != 0;name++)len++;
98 cur->len = len;
99 cur->type = type;
100 if (ExternalID != NULL)
101 cur->ExternalID = xmlStrdup(ExternalID);
102 else
103 cur->ExternalID = NULL;
104 if (SystemID != NULL)
105 cur->SystemID = xmlStrdup(SystemID);
106 else
107 cur->SystemID = NULL;
108 if (content != NULL)
109 cur->content = xmlStrdup(content);
110 else
111 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000112 cur->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000113 table->nb_entities++;
114}
115
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000116/**
117 * xmlInitializePredefinedEntities:
118 *
119 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000120 */
121void xmlInitializePredefinedEntities(void) {
122 int i;
123 CHAR name[50];
124 CHAR value[50];
125 const char *in;
126 CHAR *out;
127
128 if (xmlPredefinedEntities != NULL) return;
129
130 xmlPredefinedEntities = xmlCreateEntitiesTable();
131 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
132 sizeof(xmlPredefinedEntityValues[0]);i++) {
133 in = xmlPredefinedEntityValues[i].name;
134 out = &name[0];
135 for (;(*out++ = (CHAR) *in);)in++;
136 in = xmlPredefinedEntityValues[i].value;
137 out = &value[0];
138 for (;(*out++ = (CHAR) *in);)in++;
139 xmlAddEntity(xmlPredefinedEntities, (const CHAR *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000140 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000141 &value[0]);
142 }
143}
144
Daniel Veillardccb09631998-10-27 06:21:04 +0000145/**
146 * xmlGetPredefinedEntity:
147 * @name: the entity name
148 *
149 * Check whether this name is an predefined entity.
150 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000151 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000152 */
153xmlEntityPtr
154xmlGetPredefinedEntity(const CHAR *name) {
155 int i;
156 xmlEntityPtr cur;
157
158 if (xmlPredefinedEntities == NULL)
159 xmlInitializePredefinedEntities();
160 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
161 cur = &xmlPredefinedEntities->table[i];
162 if (!xmlStrcmp(cur->name, name)) return(cur);
163 }
164 return(NULL);
165}
166
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000167/**
168 * xmlAddDtdEntity:
169 * @doc: the document
170 * @name: the entity name
171 * @type: the entity type XML_xxx_yyy_ENTITY
172 * @ExternalID: the entity external ID if available
173 * @SystemID: the entity system ID if available
174 * @content: the entity content
175 *
176 * Register a new entity for this document DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000177 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000178void
179xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
Daniel Veillardb96e6431999-08-29 21:02:19 +0000180 const CHAR *ExternalID, const CHAR *SystemID, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000181 xmlEntitiesTablePtr table;
182
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000183 if (doc->extSubset == NULL) {
184 fprintf(stderr,
185 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000186 return;
187 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000188 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000189 if (table == NULL) {
190 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000191 doc->extSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000192 }
193 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
194}
195
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000196/**
197 * xmlAddDocEntity:
198 * @doc: the document
199 * @name: the entity name
200 * @type: the entity type XML_xxx_yyy_ENTITY
201 * @ExternalID: the entity external ID if available
202 * @SystemID: the entity system ID if available
203 * @content: the entity content
204 *
205 * Register a new entity for this document.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000206 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000207void
208xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
Daniel Veillardb96e6431999-08-29 21:02:19 +0000209 const CHAR *ExternalID, const CHAR *SystemID, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210 xmlEntitiesTablePtr table;
211
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000212 if (doc == NULL) {
213 fprintf(stderr,
214 "xmlAddDocEntity: document is NULL !\n");
215 return;
216 }
217 if (doc->intSubset == NULL) {
218 fprintf(stderr,
219 "xmlAddDtdEntity: document without internal subset !\n");
220 return;
221 }
222 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000223 if (table == NULL) {
224 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000225 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000226 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000227 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000228}
229
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000230/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000231 * xmlGetParameterEntity:
232 * @doc: the document referencing the entity
233 * @name: the entity name
234 *
235 * Do an entity lookup in the internal and external subsets and
236 * returns the corresponding parameter entity, if found.
237 *
238 * Returns A pointer to the entity structure or NULL if not found.
239 */
240xmlEntityPtr
241xmlGetParameterEntity(xmlDocPtr doc, const CHAR *name) {
242 int i;
243 xmlEntityPtr cur;
244 xmlEntitiesTablePtr table;
245
246 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
247 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
248 for (i = 0;i < table->nb_entities;i++) {
249 cur = &table->table[i];
250 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
251 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
252 (!xmlStrcmp(cur->name, name))) return(cur);
253 }
254 }
255 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
256 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
257 for (i = 0;i < table->nb_entities;i++) {
258 cur = &table->table[i];
259 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
260 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
261 (!xmlStrcmp(cur->name, name))) return(cur);
262 }
263 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000264 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
265 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
266 for (i = 0;i < table->nb_entities;i++) {
267 cur = &table->table[i];
268 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
269 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
270 (!xmlStrcmp(cur->name, name))) return(cur);
271 }
272 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000273 return(NULL);
274}
275
276/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000277 * xmlGetDtdEntity:
278 * @doc: the document referencing the entity
279 * @name: the entity name
280 *
281 * Do an entity lookup in the Dtd entity hash table and
282 * returns the corresponding entity, if found.
283 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000284 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000285 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000286xmlEntityPtr
287xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000288 int i;
289 xmlEntityPtr cur;
290 xmlEntitiesTablePtr table;
291
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000292 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
293 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000294 for (i = 0;i < table->nb_entities;i++) {
295 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000296 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
297 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
298 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000299 }
300 }
301 return(NULL);
302}
303
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000304/**
305 * xmlGetDocEntity:
306 * @doc: the document referencing the entity
307 * @name: the entity name
308 *
309 * Do an entity lookup in the document entity hash table and
310 * returns the corrsponding entity, otherwise a lookup is done
311 * in the predefined entities too.
312 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000313 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000314 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000315xmlEntityPtr
316xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000317 int i;
318 xmlEntityPtr cur;
319 xmlEntitiesTablePtr table;
320
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000321 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
322 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000323 for (i = 0;i < table->nb_entities;i++) {
324 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000325 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
326 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
327 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000328 }
329 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000330 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
331 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
332 for (i = 0;i < table->nb_entities;i++) {
333 cur = &table->table[i];
334 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
335 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
336 (!xmlStrcmp(cur->name, name))) return(cur);
337 }
338 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000339 if (xmlPredefinedEntities == NULL)
340 xmlInitializePredefinedEntities();
341 table = xmlPredefinedEntities;
342 for (i = 0;i < table->nb_entities;i++) {
343 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000344 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
345 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
346 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000347 }
348
349 return(NULL);
350}
351
352/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000353 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
354 * | [#x10000-#x10FFFF]
355 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
356 */
357#define IS_CHAR(c) \
358 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
359 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
360
Daniel Veillard14fff061999-06-22 21:49:07 +0000361/*
362 * A buffer used for converting entities to their equivalent and back.
Daniel Veillard14fff061999-06-22 21:49:07 +0000363 */
364static int buffer_size = 0;
365static CHAR *buffer = NULL;
366
367void growBuffer(void) {
368 buffer_size *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000369 buffer = (CHAR *) xmlRealloc(buffer, buffer_size * sizeof(CHAR));
Daniel Veillard14fff061999-06-22 21:49:07 +0000370 if (buffer == NULL) {
371 perror("realloc failed");
372 exit(1);
373 }
374}
375
376
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000377/**
378 * xmlEncodeEntities:
379 * @doc: the document containing the string
380 * @input: A string to convert to XML.
381 *
382 * Do a global encoding of a string, replacing the predefined entities
383 * and non ASCII values with their entities and CharRef counterparts.
384 *
Daniel Veillardb96e6431999-08-29 21:02:19 +0000385 * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
386 * compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000387 *
388 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000389 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000390 *
391 * Returns A newly allocated string with the substitution done.
392 */
393const CHAR *
394xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
395 const CHAR *cur = input;
396 CHAR *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000397 static int warning = 1;
398
399 if (warning) {
400 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
401 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
402 warning = 0;
403 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000404
405 if (input == NULL) return(NULL);
406 if (buffer == NULL) {
407 buffer_size = 1000;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000408 buffer = (CHAR *) xmlMalloc(buffer_size * sizeof(CHAR));
Daniel Veillard14fff061999-06-22 21:49:07 +0000409 if (buffer == NULL) {
410 perror("malloc failed");
411 exit(1);
412 }
413 out = buffer;
414 }
415 while (*cur != '\0') {
416 if (out - buffer > buffer_size - 100) {
417 int index = out - buffer;
418
419 growBuffer();
420 out = &buffer[index];
421 }
422
423 /*
424 * By default one have to encode at least '<', '>', '"' and '&' !
425 */
426 if (*cur == '<') {
427 *out++ = '&';
428 *out++ = 'l';
429 *out++ = 't';
430 *out++ = ';';
431 } else if (*cur == '>') {
432 *out++ = '&';
433 *out++ = 'g';
434 *out++ = 't';
435 *out++ = ';';
436 } else if (*cur == '&') {
437 *out++ = '&';
438 *out++ = 'a';
439 *out++ = 'm';
440 *out++ = 'p';
441 *out++ = ';';
442 } else if (*cur == '"') {
443 *out++ = '&';
444 *out++ = 'q';
445 *out++ = 'u';
446 *out++ = 'o';
447 *out++ = 't';
448 *out++ = ';';
449 } else if (*cur == '\'') {
450 *out++ = '&';
451 *out++ = 'a';
452 *out++ = 'p';
453 *out++ = 'o';
454 *out++ = 's';
455 *out++ = ';';
456 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
457 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
458 /*
459 * default case, just copy !
460 */
461 *out++ = *cur;
462#ifndef USE_UTF_8
463 } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
464 char buf[10], *ptr;
465#ifdef HAVE_SNPRINTF
466 snprintf(buf, 9, "&#%d;", *cur);
467#else
468 sprintf(buf, "&#%d;", *cur);
469#endif
470 ptr = buf;
471 while (*ptr != 0) *out++ = *ptr++;
472#endif
473 } else if (IS_CHAR(*cur)) {
474 char buf[10], *ptr;
475
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 }
484#if 0
485 else {
486 /*
487 * default case, this is not a valid char !
488 * Skip it...
489 */
490 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
491 }
492#endif
493 cur++;
494 }
495 *out++ = 0;
496 return(buffer);
497}
498
499/*
500 * Macro used to grow the current buffer.
501 */
502#define growBufferReentrant() { \
503 buffer_size *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000504 buffer = (CHAR *) xmlRealloc(buffer, buffer_size * sizeof(CHAR)); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000505 if (buffer == NULL) { \
506 perror("realloc failed"); \
507 exit(1); \
508 } \
509}
510
511
512/**
513 * xmlEncodeEntitiesReentrant:
514 * @doc: the document containing the string
515 * @input: A string to convert to XML.
516 *
517 * Do a global encoding of a string, replacing the predefined entities
518 * and non ASCII values with their entities and CharRef counterparts.
519 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
520 * must be deallocated.
521 *
522 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
523 * get erroneous.
524 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000525 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000526 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000527CHAR *
Daniel Veillard14fff061999-06-22 21:49:07 +0000528xmlEncodeEntitiesReentrant(xmlDocPtr doc, const CHAR *input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000529 const CHAR *cur = input;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000530 CHAR *buffer = NULL;
531 CHAR *out = NULL;
532 int buffer_size = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000533
Daniel Veillard242590e1998-11-13 18:04:35 +0000534 if (input == NULL) return(NULL);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000535
536 /*
537 * allocate an translation buffer.
538 */
539 buffer_size = 1000;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000540 buffer = (CHAR *) xmlMalloc(buffer_size * sizeof(CHAR));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000541 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000542 perror("malloc failed");
543 exit(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000544 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000545 out = buffer;
546
Daniel Veillard260a68f1998-08-13 03:39:55 +0000547 while (*cur != '\0') {
548 if (out - buffer > buffer_size - 100) {
549 int index = out - buffer;
550
Daniel Veillard14fff061999-06-22 21:49:07 +0000551 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000552 out = &buffer[index];
553 }
554
555 /*
556 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000557 */
558 if (*cur == '<') {
559 *out++ = '&';
560 *out++ = 'l';
561 *out++ = 't';
562 *out++ = ';';
563 } else if (*cur == '>') {
564 *out++ = '&';
565 *out++ = 'g';
566 *out++ = 't';
567 *out++ = ';';
568 } else if (*cur == '&') {
569 *out++ = '&';
570 *out++ = 'a';
571 *out++ = 'm';
572 *out++ = 'p';
573 *out++ = ';';
574 } else if (*cur == '"') {
575 *out++ = '&';
576 *out++ = 'q';
577 *out++ = 'u';
578 *out++ = 'o';
579 *out++ = 't';
580 *out++ = ';';
581 } else if (*cur == '\'') {
582 *out++ = '&';
583 *out++ = 'a';
584 *out++ = 'p';
585 *out++ = 'o';
586 *out++ = 's';
587 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000588 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
589 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
590 /*
591 * default case, just copy !
592 */
593 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000594#ifndef USE_UTF_8
595 } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
596 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000597#ifdef HAVE_SNPRINTF
598 snprintf(buf, 9, "&#%d;", *cur);
599#else
600 sprintf(buf, "&#%d;", *cur);
601#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000602 ptr = buf;
603 while (*ptr != 0) *out++ = *ptr++;
604#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000605 } else if (IS_CHAR(*cur)) {
606 char buf[10], *ptr;
607
608#ifdef HAVE_SNPRINTF
609 snprintf(buf, 9, "&#%d;", *cur);
610#else
611 sprintf(buf, "&#%d;", *cur);
612#endif
613 ptr = buf;
614 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000615 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000616#if 0
617 else {
618 /*
619 * default case, this is not a valid char !
620 * Skip it...
621 */
622 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
623 }
624#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000625 cur++;
626 }
627 *out++ = 0;
628 return(buffer);
629}
630
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000631/**
632 * xmlCreateEntitiesTable:
633 *
634 * create and initialize an empty entities hash table.
635 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000636 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000637 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000638xmlEntitiesTablePtr
639xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000640 xmlEntitiesTablePtr ret;
641
642 ret = (xmlEntitiesTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000643 xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000644 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000645 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000646 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000647 return(NULL);
648 }
649 ret->max_entities = XML_MIN_ENTITIES_TABLE;
650 ret->nb_entities = 0;
651 ret->table = (xmlEntityPtr )
Daniel Veillard6454aec1999-09-02 22:04:43 +0000652 xmlMalloc(ret->max_entities * sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000653 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000654 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000655 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000656 xmlFree(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000657 return(NULL);
658 }
659 return(ret);
660}
661
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000662/**
663 * xmlFreeEntitiesTable:
664 * @table: An entity table
665 *
666 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000667 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000668void
669xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000670 int i;
671
672 if (table == NULL) return;
673
674 for (i = 0;i < table->nb_entities;i++) {
675 xmlFreeEntity(&table->table[i]);
676 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000677 xmlFree(table->table);
678 xmlFree(table);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000679}
680
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000681/**
682 * xmlCopyEntitiesTable:
683 * @table: An entity table
684 *
685 * Build a copy of an entity table.
686 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000687 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000688 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000689xmlEntitiesTablePtr
690xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
691 xmlEntitiesTablePtr ret;
692 xmlEntityPtr cur, ent;
693 int i;
694
Daniel Veillard6454aec1999-09-02 22:04:43 +0000695 ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000696 if (ret == NULL) {
697 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
698 return(NULL);
699 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000700 ret->table = (xmlEntityPtr) xmlMalloc(table->max_entities *
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000701 sizeof(xmlEntity));
702 if (ret->table == NULL) {
703 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000704 xmlFree(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000705 return(NULL);
706 }
707 ret->max_entities = table->max_entities;
708 ret->nb_entities = table->nb_entities;
709 for (i = 0;i < ret->nb_entities;i++) {
710 cur = &ret->table[i];
711 ent = &table->table[i];
712 cur->len = ent->len;
713 cur->type = ent->type;
714 if (ent->name != NULL)
715 cur->name = xmlStrdup(ent->name);
716 else
717 cur->name = NULL;
718 if (ent->ExternalID != NULL)
719 cur->ExternalID = xmlStrdup(ent->ExternalID);
720 else
721 cur->ExternalID = NULL;
722 if (ent->SystemID != NULL)
723 cur->SystemID = xmlStrdup(ent->SystemID);
724 else
725 cur->SystemID = NULL;
726 if (ent->content != NULL)
727 cur->content = xmlStrdup(ent->content);
728 else
729 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000730 if (ent->orig != NULL)
731 cur->orig = xmlStrdup(ent->orig);
732 else
733 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000734 }
735 return(ret);
736}
737
738/**
739 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000740 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000741 * @table: An entity table
742 *
743 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000744 */
745void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000746xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000747 int i;
748 xmlEntityPtr cur;
749
750 if (table == NULL) return;
751
752 for (i = 0;i < table->nb_entities;i++) {
753 cur = &table->table[i];
754 switch (cur->type) {
755 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000756 xmlBufferWriteChar(buf, "<!ENTITY ");
757 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000758 xmlBufferWriteChar(buf, " ");
759 if (cur->orig != NULL)
760 xmlBufferWriteQuotedString(buf, cur->orig);
761 else
762 xmlBufferWriteQuotedString(buf, cur->content);
763 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000764 break;
765 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000766 xmlBufferWriteChar(buf, "<!ENTITY ");
767 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000768 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000769 xmlBufferWriteChar(buf, " PUBLIC ");
770 xmlBufferWriteQuotedString(buf, cur->ExternalID);
771 xmlBufferWriteChar(buf, " ");
772 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000773 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000774 xmlBufferWriteChar(buf, " SYSTEM ");
775 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000776 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000777 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000778 break;
779 case XML_EXTERNAL_GENERAL_UNPARSED_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 }
791 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000792 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000793 if (cur->orig != NULL)
794 xmlBufferWriteCHAR(buf, cur->orig);
795 else
796 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000797 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000798 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000799 break;
800 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000801 xmlBufferWriteChar(buf, "<!ENTITY % ");
802 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000803 xmlBufferWriteChar(buf, " ");
804 if (cur->orig == NULL)
805 xmlBufferWriteQuotedString(buf, cur->content);
806 else
807 xmlBufferWriteQuotedString(buf, cur->orig);
808 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000809 break;
810 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000811 xmlBufferWriteChar(buf, "<!ENTITY % ");
812 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000813 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000814 xmlBufferWriteChar(buf, " PUBLIC ");
815 xmlBufferWriteQuotedString(buf, cur->ExternalID);
816 xmlBufferWriteChar(buf, " ");
817 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000818 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000819 xmlBufferWriteChar(buf, " SYSTEM ");
820 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000821 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000822 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000823 break;
824 default:
825 fprintf(stderr,
826 "xmlDumpEntitiesTable: internal: unknown type %d\n",
827 cur->type);
828 }
829 }
830}