blob: f0971d1cfbc9fdc40d67a8c58653f6d5eabbe87b [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 *
54 * TODO !!! We should check here that the combination of type
55 * ExternalID and SystemID is valid.
56 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +000057static void
58xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
Daniel Veillard260a68f1998-08-13 03:39:55 +000059 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
60 int i;
61 xmlEntityPtr cur;
62 int len;
63
64 for (i = 0;i < table->nb_entities;i++) {
65 cur = &table->table[i];
66 if (!xmlStrcmp(cur->name, name)) {
67 /*
68 * The entity is already defined in this Dtd, the spec says to NOT
69 * override it ... Is it worth a Warning ??? !!!
70 */
Daniel Veillardb05deb71999-08-10 19:04:08 +000071 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
72 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
73 ((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
74 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)))
75 return;
76 else
77 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
78 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
79 ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
80 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY)))
81 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000082 }
83 }
84 if (table->nb_entities >= table->max_entities) {
85 /*
86 * need more elements.
87 */
88 table->max_entities *= 2;
89 table->table = (xmlEntityPtr)
90 realloc(table->table, table->max_entities * sizeof(xmlEntity));
Daniel Veillardb05deb71999-08-10 19:04:08 +000091 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000092 perror("realloc failed");
Daniel Veillardb05deb71999-08-10 19:04:08 +000093 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000094 }
95 }
96 cur = &table->table[table->nb_entities];
97 cur->name = xmlStrdup(name);
98 for (len = 0;name[0] != 0;name++)len++;
99 cur->len = len;
100 cur->type = type;
101 if (ExternalID != NULL)
102 cur->ExternalID = xmlStrdup(ExternalID);
103 else
104 cur->ExternalID = NULL;
105 if (SystemID != NULL)
106 cur->SystemID = xmlStrdup(SystemID);
107 else
108 cur->SystemID = NULL;
109 if (content != NULL)
110 cur->content = xmlStrdup(content);
111 else
112 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000113 cur->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000114 table->nb_entities++;
115}
116
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000117/**
118 * xmlInitializePredefinedEntities:
119 *
120 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000121 */
122void xmlInitializePredefinedEntities(void) {
123 int i;
124 CHAR name[50];
125 CHAR value[50];
126 const char *in;
127 CHAR *out;
128
129 if (xmlPredefinedEntities != NULL) return;
130
131 xmlPredefinedEntities = xmlCreateEntitiesTable();
132 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
133 sizeof(xmlPredefinedEntityValues[0]);i++) {
134 in = xmlPredefinedEntityValues[i].name;
135 out = &name[0];
136 for (;(*out++ = (CHAR) *in);)in++;
137 in = xmlPredefinedEntityValues[i].value;
138 out = &value[0];
139 for (;(*out++ = (CHAR) *in);)in++;
140 xmlAddEntity(xmlPredefinedEntities, (const CHAR *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000141 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000142 &value[0]);
143 }
144}
145
Daniel Veillardccb09631998-10-27 06:21:04 +0000146/**
147 * xmlGetPredefinedEntity:
148 * @name: the entity name
149 *
150 * Check whether this name is an predefined entity.
151 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000152 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000153 */
154xmlEntityPtr
155xmlGetPredefinedEntity(const CHAR *name) {
156 int i;
157 xmlEntityPtr cur;
158
159 if (xmlPredefinedEntities == NULL)
160 xmlInitializePredefinedEntities();
161 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
162 cur = &xmlPredefinedEntities->table[i];
163 if (!xmlStrcmp(cur->name, name)) return(cur);
164 }
165 return(NULL);
166}
167
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000168/**
169 * xmlAddDtdEntity:
170 * @doc: the document
171 * @name: the entity name
172 * @type: the entity type XML_xxx_yyy_ENTITY
173 * @ExternalID: the entity external ID if available
174 * @SystemID: the entity system ID if available
175 * @content: the entity content
176 *
177 * Register a new entity for this document DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000178 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000179void
180xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000181 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
182 xmlEntitiesTablePtr table;
183
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000184 if (doc->extSubset == NULL) {
185 fprintf(stderr,
186 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000187 return;
188 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000189 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000190 if (table == NULL) {
191 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000192 doc->extSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000193 }
194 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
195}
196
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000197/**
198 * xmlAddDocEntity:
199 * @doc: the document
200 * @name: the entity name
201 * @type: the entity type XML_xxx_yyy_ENTITY
202 * @ExternalID: the entity external ID if available
203 * @SystemID: the entity system ID if available
204 * @content: the entity content
205 *
206 * Register a new entity for this document.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000207 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000208void
209xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
211 xmlEntitiesTablePtr table;
212
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000213 if (doc == NULL) {
214 fprintf(stderr,
215 "xmlAddDocEntity: document is NULL !\n");
216 return;
217 }
218 if (doc->intSubset == NULL) {
219 fprintf(stderr,
220 "xmlAddDtdEntity: document without internal subset !\n");
221 return;
222 }
223 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000224 if (table == NULL) {
225 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000226 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000227 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000228 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000229}
230
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000231/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000232 * xmlGetParameterEntity:
233 * @doc: the document referencing the entity
234 * @name: the entity name
235 *
236 * Do an entity lookup in the internal and external subsets and
237 * returns the corresponding parameter entity, if found.
238 *
239 * Returns A pointer to the entity structure or NULL if not found.
240 */
241xmlEntityPtr
242xmlGetParameterEntity(xmlDocPtr doc, const CHAR *name) {
243 int i;
244 xmlEntityPtr cur;
245 xmlEntitiesTablePtr table;
246
247 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
248 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
249 for (i = 0;i < table->nb_entities;i++) {
250 cur = &table->table[i];
251 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
252 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
253 (!xmlStrcmp(cur->name, name))) return(cur);
254 }
255 }
256 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
257 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
258 for (i = 0;i < table->nb_entities;i++) {
259 cur = &table->table[i];
260 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
261 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
262 (!xmlStrcmp(cur->name, name))) return(cur);
263 }
264 }
265 return(NULL);
266}
267
268/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000269 * xmlGetDtdEntity:
270 * @doc: the document referencing the entity
271 * @name: the entity name
272 *
273 * Do an entity lookup in the Dtd entity hash table and
274 * returns the corresponding entity, if found.
275 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000276 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000277 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000278xmlEntityPtr
279xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000280 int i;
281 xmlEntityPtr cur;
282 xmlEntitiesTablePtr table;
283
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000284 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
285 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000286 for (i = 0;i < table->nb_entities;i++) {
287 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000288 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
289 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
290 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000291 }
292 }
293 return(NULL);
294}
295
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000296/**
297 * xmlGetDocEntity:
298 * @doc: the document referencing the entity
299 * @name: the entity name
300 *
301 * Do an entity lookup in the document entity hash table and
302 * returns the corrsponding entity, otherwise a lookup is done
303 * in the predefined entities too.
304 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000305 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000306 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000307xmlEntityPtr
308xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000309 int i;
310 xmlEntityPtr cur;
311 xmlEntitiesTablePtr table;
312
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000313 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
314 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000315 for (i = 0;i < table->nb_entities;i++) {
316 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000317 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
318 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
319 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000320 }
321 }
322 if (xmlPredefinedEntities == NULL)
323 xmlInitializePredefinedEntities();
324 table = xmlPredefinedEntities;
325 for (i = 0;i < table->nb_entities;i++) {
326 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000327 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
328 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
329 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000330 }
331
332 return(NULL);
333}
334
335/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000336 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
337 * | [#x10000-#x10FFFF]
338 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
339 */
340#define IS_CHAR(c) \
341 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
342 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
343
Daniel Veillard14fff061999-06-22 21:49:07 +0000344/*
345 * A buffer used for converting entities to their equivalent and back.
346 *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000347 * TODO: remove this, once we are not afraid of breaking binary compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000348 */
349static int buffer_size = 0;
350static CHAR *buffer = NULL;
351
352void growBuffer(void) {
353 buffer_size *= 2;
354 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
355 if (buffer == NULL) {
356 perror("realloc failed");
357 exit(1);
358 }
359}
360
361
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000362/**
363 * xmlEncodeEntities:
364 * @doc: the document containing the string
365 * @input: A string to convert to XML.
366 *
367 * Do a global encoding of a string, replacing the predefined entities
368 * and non ASCII values with their entities and CharRef counterparts.
369 *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000370 * TODO: remove this, once we are not afraid of breaking binary compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000371 *
372 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000373 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000374 *
375 * Returns A newly allocated string with the substitution done.
376 */
377const CHAR *
378xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
379 const CHAR *cur = input;
380 CHAR *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000381 static int warning = 1;
382
383 if (warning) {
384 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
385 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
386 warning = 0;
387 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000388
389 if (input == NULL) return(NULL);
390 if (buffer == NULL) {
391 buffer_size = 1000;
392 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
393 if (buffer == NULL) {
394 perror("malloc failed");
395 exit(1);
396 }
397 out = buffer;
398 }
399 while (*cur != '\0') {
400 if (out - buffer > buffer_size - 100) {
401 int index = out - buffer;
402
403 growBuffer();
404 out = &buffer[index];
405 }
406
407 /*
408 * By default one have to encode at least '<', '>', '"' and '&' !
409 */
410 if (*cur == '<') {
411 *out++ = '&';
412 *out++ = 'l';
413 *out++ = 't';
414 *out++ = ';';
415 } else if (*cur == '>') {
416 *out++ = '&';
417 *out++ = 'g';
418 *out++ = 't';
419 *out++ = ';';
420 } else if (*cur == '&') {
421 *out++ = '&';
422 *out++ = 'a';
423 *out++ = 'm';
424 *out++ = 'p';
425 *out++ = ';';
426 } else if (*cur == '"') {
427 *out++ = '&';
428 *out++ = 'q';
429 *out++ = 'u';
430 *out++ = 'o';
431 *out++ = 't';
432 *out++ = ';';
433 } else if (*cur == '\'') {
434 *out++ = '&';
435 *out++ = 'a';
436 *out++ = 'p';
437 *out++ = 'o';
438 *out++ = 's';
439 *out++ = ';';
440 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
441 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
442 /*
443 * default case, just copy !
444 */
445 *out++ = *cur;
446#ifndef USE_UTF_8
447 } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
448 char buf[10], *ptr;
449#ifdef HAVE_SNPRINTF
450 snprintf(buf, 9, "&#%d;", *cur);
451#else
452 sprintf(buf, "&#%d;", *cur);
453#endif
454 ptr = buf;
455 while (*ptr != 0) *out++ = *ptr++;
456#endif
457 } else if (IS_CHAR(*cur)) {
458 char buf[10], *ptr;
459
460#ifdef HAVE_SNPRINTF
461 snprintf(buf, 9, "&#%d;", *cur);
462#else
463 sprintf(buf, "&#%d;", *cur);
464#endif
465 ptr = buf;
466 while (*ptr != 0) *out++ = *ptr++;
467 }
468#if 0
469 else {
470 /*
471 * default case, this is not a valid char !
472 * Skip it...
473 */
474 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
475 }
476#endif
477 cur++;
478 }
479 *out++ = 0;
480 return(buffer);
481}
482
483/*
484 * Macro used to grow the current buffer.
485 */
486#define growBufferReentrant() { \
487 buffer_size *= 2; \
488 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR)); \
489 if (buffer == NULL) { \
490 perror("realloc failed"); \
491 exit(1); \
492 } \
493}
494
495
496/**
497 * xmlEncodeEntitiesReentrant:
498 * @doc: the document containing the string
499 * @input: A string to convert to XML.
500 *
501 * Do a global encoding of a string, replacing the predefined entities
502 * and non ASCII values with their entities and CharRef counterparts.
503 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
504 * must be deallocated.
505 *
506 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
507 * get erroneous.
508 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000509 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000510 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000511CHAR *
Daniel Veillard14fff061999-06-22 21:49:07 +0000512xmlEncodeEntitiesReentrant(xmlDocPtr doc, const CHAR *input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000513 const CHAR *cur = input;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000514 CHAR *buffer = NULL;
515 CHAR *out = NULL;
516 int buffer_size = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000517
Daniel Veillard242590e1998-11-13 18:04:35 +0000518 if (input == NULL) return(NULL);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000519
520 /*
521 * allocate an translation buffer.
522 */
523 buffer_size = 1000;
524 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000525 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000526 perror("malloc failed");
527 exit(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000528 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000529 out = buffer;
530
Daniel Veillard260a68f1998-08-13 03:39:55 +0000531 while (*cur != '\0') {
532 if (out - buffer > buffer_size - 100) {
533 int index = out - buffer;
534
Daniel Veillard14fff061999-06-22 21:49:07 +0000535 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000536 out = &buffer[index];
537 }
538
539 /*
540 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000541 */
542 if (*cur == '<') {
543 *out++ = '&';
544 *out++ = 'l';
545 *out++ = 't';
546 *out++ = ';';
547 } else if (*cur == '>') {
548 *out++ = '&';
549 *out++ = 'g';
550 *out++ = 't';
551 *out++ = ';';
552 } else if (*cur == '&') {
553 *out++ = '&';
554 *out++ = 'a';
555 *out++ = 'm';
556 *out++ = 'p';
557 *out++ = ';';
558 } else if (*cur == '"') {
559 *out++ = '&';
560 *out++ = 'q';
561 *out++ = 'u';
562 *out++ = 'o';
563 *out++ = 't';
564 *out++ = ';';
565 } else if (*cur == '\'') {
566 *out++ = '&';
567 *out++ = 'a';
568 *out++ = 'p';
569 *out++ = 'o';
570 *out++ = 's';
571 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000572 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
573 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
574 /*
575 * default case, just copy !
576 */
577 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000578#ifndef USE_UTF_8
579 } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
580 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000581#ifdef HAVE_SNPRINTF
582 snprintf(buf, 9, "&#%d;", *cur);
583#else
584 sprintf(buf, "&#%d;", *cur);
585#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000586 ptr = buf;
587 while (*ptr != 0) *out++ = *ptr++;
588#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000589 } else if (IS_CHAR(*cur)) {
590 char buf[10], *ptr;
591
592#ifdef HAVE_SNPRINTF
593 snprintf(buf, 9, "&#%d;", *cur);
594#else
595 sprintf(buf, "&#%d;", *cur);
596#endif
597 ptr = buf;
598 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000599 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000600#if 0
601 else {
602 /*
603 * default case, this is not a valid char !
604 * Skip it...
605 */
606 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
607 }
608#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000609 cur++;
610 }
611 *out++ = 0;
612 return(buffer);
613}
614
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000615/**
616 * xmlCreateEntitiesTable:
617 *
618 * create and initialize an empty entities hash table.
619 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000620 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000621 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000622xmlEntitiesTablePtr
623xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000624 xmlEntitiesTablePtr ret;
625
626 ret = (xmlEntitiesTablePtr)
627 malloc(sizeof(xmlEntitiesTable));
628 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000629 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%ld) failed\n",
630 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000631 return(NULL);
632 }
633 ret->max_entities = XML_MIN_ENTITIES_TABLE;
634 ret->nb_entities = 0;
635 ret->table = (xmlEntityPtr )
636 malloc(ret->max_entities * sizeof(xmlEntity));
637 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000638 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%ld) failed\n",
639 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000640 free(ret);
641 return(NULL);
642 }
643 return(ret);
644}
645
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000646/**
647 * xmlFreeEntitiesTable:
648 * @table: An entity table
649 *
650 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000651 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000652void
653xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000654 int i;
655
656 if (table == NULL) return;
657
658 for (i = 0;i < table->nb_entities;i++) {
659 xmlFreeEntity(&table->table[i]);
660 }
661 free(table->table);
662 free(table);
663}
664
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000665/**
666 * xmlCopyEntitiesTable:
667 * @table: An entity table
668 *
669 * Build a copy of an entity table.
670 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000671 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000672 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000673xmlEntitiesTablePtr
674xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
675 xmlEntitiesTablePtr ret;
676 xmlEntityPtr cur, ent;
677 int i;
678
679 ret = (xmlEntitiesTablePtr) malloc(sizeof(xmlEntitiesTable));
680 if (ret == NULL) {
681 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
682 return(NULL);
683 }
684 ret->table = (xmlEntityPtr) malloc(table->max_entities *
685 sizeof(xmlEntity));
686 if (ret->table == NULL) {
687 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
688 free(ret);
689 return(NULL);
690 }
691 ret->max_entities = table->max_entities;
692 ret->nb_entities = table->nb_entities;
693 for (i = 0;i < ret->nb_entities;i++) {
694 cur = &ret->table[i];
695 ent = &table->table[i];
696 cur->len = ent->len;
697 cur->type = ent->type;
698 if (ent->name != NULL)
699 cur->name = xmlStrdup(ent->name);
700 else
701 cur->name = NULL;
702 if (ent->ExternalID != NULL)
703 cur->ExternalID = xmlStrdup(ent->ExternalID);
704 else
705 cur->ExternalID = NULL;
706 if (ent->SystemID != NULL)
707 cur->SystemID = xmlStrdup(ent->SystemID);
708 else
709 cur->SystemID = NULL;
710 if (ent->content != NULL)
711 cur->content = xmlStrdup(ent->content);
712 else
713 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000714 if (ent->orig != NULL)
715 cur->orig = xmlStrdup(ent->orig);
716 else
717 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000718 }
719 return(ret);
720}
721
722/**
723 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000724 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000725 * @table: An entity table
726 *
727 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000728 */
729void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000730xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000731 int i;
732 xmlEntityPtr cur;
733
734 if (table == NULL) return;
735
736 for (i = 0;i < table->nb_entities;i++) {
737 cur = &table->table[i];
738 switch (cur->type) {
739 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000740 xmlBufferWriteChar(buf, "<!ENTITY ");
741 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000742 xmlBufferWriteChar(buf, " ");
743 if (cur->orig != NULL)
744 xmlBufferWriteQuotedString(buf, cur->orig);
745 else
746 xmlBufferWriteQuotedString(buf, cur->content);
747 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000748 break;
749 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000750 xmlBufferWriteChar(buf, "<!ENTITY ");
751 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000752 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000753 xmlBufferWriteChar(buf, " PUBLIC ");
754 xmlBufferWriteQuotedString(buf, cur->ExternalID);
755 xmlBufferWriteChar(buf, " ");
756 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000757 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000758 xmlBufferWriteChar(buf, " SYSTEM ");
759 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000760 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000761 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000762 break;
763 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000764 xmlBufferWriteChar(buf, "<!ENTITY ");
765 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000766 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000767 xmlBufferWriteChar(buf, " PUBLIC ");
768 xmlBufferWriteQuotedString(buf, cur->ExternalID);
769 xmlBufferWriteChar(buf, " ");
770 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000771 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000772 xmlBufferWriteChar(buf, " SYSTEM ");
773 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000774 }
775 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000776 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000777 if (cur->orig != NULL)
778 xmlBufferWriteCHAR(buf, cur->orig);
779 else
780 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000781 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000782 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000783 break;
784 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000785 xmlBufferWriteChar(buf, "<!ENTITY % ");
786 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000787 xmlBufferWriteChar(buf, " ");
788 if (cur->orig == NULL)
789 xmlBufferWriteQuotedString(buf, cur->content);
790 else
791 xmlBufferWriteQuotedString(buf, cur->orig);
792 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000793 break;
794 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000795 xmlBufferWriteChar(buf, "<!ENTITY % ");
796 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000797 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000798 xmlBufferWriteChar(buf, " PUBLIC ");
799 xmlBufferWriteQuotedString(buf, cur->ExternalID);
800 xmlBufferWriteChar(buf, " ");
801 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000802 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000803 xmlBufferWriteChar(buf, " SYSTEM ");
804 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000805 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000806 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000807 break;
808 default:
809 fprintf(stderr,
810 "xmlDumpEntitiesTable: internal: unknown type %d\n",
811 cur->type);
812 }
813 }
814}