Coverage Report

Created: 2025-07-01 06:26

/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
 * Author: Daniel Veillard
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
#include <libxml/xmlsave.h>
28
29
#include "private/entities.h"
30
#include "private/error.h"
31
#include "private/io.h"
32
33
#ifndef SIZE_MAX
34
  #define SIZE_MAX ((size_t) -1)
35
#endif
36
37
/*
38
 * The XML predefined entities.
39
 */
40
41
static xmlEntity xmlEntityLt = {
42
    NULL, XML_ENTITY_DECL, BAD_CAST "lt",
43
    NULL, NULL, NULL, NULL, NULL, NULL,
44
    BAD_CAST "<", BAD_CAST "<", 1,
45
    XML_INTERNAL_PREDEFINED_ENTITY,
46
    NULL, NULL, NULL, NULL, 0, 0, 0
47
};
48
static xmlEntity xmlEntityGt = {
49
    NULL, XML_ENTITY_DECL, BAD_CAST "gt",
50
    NULL, NULL, NULL, NULL, NULL, NULL,
51
    BAD_CAST ">", BAD_CAST ">", 1,
52
    XML_INTERNAL_PREDEFINED_ENTITY,
53
    NULL, NULL, NULL, NULL, 0, 0, 0
54
};
55
static xmlEntity xmlEntityAmp = {
56
    NULL, XML_ENTITY_DECL, BAD_CAST "amp",
57
    NULL, NULL, NULL, NULL, NULL, NULL,
58
    BAD_CAST "&", BAD_CAST "&", 1,
59
    XML_INTERNAL_PREDEFINED_ENTITY,
60
    NULL, NULL, NULL, NULL, 0, 0, 0
61
};
62
static xmlEntity xmlEntityQuot = {
63
    NULL, XML_ENTITY_DECL, BAD_CAST "quot",
64
    NULL, NULL, NULL, NULL, NULL, NULL,
65
    BAD_CAST "\"", BAD_CAST "\"", 1,
66
    XML_INTERNAL_PREDEFINED_ENTITY,
67
    NULL, NULL, NULL, NULL, 0, 0, 0
68
};
69
static xmlEntity xmlEntityApos = {
70
    NULL, XML_ENTITY_DECL, BAD_CAST "apos",
71
    NULL, NULL, NULL, NULL, NULL, NULL,
72
    BAD_CAST "'", BAD_CAST "'", 1,
73
    XML_INTERNAL_PREDEFINED_ENTITY,
74
    NULL, NULL, NULL, NULL, 0, 0, 0
75
};
76
77
/**
78
 * Frees the entity.
79
 *
80
 * @param entity  an entity
81
 */
82
void
83
xmlFreeEntity(xmlEntity *entity)
84
0
{
85
0
    xmlDictPtr dict = NULL;
86
87
0
    if (entity == NULL)
88
0
        return;
89
90
0
    if (entity->doc != NULL)
91
0
        dict = entity->doc->dict;
92
93
94
0
    if ((entity->children) &&
95
0
        (entity == (xmlEntityPtr) entity->children->parent))
96
0
        xmlFreeNodeList(entity->children);
97
0
    if ((entity->name != NULL) &&
98
0
        ((dict == NULL) || (!xmlDictOwns(dict, entity->name))))
99
0
        xmlFree((char *) entity->name);
100
0
    if (entity->ExternalID != NULL)
101
0
        xmlFree((char *) entity->ExternalID);
102
0
    if (entity->SystemID != NULL)
103
0
        xmlFree((char *) entity->SystemID);
104
0
    if (entity->URI != NULL)
105
0
        xmlFree((char *) entity->URI);
106
0
    if (entity->content != NULL)
107
0
        xmlFree((char *) entity->content);
108
0
    if (entity->orig != NULL)
109
0
        xmlFree((char *) entity->orig);
110
0
    xmlFree(entity);
111
0
}
112
113
/*
114
 * internal routine doing the entity node structures allocations
115
 */
116
static xmlEntityPtr
117
xmlCreateEntity(xmlDocPtr doc, const xmlChar *name, int type,
118
          const xmlChar *publicId, const xmlChar *systemId,
119
0
          const xmlChar *content) {
120
0
    xmlEntityPtr ret;
121
122
0
    ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
123
0
    if (ret == NULL)
124
0
  return(NULL);
125
0
    memset(ret, 0, sizeof(xmlEntity));
126
0
    ret->doc = doc;
127
0
    ret->type = XML_ENTITY_DECL;
128
129
    /*
130
     * fill the structure.
131
     */
132
0
    ret->etype = (xmlEntityType) type;
133
0
    if ((doc == NULL) || (doc->dict == NULL))
134
0
  ret->name = xmlStrdup(name);
135
0
    else
136
0
        ret->name = xmlDictLookup(doc->dict, name, -1);
137
0
    if (ret->name == NULL)
138
0
        goto error;
139
0
    if (publicId != NULL) {
140
0
        ret->ExternalID = xmlStrdup(publicId);
141
0
        if (ret->ExternalID == NULL)
142
0
            goto error;
143
0
    }
144
0
    if (systemId != NULL) {
145
0
        ret->SystemID = xmlStrdup(systemId);
146
0
        if (ret->SystemID == NULL)
147
0
            goto error;
148
0
    }
149
0
    if (content != NULL) {
150
0
        ret->length = xmlStrlen(content);
151
0
  ret->content = xmlStrndup(content, ret->length);
152
0
        if (ret->content == NULL)
153
0
            goto error;
154
0
     } else {
155
0
        ret->length = 0;
156
0
        ret->content = NULL;
157
0
    }
158
0
    ret->URI = NULL; /* to be computed by the layer knowing
159
      the defining entity */
160
0
    ret->orig = NULL;
161
162
0
    return(ret);
163
164
0
error:
165
0
    xmlFreeEntity(ret);
166
0
    return(NULL);
167
0
}
168
169
/**
170
 * Register a new entity for this document.
171
 *
172
 * @since 2.13.0
173
 *
174
 * @param doc  the document
175
 * @param extSubset  add to the external or internal subset
176
 * @param name  the entity name
177
 * @param type  an xmlEntityType value
178
 * @param publicId  the publid identifier (optional)
179
 * @param systemId  the system identifier (URL) (optional)
180
 * @param content  the entity content
181
 * @param out  pointer to resulting entity (optional)
182
 * @returns an xmlParserErrors error code.
183
 */
184
int
185
xmlAddEntity(xmlDoc *doc, int extSubset, const xmlChar *name, int type,
186
    const xmlChar *publicId, const xmlChar *systemId,
187
0
    const xmlChar *content, xmlEntity **out) {
188
0
    xmlDtdPtr dtd;
189
0
    xmlDictPtr dict = NULL;
190
0
    xmlEntitiesTablePtr table = NULL;
191
0
    xmlEntityPtr ret, predef;
192
0
    int res;
193
194
0
    if (out != NULL)
195
0
        *out = NULL;
196
0
    if ((doc == NULL) || (name == NULL))
197
0
  return(XML_ERR_ARGUMENT);
198
0
    dict = doc->dict;
199
200
0
    if (extSubset)
201
0
        dtd = doc->extSubset;
202
0
    else
203
0
        dtd = doc->intSubset;
204
0
    if (dtd == NULL)
205
0
        return(XML_DTD_NO_DTD);
206
207
0
    switch (type) {
208
0
        case XML_INTERNAL_GENERAL_ENTITY:
209
0
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
210
0
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
211
0
            predef = xmlGetPredefinedEntity(name);
212
0
            if (predef != NULL) {
213
0
                int valid = 0;
214
215
                /* 4.6 Predefined Entities */
216
0
                if ((type == XML_INTERNAL_GENERAL_ENTITY) &&
217
0
                    (content != NULL)) {
218
0
                    int c = predef->content[0];
219
220
0
                    if (((content[0] == c) && (content[1] == 0)) &&
221
0
                        ((c == '>') || (c == '\'') || (c == '"'))) {
222
0
                        valid = 1;
223
0
                    } else if ((content[0] == '&') && (content[1] == '#')) {
224
0
                        if (content[2] == 'x') {
225
0
                            xmlChar *hex = BAD_CAST "0123456789ABCDEF";
226
0
                            xmlChar ref[] = "00;";
227
228
0
                            ref[0] = hex[c / 16 % 16];
229
0
                            ref[1] = hex[c % 16];
230
0
                            if (xmlStrcasecmp(&content[3], ref) == 0)
231
0
                                valid = 1;
232
0
                        } else {
233
0
                            xmlChar ref[] = "00;";
234
235
0
                            ref[0] = '0' + c / 10 % 10;
236
0
                            ref[1] = '0' + c % 10;
237
0
                            if (xmlStrEqual(&content[2], ref))
238
0
                                valid = 1;
239
0
                        }
240
0
                    }
241
0
                }
242
0
                if (!valid)
243
0
                    return(XML_ERR_REDECL_PREDEF_ENTITY);
244
0
            }
245
0
      if (dtd->entities == NULL) {
246
0
    dtd->entities = xmlHashCreateDict(0, dict);
247
0
                if (dtd->entities == NULL)
248
0
                    return(XML_ERR_NO_MEMORY);
249
0
            }
250
0
      table = dtd->entities;
251
0
      break;
252
0
        case XML_INTERNAL_PARAMETER_ENTITY:
253
0
        case XML_EXTERNAL_PARAMETER_ENTITY:
254
0
      if (dtd->pentities == NULL) {
255
0
    dtd->pentities = xmlHashCreateDict(0, dict);
256
0
                if (dtd->pentities == NULL)
257
0
                    return(XML_ERR_NO_MEMORY);
258
0
            }
259
0
      table = dtd->pentities;
260
0
      break;
261
0
        default:
262
0
      return(XML_ERR_ARGUMENT);
263
0
    }
264
0
    ret = xmlCreateEntity(dtd->doc, name, type, publicId, systemId, content);
265
0
    if (ret == NULL)
266
0
        return(XML_ERR_NO_MEMORY);
267
268
0
    res = xmlHashAdd(table, name, ret);
269
0
    if (res < 0) {
270
0
        xmlFreeEntity(ret);
271
0
        return(XML_ERR_NO_MEMORY);
272
0
    } else if (res == 0) {
273
  /*
274
   * entity was already defined at another level.
275
   */
276
0
        xmlFreeEntity(ret);
277
0
  return(XML_WAR_ENTITY_REDEFINED);
278
0
    }
279
280
    /*
281
     * Link it to the DTD
282
     */
283
0
    ret->parent = dtd;
284
0
    ret->doc = dtd->doc;
285
0
    if (dtd->last == NULL) {
286
0
  dtd->children = dtd->last = (xmlNodePtr) ret;
287
0
    } else {
288
0
  dtd->last->next = (xmlNodePtr) ret;
289
0
  ret->prev = dtd->last;
290
0
  dtd->last = (xmlNodePtr) ret;
291
0
    }
292
293
0
    if (out != NULL)
294
0
        *out = ret;
295
0
    return(0);
296
0
}
297
298
/**
299
 * Look up a predefined entity.
300
 *
301
 * @param name  the entity name
302
 * @returns the entity, or NULL if not found.
303
 */
304
xmlEntity *
305
0
xmlGetPredefinedEntity(const xmlChar *name) {
306
0
    if (name == NULL) return(NULL);
307
0
    switch (name[0]) {
308
0
        case 'l':
309
0
      if (xmlStrEqual(name, BAD_CAST "lt"))
310
0
          return(&xmlEntityLt);
311
0
      break;
312
0
        case 'g':
313
0
      if (xmlStrEqual(name, BAD_CAST "gt"))
314
0
          return(&xmlEntityGt);
315
0
      break;
316
0
        case 'a':
317
0
      if (xmlStrEqual(name, BAD_CAST "amp"))
318
0
          return(&xmlEntityAmp);
319
0
      if (xmlStrEqual(name, BAD_CAST "apos"))
320
0
          return(&xmlEntityApos);
321
0
      break;
322
0
        case 'q':
323
0
      if (xmlStrEqual(name, BAD_CAST "quot"))
324
0
          return(&xmlEntityQuot);
325
0
      break;
326
0
  default:
327
0
      break;
328
0
    }
329
0
    return(NULL);
330
0
}
331
332
/**
333
 * Add a new entity to the document's external subset.
334
 *
335
 * #xmlAddEntity offers better error handling.
336
 *
337
 * @param doc  the document
338
 * @param name  the entity name
339
 * @param type  an xmlEntityType value
340
 * @param publicId  the publid identifier (optional)
341
 * @param systemId  the system identifier (URL) (optional)
342
 * @param content  the entity content
343
 * @returns a pointer to the entity or NULL in case of error
344
 */
345
xmlEntity *
346
xmlAddDtdEntity(xmlDoc *doc, const xmlChar *name, int type,
347
          const xmlChar *publicId, const xmlChar *systemId,
348
0
    const xmlChar *content) {
349
0
    xmlEntityPtr ret;
350
351
0
    xmlAddEntity(doc, 1, name, type, publicId, systemId, content, &ret);
352
0
    return(ret);
353
0
}
354
355
/**
356
 * Add a new entity to the document's internal subset.
357
 *
358
 * #xmlAddEntity offers better error handling.
359
 *
360
 * @param doc  the document
361
 * @param name  the entity name
362
 * @param type  an xmlEntityType value
363
 * @param publicId  the publid identifier (optional)
364
 * @param systemId  the system identifier (URL) (optional)
365
 * @param content  the entity content
366
 * @returns a pointer to the entity or NULL in case of error
367
 */
368
xmlEntity *
369
xmlAddDocEntity(xmlDoc *doc, const xmlChar *name, int type,
370
          const xmlChar *publicId, const xmlChar *systemId,
371
0
          const xmlChar *content) {
372
0
    xmlEntityPtr ret;
373
374
0
    xmlAddEntity(doc, 0, name, type, publicId, systemId, content, &ret);
375
0
    return(ret);
376
0
}
377
378
/**
379
 * Create a new entity.
380
 *
381
 * Like #xmlAddDocEntity, but if `doc` is NULL or has no internal
382
 * subset defined, an unlinked entity will be returned. It is then
383
 * the responsibility of the caller to link it to the document later
384
 * or free it when not needed anymore.
385
 *
386
 * @param doc  the document (optional)
387
 * @param name  the entity name
388
 * @param type  an xmlEntityType value
389
 * @param publicId  the publid identifier (optional)
390
 * @param systemId  the system identifier (URL) (optional)
391
 * @param content  the entity content
392
 * @returns a pointer to the entity or NULL in case of error
393
 */
394
xmlEntity *
395
xmlNewEntity(xmlDoc *doc, const xmlChar *name, int type,
396
       const xmlChar *publicId, const xmlChar *systemId,
397
0
       const xmlChar *content) {
398
0
    if ((doc != NULL) && (doc->intSubset != NULL)) {
399
0
  return(xmlAddDocEntity(doc, name, type, publicId, systemId, content));
400
0
    }
401
0
    if (name == NULL)
402
0
        return(NULL);
403
0
    return(xmlCreateEntity(doc, name, type, publicId, systemId, content));
404
0
}
405
406
/**
407
 * Look up an entity in a table.
408
 *
409
 * @param table  an entity table
410
 * @param name  the entity name
411
 * @returns a pointer to the entity or NULL if not found.
412
 */
413
static xmlEntityPtr
414
0
xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
415
0
    return((xmlEntityPtr) xmlHashLookup(table, name));
416
0
}
417
418
/**
419
 * Look up a paramater entity in the internal and external subset
420
 * of `doc`.
421
 *
422
 * @param doc  the document
423
 * @param name  the entity name
424
 * @returns a pointer to the entity or NULL if not found.
425
 */
426
xmlEntity *
427
0
xmlGetParameterEntity(xmlDoc *doc, const xmlChar *name) {
428
0
    xmlEntitiesTablePtr table;
429
0
    xmlEntityPtr ret;
430
431
0
    if (doc == NULL)
432
0
  return(NULL);
433
0
    if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
434
0
  table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
435
0
  ret = xmlGetEntityFromTable(table, name);
436
0
  if (ret != NULL)
437
0
      return(ret);
438
0
    }
439
0
    if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
440
0
  table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
441
0
  return(xmlGetEntityFromTable(table, name));
442
0
    }
443
0
    return(NULL);
444
0
}
445
446
/**
447
 * Look up a general entity in the external subset of `doc`.
448
 *
449
 * @param doc  the document
450
 * @param name  the entity name
451
 * @returns a pointer to the entity or NULL if not found.
452
 */
453
xmlEntity *
454
0
xmlGetDtdEntity(xmlDoc *doc, const xmlChar *name) {
455
0
    xmlEntitiesTablePtr table;
456
457
0
    if (doc == NULL)
458
0
  return(NULL);
459
0
    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
460
0
  table = (xmlEntitiesTablePtr) doc->extSubset->entities;
461
0
  return(xmlGetEntityFromTable(table, name));
462
0
    }
463
0
    return(NULL);
464
0
}
465
466
/**
467
 * Look up a general entity in the internal and external subset
468
 * of `doc`. Also checks for predefined entities.
469
 *
470
 * @param doc  the document referencing the entity
471
 * @param name  the entity name
472
 * @returns a pointer to the entity or NULL if not found.
473
 */
474
xmlEntity *
475
0
xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) {
476
0
    xmlEntityPtr cur;
477
0
    xmlEntitiesTablePtr table;
478
479
0
    if (doc != NULL) {
480
0
  if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
481
0
      table = (xmlEntitiesTablePtr) doc->intSubset->entities;
482
0
      cur = xmlGetEntityFromTable(table, name);
483
0
      if (cur != NULL)
484
0
    return(cur);
485
0
  }
486
0
  if (doc->standalone != 1) {
487
0
      if ((doc->extSubset != NULL) &&
488
0
    (doc->extSubset->entities != NULL)) {
489
0
    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
490
0
    cur = xmlGetEntityFromTable(table, name);
491
0
    if (cur != NULL)
492
0
        return(cur);
493
0
      }
494
0
  }
495
0
    }
496
0
    return(xmlGetPredefinedEntity(name));
497
0
}
498
499
/**
500
 * Replace special characters with predefined entities or numeric
501
 * character references.
502
 *
503
 * If `doc` is NULL or an XML document, replaces `<`, `>` and `&`
504
 * with predefined entities. Carriage return is replaced with
505
 * `&#13;`. If `doc` or its encoding are NULL, non-ASCII
506
 * characters are replaced with a hexadecimal character reference.
507
 *
508
 * If `doc` is an HTML document, follows the HTML serialization
509
 * rules.
510
 *
511
 * Silently removes some invalid characters like ASCII control
512
 * codes.
513
 *
514
 * See #xmlEncodeSpecialChars for an alternative.
515
 *
516
 * @param doc  the document containing the string (optional)
517
 * @param input  A string to convert to XML.
518
 * @returns a newly allocated string with substitutions.
519
 */
520
xmlChar *
521
0
xmlEncodeEntitiesReentrant(xmlDoc *doc, const xmlChar *input) {
522
0
    int flags = 0;
523
524
0
    if (input == NULL)
525
0
        return(NULL);
526
527
0
    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE))
528
0
        flags |= XML_ESCAPE_HTML;
529
0
    else if ((doc == NULL) || (doc->encoding == NULL))
530
0
        flags |= XML_ESCAPE_NON_ASCII;
531
532
0
    return(xmlEscapeText(input, flags));
533
0
}
534
535
/**
536
 * Replace special characters with predefined entities or numeric
537
 * character references.
538
 *
539
 * Replaces `<`, `>`, `&` and `"` with predefined entities. Carriage
540
 * return is replaced with `&#13;`.
541
 *
542
 * @param doc  unused
543
 * @param input  A string to convert to XML.
544
 * @returns a newly allocated string with substitutions.
545
 */
546
xmlChar *
547
xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED,
548
0
                      const xmlChar *input) {
549
0
    if (input == NULL)
550
0
        return(NULL);
551
552
0
    return(xmlEscapeText(input, XML_ESCAPE_QUOT));
553
0
}
554
555
/**
556
 * Create and initialize an empty entities hash table.
557
 *
558
 * @deprecated Internal function, don't use.
559
 *
560
 * @returns the xmlEntitiesTable just created or NULL in case of error.
561
 */
562
xmlEntitiesTable *
563
0
xmlCreateEntitiesTable(void) {
564
0
    return((xmlEntitiesTablePtr) xmlHashCreate(0));
565
0
}
566
567
/**
568
 * Deallocate the memory used by an entities in the hash table.
569
 *
570
 * @param entity  An entity
571
 * @param name  its name
572
 */
573
static void
574
0
xmlFreeEntityWrapper(void *entity, const xmlChar *name ATTRIBUTE_UNUSED) {
575
0
    if (entity != NULL)
576
0
  xmlFreeEntity((xmlEntityPtr) entity);
577
0
}
578
579
/**
580
 * Deallocate the memory used by an entities hash table.
581
 *
582
 * @deprecated Internal function, don't use.
583
 *
584
 * @param table  An entity table
585
 */
586
void
587
0
xmlFreeEntitiesTable(xmlEntitiesTable *table) {
588
0
    xmlHashFree(table, xmlFreeEntityWrapper);
589
0
}
590
591
/**
592
 * Build a copy of an entity
593
 *
594
 * @param payload  An entity
595
 * @param name  unused
596
 * @returns the new xmlEntities or NULL in case of error.
597
 */
598
static void *
599
0
xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
600
0
    xmlEntityPtr ent = (xmlEntityPtr) payload;
601
0
    xmlEntityPtr cur;
602
603
0
    cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
604
0
    if (cur == NULL)
605
0
  return(NULL);
606
0
    memset(cur, 0, sizeof(xmlEntity));
607
0
    cur->type = XML_ENTITY_DECL;
608
609
0
    cur->etype = ent->etype;
610
0
    if (ent->name != NULL) {
611
0
  cur->name = xmlStrdup(ent->name);
612
0
        if (cur->name == NULL)
613
0
            goto error;
614
0
    }
615
0
    if (ent->ExternalID != NULL) {
616
0
  cur->ExternalID = xmlStrdup(ent->ExternalID);
617
0
        if (cur->ExternalID == NULL)
618
0
            goto error;
619
0
    }
620
0
    if (ent->SystemID != NULL) {
621
0
  cur->SystemID = xmlStrdup(ent->SystemID);
622
0
        if (cur->SystemID == NULL)
623
0
            goto error;
624
0
    }
625
0
    if (ent->content != NULL) {
626
0
  cur->content = xmlStrdup(ent->content);
627
0
        if (cur->content == NULL)
628
0
            goto error;
629
0
    }
630
0
    if (ent->orig != NULL) {
631
0
  cur->orig = xmlStrdup(ent->orig);
632
0
        if (cur->orig == NULL)
633
0
            goto error;
634
0
    }
635
0
    if (ent->URI != NULL) {
636
0
  cur->URI = xmlStrdup(ent->URI);
637
0
        if (cur->URI == NULL)
638
0
            goto error;
639
0
    }
640
0
    return(cur);
641
642
0
error:
643
0
    xmlFreeEntity(cur);
644
0
    return(NULL);
645
0
}
646
647
/**
648
 * Build a copy of an entity table.
649
 *
650
 * @deprecated Internal function, don't use.
651
 *
652
 * @param table  An entity table
653
 * @returns the new xmlEntitiesTable or NULL in case of error.
654
 */
655
xmlEntitiesTable *
656
0
xmlCopyEntitiesTable(xmlEntitiesTable *table) {
657
0
    return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper));
658
0
}
659
660
#ifdef LIBXML_OUTPUT_ENABLED
661
662
/**
663
 * This will dump the content of the entity table as an XML DTD
664
 * definition.
665
 *
666
 * @deprecated Internal function, don't use.
667
 *
668
 * @param buf  An XML buffer.
669
 * @param ent  An entity table
670
 */
671
void
672
0
xmlDumpEntityDecl(xmlBuffer *buf, xmlEntity *ent) {
673
0
    xmlSaveCtxtPtr save;
674
675
0
    if ((buf == NULL) || (ent == NULL))
676
0
        return;
677
678
0
    save = xmlSaveToBuffer(buf, NULL, 0);
679
0
    xmlSaveTree(save, (xmlNodePtr) ent);
680
0
    if (xmlSaveFinish(save) != XML_ERR_OK)
681
0
        xmlFree(xmlBufferDetach(buf));
682
0
}
683
684
/**
685
 * When using the hash table scan function, arguments need to be
686
 * reversed.
687
 *
688
 * @param ent  an entity table
689
 * @param save  a save context
690
 * @param name  unused
691
 */
692
static void
693
xmlDumpEntityDeclScan(void *ent, void *save,
694
0
                      const xmlChar *name ATTRIBUTE_UNUSED) {
695
0
    xmlSaveTree(save, ent);
696
0
}
697
698
/**
699
 * This will dump the content of the entity table as an XML DTD
700
 * definition.
701
 *
702
 * @deprecated Internal function, don't use.
703
 *
704
 * @param buf  An XML buffer.
705
 * @param table  An entity table
706
 */
707
void
708
0
xmlDumpEntitiesTable(xmlBuffer *buf, xmlEntitiesTable *table) {
709
0
    xmlSaveCtxtPtr save;
710
711
0
    if ((buf == NULL) || (table == NULL))
712
0
        return;
713
714
0
    save = xmlSaveToBuffer(buf, NULL, 0);
715
0
    xmlHashScan(table, xmlDumpEntityDeclScan, save);
716
0
    if (xmlSaveFinish(save) != XML_ERR_OK)
717
0
        xmlFree(xmlBufferDetach(buf));
718
0
}
719
#endif /* LIBXML_OUTPUT_ENABLED */