blob: 3c9d55cd3f75ba0139066c36758535c6acea18dc [file] [log] [blame]
Daniel Veillard01791d51998-07-24 19:24:09 +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 <strings.h>
12#include "xml_entities.h"
13
14/*
15 * A buffer used for converting entities to their equivalent and back.
16 */
17static CHAR *buffer = NULL;
18static int buffer_size = 0;
19
20void growBuffer(void) {
21 buffer_size *= 2;
22 buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
23 if (buffer == NULL) {
24 perror("realloc failed");
25 exit(1);
26 }
27}
28
29/*
30 * xmlFreeEntity : clean-up an entity record.
31 */
32
33void xmlFreeEntity(xmlEntityPtr entity) {
34 if (entity == NULL) return;
35
36 if (entity->value != NULL) free(entity->value);
37 entity->value = NULL;
38 if (entity->id != NULL)
39 free((char *) entity->id);
40}
41
42/*
43 * xmlAddDocEntity : register a new entity for an entities table.
44 */
45static void xmlAddEntity(xmlEntitiesTablePtr table, CHAR *value,
46 const CHAR *id) {
47 int i;
48 xmlEntityPtr cur;
49
50 for (i = 0;i < table->nb_entities;i++) {
51 cur = &table->table[i];
52 if (!xmlStrcmp(cur->id, id)) {
53 free(cur->value);
54 cur->value = xmlStrdup(value);
55 }
56 }
57 if (table->nb_entities >= table->max_entities) {
58 /*
59 * need more elements.
60 */
61 table->max_entities *= 2;
62 table->table = (xmlEntityPtr)
63 realloc(table->table, table->max_entities * sizeof(xmlEntity));
64 if (table->table) {
65 perror("realloc failed");
66 exit(1);
67 }
68 }
69 cur = &table->table[table->nb_entities];
70 cur->value = xmlStrdup(value);
71 cur->id = xmlStrdup(id);
72 table->nb_entities++;
73}
74
75
76/*
77 * xmlAddDtdEntity : register a new entity for this document.
78 */
79void xmlAddDtdEntity(xmlDtdPtr dtd, CHAR *value, const CHAR *id) {
80 xmlEntitiesTablePtr table;
81
82 table = (xmlEntitiesTablePtr) dtd->entities;
83 if (table == NULL) {
84 table = xmlCreateEntitiesTable();
85 dtd->entities = table;
86 }
87 xmlAddEntity(table, value, id);
88}
89
90/*
91 * xmlAddDocEntity : register a new entity for this document.
92 */
93void xmlAddDocEntity(xmlDocPtr doc, CHAR *value, const CHAR *id) {
94 xmlEntitiesTablePtr table;
95
96 table = (xmlEntitiesTablePtr) doc->entities;
97 if (table == NULL) {
98 table = xmlCreateEntitiesTable();
99 doc->entities = table;
100 }
101 xmlAddEntity(table, value, id);
102}
103
104/*
105 * xmlGetEntity : do an entity lookup in the hash table and
106 * returns the corrsponding CHAR *, if found, zero otherwise.
107 */
108CHAR *xmlGetEntity(xmlDocPtr doc, const CHAR *id) {
109 int i;
110 xmlEntityPtr cur;
111 xmlEntitiesTablePtr table;
112
113 if (doc->entities == NULL) return(0);
114 table = (xmlEntitiesTablePtr) doc->entities;
115 for (i = 0;i < table->nb_entities;i++) {
116 cur = &table->table[i];
117 if (!xmlStrcmp(cur->id, id)) return(cur->value);
118 }
119 return(NULL);
120}
121
122/*
123 * xmlReadEntities : read an entity.
124 */
125const CHAR *xmlReadEntity(xmlDocPtr doc, const CHAR **input) {
126 static CHAR *entity = NULL;
127 static int entity_size = 100;
128 const CHAR *cur = *input;
129
130 if (entity == NULL) {
131 entity = (CHAR *) malloc(entity_size * sizeof(CHAR));
132 if (entity == NULL) {
133 fprintf(stderr, "xmlReadEntity : cannot allocate %d bytes\n",
134 entity_size * sizeof(CHAR));
135 return(NULL);
136 }
137 }
138 if (*cur == '&') {
139 cur++;
140 if (*cur == '#') {
141 /* TODO !!!!
142 fprintf(stderr, "Character reference not yet implemented\n"); */
143 } else {
144 /* TODO !!!!
145 fprintf(stderr, "Entity search not yet implemented\n"); */
146 }
147 }
148
149 /*
150 * The few predefined entities.
151 */
152 if ((cur[0] == 'a') && (cur[1] == 'm') && (cur[2] == 'p') &&
153 (cur[3] == ';')) {
154 entity[0] = '%';
155 entity[1] = 0;
156 cur += 3;
157 *input = cur;
158 return(entity);
159 } else if ((cur[0] == 'q') && (cur[1] == 'u') && (cur[2] == 'o') &&
160 (cur[3] == 't') && (cur[4] == ';')) {
161 entity[0] = '"';
162 entity[1] = 0;
163 cur += 4;
164 *input = cur;
165 return(entity);
166 } else if ((cur[0] == 'a') && (cur[1] == 'p') && (cur[2] == 'o') &&
167 (cur[3] == 's') && (cur[4] == ';')) {
168 entity[0] = '\'';
169 entity[1] = 0;
170 cur += 4;
171 *input = cur;
172 return(entity);
173 } else if ((cur[0] == 'l') && (cur[1] == 't') && (cur[2] == ';')) {
174 entity[0] = '<';
175 entity[1] = 0;
176 cur += 2;
177 *input = cur;
178 return(entity);
179 } else if ((cur[0] == 'g') && (cur[1] == 't') && (cur[2] == ';')) {
180 entity[0] = '>';
181 entity[1] = 0;
182 cur += 2;
183 *input = cur;
184 return(entity);
185 }
186
187 return(NULL);
188}
189
190/*
191 * xmlDecodeEntities : do a global entities lookup on a input string
192 * and returns a duplicate after the entities substitution.
193 */
194CHAR *xmlDecodeEntities(xmlDocPtr doc, const CHAR *input, int len) {
195 const CHAR *cur = input;
196 CHAR *out = buffer;
197 int i;
198
199 if (buffer == NULL) {
200 buffer_size = 1000;
201 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
202 if (buffer == NULL) {
203 perror("malloc failed");
204 exit(1);
205 }
206 out = buffer;
207 }
208 for (i = 0;(*cur != 0) && (cur - input < len);cur++) {
209 if (*cur == '&') {
210 const CHAR *entity = xmlReadEntity(doc, &cur);
211 if (entity != NULL)
212 while (*entity != 0) {
213 *out++ = *entity++;
214 i++;
215 if (i + 10 > buffer_size) {
216 int index = out - buffer;
217
218 growBuffer();
219 out = &buffer[index];
220 }
221 }
222 } else if (*cur == '%') {
223 /* TODO !!!!!
224 fprintf(stderr, " \n"); */
225 } else {
226 *out++ = *cur;
227 i++;
228 }
229
230 if (i + 10 > buffer_size) {
231 int index = out - buffer;
232
233 growBuffer();
234 out = &buffer[index];
235 }
236 }
237 *out++ = 0;
238 return(buffer);
239}
240
241/*
242 * xmlEncodeEntities : do a global encoding of a string, replacing the
243 * basic values with their entities form.
244 */
245CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
246 const CHAR *cur = input;
247 CHAR *out = buffer;
248
249 if (buffer == NULL) {
250 buffer_size = 1000;
251 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
252 if (buffer == NULL) {
253 perror("malloc failed");
254 exit(1);
255 }
256 out = buffer;
257 }
258 while (*cur != '\0') {
259 if (out - buffer > buffer_size - 100) {
260 int index = out - buffer;
261
262 growBuffer();
263 out = &buffer[index];
264 }
265
266 /*
267 * By default one have to encode at least '<', '>', '"' and '&' !
268 * One could try a better encoding using the entities defined and
269 * used as a compression code !!!.
270 */
271 if (*cur == '<') {
272 *out++ = '&';
273 *out++ = 'l';
274 *out++ = 't';
275 *out++ = ';';
276 } else if (*cur == '>') {
277 *out++ = '&';
278 *out++ = 'g';
279 *out++ = 't';
280 *out++ = ';';
281 } else if (*cur == '&') {
282 *out++ = '&';
283 *out++ = 'a';
284 *out++ = 'm';
285 *out++ = 'p';
286 *out++ = ';';
287 } else if (*cur == '"') {
288 *out++ = '&';
289 *out++ = 'q';
290 *out++ = 'u';
291 *out++ = 'o';
292 *out++ = 't';
293 *out++ = ';';
294 } else if (*cur == '\'') {
295 *out++ = '&';
296 *out++ = 'a';
297 *out++ = 'p';
298 *out++ = 'o';
299 *out++ = 's';
300 *out++ = ';';
301 } else {
302 /*
303 * default case, just copy !
304 */
305 *out++ = *cur;
306 }
307 cur++;
308 }
309 *out++ = 0;
310 return(buffer);
311}
312
313/*
314 * xmlCreateEntitiesTable : create and initialize an enmpty hash table
315 */
316xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
317 xmlEntitiesTablePtr ret;
318
319 ret = (xmlEntitiesTablePtr)
320 malloc(sizeof(xmlEntitiesTable));
321 if (ret == NULL) {
322 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
323 sizeof(xmlEntitiesTable));
324 return(NULL);
325 }
326 ret->max_entities = XML_MIN_ENTITIES_TABLE;
327 ret->nb_entities = 0;
328 ret->table = (xmlEntityPtr )
329 malloc(ret->max_entities * sizeof(xmlEntity));
330 if (ret == NULL) {
331 fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
332 ret->max_entities * sizeof(xmlEntity));
333 free(ret);
334 return(NULL);
335 }
336 return(ret);
337}
338
339/*
340 * xmlFreeEntitiesTable : clean up and free an entities hash table.
341 */
342void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
343 int i;
344
345 if (table == NULL) return;
346
347 for (i = 0;i < table->nb_entities;i++) {
348 xmlFreeEntity(&table->table[i]);
349 }
350 free(table->table);
351 free(table);
352}
353