blob: 027acd057aab6b94c1604875b763f8d94cd149b1 [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * entities.c : implementation for the XML entities handking
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00007 */
8
Daniel Veillard3c558c31999-12-22 11:30:41 +00009#ifdef WIN32
10#include "win32config.h"
11#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#include "config.h"
13#endif
14
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000016#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000017#ifdef HAVE_STDLIB_H
18#include <stdlib.h>
19#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +000020#include "xmlmemory.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000021#include "entities.h"
Daniel Veillarda0555cc1999-12-01 09:51:45 +000022#include "parser.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000023
24/*
25 * The XML predefined entities.
26 */
27
28struct xmlPredefinedEntityValue {
29 const char *name;
30 const char *value;
31};
32struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
33 { "lt", "<" },
34 { "gt", ">" },
35 { "apos", "'" },
36 { "quot", "\"" },
37 { "amp", "&" }
38};
39
40xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
41
42/*
Daniel Veillard260a68f1998-08-13 03:39:55 +000043 * xmlFreeEntity : clean-up an entity record.
44 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000045void xmlFreeEntity(xmlEntityPtr entity) {
46 if (entity == NULL) return;
47
48 if (entity->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000049 xmlFree((char *) entity->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +000050 if (entity->ExternalID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000051 xmlFree((char *) entity->ExternalID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000052 if (entity->SystemID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000053 xmlFree((char *) entity->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +000054 if (entity->content != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000055 xmlFree((char *) entity->content);
Daniel Veillard011b63c1999-06-02 17:44:04 +000056 if (entity->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +000057 xmlFree((char *) entity->orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +000058 memset(entity, -1, sizeof(xmlEntity));
59}
60
61/*
Daniel Veillardbe36afe1998-11-27 06:39:50 +000062 * xmlAddEntity : register a new entity for an entities table.
Daniel Veillard260a68f1998-08-13 03:39:55 +000063 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +000064static void
Daniel Veillarddd6b3671999-09-23 22:19:22 +000065xmlAddEntity(xmlEntitiesTablePtr table, const xmlChar *name, int type,
66 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +000067 int i;
68 xmlEntityPtr cur;
69 int len;
70
71 for (i = 0;i < table->nb_entities;i++) {
72 cur = &table->table[i];
73 if (!xmlStrcmp(cur->name, name)) {
74 /*
75 * The entity is already defined in this Dtd, the spec says to NOT
76 * override it ... Is it worth a Warning ??? !!!
Daniel Veillardb96e6431999-08-29 21:02:19 +000077 * Not having a cprinting context this seems hard ...
Daniel Veillard260a68f1998-08-13 03:39:55 +000078 */
Daniel Veillardb05deb71999-08-10 19:04:08 +000079 if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
80 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
81 ((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
82 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)))
83 return;
84 else
85 if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
86 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
87 ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
88 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY)))
89 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +000090 }
91 }
92 if (table->nb_entities >= table->max_entities) {
93 /*
94 * need more elements.
95 */
96 table->max_entities *= 2;
97 table->table = (xmlEntityPtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +000098 xmlRealloc(table->table, table->max_entities * sizeof(xmlEntity));
Daniel Veillardb05deb71999-08-10 19:04:08 +000099 if (table->table == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000100 perror("realloc failed");
Daniel Veillardb05deb71999-08-10 19:04:08 +0000101 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000102 }
103 }
104 cur = &table->table[table->nb_entities];
105 cur->name = xmlStrdup(name);
106 for (len = 0;name[0] != 0;name++)len++;
107 cur->len = len;
108 cur->type = type;
109 if (ExternalID != NULL)
110 cur->ExternalID = xmlStrdup(ExternalID);
111 else
112 cur->ExternalID = NULL;
113 if (SystemID != NULL)
114 cur->SystemID = xmlStrdup(SystemID);
115 else
116 cur->SystemID = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000117 if (content != NULL) {
118 cur->length = xmlStrlen(content);
119 cur->content = xmlStrndup(content, cur->length);
120 } else {
121 cur->length = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000122 cur->content = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000123 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000124 cur->orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000125 table->nb_entities++;
126}
127
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000128/**
129 * xmlInitializePredefinedEntities:
130 *
131 * Set up the predefined entities.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000132 */
133void xmlInitializePredefinedEntities(void) {
134 int i;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000135 xmlChar name[50];
136 xmlChar value[50];
Daniel Veillard260a68f1998-08-13 03:39:55 +0000137 const char *in;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000138 xmlChar *out;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000139
140 if (xmlPredefinedEntities != NULL) return;
141
142 xmlPredefinedEntities = xmlCreateEntitiesTable();
143 for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
144 sizeof(xmlPredefinedEntityValues[0]);i++) {
145 in = xmlPredefinedEntityValues[i].name;
146 out = &name[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000147 for (;(*out++ = (xmlChar) *in);)in++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000148 in = xmlPredefinedEntityValues[i].value;
149 out = &value[0];
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000150 for (;(*out++ = (xmlChar) *in);)in++;
151 xmlAddEntity(xmlPredefinedEntities, (const xmlChar *) &name[0],
Daniel Veillard25940b71998-10-29 05:51:30 +0000152 XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000153 &value[0]);
154 }
155}
156
Daniel Veillardccb09631998-10-27 06:21:04 +0000157/**
Daniel Veillarda594bf41999-12-01 09:51:45 +0000158 * xmlCleanupPredefinedEntities:
159 *
160 * Cleanup up the predefined entities table.
161 */
162void xmlCleanupPredefinedEntities(void) {
163 if (xmlPredefinedEntities == NULL) return;
164
165 xmlFreeEntitiesTable(xmlPredefinedEntities);
166 xmlPredefinedEntities = NULL;
167}
168
169/**
Daniel Veillardccb09631998-10-27 06:21:04 +0000170 * xmlGetPredefinedEntity:
171 * @name: the entity name
172 *
173 * Check whether this name is an predefined entity.
174 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000175 * Returns NULL if not, othervise the entity
Daniel Veillardccb09631998-10-27 06:21:04 +0000176 */
177xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000178xmlGetPredefinedEntity(const xmlChar *name) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000179 int i;
180 xmlEntityPtr cur;
181
182 if (xmlPredefinedEntities == NULL)
183 xmlInitializePredefinedEntities();
184 for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
185 cur = &xmlPredefinedEntities->table[i];
186 if (!xmlStrcmp(cur->name, name)) return(cur);
187 }
188 return(NULL);
189}
190
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000191/**
192 * xmlAddDtdEntity:
193 * @doc: the document
194 * @name: the entity name
195 * @type: the entity type XML_xxx_yyy_ENTITY
196 * @ExternalID: the entity external ID if available
197 * @SystemID: the entity system ID if available
198 * @content: the entity content
199 *
200 * Register a new entity for this document DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000201 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000202void
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000203xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
204 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000205 xmlEntitiesTablePtr table;
206
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000207 if (doc->extSubset == NULL) {
208 fprintf(stderr,
209 "xmlAddDtdEntity: document without external subset !\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000210 return;
211 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000212 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000213 if (table == NULL) {
214 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000215 doc->extSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000216 }
217 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
218}
219
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000220/**
221 * xmlAddDocEntity:
222 * @doc: the document
223 * @name: the entity name
224 * @type: the entity type XML_xxx_yyy_ENTITY
225 * @ExternalID: the entity external ID if available
226 * @SystemID: the entity system ID if available
227 * @content: the entity content
228 *
229 * Register a new entity for this document.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000230 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000231void
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
233 const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000234 xmlEntitiesTablePtr table;
235
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000236 if (doc == NULL) {
237 fprintf(stderr,
238 "xmlAddDocEntity: document is NULL !\n");
239 return;
240 }
241 if (doc->intSubset == NULL) {
242 fprintf(stderr,
243 "xmlAddDtdEntity: document without internal subset !\n");
244 return;
245 }
246 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000247 if (table == NULL) {
248 table = xmlCreateEntitiesTable();
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249 doc->intSubset->entities = table;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000250 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000251 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000252}
253
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000254/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000255 * xmlGetParameterEntity:
256 * @doc: the document referencing the entity
257 * @name: the entity name
258 *
259 * Do an entity lookup in the internal and external subsets and
260 * returns the corresponding parameter entity, if found.
261 *
262 * Returns A pointer to the entity structure or NULL if not found.
263 */
264xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000265xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000266 int i;
267 xmlEntityPtr cur;
268 xmlEntitiesTablePtr table;
269
270 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
271 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
272 for (i = 0;i < table->nb_entities;i++) {
273 cur = &table->table[i];
274 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
275 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
276 (!xmlStrcmp(cur->name, name))) return(cur);
277 }
278 }
279 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
280 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
281 for (i = 0;i < table->nb_entities;i++) {
282 cur = &table->table[i];
283 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
284 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
285 (!xmlStrcmp(cur->name, name))) return(cur);
286 }
287 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000288 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
289 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
290 for (i = 0;i < table->nb_entities;i++) {
291 cur = &table->table[i];
292 if (((cur->type == XML_INTERNAL_PARAMETER_ENTITY) ||
293 (cur->type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
294 (!xmlStrcmp(cur->name, name))) return(cur);
295 }
296 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000297 return(NULL);
298}
299
300/**
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000301 * xmlGetDtdEntity:
302 * @doc: the document referencing the entity
303 * @name: the entity name
304 *
305 * Do an entity lookup in the Dtd entity hash table and
306 * returns the corresponding entity, if found.
307 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000308 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000309 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000310xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000311xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000312 int i;
313 xmlEntityPtr cur;
314 xmlEntitiesTablePtr table;
315
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000316 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
317 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000318 for (i = 0;i < table->nb_entities;i++) {
319 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000320 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
321 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
322 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000323 }
324 }
325 return(NULL);
326}
327
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000328/**
329 * xmlGetDocEntity:
330 * @doc: the document referencing the entity
331 * @name: the entity name
332 *
333 * Do an entity lookup in the document entity hash table and
334 * returns the corrsponding entity, otherwise a lookup is done
335 * in the predefined entities too.
336 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000337 * Returns A pointer to the entity structure or NULL if not found.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000338 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000339xmlEntityPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000340xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000341 int i;
342 xmlEntityPtr cur;
343 xmlEntitiesTablePtr table;
344
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000345 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
346 table = (xmlEntitiesTablePtr) doc->intSubset->entities;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000347 for (i = 0;i < table->nb_entities;i++) {
348 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000349 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
350 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
351 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000352 }
353 }
Daniel Veillard1ff7ae31999-09-01 12:19:13 +0000354 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
355 table = (xmlEntitiesTablePtr) doc->extSubset->entities;
356 for (i = 0;i < table->nb_entities;i++) {
357 cur = &table->table[i];
358 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
359 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
360 (!xmlStrcmp(cur->name, name))) return(cur);
361 }
362 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000363 if (xmlPredefinedEntities == NULL)
364 xmlInitializePredefinedEntities();
365 table = xmlPredefinedEntities;
366 for (i = 0;i < table->nb_entities;i++) {
367 cur = &table->table[i];
Daniel Veillardb05deb71999-08-10 19:04:08 +0000368 if ((cur->type != XML_INTERNAL_PARAMETER_ENTITY) &&
369 (cur->type != XML_EXTERNAL_PARAMETER_ENTITY) &&
370 (!xmlStrcmp(cur->name, name))) return(cur);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000371 }
372
373 return(NULL);
374}
375
376/*
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000377 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
378 * | [#x10000-#x10FFFF]
379 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
380 */
381#define IS_CHAR(c) \
382 (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
383 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
384
Daniel Veillard14fff061999-06-22 21:49:07 +0000385/*
386 * A buffer used for converting entities to their equivalent and back.
Daniel Veillard14fff061999-06-22 21:49:07 +0000387 */
388static int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000389static xmlChar *buffer = NULL;
Daniel Veillard14fff061999-06-22 21:49:07 +0000390
391void growBuffer(void) {
392 buffer_size *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000393 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000394 if (buffer == NULL) {
395 perror("realloc failed");
396 exit(1);
397 }
398}
399
400
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000401/**
402 * xmlEncodeEntities:
403 * @doc: the document containing the string
404 * @input: A string to convert to XML.
405 *
406 * Do a global encoding of a string, replacing the predefined entities
407 * and non ASCII values with their entities and CharRef counterparts.
408 *
Daniel Veillardb96e6431999-08-29 21:02:19 +0000409 * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
410 * compatibility
Daniel Veillard14fff061999-06-22 21:49:07 +0000411 *
412 * People must migrate their code to xmlEncodeEntitiesReentrant !
Daniel Veillardb05deb71999-08-10 19:04:08 +0000413 * This routine will issue a warning when encountered.
Daniel Veillard14fff061999-06-22 21:49:07 +0000414 *
415 * Returns A newly allocated string with the substitution done.
416 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000417const xmlChar *
418xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
419 const xmlChar *cur = input;
420 xmlChar *out = buffer;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000421 static int warning = 1;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000422 int html = 0;
423
Daniel Veillardb05deb71999-08-10 19:04:08 +0000424
425 if (warning) {
426 fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
427 fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
428 warning = 0;
429 }
Daniel Veillard14fff061999-06-22 21:49:07 +0000430
431 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000432 if (doc != NULL)
433 html = (doc->type == XML_HTML_DOCUMENT_NODE);
434
Daniel Veillard14fff061999-06-22 21:49:07 +0000435 if (buffer == NULL) {
436 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000437 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard14fff061999-06-22 21:49:07 +0000438 if (buffer == NULL) {
439 perror("malloc failed");
440 exit(1);
441 }
442 out = buffer;
443 }
444 while (*cur != '\0') {
445 if (out - buffer > buffer_size - 100) {
446 int index = out - buffer;
447
448 growBuffer();
449 out = &buffer[index];
450 }
451
452 /*
453 * By default one have to encode at least '<', '>', '"' and '&' !
454 */
455 if (*cur == '<') {
456 *out++ = '&';
457 *out++ = 'l';
458 *out++ = 't';
459 *out++ = ';';
460 } else if (*cur == '>') {
461 *out++ = '&';
462 *out++ = 'g';
463 *out++ = 't';
464 *out++ = ';';
465 } else if (*cur == '&') {
466 *out++ = '&';
467 *out++ = 'a';
468 *out++ = 'm';
469 *out++ = 'p';
470 *out++ = ';';
471 } else if (*cur == '"') {
472 *out++ = '&';
473 *out++ = 'q';
474 *out++ = 'u';
475 *out++ = 'o';
476 *out++ = 't';
477 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000478 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000479 *out++ = '&';
480 *out++ = 'a';
481 *out++ = 'p';
482 *out++ = 'o';
483 *out++ = 's';
484 *out++ = ';';
485 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
486 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
487 /*
488 * default case, just copy !
489 */
490 *out++ = *cur;
491#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000492 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard14fff061999-06-22 21:49:07 +0000493 char buf[10], *ptr;
494#ifdef HAVE_SNPRINTF
495 snprintf(buf, 9, "&#%d;", *cur);
496#else
497 sprintf(buf, "&#%d;", *cur);
498#endif
499 ptr = buf;
500 while (*ptr != 0) *out++ = *ptr++;
501#endif
502 } else if (IS_CHAR(*cur)) {
503 char buf[10], *ptr;
504
505#ifdef HAVE_SNPRINTF
506 snprintf(buf, 9, "&#%d;", *cur);
507#else
508 sprintf(buf, "&#%d;", *cur);
509#endif
510 ptr = buf;
511 while (*ptr != 0) *out++ = *ptr++;
512 }
513#if 0
514 else {
515 /*
516 * default case, this is not a valid char !
517 * Skip it...
518 */
519 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
520 }
521#endif
522 cur++;
523 }
524 *out++ = 0;
525 return(buffer);
526}
527
528/*
529 * Macro used to grow the current buffer.
530 */
531#define growBufferReentrant() { \
532 buffer_size *= 2; \
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000533 buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
Daniel Veillard14fff061999-06-22 21:49:07 +0000534 if (buffer == NULL) { \
535 perror("realloc failed"); \
536 exit(1); \
537 } \
538}
539
540
541/**
542 * xmlEncodeEntitiesReentrant:
543 * @doc: the document containing the string
544 * @input: A string to convert to XML.
545 *
546 * Do a global encoding of a string, replacing the predefined entities
547 * and non ASCII values with their entities and CharRef counterparts.
548 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
549 * must be deallocated.
550 *
551 * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
552 * get erroneous.
553 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000554 * Returns A newly allocated string with the substitution done.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000555 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000556xmlChar *
557xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
558 const xmlChar *cur = input;
559 xmlChar *buffer = NULL;
560 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000561 int buffer_size = 0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000562 int html = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000563
Daniel Veillard242590e1998-11-13 18:04:35 +0000564 if (input == NULL) return(NULL);
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000565 if (doc != NULL)
566 html = (doc->type == XML_HTML_DOCUMENT_NODE);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000567
568 /*
569 * allocate an translation buffer.
570 */
571 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000572 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000573 if (buffer == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000574 perror("malloc failed");
575 exit(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000576 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000577 out = buffer;
578
Daniel Veillard260a68f1998-08-13 03:39:55 +0000579 while (*cur != '\0') {
580 if (out - buffer > buffer_size - 100) {
581 int index = out - buffer;
582
Daniel Veillard14fff061999-06-22 21:49:07 +0000583 growBufferReentrant();
Daniel Veillard260a68f1998-08-13 03:39:55 +0000584 out = &buffer[index];
585 }
586
587 /*
588 * By default one have to encode at least '<', '>', '"' and '&' !
Daniel Veillard260a68f1998-08-13 03:39:55 +0000589 */
590 if (*cur == '<') {
591 *out++ = '&';
592 *out++ = 'l';
593 *out++ = 't';
594 *out++ = ';';
595 } else if (*cur == '>') {
596 *out++ = '&';
597 *out++ = 'g';
598 *out++ = 't';
599 *out++ = ';';
600 } else if (*cur == '&') {
601 *out++ = '&';
602 *out++ = 'a';
603 *out++ = 'm';
604 *out++ = 'p';
605 *out++ = ';';
606 } else if (*cur == '"') {
607 *out++ = '&';
608 *out++ = 'q';
609 *out++ = 'u';
610 *out++ = 'o';
611 *out++ = 't';
612 *out++ = ';';
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000613 } else if ((*cur == '\'') && (!html)) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000614 *out++ = '&';
615 *out++ = 'a';
616 *out++ = 'p';
617 *out++ = 'o';
618 *out++ = 's';
619 *out++ = ';';
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000620 } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
621 (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
622 /*
623 * default case, just copy !
624 */
625 *out++ = *cur;
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000626#ifndef USE_UTF_8
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000627 } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000628 char buf[10], *ptr;
Daniel Veillardda4d3c41998-11-04 20:07:05 +0000629#ifdef HAVE_SNPRINTF
630 snprintf(buf, 9, "&#%d;", *cur);
631#else
632 sprintf(buf, "&#%d;", *cur);
633#endif
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000634 ptr = buf;
635 while (*ptr != 0) *out++ = *ptr++;
636#endif
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000637 } else if (IS_CHAR(*cur)) {
638 char buf[10], *ptr;
639
640#ifdef HAVE_SNPRINTF
641 snprintf(buf, 9, "&#%d;", *cur);
642#else
643 sprintf(buf, "&#%d;", *cur);
644#endif
645 ptr = buf;
646 while (*ptr != 0) *out++ = *ptr++;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000647 }
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +0000648#if 0
649 else {
650 /*
651 * default case, this is not a valid char !
652 * Skip it...
653 */
654 fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
655 }
656#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000657 cur++;
658 }
659 *out++ = 0;
660 return(buffer);
661}
662
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000663/**
664 * xmlCreateEntitiesTable:
665 *
666 * create and initialize an empty entities hash table.
667 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000668 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000669 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000670xmlEntitiesTablePtr
671xmlCreateEntitiesTable(void) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000672 xmlEntitiesTablePtr ret;
673
674 ret = (xmlEntitiesTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000675 xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000676 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000677 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000678 (long)sizeof(xmlEntitiesTable));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000679 return(NULL);
680 }
681 ret->max_entities = XML_MIN_ENTITIES_TABLE;
682 ret->nb_entities = 0;
683 ret->table = (xmlEntityPtr )
Daniel Veillard6454aec1999-09-02 22:04:43 +0000684 xmlMalloc(ret->max_entities * sizeof(xmlEntity));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000685 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000686 fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000687 ret->max_entities * (long)sizeof(xmlEntity));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000688 xmlFree(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000689 return(NULL);
690 }
691 return(ret);
692}
693
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000694/**
695 * xmlFreeEntitiesTable:
696 * @table: An entity table
697 *
698 * Deallocate the memory used by an entities hash table.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000699 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000700void
701xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000702 int i;
703
704 if (table == NULL) return;
705
706 for (i = 0;i < table->nb_entities;i++) {
707 xmlFreeEntity(&table->table[i]);
708 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000709 xmlFree(table->table);
710 xmlFree(table);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000711}
712
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000713/**
714 * xmlCopyEntitiesTable:
715 * @table: An entity table
716 *
717 * Build a copy of an entity table.
718 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000719 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000720 */
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000721xmlEntitiesTablePtr
722xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
723 xmlEntitiesTablePtr ret;
724 xmlEntityPtr cur, ent;
725 int i;
726
Daniel Veillard6454aec1999-09-02 22:04:43 +0000727 ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000728 if (ret == NULL) {
729 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
730 return(NULL);
731 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000732 ret->table = (xmlEntityPtr) xmlMalloc(table->max_entities *
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000733 sizeof(xmlEntity));
734 if (ret->table == NULL) {
735 fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000736 xmlFree(ret);
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000737 return(NULL);
738 }
739 ret->max_entities = table->max_entities;
740 ret->nb_entities = table->nb_entities;
741 for (i = 0;i < ret->nb_entities;i++) {
742 cur = &ret->table[i];
743 ent = &table->table[i];
744 cur->len = ent->len;
745 cur->type = ent->type;
746 if (ent->name != NULL)
747 cur->name = xmlStrdup(ent->name);
748 else
749 cur->name = NULL;
750 if (ent->ExternalID != NULL)
751 cur->ExternalID = xmlStrdup(ent->ExternalID);
752 else
753 cur->ExternalID = NULL;
754 if (ent->SystemID != NULL)
755 cur->SystemID = xmlStrdup(ent->SystemID);
756 else
757 cur->SystemID = NULL;
758 if (ent->content != NULL)
759 cur->content = xmlStrdup(ent->content);
760 else
761 cur->content = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000762 if (ent->orig != NULL)
763 cur->orig = xmlStrdup(ent->orig);
764 else
765 cur->orig = NULL;
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000766 }
767 return(ret);
768}
769
770/**
771 * xmlDumpEntitiesTable:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000772 * @buf: An XML buffer.
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000773 * @table: An entity table
774 *
775 * This will dump the content of the entity table as an XML DTD definition
Daniel Veillardbe36afe1998-11-27 06:39:50 +0000776 */
777void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000778xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000779 int i;
780 xmlEntityPtr cur;
781
782 if (table == NULL) return;
783
784 for (i = 0;i < table->nb_entities;i++) {
785 cur = &table->table[i];
786 switch (cur->type) {
787 case XML_INTERNAL_GENERAL_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000788 xmlBufferWriteChar(buf, "<!ENTITY ");
789 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000790 xmlBufferWriteChar(buf, " ");
791 if (cur->orig != NULL)
792 xmlBufferWriteQuotedString(buf, cur->orig);
793 else
794 xmlBufferWriteQuotedString(buf, cur->content);
795 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000796 break;
797 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000798 xmlBufferWriteChar(buf, "<!ENTITY ");
799 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000800 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000801 xmlBufferWriteChar(buf, " PUBLIC ");
802 xmlBufferWriteQuotedString(buf, cur->ExternalID);
803 xmlBufferWriteChar(buf, " ");
804 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000805 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000806 xmlBufferWriteChar(buf, " SYSTEM ");
807 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000808 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000809 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000810 break;
811 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000812 xmlBufferWriteChar(buf, "<!ENTITY ");
813 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000814 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000815 xmlBufferWriteChar(buf, " PUBLIC ");
816 xmlBufferWriteQuotedString(buf, cur->ExternalID);
817 xmlBufferWriteChar(buf, " ");
818 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000819 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000820 xmlBufferWriteChar(buf, " SYSTEM ");
821 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000822 }
823 if (cur->content != NULL) { /* Should be true ! */
Daniel Veillard5099ae81999-04-21 20:12:07 +0000824 xmlBufferWriteChar(buf, " NDATA ");
Daniel Veillard011b63c1999-06-02 17:44:04 +0000825 if (cur->orig != NULL)
826 xmlBufferWriteCHAR(buf, cur->orig);
827 else
828 xmlBufferWriteCHAR(buf, cur->content);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000829 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000830 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000831 break;
832 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000833 xmlBufferWriteChar(buf, "<!ENTITY % ");
834 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000835 xmlBufferWriteChar(buf, " ");
836 if (cur->orig == NULL)
837 xmlBufferWriteQuotedString(buf, cur->content);
838 else
839 xmlBufferWriteQuotedString(buf, cur->orig);
840 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000841 break;
842 case XML_EXTERNAL_PARAMETER_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000843 xmlBufferWriteChar(buf, "<!ENTITY % ");
844 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000845 if (cur->ExternalID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000846 xmlBufferWriteChar(buf, " PUBLIC ");
847 xmlBufferWriteQuotedString(buf, cur->ExternalID);
848 xmlBufferWriteChar(buf, " ");
849 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000850 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +0000851 xmlBufferWriteChar(buf, " SYSTEM ");
852 xmlBufferWriteQuotedString(buf, cur->SystemID);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000853 }
Daniel Veillard5099ae81999-04-21 20:12:07 +0000854 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +0000855 break;
856 default:
857 fprintf(stderr,
858 "xmlDumpEntitiesTable: internal: unknown type %d\n",
859 cur->type);
860 }
861 }
862}