Coverage Report

Created: 2026-05-30 06:18

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