Coverage Report

Created: 2026-09-03 06:06

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
37.2k
{
86
37.2k
    xmlDictPtr dict = NULL;
87
88
37.2k
    if (entity == NULL)
89
447
        return;
90
91
36.8k
    if (entity->doc != NULL)
92
35.4k
        dict = entity->doc->dict;
93
94
95
36.8k
    if ((entity->children) &&
96
3.36k
        (entity == (xmlEntityPtr) entity->children->parent))
97
3.36k
        xmlFreeNodeList(entity->children);
98
36.8k
    if ((entity->name != NULL) &&
99
36.8k
        ((dict == NULL) || (!xmlDictOwns(dict, entity->name))))
100
16.8k
        xmlFree((char *) entity->name);
101
36.8k
    if (entity->ExternalID != NULL)
102
8.39k
        xmlFree((char *) entity->ExternalID);
103
36.8k
    if (entity->SystemID != NULL)
104
11.2k
        xmlFree((char *) entity->SystemID);
105
36.8k
    if (entity->URI != NULL)
106
4.20k
        xmlFree((char *) entity->URI);
107
36.8k
    if (entity->content != NULL)
108
23.7k
        xmlFree((char *) entity->content);
109
36.8k
    if (entity->orig != NULL)
110
16.6k
        xmlFree((char *) entity->orig);
111
36.8k
    xmlFree(entity);
112
36.8k
}
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
32.1k
          const xmlChar *content) {
121
32.1k
    xmlEntityPtr ret;
122
123
32.1k
    ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
124
32.1k
    if (ret == NULL)
125
10
  return(NULL);
126
32.1k
    memset(ret, 0, sizeof(xmlEntity));
127
32.1k
    ret->doc = doc;
128
32.1k
    ret->type = XML_ENTITY_DECL;
129
130
    /*
131
     * fill the structure.
132
     */
133
32.1k
    ret->etype = (xmlEntityType) type;
134
32.1k
    if ((doc == NULL) || (doc->dict == NULL))
135
12.1k
  ret->name = xmlStrdup(name);
136
20.0k
    else
137
20.0k
        ret->name = xmlDictLookup(doc->dict, name, -1);
138
32.1k
    if (ret->name == NULL)
139
2
        goto error;
140
32.1k
    if (publicId != NULL) {
141
5.94k
        ret->ExternalID = xmlStrdup(publicId);
142
5.94k
        if (ret->ExternalID == NULL)
143
2
            goto error;
144
5.94k
    }
145
32.1k
    if (systemId != NULL) {
146
8.78k
        ret->SystemID = xmlStrdup(systemId);
147
8.78k
        if (ret->SystemID == NULL)
148
2
            goto error;
149
8.78k
    }
150
32.1k
    if (content != NULL) {
151
21.6k
        ret->length = xmlStrlen(content);
152
21.6k
  ret->content = xmlStrndup(content, ret->length);
153
21.6k
        if (ret->content == NULL)
154
6
            goto error;
155
21.6k
     } else {
156
10.5k
        ret->length = 0;
157
10.5k
        ret->content = NULL;
158
10.5k
    }
159
32.1k
    ret->URI = NULL; /* to be computed by the layer knowing
160
      the defining entity */
161
32.1k
    ret->orig = NULL;
162
163
32.1k
    return(ret);
164
165
12
error:
166
12
    xmlFreeEntity(ret);
167
12
    return(NULL);
168
32.1k
}
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
36.3k
    const xmlChar *content, xmlEntity **out) {
189
36.3k
    xmlDtdPtr dtd;
190
36.3k
    xmlDictPtr dict = NULL;
191
36.3k
    xmlEntitiesTablePtr table = NULL;
192
36.3k
    xmlEntityPtr ret, predef;
193
36.3k
    int res;
194
195
36.3k
    if (out != NULL)
196
36.3k
        *out = NULL;
197
36.3k
    if ((doc == NULL) || (name == NULL))
198
2.29k
  return(XML_ERR_ARGUMENT);
199
34.0k
    dict = doc->dict;
200
201
34.0k
    if (extSubset)
202
690
        dtd = doc->extSubset;
203
33.3k
    else
204
33.3k
        dtd = doc->intSubset;
205
34.0k
    if (dtd == NULL)
206
443
        return(XML_DTD_NO_DTD);
207
208
33.6k
    switch (type) {
209
17.6k
        case XML_INTERNAL_GENERAL_ENTITY:
210
22.1k
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
211
23.7k
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
212
23.7k
            predef = xmlGetPredefinedEntity(name);
213
23.7k
            if (predef != NULL) {
214
2.07k
                int valid = 0;
215
216
                /* 4.6 Predefined Entities */
217
2.07k
                if ((type == XML_INTERNAL_GENERAL_ENTITY) &&
218
1.88k
                    (content != NULL)) {
219
1.62k
                    int c = predef->content[0];
220
221
1.62k
                    if (((content[0] == c) && (content[1] == 0)) &&
222
779
                        ((c == '>') || (c == '\'') || (c == '"'))) {
223
585
                        valid = 1;
224
1.03k
                    } else if ((content[0] == '&') && (content[1] == '#')) {
225
395
                        if (content[2] == 'x') {
226
201
                            xmlChar *hex = BAD_CAST "0123456789ABCDEF";
227
201
                            xmlChar ref[] = "00;";
228
229
201
                            ref[0] = hex[c / 16 % 16];
230
201
                            ref[1] = hex[c % 16];
231
201
                            if (xmlStrcasecmp(&content[3], ref) == 0)
232
0
                                valid = 1;
233
201
                        } else {
234
194
                            xmlChar ref[] = "00;";
235
236
194
                            ref[0] = '0' + c / 10 % 10;
237
194
                            ref[1] = '0' + c % 10;
238
194
                            if (xmlStrEqual(&content[2], ref))
239
0
                                valid = 1;
240
194
                        }
241
395
                    }
242
1.62k
                }
243
2.07k
                if (!valid)
244
1.49k
                    return(XML_ERR_REDECL_PREDEF_ENTITY);
245
2.07k
            }
246
22.2k
      if (dtd->entities == NULL) {
247
19.1k
    dtd->entities = xmlHashCreateDict(0, dict);
248
19.1k
                if (dtd->entities == NULL)
249
9
                    return(XML_ERR_NO_MEMORY);
250
19.1k
            }
251
22.2k
      table = dtd->entities;
252
22.2k
      break;
253
6.45k
        case XML_INTERNAL_PARAMETER_ENTITY:
254
9.56k
        case XML_EXTERNAL_PARAMETER_ENTITY:
255
9.56k
      if (dtd->pentities == NULL) {
256
7.22k
    dtd->pentities = xmlHashCreateDict(0, dict);
257
7.22k
                if (dtd->pentities == NULL)
258
2
                    return(XML_ERR_NO_MEMORY);
259
7.22k
            }
260
9.56k
      table = dtd->pentities;
261
9.56k
      break;
262
301
        default:
263
301
      return(XML_ERR_ARGUMENT);
264
33.6k
    }
265
31.7k
    ret = xmlCreateEntity(dtd->doc, name, type, publicId, systemId, content);
266
31.7k
    if (ret == NULL)
267
17
        return(XML_ERR_NO_MEMORY);
268
269
31.7k
    res = xmlHashAdd(table, name, ret);
270
31.7k
    if (res < 0) {
271
5
        xmlFreeEntity(ret);
272
5
        return(XML_ERR_NO_MEMORY);
273
31.7k
    } else if (res == 0) {
274
  /*
275
   * entity was already defined at another level.
276
   */
277
3.15k
        xmlFreeEntity(ret);
278
3.15k
  return(XML_WAR_ENTITY_REDEFINED);
279
3.15k
    }
280
281
    /*
282
     * Link it to the DTD
283
     */
284
28.6k
    ret->parent = dtd;
285
28.6k
    ret->doc = dtd->doc;
286
28.6k
    if (dtd->last == NULL) {
287
25.5k
  dtd->children = dtd->last = (xmlNodePtr) ret;
288
25.5k
    } else {
289
3.09k
  dtd->last->next = (xmlNodePtr) ret;
290
3.09k
  ret->prev = dtd->last;
291
3.09k
  dtd->last = (xmlNodePtr) ret;
292
3.09k
    }
293
294
28.6k
    if (out != NULL)
295
28.6k
        *out = ret;
296
28.6k
    return(0);
297
31.7k
}
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
1.64M
xmlGetPredefinedEntity(const xmlChar *name) {
307
1.64M
    if (name == NULL) return(NULL);
308
1.64M
    switch (name[0]) {
309
162k
        case 'l':
310
162k
      if (xmlStrEqual(name, BAD_CAST "lt"))
311
162k
          return(&xmlEntityLt);
312
481
      break;
313
155k
        case 'g':
314
155k
      if (xmlStrEqual(name, BAD_CAST "gt"))
315
154k
          return(&xmlEntityGt);
316
600
      break;
317
150k
        case 'a':
318
150k
      if (xmlStrEqual(name, BAD_CAST "amp"))
319
146k
          return(&xmlEntityAmp);
320
3.74k
      if (xmlStrEqual(name, BAD_CAST "apos"))
321
1.03k
          return(&xmlEntityApos);
322
2.71k
      break;
323
85.7k
        case 'q':
324
85.7k
      if (xmlStrEqual(name, BAD_CAST "quot"))
325
85.3k
          return(&xmlEntityQuot);
326
472
      break;
327
1.08M
  default:
328
1.08M
      break;
329
1.64M
    }
330
1.09M
    return(NULL);
331
1.64M
}
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
1.28k
    const xmlChar *content) {
350
1.28k
    xmlEntityPtr ret;
351
352
1.28k
    xmlAddEntity(doc, 1, name, type, publicId, systemId, content, &ret);
353
1.28k
    return(ret);
354
1.28k
}
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.79k
          const xmlChar *content) {
373
6.79k
    xmlEntityPtr ret;
374
375
6.79k
    xmlAddEntity(doc, 0, name, type, publicId, systemId, content, &ret);
376
6.79k
    return(ret);
377
6.79k
}
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.65k
       const xmlChar *content) {
399
5.65k
    if ((doc != NULL) && (doc->intSubset != NULL)) {
400
4.81k
  return(xmlAddDocEntity(doc, name, type, publicId, systemId, content));
401
4.81k
    }
402
839
    if (name == NULL)
403
442
        return(NULL);
404
397
    return(xmlCreateEntity(doc, name, type, publicId, systemId, content));
405
839
}
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
122k
xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
416
122k
    return((xmlEntityPtr) xmlHashLookup(table, name));
417
122k
}
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
17.4k
xmlGetParameterEntity(xmlDoc *doc, const xmlChar *name) {
429
17.4k
    xmlEntitiesTablePtr table;
430
17.4k
    xmlEntityPtr ret;
431
432
17.4k
    if (doc == NULL)
433
464
  return(NULL);
434
16.9k
    if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
435
14.7k
  table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
436
14.7k
  ret = xmlGetEntityFromTable(table, name);
437
14.7k
  if (ret != NULL)
438
13.9k
      return(ret);
439
14.7k
    }
440
2.94k
    if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
441
194
  table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
442
194
  return(xmlGetEntityFromTable(table, name));
443
194
    }
444
2.75k
    return(NULL);
445
2.94k
}
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.12k
xmlGetDtdEntity(xmlDoc *doc, const xmlChar *name) {
456
1.12k
    xmlEntitiesTablePtr table;
457
458
1.12k
    if (doc == NULL)
459
340
  return(NULL);
460
789
    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
461
384
  table = (xmlEntitiesTablePtr) doc->extSubset->entities;
462
384
  return(xmlGetEntityFromTable(table, name));
463
384
    }
464
405
    return(NULL);
465
789
}
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
1.13M
xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) {
477
1.13M
    xmlEntityPtr cur;
478
1.13M
    xmlEntitiesTablePtr table;
479
480
1.13M
    if (doc != NULL) {
481
1.11M
  if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
482
107k
      table = (xmlEntitiesTablePtr) doc->intSubset->entities;
483
107k
      cur = xmlGetEntityFromTable(table, name);
484
107k
      if (cur != NULL)
485
74.6k
    return(cur);
486
107k
  }
487
1.03M
  if (doc->standalone != 1) {
488
984k
      if ((doc->extSubset != NULL) &&
489
972k
    (doc->extSubset->entities != NULL)) {
490
469
    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
491
469
    cur = xmlGetEntityFromTable(table, name);
492
469
    if (cur != NULL)
493
259
        return(cur);
494
469
      }
495
984k
  }
496
1.03M
    }
497
1.05M
    return(xmlGetPredefinedEntity(name));
498
1.13M
}
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.94k
xmlEncodeEntitiesReentrant(xmlDoc *doc, const xmlChar *input) {
523
2.94k
    int flags = 0;
524
525
2.94k
    if (input == NULL)
526
432
        return(NULL);
527
528
2.51k
    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE))
529
1.55k
        flags |= XML_ESCAPE_HTML;
530
965
    else if ((doc == NULL) || (doc->encoding == NULL))
531
692
        flags |= XML_ESCAPE_NON_ASCII;
532
533
2.51k
    return(xmlEscapeText(input, flags));
534
2.94k
}
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
2.40k
                      const xmlChar *input) {
550
2.40k
    if (input == NULL)
551
643
        return(NULL);
552
553
1.76k
    return(xmlEscapeText(input, XML_ESCAPE_QUOT));
554
2.40k
}
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
33.2k
xmlFreeEntityWrapper(void *entity, const xmlChar *name ATTRIBUTE_UNUSED) {
576
33.2k
    if (entity != NULL)
577
33.2k
  xmlFreeEntity((xmlEntityPtr) entity);
578
33.2k
}
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
29.1k
xmlFreeEntitiesTable(xmlEntitiesTable *table) {
589
29.1k
    xmlHashFree(table, xmlFreeEntityWrapper);
590
29.1k
}
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
4.63k
xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
601
4.63k
    xmlEntityPtr ent = (xmlEntityPtr) payload;
602
4.63k
    xmlEntityPtr cur;
603
604
4.63k
    cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
605
4.63k
    if (cur == NULL)
606
2
  return(NULL);
607
4.63k
    memset(cur, 0, sizeof(xmlEntity));
608
4.63k
    cur->type = XML_ENTITY_DECL;
609
610
4.63k
    cur->etype = ent->etype;
611
4.63k
    if (ent->name != NULL) {
612
4.63k
  cur->name = xmlStrdup(ent->name);
613
4.63k
        if (cur->name == NULL)
614
2
            goto error;
615
4.63k
    }
616
4.63k
    if (ent->ExternalID != NULL) {
617
2.45k
  cur->ExternalID = xmlStrdup(ent->ExternalID);
618
2.45k
        if (cur->ExternalID == NULL)
619
1
            goto error;
620
2.45k
    }
621
4.62k
    if (ent->SystemID != NULL) {
622
2.44k
  cur->SystemID = xmlStrdup(ent->SystemID);
623
2.44k
        if (cur->SystemID == NULL)
624
1
            goto error;
625
2.44k
    }
626
4.62k
    if (ent->content != NULL) {
627
2.15k
  cur->content = xmlStrdup(ent->content);
628
2.15k
        if (cur->content == NULL)
629
1
            goto error;
630
2.15k
    }
631
4.62k
    if (ent->orig != NULL) {
632
642
  cur->orig = xmlStrdup(ent->orig);
633
642
        if (cur->orig == NULL)
634
1
            goto error;
635
642
    }
636
4.62k
    if (ent->URI != NULL) {
637
295
  cur->URI = xmlStrdup(ent->URI);
638
295
        if (cur->URI == NULL)
639
1
            goto error;
640
295
    }
641
    /* Handle XML_TEXT_NODE children for XML_ENTITY_DECL */
642
4.62k
    if (ent->children != NULL) {
643
355
        cur->children = xmlStaticCopyNodeList(ent->children, cur->doc, (xmlNodePtr)cur);
644
        /* Update last pointers */
645
355
        cur->last = cur->children;
646
908
        while (cur->last && cur->last->next) cur->last = cur->last->next;
647
355
    }
648
649
4.62k
    return(cur);
650
651
7
error:
652
7
    xmlFreeEntity(cur);
653
7
    return(NULL);
654
4.62k
}
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
2.73k
xmlCopyEntitiesTable(xmlEntitiesTable *table) {
666
2.73k
    return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper));
667
2.73k
}
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.63k
xmlDumpEntityDecl(xmlBuffer *buf, xmlEntity *ent) {
682
3.63k
    xmlSaveCtxtPtr save;
683
684
3.63k
    if ((buf == NULL) || (ent == NULL))
685
3.42k
        return;
686
687
213
    save = xmlSaveToBuffer(buf, NULL, 0);
688
213
    xmlSaveTree(save, (xmlNodePtr) ent);
689
213
    if (xmlSaveFinish(save) != XML_ERR_OK)
690
1
        xmlFree(xmlBufferDetach(buf));
691
213
}
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
615
                      const xmlChar *name ATTRIBUTE_UNUSED) {
704
615
    xmlSaveTree(save, ent);
705
615
}
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.74k
xmlDumpEntitiesTable(xmlBuffer *buf, xmlEntitiesTable *table) {
718
3.74k
    xmlSaveCtxtPtr save;
719
720
3.74k
    if ((buf == NULL) || (table == NULL))
721
3.38k
        return;
722
723
364
    save = xmlSaveToBuffer(buf, NULL, 0);
724
364
    xmlHashScan(table, xmlDumpEntityDeclScan, save);
725
364
    if (xmlSaveFinish(save) != XML_ERR_OK)
726
1
        xmlFree(xmlBufferDetach(buf));
727
364
}
728
#endif /* LIBXML_OUTPUT_ENABLED */