Coverage Report

Created: 2022-06-08 06:16

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