blob: 2cedf9282028c174e4c0af8aa68d5a9864634e2f [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>
12#include "entities.h"
13
14/*
15 * The XML predefined entities.
16 */
17
18struct xmlPredefinedEntityValue {
19 const char *name;
20 const char *value;
21};
22struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
23 { "lt", "<" },
24 { "gt", ">" },
25 { "apos", "'" },
26 { "quot", "\"" },
27 { "amp", "&" }
28};
29
30xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
31
32/*
Daniel Veillard260a68f1998-08-13 03:39:55 +000033 * xmlFreeEntity : clean-up an entity record.
34 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000035void xmlFreeEntity(xmlEntityPtr entity) {
36 if (entity == NULL) return;
37
38 if (entity->name != NULL)
39 free((char *) entity->name);
40 if (entity->ExternalID != NULL)
41 free((char *) entity->ExternalID);
42 if (entity->SystemID != NULL)
43 free((char *) entity->SystemID);
44 if (entity->content != NULL)
45 free((char *) entity->content);
Daniel Veillard011b63c1999-06-02 17:44:04 +000046 if (entity->orig != NULL)
47 free((char *) entity->orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +000048 memset(entity, -1, sizeof(xmlEntity));
49}
50
51/*
Daniel Veillardbe36afe1998-11-27 06:39:50 +000052 * xmlAddEntity : register a new entity for an entities table.
Daniel Veillard260a68f1998-08-13 03:39:55 +000053 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +000054static void
55xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
Daniel Veillardb96e6431999-08-29 21:02:19 +000056 const CHAR *ExternalID, const CHAR *SystemID, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000057 int i;
58 xmlEntityPtr cur;
59 int len;
60
61 for (i = 0;i < table->nb_entities;i++) {
62 cur = &table->table[i];
63 if (!xmlStrcmp(cur->name, name)) {
64 /*
65 * The entity is already defined in this Dtd, the spec says to NOT
66 * override it ... Is it worth a Warning ??? !!!
Daniel Veillardb96e6431999-08-29 21:02:19 +000067 * Not having a cprinting context this seems hard ...
Daniel Veillard260a68f1998-08-13 03:39:55 +000068 */
Daniel Veillardb05deb71999-08-10 19:04:08 +000069 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
70 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
71 ((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
72 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)))
73 return;
74 else
75 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
76 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
77 ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
78 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY)))
79 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000080 }
81 }
82 if (table->nb_entities >= table->max_entities) {
83 /*
84 * need more elements.
85 */
86 table->max_entities *= 2;
87 table->table = (xmlEntityPtr)
88 realloc(table->table, table->max_entities * sizeof(xmlEntity));
Daniel Veillardb05deb71999-08-10 19:04:08 +000089 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000090 perror("realloc failed");
Daniel Veillardb05deb71999-08-10 19:04:08 +000091 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000092 }
93 }
94 cur = &table->table[table->nb_entities];
95 cur->name = xmlStrdup(name);
96 for (len = 0;name[0] != 0;name++)len++;
97 cur->len = len;
98 cur->type = type;
99 if (ExternalID != NULL)
100 cur->ExternalID = xmlStrdup(ExternalID);
101 else
102 cur->ExternalID = NULL;
103 if (SystemID != NULL)
104 cur->SystemID = xmlStrdup(SystemID);
105 else
106 cur->SystemID = NULL;
107 if (content != NULL)
108 cur->content = xmlStrdup(content);
109 else
110 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000111 cur->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000112 table->nb_entities++;
113}
114
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000115/**
116 * xmlInitializePredefinedEntities:
117 *
118 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000119 */
120void xmlInitializePredefinedEntities(void) {
121 int i;
122 CHAR name[50];
123 CHAR value[50];
124 const char *in;
125 CHAR *out;
126
127 if (xmlPredefinedEntities != NULL) return;
128
129 xmlPredefinedEntities = xmlCreateEntitiesTable();
130 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
131 sizeof(xmlPredefinedEntityValues[0]);i++) {
132 in = xmlPredefinedEntityValues[i].name;
133 out = &name[0];
134 for (;(*out++ = (CHAR) *in);)in++;
135 in = xmlPredefinedEntityValues[i].value;
136 out = &value[0];
137 for (;(*out++ = (CHAR) *in);)in++;
138 xmlAddEntity(xmlPredefinedEntities, (const CHAR *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000139 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000140 &value[0]);
141 }
142}
143
Daniel Veillardccb09631998-10-27 06:21:04 +0000144/**
145 * xmlGetPredefinedEntity:
146 * @name: the entity name
147 *
148 * Check whether this name is an predefined entity.
149 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000150 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000151 */
152xmlEntityPtr
153xmlGetPredefinedEntity(const CHAR *name) {
154 int i;
155 xmlEntityPtr cur;
156
157 if (xmlPredefinedEntities == NULL)
158 xmlInitializePredefinedEntities();
159 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
160 cur = &xmlPredefinedEntities->table[i];
161 if (!xmlStrcmp(cur->name, name)) return(cur);
162 }
163 return(NULL);
164}
165
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000166/**
167 * xmlAddDtdEntity:
168 * @doc: the document
169 * @name: the entity name
170 * @type: the entity type XML_xxx_yyy_ENTITY
171 * @ExternalID: the entity external ID if available
172 * @SystemID: the entity system ID if available
173 * @content: the entity content
174 *
175 * Register a new entity for this document DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000176 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000177void
178xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
Daniel Veillardb96e6431999-08-29 21:02:19 +0000179 const CHAR *ExternalID, const CHAR *SystemID, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000180 xmlEntitiesTablePtr table;
181
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000182 if (doc->extSubset == NULL) {
183 fprintf(stderr,
184 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000185 return;
186 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000187 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000188 if (table == NULL) {
189 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000190 doc->extSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000191 }
192 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
193}
194
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000195/**
196 * xmlAddDocEntity:
197 * @doc: the document
198 * @name: the entity name
199 * @type: the entity type XML_xxx_yyy_ENTITY
200 * @ExternalID: the entity external ID if available
201 * @SystemID: the entity system ID if available
202 * @content: the entity content
203 *
204 * Register a new entity for this document.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000205 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000206void
207xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
Daniel Veillardb96e6431999-08-29 21:02:19 +0000208 const CHAR *ExternalID, const CHAR *SystemID, const CHAR *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000209 xmlEntitiesTablePtr table;
210
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000211 if (doc == NULL) {
212 fprintf(stderr,
213 "xmlAddDocEntity: document is NULL !\n");
214 return;
215 }
216 if (doc->intSubset == NULL) {
217 fprintf(stderr,
218 "xmlAddDtdEntity: document without internal subset !\n");
219 return;
220 }
221 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000222 if (table == NULL) {
223 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000224 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000225 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000226 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000227}
228
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000229/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000230 * xmlGetParameterEntity:
231 * @doc: the document referencing the entity
232 * @name: the entity name
233 *
234 * Do an entity lookup in the internal and external subsets and
235 * returns the corresponding parameter entity, if found.
236 *
237 * Returns A pointer to the entity structure or NULL if not found.
238 */
239xmlEntityPtr
240xmlGetParameterEntity(xmlDocPtr doc, const CHAR *name) {
241 int i;
242 xmlEntityPtr cur;
243 xmlEntitiesTablePtr table;
244
245 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
246 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
247 for (i = 0;i < table->nb_entities;i++) {
248 cur = &table->table[i];
249 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
250 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
251 (!xmlStrcmp(cur->name, name))) return(cur);
252 }
253 }
254 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
255 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
256 for (i = 0;i < table->nb_entities;i++) {
257 cur = &table->table[i];
258 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
259 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
260 (!xmlStrcmp(cur->name, name))) return(cur);
261 }
262 }
263 return(NULL);
264}
265
266/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000267 * xmlGetDtdEntity:
268 * @doc: the document referencing the entity
269 * @name: the entity name
270 *
271 * Do an entity lookup in the Dtd entity hash table and
272 * returns the corresponding entity, if found.
273 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000274 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000275 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000276xmlEntityPtr
277xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000278 int i;
279 xmlEntityPtr cur;
280 xmlEntitiesTablePtr table;
281
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000282 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
283 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000284 for (i = 0;i < table->nb_entities;i++) {
285 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000286 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
287 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
288 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000289 }
290 }
291 return(NULL);
292}
293
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000294/**
295 * xmlGetDocEntity:
296 * @doc: the document referencing the entity
297 * @name: the entity name
298 *
299 * Do an entity lookup in the document entity hash table and
300 * returns the corrsponding entity, otherwise a lookup is done
301 * in the predefined entities too.
302 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000303 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000304 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000305xmlEntityPtr
306xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000307 int i;
308 xmlEntityPtr cur;
309 xmlEntitiesTablePtr table;
310
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000311 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
312 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000313 for (i = 0;i < table->nb_entities;i++) {
314 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000315 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
316 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
317 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000318 }
319 }
320 if (xmlPredefinedEntities == NULL)
321 xmlInitializePredefinedEntities();
322 table = xmlPredefinedEntities;
323 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
330 return(NULL);
331}
332
333/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000334 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
335 * | [#x10000-#x10FFFF]
336 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
337 */
338#define IS_CHAR(c) \
339 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
340 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
341
Daniel Veillard14fff061999-06-22 21:49:07 +0000342/*
343 * A buffer used for converting entities to their equivalent and back.
Daniel Veillard14fff061999-06-22 21:49:07 +0000344 */
345static int buffer_size = 0;
346static CHAR *buffer = NULL;
347
348void growBuffer(void) {
349 buffer_size *= 2;
350 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
351 if (buffer == NULL) {
352 perror("realloc failed");
353 exit(1);
354 }
355}
356
357
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000358/**
359 * xmlEncodeEntities:
360 * @doc: the document containing the string
361 * @input: A string to convert to XML.
362 *
363 * Do a global encoding of a string, replacing the predefined entities
364 * and non ASCII values with their entities and CharRef counterparts.
365 *
Daniel Veillardb96e6431999-08-29 21:02:19 +0000366 * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
367 * compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000368 *
369 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000370 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000371 *
372 * Returns A newly allocated string with the substitution done.
373 */
374const CHAR *
375xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
376 const CHAR *cur = input;
377 CHAR *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000378 static int warning = 1;
379
380 if (warning) {
381 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
382 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
383 warning = 0;
384 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000385
386 if (input == NULL) return(NULL);
387 if (buffer == NULL) {
388 buffer_size = 1000;
389 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
390 if (buffer == NULL) {
391 perror("malloc failed");
392 exit(1);
393 }
394 out = buffer;
395 }
396 while (*cur != '\0') {
397 if (out - buffer > buffer_size - 100) {
398 int index = out - buffer;
399
400 growBuffer();
401 out = &buffer[index];
402 }
403
404 /*
405 * By default one have to encode at least '<', '>', '"' and '&' !
406 */
407 if (*cur == '<') {
408 *out++ = '&';
409 *out++ = 'l';
410 *out++ = 't';
411 *out++ = ';';
412 } else if (*cur == '>') {
413 *out++ = '&';
414 *out++ = 'g';
415 *out++ = 't';
416 *out++ = ';';
417 } else if (*cur == '&') {
418 *out++ = '&';
419 *out++ = 'a';
420 *out++ = 'm';
421 *out++ = 'p';
422 *out++ = ';';
423 } else if (*cur == '"') {
424 *out++ = '&';
425 *out++ = 'q';
426 *out++ = 'u';
427 *out++ = 'o';
428 *out++ = 't';
429 *out++ = ';';
430 } else if (*cur == '\'') {
431 *out++ = '&';
432 *out++ = 'a';
433 *out++ = 'p';
434 *out++ = 'o';
435 *out++ = 's';
436 *out++ = ';';
437 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
438 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
439 /*
440 * default case, just copy !
441 */
442 *out++ = *cur;
443#ifndef USE_UTF_8
444 } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
445 char buf[10], *ptr;
446#ifdef HAVE_SNPRINTF
447 snprintf(buf, 9, "&#%d;", *cur);
448#else
449 sprintf(buf, "&#%d;", *cur);
450#endif
451 ptr = buf;
452 while (*ptr != 0) *out++ = *ptr++;
453#endif
454 } else if (IS_CHAR(*cur)) {
455 char buf[10], *ptr;
456
457#ifdef HAVE_SNPRINTF
458 snprintf(buf, 9, "&#%d;", *cur);
459#else
460 sprintf(buf, "&#%d;", *cur);
461#endif
462 ptr = buf;
463 while (*ptr != 0) *out++ = *ptr++;
464 }
465#if 0
466 else {
467 /*
468 * default case, this is not a valid char !
469 * Skip it...
470 */
471 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
472 }
473#endif
474 cur++;
475 }
476 *out++ = 0;
477 return(buffer);
478}
479
480/*
481 * Macro used to grow the current buffer.
482 */
483#define growBufferReentrant() { \
484 buffer_size *= 2; \
485 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR)); \
486 if (buffer == NULL) { \
487 perror("realloc failed"); \
488 exit(1); \
489 } \
490}
491
492
493/**
494 * xmlEncodeEntitiesReentrant:
495 * @doc: the document containing the string
496 * @input: A string to convert to XML.
497 *
498 * Do a global encoding of a string, replacing the predefined entities
499 * and non ASCII values with their entities and CharRef counterparts.
500 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
501 * must be deallocated.
502 *
503 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
504 * get erroneous.
505 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000506 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000507 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000508CHAR *
Daniel Veillard14fff061999-06-22 21:49:07 +0000509xmlEncodeEntitiesReentrant(xmlDocPtr doc, const CHAR *input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000510 const CHAR *cur = input;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000511 CHAR *buffer = NULL;
512 CHAR *out = NULL;
513 int buffer_size = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000514
Daniel Veillard242590e1998-11-13 18:04:35 +0000515 if (input == NULL) return(NULL);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000516
517 /*
518 * allocate an translation buffer.
519 */
520 buffer_size = 1000;
521 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000522 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000523 perror("malloc failed");
524 exit(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000525 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000526 out = buffer;
527
Daniel Veillard260a68f1998-08-13 03:39:55 +0000528 while (*cur != '\0') {
529 if (out - buffer > buffer_size - 100) {
530 int index = out - buffer;
531
Daniel Veillard14fff061999-06-22 21:49:07 +0000532 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000533 out = &buffer[index];
534 }
535
536 /*
537 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000538 */
539 if (*cur == '<') {
540 *out++ = '&';
541 *out++ = 'l';
542 *out++ = 't';
543 *out++ = ';';
544 } else if (*cur == '>') {
545 *out++ = '&';
546 *out++ = 'g';
547 *out++ = 't';
548 *out++ = ';';
549 } else if (*cur == '&') {
550 *out++ = '&';
551 *out++ = 'a';
552 *out++ = 'm';
553 *out++ = 'p';
554 *out++ = ';';
555 } else if (*cur == '"') {
556 *out++ = '&';
557 *out++ = 'q';
558 *out++ = 'u';
559 *out++ = 'o';
560 *out++ = 't';
561 *out++ = ';';
562 } else if (*cur == '\'') {
563 *out++ = '&';
564 *out++ = 'a';
565 *out++ = 'p';
566 *out++ = 'o';
567 *out++ = 's';
568 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000569 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
570 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
571 /*
572 * default case, just copy !
573 */
574 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000575#ifndef USE_UTF_8
576 } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
577 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000578#ifdef HAVE_SNPRINTF
579 snprintf(buf, 9, "&#%d;", *cur);
580#else
581 sprintf(buf, "&#%d;", *cur);
582#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000583 ptr = buf;
584 while (*ptr != 0) *out++ = *ptr++;
585#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000586 } else if (IS_CHAR(*cur)) {
587 char buf[10], *ptr;
588
589#ifdef HAVE_SNPRINTF
590 snprintf(buf, 9, "&#%d;", *cur);
591#else
592 sprintf(buf, "&#%d;", *cur);
593#endif
594 ptr = buf;
595 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000596 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000597#if 0
598 else {
599 /*
600 * default case, this is not a valid char !
601 * Skip it...
602 */
603 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
604 }
605#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000606 cur++;
607 }
608 *out++ = 0;
609 return(buffer);
610}
611
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000612/**
613 * xmlCreateEntitiesTable:
614 *
615 * create and initialize an empty entities hash table.
616 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000617 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000618 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000619xmlEntitiesTablePtr
620xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000621 xmlEntitiesTablePtr ret;
622
623 ret = (xmlEntitiesTablePtr)
624 malloc(sizeof(xmlEntitiesTable));
625 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000626 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%ld) failed\n",
627 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000628 return(NULL);
629 }
630 ret->max_entities = XML_MIN_ENTITIES_TABLE;
631 ret->nb_entities = 0;
632 ret->table = (xmlEntityPtr )
633 malloc(ret->max_entities * sizeof(xmlEntity));
634 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000635 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%ld) failed\n",
636 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000637 free(ret);
638 return(NULL);
639 }
640 return(ret);
641}
642
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000643/**
644 * xmlFreeEntitiesTable:
645 * @table: An entity table
646 *
647 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000648 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000649void
650xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000651 int i;
652
653 if (table == NULL) return;
654
655 for (i = 0;i < table->nb_entities;i++) {
656 xmlFreeEntity(&table->table[i]);
657 }
658 free(table->table);
659 free(table);
660}
661
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000662/**
663 * xmlCopyEntitiesTable:
664 * @table: An entity table
665 *
666 * Build a copy of an entity table.
667 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000668 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000669 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000670xmlEntitiesTablePtr
671xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
672 xmlEntitiesTablePtr ret;
673 xmlEntityPtr cur, ent;
674 int i;
675
676 ret = (xmlEntitiesTablePtr) malloc(sizeof(xmlEntitiesTable));
677 if (ret == NULL) {
678 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
679 return(NULL);
680 }
681 ret->table = (xmlEntityPtr) malloc(table->max_entities *
682 sizeof(xmlEntity));
683 if (ret->table == NULL) {
684 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
685 free(ret);
686 return(NULL);
687 }
688 ret->max_entities = table->max_entities;
689 ret->nb_entities = table->nb_entities;
690 for (i = 0;i < ret->nb_entities;i++) {
691 cur = &ret->table[i];
692 ent = &table->table[i];
693 cur->len = ent->len;
694 cur->type = ent->type;
695 if (ent->name != NULL)
696 cur->name = xmlStrdup(ent->name);
697 else
698 cur->name = NULL;
699 if (ent->ExternalID != NULL)
700 cur->ExternalID = xmlStrdup(ent->ExternalID);
701 else
702 cur->ExternalID = NULL;
703 if (ent->SystemID != NULL)
704 cur->SystemID = xmlStrdup(ent->SystemID);
705 else
706 cur->SystemID = NULL;
707 if (ent->content != NULL)
708 cur->content = xmlStrdup(ent->content);
709 else
710 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000711 if (ent->orig != NULL)
712 cur->orig = xmlStrdup(ent->orig);
713 else
714 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000715 }
716 return(ret);
717}
718
719/**
720 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000721 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000722 * @table: An entity table
723 *
724 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000725 */
726void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000727xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000728 int i;
729 xmlEntityPtr cur;
730
731 if (table == NULL) return;
732
733 for (i = 0;i < table->nb_entities;i++) {
734 cur = &table->table[i];
735 switch (cur->type) {
736 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000737 xmlBufferWriteChar(buf, "<!ENTITY ");
738 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000739 xmlBufferWriteChar(buf, " ");
740 if (cur->orig != NULL)
741 xmlBufferWriteQuotedString(buf, cur->orig);
742 else
743 xmlBufferWriteQuotedString(buf, cur->content);
744 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000745 break;
746 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000747 xmlBufferWriteChar(buf, "<!ENTITY ");
748 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000749 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000750 xmlBufferWriteChar(buf, " PUBLIC ");
751 xmlBufferWriteQuotedString(buf, cur->ExternalID);
752 xmlBufferWriteChar(buf, " ");
753 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000754 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000755 xmlBufferWriteChar(buf, " SYSTEM ");
756 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000757 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000758 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000759 break;
760 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000761 xmlBufferWriteChar(buf, "<!ENTITY ");
762 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000763 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000764 xmlBufferWriteChar(buf, " PUBLIC ");
765 xmlBufferWriteQuotedString(buf, cur->ExternalID);
766 xmlBufferWriteChar(buf, " ");
767 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000768 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000769 xmlBufferWriteChar(buf, " SYSTEM ");
770 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000771 }
772 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000773 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000774 if (cur->orig != NULL)
775 xmlBufferWriteCHAR(buf, cur->orig);
776 else
777 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000778 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000779 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000780 break;
781 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000782 xmlBufferWriteChar(buf, "<!ENTITY % ");
783 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000784 xmlBufferWriteChar(buf, " ");
785 if (cur->orig == NULL)
786 xmlBufferWriteQuotedString(buf, cur->content);
787 else
788 xmlBufferWriteQuotedString(buf, cur->orig);
789 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000790 break;
791 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000792 xmlBufferWriteChar(buf, "<!ENTITY % ");
793 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000794 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000795 xmlBufferWriteChar(buf, " PUBLIC ");
796 xmlBufferWriteQuotedString(buf, cur->ExternalID);
797 xmlBufferWriteChar(buf, " ");
798 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000799 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000800 xmlBufferWriteChar(buf, " SYSTEM ");
801 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000802 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000803 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000804 break;
805 default:
806 fprintf(stderr,
807 "xmlDumpEntitiesTable: internal: unknown type %d\n",
808 cur->type);
809 }
810 }
811}