Coverage Report

Created: 2023-12-12 01:56

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