Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xml2/entities.c
4389 views
1
/*
2
* entities.c : implementation for the XML entities handling
3
*
4
* See Copyright for the status of this software.
5
*
6
* [email protected]
7
*/
8
9
/* To avoid EBCDIC trouble when parsing on zOS */
10
#if defined(__MVS__)
11
#pragma convert("ISO8859-1")
12
#endif
13
14
#define IN_LIBXML
15
#include "libxml.h"
16
17
#include <string.h>
18
#include <stdlib.h>
19
20
#include <libxml/xmlmemory.h>
21
#include <libxml/hash.h>
22
#include <libxml/entities.h>
23
#include <libxml/parser.h>
24
#include <libxml/parserInternals.h>
25
#include <libxml/xmlerror.h>
26
#include <libxml/dict.h>
27
28
#include "private/entities.h"
29
#include "private/error.h"
30
31
/*
32
* The XML predefined entities.
33
*/
34
35
static xmlEntity xmlEntityLt = {
36
NULL, XML_ENTITY_DECL, BAD_CAST "lt",
37
NULL, NULL, NULL, NULL, NULL, NULL,
38
BAD_CAST "<", BAD_CAST "<", 1,
39
XML_INTERNAL_PREDEFINED_ENTITY,
40
NULL, NULL, NULL, NULL, 0, 0, 0
41
};
42
static xmlEntity xmlEntityGt = {
43
NULL, XML_ENTITY_DECL, BAD_CAST "gt",
44
NULL, NULL, NULL, NULL, NULL, NULL,
45
BAD_CAST ">", BAD_CAST ">", 1,
46
XML_INTERNAL_PREDEFINED_ENTITY,
47
NULL, NULL, NULL, NULL, 0, 0, 0
48
};
49
static xmlEntity xmlEntityAmp = {
50
NULL, XML_ENTITY_DECL, BAD_CAST "amp",
51
NULL, NULL, NULL, NULL, NULL, NULL,
52
BAD_CAST "&", BAD_CAST "&", 1,
53
XML_INTERNAL_PREDEFINED_ENTITY,
54
NULL, NULL, NULL, NULL, 0, 0, 0
55
};
56
static xmlEntity xmlEntityQuot = {
57
NULL, XML_ENTITY_DECL, BAD_CAST "quot",
58
NULL, NULL, NULL, NULL, NULL, NULL,
59
BAD_CAST "\"", BAD_CAST "\"", 1,
60
XML_INTERNAL_PREDEFINED_ENTITY,
61
NULL, NULL, NULL, NULL, 0, 0, 0
62
};
63
static xmlEntity xmlEntityApos = {
64
NULL, XML_ENTITY_DECL, BAD_CAST "apos",
65
NULL, NULL, NULL, NULL, NULL, NULL,
66
BAD_CAST "'", BAD_CAST "'", 1,
67
XML_INTERNAL_PREDEFINED_ENTITY,
68
NULL, NULL, NULL, NULL, 0, 0, 0
69
};
70
71
/**
72
* xmlEntitiesErrMemory:
73
* @extra: extra information
74
*
75
* Handle an out of memory condition
76
*/
77
static void
78
xmlEntitiesErrMemory(const char *extra)
79
{
80
__xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
81
}
82
83
/**
84
* xmlEntitiesErr:
85
* @code: the error code
86
* @msg: the message
87
*
88
* Raise an error.
89
*/
90
static void LIBXML_ATTR_FORMAT(2,0)
91
xmlEntitiesErr(xmlParserErrors code, const char *msg)
92
{
93
__xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL);
94
}
95
96
/**
97
* xmlEntitiesWarn:
98
* @code: the error code
99
* @msg: the message
100
*
101
* Raise a warning.
102
*/
103
static void LIBXML_ATTR_FORMAT(2,0)
104
xmlEntitiesWarn(xmlParserErrors code, const char *msg, const xmlChar *str1)
105
{
106
__xmlRaiseError(NULL, NULL, NULL,
107
NULL, NULL, XML_FROM_TREE, code,
108
XML_ERR_WARNING, NULL, 0,
109
(const char *)str1, NULL, NULL, 0, 0,
110
msg, (const char *)str1, NULL);
111
}
112
113
/*
114
* xmlFreeEntity : clean-up an entity record.
115
*/
116
void
117
xmlFreeEntity(xmlEntityPtr entity)
118
{
119
xmlDictPtr dict = NULL;
120
121
if (entity == NULL)
122
return;
123
124
if (entity->doc != NULL)
125
dict = entity->doc->dict;
126
127
128
if ((entity->children) && (entity->owner == 1) &&
129
(entity == (xmlEntityPtr) entity->children->parent))
130
xmlFreeNodeList(entity->children);
131
if ((entity->name != NULL) &&
132
((dict == NULL) || (!xmlDictOwns(dict, entity->name))))
133
xmlFree((char *) entity->name);
134
if (entity->ExternalID != NULL)
135
xmlFree((char *) entity->ExternalID);
136
if (entity->SystemID != NULL)
137
xmlFree((char *) entity->SystemID);
138
if (entity->URI != NULL)
139
xmlFree((char *) entity->URI);
140
if (entity->content != NULL)
141
xmlFree((char *) entity->content);
142
if (entity->orig != NULL)
143
xmlFree((char *) entity->orig);
144
xmlFree(entity);
145
}
146
147
/*
148
* xmlCreateEntity:
149
*
150
* internal routine doing the entity node structures allocations
151
*/
152
static xmlEntityPtr
153
xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
154
const xmlChar *ExternalID, const xmlChar *SystemID,
155
const xmlChar *content) {
156
xmlEntityPtr ret;
157
158
ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
159
if (ret == NULL) {
160
xmlEntitiesErrMemory("xmlCreateEntity: malloc failed");
161
return(NULL);
162
}
163
memset(ret, 0, sizeof(xmlEntity));
164
ret->type = XML_ENTITY_DECL;
165
166
/*
167
* fill the structure.
168
*/
169
ret->etype = (xmlEntityType) type;
170
if (dict == NULL) {
171
ret->name = xmlStrdup(name);
172
if (ExternalID != NULL)
173
ret->ExternalID = xmlStrdup(ExternalID);
174
if (SystemID != NULL)
175
ret->SystemID = xmlStrdup(SystemID);
176
} else {
177
ret->name = xmlDictLookup(dict, name, -1);
178
ret->ExternalID = xmlStrdup(ExternalID);
179
ret->SystemID = xmlStrdup(SystemID);
180
}
181
if (content != NULL) {
182
ret->length = xmlStrlen(content);
183
ret->content = xmlStrndup(content, ret->length);
184
} else {
185
ret->length = 0;
186
ret->content = NULL;
187
}
188
ret->URI = NULL; /* to be computed by the layer knowing
189
the defining entity */
190
ret->orig = NULL;
191
ret->owner = 0;
192
193
return(ret);
194
}
195
196
/*
197
* xmlAddEntity : register a new entity for an entities table.
198
*/
199
static xmlEntityPtr
200
xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
201
const xmlChar *ExternalID, const xmlChar *SystemID,
202
const xmlChar *content) {
203
xmlDictPtr dict = NULL;
204
xmlEntitiesTablePtr table = NULL;
205
xmlEntityPtr ret, predef;
206
207
if (name == NULL)
208
return(NULL);
209
if (dtd == NULL)
210
return(NULL);
211
if (dtd->doc != NULL)
212
dict = dtd->doc->dict;
213
214
switch (type) {
215
case XML_INTERNAL_GENERAL_ENTITY:
216
case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
217
case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
218
predef = xmlGetPredefinedEntity(name);
219
if (predef != NULL) {
220
int valid = 0;
221
222
/* 4.6 Predefined Entities */
223
if ((type == XML_INTERNAL_GENERAL_ENTITY) &&
224
(content != NULL)) {
225
int c = predef->content[0];
226
227
if (((content[0] == c) && (content[1] == 0)) &&
228
((c == '>') || (c == '\'') || (c == '"'))) {
229
valid = 1;
230
} else if ((content[0] == '&') && (content[1] == '#')) {
231
if (content[2] == 'x') {
232
xmlChar *hex = BAD_CAST "0123456789ABCDEF";
233
xmlChar ref[] = "00;";
234
235
ref[0] = hex[c / 16 % 16];
236
ref[1] = hex[c % 16];
237
if (xmlStrcasecmp(&content[3], ref) == 0)
238
valid = 1;
239
} else {
240
xmlChar ref[] = "00;";
241
242
ref[0] = '0' + c / 10 % 10;
243
ref[1] = '0' + c % 10;
244
if (xmlStrEqual(&content[2], ref))
245
valid = 1;
246
}
247
}
248
}
249
if (!valid) {
250
xmlEntitiesWarn(XML_ERR_ENTITY_PROCESSING,
251
"xmlAddEntity: invalid redeclaration of predefined"
252
" entity '%s'", name);
253
return(NULL);
254
}
255
}
256
if (dtd->entities == NULL)
257
dtd->entities = xmlHashCreateDict(0, dict);
258
table = dtd->entities;
259
break;
260
case XML_INTERNAL_PARAMETER_ENTITY:
261
case XML_EXTERNAL_PARAMETER_ENTITY:
262
if (dtd->pentities == NULL)
263
dtd->pentities = xmlHashCreateDict(0, dict);
264
table = dtd->pentities;
265
break;
266
case XML_INTERNAL_PREDEFINED_ENTITY:
267
return(NULL);
268
}
269
if (table == NULL)
270
return(NULL);
271
ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
272
if (ret == NULL)
273
return(NULL);
274
ret->doc = dtd->doc;
275
276
if (xmlHashAddEntry(table, name, ret)) {
277
/*
278
* entity was already defined at another level.
279
*/
280
xmlFreeEntity(ret);
281
return(NULL);
282
}
283
return(ret);
284
}
285
286
/**
287
* xmlGetPredefinedEntity:
288
* @name: the entity name
289
*
290
* Check whether this name is an predefined entity.
291
*
292
* Returns NULL if not, otherwise the entity
293
*/
294
xmlEntityPtr
295
xmlGetPredefinedEntity(const xmlChar *name) {
296
if (name == NULL) return(NULL);
297
switch (name[0]) {
298
case 'l':
299
if (xmlStrEqual(name, BAD_CAST "lt"))
300
return(&xmlEntityLt);
301
break;
302
case 'g':
303
if (xmlStrEqual(name, BAD_CAST "gt"))
304
return(&xmlEntityGt);
305
break;
306
case 'a':
307
if (xmlStrEqual(name, BAD_CAST "amp"))
308
return(&xmlEntityAmp);
309
if (xmlStrEqual(name, BAD_CAST "apos"))
310
return(&xmlEntityApos);
311
break;
312
case 'q':
313
if (xmlStrEqual(name, BAD_CAST "quot"))
314
return(&xmlEntityQuot);
315
break;
316
default:
317
break;
318
}
319
return(NULL);
320
}
321
322
/**
323
* xmlAddDtdEntity:
324
* @doc: the document
325
* @name: the entity name
326
* @type: the entity type XML_xxx_yyy_ENTITY
327
* @ExternalID: the entity external ID if available
328
* @SystemID: the entity system ID if available
329
* @content: the entity content
330
*
331
* Register a new entity for this document DTD external subset.
332
*
333
* Returns a pointer to the entity or NULL in case of error
334
*/
335
xmlEntityPtr
336
xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
337
const xmlChar *ExternalID, const xmlChar *SystemID,
338
const xmlChar *content) {
339
xmlEntityPtr ret;
340
xmlDtdPtr dtd;
341
342
if (doc == NULL) {
343
xmlEntitiesErr(XML_DTD_NO_DOC,
344
"xmlAddDtdEntity: document is NULL");
345
return(NULL);
346
}
347
if (doc->extSubset == NULL) {
348
xmlEntitiesErr(XML_DTD_NO_DTD,
349
"xmlAddDtdEntity: document without external subset");
350
return(NULL);
351
}
352
dtd = doc->extSubset;
353
ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
354
if (ret == NULL) return(NULL);
355
356
/*
357
* Link it to the DTD
358
*/
359
ret->parent = dtd;
360
ret->doc = dtd->doc;
361
if (dtd->last == NULL) {
362
dtd->children = dtd->last = (xmlNodePtr) ret;
363
} else {
364
dtd->last->next = (xmlNodePtr) ret;
365
ret->prev = dtd->last;
366
dtd->last = (xmlNodePtr) ret;
367
}
368
return(ret);
369
}
370
371
/**
372
* xmlAddDocEntity:
373
* @doc: the document
374
* @name: the entity name
375
* @type: the entity type XML_xxx_yyy_ENTITY
376
* @ExternalID: the entity external ID if available
377
* @SystemID: the entity system ID if available
378
* @content: the entity content
379
*
380
* Register a new entity for this document.
381
*
382
* Returns a pointer to the entity or NULL in case of error
383
*/
384
xmlEntityPtr
385
xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
386
const xmlChar *ExternalID, const xmlChar *SystemID,
387
const xmlChar *content) {
388
xmlEntityPtr ret;
389
xmlDtdPtr dtd;
390
391
if (doc == NULL) {
392
xmlEntitiesErr(XML_DTD_NO_DOC,
393
"xmlAddDocEntity: document is NULL");
394
return(NULL);
395
}
396
if (doc->intSubset == NULL) {
397
xmlEntitiesErr(XML_DTD_NO_DTD,
398
"xmlAddDocEntity: document without internal subset");
399
return(NULL);
400
}
401
dtd = doc->intSubset;
402
ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
403
if (ret == NULL) return(NULL);
404
405
/*
406
* Link it to the DTD
407
*/
408
ret->parent = dtd;
409
ret->doc = dtd->doc;
410
if (dtd->last == NULL) {
411
dtd->children = dtd->last = (xmlNodePtr) ret;
412
} else {
413
dtd->last->next = (xmlNodePtr) ret;
414
ret->prev = dtd->last;
415
dtd->last = (xmlNodePtr) ret;
416
}
417
return(ret);
418
}
419
420
/**
421
* xmlNewEntity:
422
* @doc: the document
423
* @name: the entity name
424
* @type: the entity type XML_xxx_yyy_ENTITY
425
* @ExternalID: the entity external ID if available
426
* @SystemID: the entity system ID if available
427
* @content: the entity content
428
*
429
* Create a new entity, this differs from xmlAddDocEntity() that if
430
* the document is NULL or has no internal subset defined, then an
431
* unlinked entity structure will be returned, it is then the responsibility
432
* of the caller to link it to the document later or free it when not needed
433
* anymore.
434
*
435
* Returns a pointer to the entity or NULL in case of error
436
*/
437
xmlEntityPtr
438
xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type,
439
const xmlChar *ExternalID, const xmlChar *SystemID,
440
const xmlChar *content) {
441
xmlEntityPtr ret;
442
xmlDictPtr dict;
443
444
if ((doc != NULL) && (doc->intSubset != NULL)) {
445
return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
446
}
447
if (doc != NULL)
448
dict = doc->dict;
449
else
450
dict = NULL;
451
ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
452
if (ret == NULL)
453
return(NULL);
454
ret->doc = doc;
455
return(ret);
456
}
457
458
/**
459
* xmlGetEntityFromTable:
460
* @table: an entity table
461
* @name: the entity name
462
* @parameter: look for parameter entities
463
*
464
* Do an entity lookup in the table.
465
* returns the corresponding parameter entity, if found.
466
*
467
* Returns A pointer to the entity structure or NULL if not found.
468
*/
469
static xmlEntityPtr
470
xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
471
return((xmlEntityPtr) xmlHashLookup(table, name));
472
}
473
474
/**
475
* xmlGetParameterEntity:
476
* @doc: the document referencing the entity
477
* @name: the entity name
478
*
479
* Do an entity lookup in the internal and external subsets and
480
* returns the corresponding parameter entity, if found.
481
*
482
* Returns A pointer to the entity structure or NULL if not found.
483
*/
484
xmlEntityPtr
485
xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
486
xmlEntitiesTablePtr table;
487
xmlEntityPtr ret;
488
489
if (doc == NULL)
490
return(NULL);
491
if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
492
table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
493
ret = xmlGetEntityFromTable(table, name);
494
if (ret != NULL)
495
return(ret);
496
}
497
if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
498
table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
499
return(xmlGetEntityFromTable(table, name));
500
}
501
return(NULL);
502
}
503
504
/**
505
* xmlGetDtdEntity:
506
* @doc: the document referencing the entity
507
* @name: the entity name
508
*
509
* Do an entity lookup in the DTD entity hash table and
510
* returns the corresponding entity, if found.
511
* Note: the first argument is the document node, not the DTD node.
512
*
513
* Returns A pointer to the entity structure or NULL if not found.
514
*/
515
xmlEntityPtr
516
xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
517
xmlEntitiesTablePtr table;
518
519
if (doc == NULL)
520
return(NULL);
521
if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
522
table = (xmlEntitiesTablePtr) doc->extSubset->entities;
523
return(xmlGetEntityFromTable(table, name));
524
}
525
return(NULL);
526
}
527
528
/**
529
* xmlGetDocEntity:
530
* @doc: the document referencing the entity
531
* @name: the entity name
532
*
533
* Do an entity lookup in the document entity hash table and
534
* returns the corresponding entity, otherwise a lookup is done
535
* in the predefined entities too.
536
*
537
* Returns A pointer to the entity structure or NULL if not found.
538
*/
539
xmlEntityPtr
540
xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) {
541
xmlEntityPtr cur;
542
xmlEntitiesTablePtr table;
543
544
if (doc != NULL) {
545
if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
546
table = (xmlEntitiesTablePtr) doc->intSubset->entities;
547
cur = xmlGetEntityFromTable(table, name);
548
if (cur != NULL)
549
return(cur);
550
}
551
if (doc->standalone != 1) {
552
if ((doc->extSubset != NULL) &&
553
(doc->extSubset->entities != NULL)) {
554
table = (xmlEntitiesTablePtr) doc->extSubset->entities;
555
cur = xmlGetEntityFromTable(table, name);
556
if (cur != NULL)
557
return(cur);
558
}
559
}
560
}
561
return(xmlGetPredefinedEntity(name));
562
}
563
564
/*
565
* Macro used to grow the current buffer.
566
*/
567
#define growBufferReentrant() { \
568
xmlChar *tmp; \
569
size_t new_size = buffer_size * 2; \
570
if (new_size < buffer_size) goto mem_error; \
571
tmp = (xmlChar *) xmlRealloc(buffer, new_size); \
572
if (tmp == NULL) goto mem_error; \
573
buffer = tmp; \
574
buffer_size = new_size; \
575
}
576
577
/**
578
* xmlEncodeEntitiesInternal:
579
* @doc: the document containing the string
580
* @input: A string to convert to XML.
581
* @attr: are we handling an attribute value
582
*
583
* Do a global encoding of a string, replacing the predefined entities
584
* and non ASCII values with their entities and CharRef counterparts.
585
* Contrary to xmlEncodeEntities, this routine is reentrant, and result
586
* must be deallocated.
587
*
588
* Returns A newly allocated string with the substitution done.
589
*/
590
static xmlChar *
591
xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
592
const xmlChar *cur = input;
593
xmlChar *buffer = NULL;
594
xmlChar *out = NULL;
595
size_t buffer_size = 0;
596
int html = 0;
597
598
if (input == NULL) return(NULL);
599
if (doc != NULL)
600
html = (doc->type == XML_HTML_DOCUMENT_NODE);
601
602
/*
603
* allocate an translation buffer.
604
*/
605
buffer_size = 1000;
606
buffer = (xmlChar *) xmlMalloc(buffer_size);
607
if (buffer == NULL) {
608
xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed");
609
return(NULL);
610
}
611
out = buffer;
612
613
while (*cur != '\0') {
614
size_t indx = out - buffer;
615
if (indx + 100 > buffer_size) {
616
617
growBufferReentrant();
618
out = &buffer[indx];
619
}
620
621
/*
622
* By default one have to encode at least '<', '>', '"' and '&' !
623
*/
624
if (*cur == '<') {
625
const xmlChar *end;
626
627
/*
628
* Special handling of server side include in HTML attributes
629
*/
630
if (html && attr &&
631
(cur[1] == '!') && (cur[2] == '-') && (cur[3] == '-') &&
632
((end = xmlStrstr(cur, BAD_CAST "-->")) != NULL)) {
633
while (cur != end) {
634
*out++ = *cur++;
635
indx = out - buffer;
636
if (indx + 100 > buffer_size) {
637
growBufferReentrant();
638
out = &buffer[indx];
639
}
640
}
641
*out++ = *cur++;
642
*out++ = *cur++;
643
*out++ = *cur++;
644
continue;
645
}
646
*out++ = '&';
647
*out++ = 'l';
648
*out++ = 't';
649
*out++ = ';';
650
} else if (*cur == '>') {
651
*out++ = '&';
652
*out++ = 'g';
653
*out++ = 't';
654
*out++ = ';';
655
} else if (*cur == '&') {
656
/*
657
* Special handling of &{...} construct from HTML 4, see
658
* http://www.w3.org/TR/html401/appendix/notes.html#h-B.7.1
659
*/
660
if (html && attr && (cur[1] == '{') &&
661
(strchr((const char *) cur, '}'))) {
662
while (*cur != '}') {
663
*out++ = *cur++;
664
indx = out - buffer;
665
if (indx + 100 > buffer_size) {
666
growBufferReentrant();
667
out = &buffer[indx];
668
}
669
}
670
*out++ = *cur++;
671
continue;
672
}
673
*out++ = '&';
674
*out++ = 'a';
675
*out++ = 'm';
676
*out++ = 'p';
677
*out++ = ';';
678
} else if (((*cur >= 0x20) && (*cur < 0x80)) ||
679
(*cur == '\n') || (*cur == '\t') || ((html) && (*cur == '\r'))) {
680
/*
681
* default case, just copy !
682
*/
683
*out++ = *cur;
684
} else if (*cur >= 0x80) {
685
if (((doc != NULL) && (doc->encoding != NULL)) || (html)) {
686
/*
687
* Bjørn Reese <[email protected]> provided the patch
688
xmlChar xc;
689
xc = (*cur & 0x3F) << 6;
690
if (cur[1] != 0) {
691
xc += *(++cur) & 0x3F;
692
*out++ = xc;
693
} else
694
*/
695
*out++ = *cur;
696
} else {
697
/*
698
* We assume we have UTF-8 input.
699
* It must match either:
700
* 110xxxxx 10xxxxxx
701
* 1110xxxx 10xxxxxx 10xxxxxx
702
* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
703
* That is:
704
* cur[0] is 11xxxxxx
705
* cur[1] is 10xxxxxx
706
* cur[2] is 10xxxxxx if cur[0] is 111xxxxx
707
* cur[3] is 10xxxxxx if cur[0] is 1111xxxx
708
* cur[0] is not 11111xxx
709
*/
710
char buf[11], *ptr;
711
int val = 0, l = 1;
712
713
if (((cur[0] & 0xC0) != 0xC0) ||
714
((cur[1] & 0xC0) != 0x80) ||
715
(((cur[0] & 0xE0) == 0xE0) && ((cur[2] & 0xC0) != 0x80)) ||
716
(((cur[0] & 0xF0) == 0xF0) && ((cur[3] & 0xC0) != 0x80)) ||
717
(((cur[0] & 0xF8) == 0xF8))) {
718
xmlEntitiesErr(XML_CHECK_NOT_UTF8,
719
"xmlEncodeEntities: input not UTF-8");
720
snprintf(buf, sizeof(buf), "&#%d;", *cur);
721
buf[sizeof(buf) - 1] = 0;
722
ptr = buf;
723
while (*ptr != 0) *out++ = *ptr++;
724
cur++;
725
continue;
726
} else if (*cur < 0xE0) {
727
val = (cur[0]) & 0x1F;
728
val <<= 6;
729
val |= (cur[1]) & 0x3F;
730
l = 2;
731
} else if (*cur < 0xF0) {
732
val = (cur[0]) & 0x0F;
733
val <<= 6;
734
val |= (cur[1]) & 0x3F;
735
val <<= 6;
736
val |= (cur[2]) & 0x3F;
737
l = 3;
738
} else if (*cur < 0xF8) {
739
val = (cur[0]) & 0x07;
740
val <<= 6;
741
val |= (cur[1]) & 0x3F;
742
val <<= 6;
743
val |= (cur[2]) & 0x3F;
744
val <<= 6;
745
val |= (cur[3]) & 0x3F;
746
l = 4;
747
}
748
if ((l == 1) || (!IS_CHAR(val))) {
749
xmlEntitiesErr(XML_ERR_INVALID_CHAR,
750
"xmlEncodeEntities: char out of range\n");
751
snprintf(buf, sizeof(buf), "&#%d;", *cur);
752
buf[sizeof(buf) - 1] = 0;
753
ptr = buf;
754
while (*ptr != 0) *out++ = *ptr++;
755
cur++;
756
continue;
757
}
758
/*
759
* We could do multiple things here. Just save as a char ref
760
*/
761
snprintf(buf, sizeof(buf), "&#x%X;", val);
762
buf[sizeof(buf) - 1] = 0;
763
ptr = buf;
764
while (*ptr != 0) *out++ = *ptr++;
765
cur += l;
766
continue;
767
}
768
} else if (IS_BYTE_CHAR(*cur)) {
769
char buf[11], *ptr;
770
771
snprintf(buf, sizeof(buf), "&#%d;", *cur);
772
buf[sizeof(buf) - 1] = 0;
773
ptr = buf;
774
while (*ptr != 0) *out++ = *ptr++;
775
}
776
cur++;
777
}
778
*out = 0;
779
return(buffer);
780
781
mem_error:
782
xmlEntitiesErrMemory("xmlEncodeEntities: realloc failed");
783
xmlFree(buffer);
784
return(NULL);
785
}
786
787
/**
788
* xmlEncodeAttributeEntities:
789
* @doc: the document containing the string
790
* @input: A string to convert to XML.
791
*
792
* Do a global encoding of a string, replacing the predefined entities
793
* and non ASCII values with their entities and CharRef counterparts for
794
* attribute values.
795
*
796
* Returns A newly allocated string with the substitution done.
797
*/
798
xmlChar *
799
xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input) {
800
return xmlEncodeEntitiesInternal(doc, input, 1);
801
}
802
803
/**
804
* xmlEncodeEntitiesReentrant:
805
* @doc: the document containing the string
806
* @input: A string to convert to XML.
807
*
808
* Do a global encoding of a string, replacing the predefined entities
809
* and non ASCII values with their entities and CharRef counterparts.
810
* Contrary to xmlEncodeEntities, this routine is reentrant, and result
811
* must be deallocated.
812
*
813
* Returns A newly allocated string with the substitution done.
814
*/
815
xmlChar *
816
xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
817
return xmlEncodeEntitiesInternal(doc, input, 0);
818
}
819
820
/**
821
* xmlEncodeSpecialChars:
822
* @doc: the document containing the string
823
* @input: A string to convert to XML.
824
*
825
* Do a global encoding of a string, replacing the predefined entities
826
* this routine is reentrant, and result must be deallocated.
827
*
828
* Returns A newly allocated string with the substitution done.
829
*/
830
xmlChar *
831
xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) {
832
const xmlChar *cur = input;
833
xmlChar *buffer = NULL;
834
xmlChar *out = NULL;
835
size_t buffer_size = 0;
836
if (input == NULL) return(NULL);
837
838
/*
839
* allocate an translation buffer.
840
*/
841
buffer_size = 1000;
842
buffer = (xmlChar *) xmlMalloc(buffer_size);
843
if (buffer == NULL) {
844
xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed");
845
return(NULL);
846
}
847
out = buffer;
848
849
while (*cur != '\0') {
850
size_t indx = out - buffer;
851
if (indx + 10 > buffer_size) {
852
853
growBufferReentrant();
854
out = &buffer[indx];
855
}
856
857
/*
858
* By default one have to encode at least '<', '>', '"' and '&' !
859
*/
860
if (*cur == '<') {
861
*out++ = '&';
862
*out++ = 'l';
863
*out++ = 't';
864
*out++ = ';';
865
} else if (*cur == '>') {
866
*out++ = '&';
867
*out++ = 'g';
868
*out++ = 't';
869
*out++ = ';';
870
} else if (*cur == '&') {
871
*out++ = '&';
872
*out++ = 'a';
873
*out++ = 'm';
874
*out++ = 'p';
875
*out++ = ';';
876
} else if (*cur == '"') {
877
*out++ = '&';
878
*out++ = 'q';
879
*out++ = 'u';
880
*out++ = 'o';
881
*out++ = 't';
882
*out++ = ';';
883
} else if (*cur == '\r') {
884
*out++ = '&';
885
*out++ = '#';
886
*out++ = '1';
887
*out++ = '3';
888
*out++ = ';';
889
} else {
890
/*
891
* Works because on UTF-8, all extended sequences cannot
892
* result in bytes in the ASCII range.
893
*/
894
*out++ = *cur;
895
}
896
cur++;
897
}
898
*out = 0;
899
return(buffer);
900
901
mem_error:
902
xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed");
903
xmlFree(buffer);
904
return(NULL);
905
}
906
907
/**
908
* xmlCreateEntitiesTable:
909
*
910
* create and initialize an empty entities hash table.
911
* This really doesn't make sense and should be deprecated
912
*
913
* Returns the xmlEntitiesTablePtr just created or NULL in case of error.
914
*/
915
xmlEntitiesTablePtr
916
xmlCreateEntitiesTable(void) {
917
return((xmlEntitiesTablePtr) xmlHashCreate(0));
918
}
919
920
/**
921
* xmlFreeEntityWrapper:
922
* @entity: An entity
923
* @name: its name
924
*
925
* Deallocate the memory used by an entities in the hash table.
926
*/
927
static void
928
xmlFreeEntityWrapper(void *entity, const xmlChar *name ATTRIBUTE_UNUSED) {
929
if (entity != NULL)
930
xmlFreeEntity((xmlEntityPtr) entity);
931
}
932
933
/**
934
* xmlFreeEntitiesTable:
935
* @table: An entity table
936
*
937
* Deallocate the memory used by an entities hash table.
938
*/
939
void
940
xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
941
xmlHashFree(table, xmlFreeEntityWrapper);
942
}
943
944
#ifdef LIBXML_TREE_ENABLED
945
/**
946
* xmlCopyEntity:
947
* @ent: An entity
948
*
949
* Build a copy of an entity
950
*
951
* Returns the new xmlEntitiesPtr or NULL in case of error.
952
*/
953
static void *
954
xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
955
xmlEntityPtr ent = (xmlEntityPtr) payload;
956
xmlEntityPtr cur;
957
958
cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
959
if (cur == NULL) {
960
xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed");
961
return(NULL);
962
}
963
memset(cur, 0, sizeof(xmlEntity));
964
cur->type = XML_ENTITY_DECL;
965
966
cur->etype = ent->etype;
967
if (ent->name != NULL)
968
cur->name = xmlStrdup(ent->name);
969
if (ent->ExternalID != NULL)
970
cur->ExternalID = xmlStrdup(ent->ExternalID);
971
if (ent->SystemID != NULL)
972
cur->SystemID = xmlStrdup(ent->SystemID);
973
if (ent->content != NULL)
974
cur->content = xmlStrdup(ent->content);
975
if (ent->orig != NULL)
976
cur->orig = xmlStrdup(ent->orig);
977
if (ent->URI != NULL)
978
cur->URI = xmlStrdup(ent->URI);
979
return(cur);
980
}
981
982
/**
983
* xmlCopyEntitiesTable:
984
* @table: An entity table
985
*
986
* Build a copy of an entity table.
987
*
988
* Returns the new xmlEntitiesTablePtr or NULL in case of error.
989
*/
990
xmlEntitiesTablePtr
991
xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
992
return(xmlHashCopy(table, xmlCopyEntity));
993
}
994
#endif /* LIBXML_TREE_ENABLED */
995
996
#ifdef LIBXML_OUTPUT_ENABLED
997
998
/**
999
* xmlDumpEntityContent:
1000
* @buf: An XML buffer.
1001
* @content: The entity content.
1002
*
1003
* This will dump the quoted string value, taking care of the special
1004
* treatment required by %
1005
*/
1006
static void
1007
xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) {
1008
if (xmlStrchr(content, '%')) {
1009
const xmlChar * base, *cur;
1010
1011
xmlBufferCCat(buf, "\"");
1012
base = cur = content;
1013
while (*cur != 0) {
1014
if (*cur == '"') {
1015
if (base != cur)
1016
xmlBufferAdd(buf, base, cur - base);
1017
xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
1018
cur++;
1019
base = cur;
1020
} else if (*cur == '%') {
1021
if (base != cur)
1022
xmlBufferAdd(buf, base, cur - base);
1023
xmlBufferAdd(buf, BAD_CAST "&#x25;", 6);
1024
cur++;
1025
base = cur;
1026
} else {
1027
cur++;
1028
}
1029
}
1030
if (base != cur)
1031
xmlBufferAdd(buf, base, cur - base);
1032
xmlBufferCCat(buf, "\"");
1033
} else {
1034
xmlBufferWriteQuotedString(buf, content);
1035
}
1036
}
1037
1038
/**
1039
* xmlDumpEntityDecl:
1040
* @buf: An XML buffer.
1041
* @ent: An entity table
1042
*
1043
* This will dump the content of the entity table as an XML DTD definition
1044
*/
1045
void
1046
xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
1047
if ((buf == NULL) || (ent == NULL)) return;
1048
switch (ent->etype) {
1049
case XML_INTERNAL_GENERAL_ENTITY:
1050
xmlBufferWriteChar(buf, "<!ENTITY ");
1051
xmlBufferWriteCHAR(buf, ent->name);
1052
xmlBufferWriteChar(buf, " ");
1053
if (ent->orig != NULL)
1054
xmlBufferWriteQuotedString(buf, ent->orig);
1055
else
1056
xmlDumpEntityContent(buf, ent->content);
1057
xmlBufferWriteChar(buf, ">\n");
1058
break;
1059
case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1060
xmlBufferWriteChar(buf, "<!ENTITY ");
1061
xmlBufferWriteCHAR(buf, ent->name);
1062
if (ent->ExternalID != NULL) {
1063
xmlBufferWriteChar(buf, " PUBLIC ");
1064
xmlBufferWriteQuotedString(buf, ent->ExternalID);
1065
xmlBufferWriteChar(buf, " ");
1066
xmlBufferWriteQuotedString(buf, ent->SystemID);
1067
} else {
1068
xmlBufferWriteChar(buf, " SYSTEM ");
1069
xmlBufferWriteQuotedString(buf, ent->SystemID);
1070
}
1071
xmlBufferWriteChar(buf, ">\n");
1072
break;
1073
case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1074
xmlBufferWriteChar(buf, "<!ENTITY ");
1075
xmlBufferWriteCHAR(buf, ent->name);
1076
if (ent->ExternalID != NULL) {
1077
xmlBufferWriteChar(buf, " PUBLIC ");
1078
xmlBufferWriteQuotedString(buf, ent->ExternalID);
1079
xmlBufferWriteChar(buf, " ");
1080
xmlBufferWriteQuotedString(buf, ent->SystemID);
1081
} else {
1082
xmlBufferWriteChar(buf, " SYSTEM ");
1083
xmlBufferWriteQuotedString(buf, ent->SystemID);
1084
}
1085
if (ent->content != NULL) { /* Should be true ! */
1086
xmlBufferWriteChar(buf, " NDATA ");
1087
if (ent->orig != NULL)
1088
xmlBufferWriteCHAR(buf, ent->orig);
1089
else
1090
xmlBufferWriteCHAR(buf, ent->content);
1091
}
1092
xmlBufferWriteChar(buf, ">\n");
1093
break;
1094
case XML_INTERNAL_PARAMETER_ENTITY:
1095
xmlBufferWriteChar(buf, "<!ENTITY % ");
1096
xmlBufferWriteCHAR(buf, ent->name);
1097
xmlBufferWriteChar(buf, " ");
1098
if (ent->orig == NULL)
1099
xmlDumpEntityContent(buf, ent->content);
1100
else
1101
xmlBufferWriteQuotedString(buf, ent->orig);
1102
xmlBufferWriteChar(buf, ">\n");
1103
break;
1104
case XML_EXTERNAL_PARAMETER_ENTITY:
1105
xmlBufferWriteChar(buf, "<!ENTITY % ");
1106
xmlBufferWriteCHAR(buf, ent->name);
1107
if (ent->ExternalID != NULL) {
1108
xmlBufferWriteChar(buf, " PUBLIC ");
1109
xmlBufferWriteQuotedString(buf, ent->ExternalID);
1110
xmlBufferWriteChar(buf, " ");
1111
xmlBufferWriteQuotedString(buf, ent->SystemID);
1112
} else {
1113
xmlBufferWriteChar(buf, " SYSTEM ");
1114
xmlBufferWriteQuotedString(buf, ent->SystemID);
1115
}
1116
xmlBufferWriteChar(buf, ">\n");
1117
break;
1118
default:
1119
xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY,
1120
"xmlDumpEntitiesDecl: internal: unknown type entity type");
1121
}
1122
}
1123
1124
/**
1125
* xmlDumpEntityDeclScan:
1126
* @ent: An entity table
1127
* @buf: An XML buffer.
1128
*
1129
* When using the hash table scan function, arguments need to be reversed
1130
*/
1131
static void
1132
xmlDumpEntityDeclScan(void *ent, void *buf,
1133
const xmlChar *name ATTRIBUTE_UNUSED) {
1134
xmlDumpEntityDecl((xmlBufferPtr) buf, (xmlEntityPtr) ent);
1135
}
1136
1137
/**
1138
* xmlDumpEntitiesTable:
1139
* @buf: An XML buffer.
1140
* @table: An entity table
1141
*
1142
* This will dump the content of the entity table as an XML DTD definition
1143
*/
1144
void
1145
xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
1146
xmlHashScan(table, xmlDumpEntityDeclScan, buf);
1147
}
1148
#endif /* LIBXML_OUTPUT_ENABLED */
1149
1150