blob: 351746ceb8692abca16c47cd124bf8ed33a80a97 [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 *
6 * $Id$
7 */
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/*
33 * A buffer used for converting entities to their equivalent and back.
34 */
35static int buffer_size = 0;
36static CHAR *buffer = NULL;
37
38void growBuffer(void) {
39 buffer_size *= 2;
40 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
41 if (buffer == NULL) {
42 perror("realloc failed");
43 exit(1);
44 }
45}
46
47/*
48 * xmlFreeEntity : clean-up an entity record.
49 */
50
51void xmlFreeEntity(xmlEntityPtr entity) {
52 if (entity == NULL) return;
53
54 if (entity->name != NULL)
55 free((char *) entity->name);
56 if (entity->ExternalID != NULL)
57 free((char *) entity->ExternalID);
58 if (entity->SystemID != NULL)
59 free((char *) entity->SystemID);
60 if (entity->content != NULL)
61 free((char *) entity->content);
62 memset(entity, -1, sizeof(xmlEntity));
63}
64
65/*
66 * xmlAddDocEntity : register a new entity for an entities table.
67 *
68 * TODO !!! We should check here that the combination of type
69 * ExternalID and SystemID is valid.
70 */
71static void xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
72 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
73 int i;
74 xmlEntityPtr cur;
75 int len;
76
77 for (i = 0;i < table->nb_entities;i++) {
78 cur = &table->table[i];
79 if (!xmlStrcmp(cur->name, name)) {
80 /*
81 * The entity is already defined in this Dtd, the spec says to NOT
82 * override it ... Is it worth a Warning ??? !!!
83 */
84 return;
85 }
86 }
87 if (table->nb_entities >= table->max_entities) {
88 /*
89 * need more elements.
90 */
91 table->max_entities *= 2;
92 table->table = (xmlEntityPtr)
93 realloc(table->table, table->max_entities * sizeof(xmlEntity));
94 if (table->table) {
95 perror("realloc failed");
96 exit(1);
97 }
98 }
99 cur = &table->table[table->nb_entities];
100 cur->name = xmlStrdup(name);
101 for (len = 0;name[0] != 0;name++)len++;
102 cur->len = len;
103 cur->type = type;
104 if (ExternalID != NULL)
105 cur->ExternalID = xmlStrdup(ExternalID);
106 else
107 cur->ExternalID = NULL;
108 if (SystemID != NULL)
109 cur->SystemID = xmlStrdup(SystemID);
110 else
111 cur->SystemID = NULL;
112 if (content != NULL)
113 cur->content = xmlStrdup(content);
114 else
115 cur->content = NULL;
116 table->nb_entities++;
117}
118
119/*
120 * Set up xmlPredefinedEntities from xmlPredefinedEntityValues.
121 */
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],
141 XML_INTERNAL_GENERAL_ENTITY, NULL, NULL,
142 &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 *
152 * return values: NULL if not, othervise the entity
153 */
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
168
Daniel Veillard260a68f1998-08-13 03:39:55 +0000169
170/*
171 * xmlAddDtdEntity : register a new entity for this DTD.
172 */
173void xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
174 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
175 xmlEntitiesTablePtr table;
176
177 if (doc->dtd == NULL) {
178 fprintf(stderr, "xmlAddDtdEntity: document without Dtd !\n");
179 return;
180 }
181 table = (xmlEntitiesTablePtr) doc->dtd->entities;
182 if (table == NULL) {
183 table = xmlCreateEntitiesTable();
184 doc->dtd->entities = table;
185 }
186 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
187}
188
189/*
190 * xmlAddDocEntity : register a new entity for this document.
191 */
192void xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
193 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
194 xmlEntitiesTablePtr table;
195
196 table = (xmlEntitiesTablePtr) doc->entities;
197 if (table == NULL) {
198 table = xmlCreateEntitiesTable();
199 doc->entities = table;
200 }
201 xmlAddEntity(doc->entities, name, type, ExternalID, SystemID, content);
202}
203
204/*
205 * xmlGetDtdEntity : do an entity lookup in the Dtd entity hash table and
206 * returns the corrsponding entity, if found, NULL otherwise.
207 */
208xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
209 int i;
210 xmlEntityPtr cur;
211 xmlEntitiesTablePtr table;
212
213 if ((doc->dtd != NULL) && (doc->dtd->entities != NULL)) {
214 table = (xmlEntitiesTablePtr) doc->dtd->entities;
215 for (i = 0;i < table->nb_entities;i++) {
216 cur = &table->table[i];
217 if (!xmlStrcmp(cur->name, name)) return(cur);
218 }
219 }
220 return(NULL);
221}
222
223/*
224 * xmlGetDocEntity : do an entity lookup in the document entity hash table and
225 * returns the corrsponding entity, otherwise a lookup is done
226 * in the predefined entities too.
227 */
228xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
229 int i;
230 xmlEntityPtr cur;
231 xmlEntitiesTablePtr table;
232
233 if (doc->entities != NULL) {
234 table = (xmlEntitiesTablePtr) doc->entities;
235 for (i = 0;i < table->nb_entities;i++) {
236 cur = &table->table[i];
237 if (!xmlStrcmp(cur->name, name)) return(cur);
238 }
239 }
240 if (xmlPredefinedEntities == NULL)
241 xmlInitializePredefinedEntities();
242 table = xmlPredefinedEntities;
243 for (i = 0;i < table->nb_entities;i++) {
244 cur = &table->table[i];
245 if (!xmlStrcmp(cur->name, name)) return(cur);
246 }
247
248 return(NULL);
249}
250
251/*
252 * xmlEncodeEntities : do a global encoding of a string, replacing the
253 * basic content with their entities form.
254 * TODO !!!! rewite !!!
255 */
256CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
257 const CHAR *cur = input;
258 CHAR *out = buffer;
259
260 if (buffer == NULL) {
261 buffer_size = 1000;
262 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
263 if (buffer == NULL) {
264 perror("malloc failed");
265 exit(1);
266 }
267 out = buffer;
268 }
269 while (*cur != '\0') {
270 if (out - buffer > buffer_size - 100) {
271 int index = out - buffer;
272
273 growBuffer();
274 out = &buffer[index];
275 }
276
277 /*
278 * By default one have to encode at least '<', '>', '"' and '&' !
279 * One could try a better encoding using the entities defined and
280 * used as a compression code !!!.
281 */
282 if (*cur == '<') {
283 *out++ = '&';
284 *out++ = 'l';
285 *out++ = 't';
286 *out++ = ';';
287 } else if (*cur == '>') {
288 *out++ = '&';
289 *out++ = 'g';
290 *out++ = 't';
291 *out++ = ';';
292 } else if (*cur == '&') {
293 *out++ = '&';
294 *out++ = 'a';
295 *out++ = 'm';
296 *out++ = 'p';
297 *out++ = ';';
298 } else if (*cur == '"') {
299 *out++ = '&';
300 *out++ = 'q';
301 *out++ = 'u';
302 *out++ = 'o';
303 *out++ = 't';
304 *out++ = ';';
305 } else if (*cur == '\'') {
306 *out++ = '&';
307 *out++ = 'a';
308 *out++ = 'p';
309 *out++ = 'o';
310 *out++ = 's';
311 *out++ = ';';
312 } else {
313 /*
314 * default case, just copy !
315 */
316 *out++ = *cur;
317 }
318 cur++;
319 }
320 *out++ = 0;
321 return(buffer);
322}
323
324/*
325 * xmlCreateEntitiesTable : create and initialize an enmpty hash table
326 */
327xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
328 xmlEntitiesTablePtr ret;
329
330 ret = (xmlEntitiesTablePtr)
331 malloc(sizeof(xmlEntitiesTable));
332 if (ret == NULL) {
333 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
334 sizeof(xmlEntitiesTable));
335 return(NULL);
336 }
337 ret->max_entities = XML_MIN_ENTITIES_TABLE;
338 ret->nb_entities = 0;
339 ret->table = (xmlEntityPtr )
340 malloc(ret->max_entities * sizeof(xmlEntity));
341 if (ret == NULL) {
342 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
343 ret->max_entities * sizeof(xmlEntity));
344 free(ret);
345 return(NULL);
346 }
347 return(ret);
348}
349
350/*
351 * xmlFreeEntitiesTable : clean up and free an entities hash table.
352 */
353void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
354 int i;
355
356 if (table == NULL) return;
357
358 for (i = 0;i < table->nb_entities;i++) {
359 xmlFreeEntity(&table->table[i]);
360 }
361 free(table->table);
362 free(table);
363}
364
365/*
366 * Dump the content of an entity table to the document output.
367 */
368void xmlDumpEntitiesTable(xmlEntitiesTablePtr table) {
369 int i;
370 xmlEntityPtr cur;
371
372 if (table == NULL) return;
373
374 for (i = 0;i < table->nb_entities;i++) {
375 cur = &table->table[i];
376 switch (cur->type) {
377 case XML_INTERNAL_GENERAL_ENTITY:
378 xmlBufferWriteChar("<!ENTITY ");
379 xmlBufferWriteCHAR(cur->name);
380 xmlBufferWriteChar(" \"");
381 xmlBufferWriteCHAR(cur->content);
382 xmlBufferWriteChar("\">\n");
383 break;
384 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
385 xmlBufferWriteChar("<!ENTITY ");
386 xmlBufferWriteCHAR(cur->name);
387 if (cur->ExternalID != NULL) {
388 xmlBufferWriteChar(" PUBLIC \"");
389 xmlBufferWriteCHAR(cur->ExternalID);
390 xmlBufferWriteChar("\" \"");
391 xmlBufferWriteCHAR(cur->SystemID);
392 xmlBufferWriteChar("\"");
393 } else {
394 xmlBufferWriteChar(" SYSTEM \"");
395 xmlBufferWriteCHAR(cur->SystemID);
396 xmlBufferWriteChar("\"");
397 }
398 xmlBufferWriteChar(">\n");
399 break;
400 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
401 xmlBufferWriteChar("<!ENTITY ");
402 xmlBufferWriteCHAR(cur->name);
403 if (cur->ExternalID != NULL) {
404 xmlBufferWriteChar(" PUBLIC \"");
405 xmlBufferWriteCHAR(cur->ExternalID);
406 xmlBufferWriteChar("\" \"");
407 xmlBufferWriteCHAR(cur->SystemID);
408 xmlBufferWriteChar("\"");
409 } else {
410 xmlBufferWriteChar(" SYSTEM \"");
411 xmlBufferWriteCHAR(cur->SystemID);
412 xmlBufferWriteChar("\"");
413 }
414 if (cur->content != NULL) { /* Should be true ! */
415 xmlBufferWriteChar(" NDATA ");
416 xmlBufferWriteCHAR(cur->content);
417 }
418 xmlBufferWriteChar(">\n");
419 break;
420 case XML_INTERNAL_PARAMETER_ENTITY:
421 xmlBufferWriteChar("<!ENTITY % ");
422 xmlBufferWriteCHAR(cur->name);
423 xmlBufferWriteChar(" \"");
424 xmlBufferWriteCHAR(cur->content);
425 xmlBufferWriteChar("\">\n");
426 break;
427 case XML_EXTERNAL_PARAMETER_ENTITY:
428 xmlBufferWriteChar("<!ENTITY % ");
429 xmlBufferWriteCHAR(cur->name);
430 if (cur->ExternalID != NULL) {
431 xmlBufferWriteChar(" PUBLIC \"");
432 xmlBufferWriteCHAR(cur->ExternalID);
433 xmlBufferWriteChar("\" \"");
434 xmlBufferWriteCHAR(cur->SystemID);
435 xmlBufferWriteChar("\"");
436 } else {
437 xmlBufferWriteChar(" SYSTEM \"");
438 xmlBufferWriteCHAR(cur->SystemID);
439 xmlBufferWriteChar("\"");
440 }
441 xmlBufferWriteChar(">\n");
442 break;
443 default:
444 fprintf(stderr,
445 "xmlDumpEntitiesTable: internal: unknown type %d\n",
446 cur->type);
447 }
448 }
449}