blob: 47b7cfa1adb1483892e8ebd5c7c7f1916134cd6a [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>
10#include <malloc.h>
11#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
146
147/*
148 * xmlAddDtdEntity : register a new entity for this DTD.
149 */
150void xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
151 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
152 xmlEntitiesTablePtr table;
153
154 if (doc->dtd == NULL) {
155 fprintf(stderr, "xmlAddDtdEntity: document without Dtd !\n");
156 return;
157 }
158 table = (xmlEntitiesTablePtr) doc->dtd->entities;
159 if (table == NULL) {
160 table = xmlCreateEntitiesTable();
161 doc->dtd->entities = table;
162 }
163 xmlAddEntity(table, name, type, ExternalID, SystemID, content);
164}
165
166/*
167 * xmlAddDocEntity : register a new entity for this document.
168 */
169void xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
170 const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
171 xmlEntitiesTablePtr table;
172
173 table = (xmlEntitiesTablePtr) doc->entities;
174 if (table == NULL) {
175 table = xmlCreateEntitiesTable();
176 doc->entities = table;
177 }
178 xmlAddEntity(doc->entities, name, type, ExternalID, SystemID, content);
179}
180
181/*
182 * xmlGetDtdEntity : do an entity lookup in the Dtd entity hash table and
183 * returns the corrsponding entity, if found, NULL otherwise.
184 */
185xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
186 int i;
187 xmlEntityPtr cur;
188 xmlEntitiesTablePtr table;
189
190 if ((doc->dtd != NULL) && (doc->dtd->entities != NULL)) {
191 table = (xmlEntitiesTablePtr) doc->dtd->entities;
192 for (i = 0;i < table->nb_entities;i++) {
193 cur = &table->table[i];
194 if (!xmlStrcmp(cur->name, name)) return(cur);
195 }
196 }
197 return(NULL);
198}
199
200/*
201 * xmlGetDocEntity : do an entity lookup in the document entity hash table and
202 * returns the corrsponding entity, otherwise a lookup is done
203 * in the predefined entities too.
204 */
205xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
206 int i;
207 xmlEntityPtr cur;
208 xmlEntitiesTablePtr table;
209
210 if (doc->entities != NULL) {
211 table = (xmlEntitiesTablePtr) doc->entities;
212 for (i = 0;i < table->nb_entities;i++) {
213 cur = &table->table[i];
214 if (!xmlStrcmp(cur->name, name)) return(cur);
215 }
216 }
217 if (xmlPredefinedEntities == NULL)
218 xmlInitializePredefinedEntities();
219 table = xmlPredefinedEntities;
220 for (i = 0;i < table->nb_entities;i++) {
221 cur = &table->table[i];
222 if (!xmlStrcmp(cur->name, name)) return(cur);
223 }
224
225 return(NULL);
226}
227
228/*
229 * xmlEncodeEntities : do a global encoding of a string, replacing the
230 * basic content with their entities form.
231 * TODO !!!! rewite !!!
232 */
233CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
234 const CHAR *cur = input;
235 CHAR *out = buffer;
236
237 if (buffer == NULL) {
238 buffer_size = 1000;
239 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
240 if (buffer == NULL) {
241 perror("malloc failed");
242 exit(1);
243 }
244 out = buffer;
245 }
246 while (*cur != '\0') {
247 if (out - buffer > buffer_size - 100) {
248 int index = out - buffer;
249
250 growBuffer();
251 out = &buffer[index];
252 }
253
254 /*
255 * By default one have to encode at least '<', '>', '"' and '&' !
256 * One could try a better encoding using the entities defined and
257 * used as a compression code !!!.
258 */
259 if (*cur == '<') {
260 *out++ = '&';
261 *out++ = 'l';
262 *out++ = 't';
263 *out++ = ';';
264 } else if (*cur == '>') {
265 *out++ = '&';
266 *out++ = 'g';
267 *out++ = 't';
268 *out++ = ';';
269 } else if (*cur == '&') {
270 *out++ = '&';
271 *out++ = 'a';
272 *out++ = 'm';
273 *out++ = 'p';
274 *out++ = ';';
275 } else if (*cur == '"') {
276 *out++ = '&';
277 *out++ = 'q';
278 *out++ = 'u';
279 *out++ = 'o';
280 *out++ = 't';
281 *out++ = ';';
282 } else if (*cur == '\'') {
283 *out++ = '&';
284 *out++ = 'a';
285 *out++ = 'p';
286 *out++ = 'o';
287 *out++ = 's';
288 *out++ = ';';
289 } else {
290 /*
291 * default case, just copy !
292 */
293 *out++ = *cur;
294 }
295 cur++;
296 }
297 *out++ = 0;
298 return(buffer);
299}
300
301/*
302 * xmlCreateEntitiesTable : create and initialize an enmpty hash table
303 */
304xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
305 xmlEntitiesTablePtr ret;
306
307 ret = (xmlEntitiesTablePtr)
308 malloc(sizeof(xmlEntitiesTable));
309 if (ret == NULL) {
310 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
311 sizeof(xmlEntitiesTable));
312 return(NULL);
313 }
314 ret->max_entities = XML_MIN_ENTITIES_TABLE;
315 ret->nb_entities = 0;
316 ret->table = (xmlEntityPtr )
317 malloc(ret->max_entities * sizeof(xmlEntity));
318 if (ret == NULL) {
319 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
320 ret->max_entities * sizeof(xmlEntity));
321 free(ret);
322 return(NULL);
323 }
324 return(ret);
325}
326
327/*
328 * xmlFreeEntitiesTable : clean up and free an entities hash table.
329 */
330void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
331 int i;
332
333 if (table == NULL) return;
334
335 for (i = 0;i < table->nb_entities;i++) {
336 xmlFreeEntity(&table->table[i]);
337 }
338 free(table->table);
339 free(table);
340}
341
342/*
343 * Dump the content of an entity table to the document output.
344 */
345void xmlDumpEntitiesTable(xmlEntitiesTablePtr table) {
346 int i;
347 xmlEntityPtr cur;
348
349 if (table == NULL) return;
350
351 for (i = 0;i < table->nb_entities;i++) {
352 cur = &table->table[i];
353 switch (cur->type) {
354 case XML_INTERNAL_GENERAL_ENTITY:
355 xmlBufferWriteChar("<!ENTITY ");
356 xmlBufferWriteCHAR(cur->name);
357 xmlBufferWriteChar(" \"");
358 xmlBufferWriteCHAR(cur->content);
359 xmlBufferWriteChar("\">\n");
360 break;
361 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
362 xmlBufferWriteChar("<!ENTITY ");
363 xmlBufferWriteCHAR(cur->name);
364 if (cur->ExternalID != NULL) {
365 xmlBufferWriteChar(" PUBLIC \"");
366 xmlBufferWriteCHAR(cur->ExternalID);
367 xmlBufferWriteChar("\" \"");
368 xmlBufferWriteCHAR(cur->SystemID);
369 xmlBufferWriteChar("\"");
370 } else {
371 xmlBufferWriteChar(" SYSTEM \"");
372 xmlBufferWriteCHAR(cur->SystemID);
373 xmlBufferWriteChar("\"");
374 }
375 xmlBufferWriteChar(">\n");
376 break;
377 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
378 xmlBufferWriteChar("<!ENTITY ");
379 xmlBufferWriteCHAR(cur->name);
380 if (cur->ExternalID != NULL) {
381 xmlBufferWriteChar(" PUBLIC \"");
382 xmlBufferWriteCHAR(cur->ExternalID);
383 xmlBufferWriteChar("\" \"");
384 xmlBufferWriteCHAR(cur->SystemID);
385 xmlBufferWriteChar("\"");
386 } else {
387 xmlBufferWriteChar(" SYSTEM \"");
388 xmlBufferWriteCHAR(cur->SystemID);
389 xmlBufferWriteChar("\"");
390 }
391 if (cur->content != NULL) { /* Should be true ! */
392 xmlBufferWriteChar(" NDATA ");
393 xmlBufferWriteCHAR(cur->content);
394 }
395 xmlBufferWriteChar(">\n");
396 break;
397 case XML_INTERNAL_PARAMETER_ENTITY:
398 xmlBufferWriteChar("<!ENTITY % ");
399 xmlBufferWriteCHAR(cur->name);
400 xmlBufferWriteChar(" \"");
401 xmlBufferWriteCHAR(cur->content);
402 xmlBufferWriteChar("\">\n");
403 break;
404 case XML_EXTERNAL_PARAMETER_ENTITY:
405 xmlBufferWriteChar("<!ENTITY % ");
406 xmlBufferWriteCHAR(cur->name);
407 if (cur->ExternalID != NULL) {
408 xmlBufferWriteChar(" PUBLIC \"");
409 xmlBufferWriteCHAR(cur->ExternalID);
410 xmlBufferWriteChar("\" \"");
411 xmlBufferWriteCHAR(cur->SystemID);
412 xmlBufferWriteChar("\"");
413 } else {
414 xmlBufferWriteChar(" SYSTEM \"");
415 xmlBufferWriteCHAR(cur->SystemID);
416 xmlBufferWriteChar("\"");
417 }
418 xmlBufferWriteChar(">\n");
419 break;
420 default:
421 fprintf(stderr,
422 "xmlDumpEntitiesTable: internal: unknown type %d\n",
423 cur->type);
424 }
425 }
426}