Coverage Report

Created: 2026-05-30 06:17

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
35.5k
{
86
35.5k
    xmlDictPtr dict = NULL;
87
88
35.5k
    if (entity == NULL)
89
582
        return;
90
91
34.9k
    if (entity->doc != NULL)
92
33.5k
        dict = entity->doc->dict;
93
94
95
34.9k
    if ((entity->children) &&
96
3.21k
        (entity == (xmlEntityPtr) entity->children->parent))
97
3.21k
        xmlFreeNodeList(entity->children);
98
34.9k
    if ((entity->name != NULL) &&
99
34.9k
        ((dict == NULL) || (!xmlDictOwns(dict, entity->name))))
100
15.2k
        xmlFree((char *) entity->name);
101
34.9k
    if (entity->ExternalID != NULL)
102
8.27k
        xmlFree((char *) entity->ExternalID);
103
34.9k
    if (entity->SystemID != NULL)
104
11.2k
        xmlFree((char *) entity->SystemID);
105
34.9k
    if (entity->URI != NULL)
106
4.67k
        xmlFree((char *) entity->URI);
107
34.9k
    if (entity->content != NULL)
108
23.3k
        xmlFree((char *) entity->content);
109
34.9k
    if (entity->orig != NULL)
110
16.4k
        xmlFree((char *) entity->orig);
111
34.9k
    xmlFree(entity);
112
34.9k
}
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
30.7k
          const xmlChar *content) {
121
30.7k
    xmlEntityPtr ret;
122
123
30.7k
    ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
124
30.7k
    if (ret == NULL)
125
9
  return(NULL);
126
30.7k
    memset(ret, 0, sizeof(xmlEntity));
127
30.7k
    ret->doc = doc;
128
30.7k
    ret->type = XML_ENTITY_DECL;
129
130
    /*
131
     * fill the structure.
132
     */
133
30.7k
    ret->etype = (xmlEntityType) type;
134
30.7k
    if ((doc == NULL) || (doc->dict == NULL))
135
11.0k
  ret->name = xmlStrdup(name);
136
19.7k
    else
137
19.7k
        ret->name = xmlDictLookup(doc->dict, name, -1);
138
30.7k
    if (ret->name == NULL)
139
3
        goto error;
140
30.7k
    if (publicId != NULL) {
141
5.72k
        ret->ExternalID = xmlStrdup(publicId);
142
5.72k
        if (ret->ExternalID == NULL)
143
3
            goto error;
144
5.72k
    }
145
30.7k
    if (systemId != NULL) {
146
9.00k
        ret->SystemID = xmlStrdup(systemId);
147
9.00k
        if (ret->SystemID == NULL)
148
1
            goto error;
149
9.00k
    }
150
30.7k
    if (content != NULL) {
151
21.0k
        ret->length = xmlStrlen(content);
152
21.0k
  ret->content = xmlStrndup(content, ret->length);
153
21.0k
        if (ret->content == NULL)
154
8
            goto error;
155
21.0k
     } else {
156
9.71k
        ret->length = 0;
157
9.71k
        ret->content = NULL;
158
9.71k
    }
159
30.7k
    ret->URI = NULL; /* to be computed by the layer knowing
160
      the defining entity */
161
30.7k
    ret->orig = NULL;
162
163
30.7k
    return(ret);
164
165
15
error:
166
15
    xmlFreeEntity(ret);
167
15
    return(NULL);
168
30.7k
}
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
34.7k
    const xmlChar *content, xmlEntity **out) {
189
34.7k
    xmlDtdPtr dtd;
190
34.7k
    xmlDictPtr dict = NULL;
191
34.7k
    xmlEntitiesTablePtr table = NULL;
192
34.7k
    xmlEntityPtr ret, predef;
193
34.7k
    int res;
194
195
34.7k
    if (out != NULL)
196
34.7k
        *out = NULL;
197
34.7k
    if ((doc == NULL) || (name == NULL))
198
2.07k
  return(XML_ERR_ARGUMENT);
199
32.7k
    dict = doc->dict;
200
201
32.7k
    if (extSubset)
202
650
        dtd = doc->extSubset;
203
32.0k
    else
204
32.0k
        dtd = doc->intSubset;
205
32.7k
    if (dtd == NULL)
206
409
        return(XML_DTD_NO_DTD);
207
208
32.3k
    switch (type) {
209
16.8k
        case XML_INTERNAL_GENERAL_ENTITY:
210
20.7k
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
211
22.4k
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
212
22.4k
            predef = xmlGetPredefinedEntity(name);
213
22.4k
            if (predef != NULL) {
214
2.08k
                int valid = 0;
215
216
                /* 4.6 Predefined Entities */
217
2.08k
                if ((type == XML_INTERNAL_GENERAL_ENTITY) &&
218
1.89k
                    (content != NULL)) {
219
1.62k
                    int c = predef->content[0];
220
221
1.62k
                    if (((content[0] == c) && (content[1] == 0)) &&
222
653
                        ((c == '>') || (c == '\'') || (c == '"'))) {
223
458
                        valid = 1;
224
1.16k
                    } else if ((content[0] == '&') && (content[1] == '#')) {
225
393
                        if (content[2] == 'x') {
226
196
                            xmlChar *hex = BAD_CAST "0123456789ABCDEF";
227
196
                            xmlChar ref[] = "00;";
228
229
196
                            ref[0] = hex[c / 16 % 16];
230
196
                            ref[1] = hex[c % 16];
231
196
                            if (xmlStrcasecmp(&content[3], ref) == 0)
232
0
                                valid = 1;
233
197
                        } else {
234
197
                            xmlChar ref[] = "00;";
235
236
197
                            ref[0] = '0' + c / 10 % 10;
237
197
                            ref[1] = '0' + c % 10;
238
197
                            if (xmlStrEqual(&content[2], ref))
239
0
                                valid = 1;
240
197
                        }
241
393
                    }
242
1.62k
                }
243
2.08k
                if (!valid)
244
1.63k
                    return(XML_ERR_REDECL_PREDEF_ENTITY);
245
2.08k
            }
246
20.8k
      if (dtd->entities == NULL) {
247
18.1k
    dtd->entities = xmlHashCreateDict(0, dict);
248
18.1k
                if (dtd->entities == NULL)
249
6
                    return(XML_ERR_NO_MEMORY);
250
18.1k
            }
251
20.8k
      table = dtd->entities;
252
20.8k
      break;
253
6.01k
        case XML_INTERNAL_PARAMETER_ENTITY:
254
9.44k
        case XML_EXTERNAL_PARAMETER_ENTITY:
255
9.44k
      if (dtd->pentities == NULL) {
256
7.49k
    dtd->pentities = xmlHashCreateDict(0, dict);
257
7.49k
                if (dtd->pentities == NULL)
258
2
                    return(XML_ERR_NO_MEMORY);
259
7.49k
            }
260
9.43k
      table = dtd->pentities;
261
9.43k
      break;
262
373
        default:
263
373
      return(XML_ERR_ARGUMENT);
264
32.3k
    }
265
30.2k
    ret = xmlCreateEntity(dtd->doc, name, type, publicId, systemId, content);
266
30.2k
    if (ret == NULL)
267
20
        return(XML_ERR_NO_MEMORY);
268
269
30.2k
    res = xmlHashAdd(table, name, ret);
270
30.2k
    if (res < 0) {
271
3
        xmlFreeEntity(ret);
272
3
        return(XML_ERR_NO_MEMORY);
273
30.2k
    } else if (res == 0) {
274
  /*
275
   * entity was already defined at another level.
276
   */
277
2.90k
        xmlFreeEntity(ret);
278
2.90k
  return(XML_WAR_ENTITY_REDEFINED);
279
2.90k
    }
280
281
    /*
282
     * Link it to the DTD
283
     */
284
27.3k
    ret->parent = dtd;
285
27.3k
    ret->doc = dtd->doc;
286
27.3k
    if (dtd->last == NULL) {
287
24.5k
  dtd->children = dtd->last = (xmlNodePtr) ret;
288
24.5k
    } else {
289
2.85k
  dtd->last->next = (xmlNodePtr) ret;
290
2.85k
  ret->prev = dtd->last;
291
2.85k
  dtd->last = (xmlNodePtr) ret;
292
2.85k
    }
293
294
27.3k
    if (out != NULL)
295
27.3k
        *out = ret;
296
27.3k
    return(0);
297
30.2k
}
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
672k
xmlGetPredefinedEntity(const xmlChar *name) {
307
672k
    if (name == NULL) return(NULL);
308
672k
    switch (name[0]) {
309
165k
        case 'l':
310
165k
      if (xmlStrEqual(name, BAD_CAST "lt"))
311
165k
          return(&xmlEntityLt);
312
495
      break;
313
149k
        case 'g':
314
149k
      if (xmlStrEqual(name, BAD_CAST "gt"))
315
149k
          return(&xmlEntityGt);
316
370
      break;
317
162k
        case 'a':
318
162k
      if (xmlStrEqual(name, BAD_CAST "amp"))
319
159k
          return(&xmlEntityAmp);
320
2.79k
      if (xmlStrEqual(name, BAD_CAST "apos"))
321
894
          return(&xmlEntityApos);
322
1.90k
      break;
323
75.7k
        case 'q':
324
75.7k
      if (xmlStrEqual(name, BAD_CAST "quot"))
325
75.4k
          return(&xmlEntityQuot);
326
332
      break;
327
118k
  default:
328
118k
      break;
329
672k
    }
330
121k
    return(NULL);
331
672k
}
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.25k
          const xmlChar *content) {
373
6.25k
    xmlEntityPtr ret;
374
375
6.25k
    xmlAddEntity(doc, 0, name, type, publicId, systemId, content, &ret);
376
6.25k
    return(ret);
377
6.25k
}
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
118k
xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
416
118k
    return((xmlEntityPtr) xmlHashLookup(table, name));
417
118k
}
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
15.7k
xmlGetParameterEntity(xmlDoc *doc, const xmlChar *name) {
429
15.7k
    xmlEntitiesTablePtr table;
430
15.7k
    xmlEntityPtr ret;
431
432
15.7k
    if (doc == NULL)
433
561
  return(NULL);
434
15.1k
    if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
435
13.3k
  table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
436
13.3k
  ret = xmlGetEntityFromTable(table, name);
437
13.3k
  if (ret != NULL)
438
12.6k
      return(ret);
439
13.3k
    }
440
2.48k
    if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
441
66
  table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
442
66
  return(xmlGetEntityFromTable(table, name));
443
66
    }
444
2.42k
    return(NULL);
445
2.48k
}
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
161k
xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) {
477
161k
    xmlEntityPtr cur;
478
161k
    xmlEntitiesTablePtr table;
479
480
161k
    if (doc != NULL) {
481
138k
  if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
482
103k
      table = (xmlEntitiesTablePtr) doc->intSubset->entities;
483
103k
      cur = xmlGetEntityFromTable(table, name);
484
103k
      if (cur != NULL)
485
72.5k
    return(cur);
486
103k
  }
487
65.5k
  if (doc->standalone != 1) {
488
12.7k
      if ((doc->extSubset != NULL) &&
489
1.52k
    (doc->extSubset->entities != NULL)) {
490
479
    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
491
479
    cur = xmlGetEntityFromTable(table, name);
492
479
    if (cur != NULL)
493
239
        return(cur);
494
479
      }
495
12.7k
  }
496
65.5k
    }
497
88.6k
    return(xmlGetPredefinedEntity(name));
498
161k
}
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
31.5k
xmlFreeEntityWrapper(void *entity, const xmlChar *name ATTRIBUTE_UNUSED) {
576
31.5k
    if (entity != NULL)
577
31.5k
  xmlFreeEntity((xmlEntityPtr) entity);
578
31.5k
}
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
28.2k
xmlFreeEntitiesTable(xmlEntitiesTable *table) {
589
28.2k
    xmlHashFree(table, xmlFreeEntityWrapper);
590
28.2k
}
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.16k
xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
601
4.16k
    xmlEntityPtr ent = (xmlEntityPtr) payload;
602
4.16k
    xmlEntityPtr cur;
603
604
4.16k
    cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
605
4.16k
    if (cur == NULL)
606
1
  return(NULL);
607
4.16k
    memset(cur, 0, sizeof(xmlEntity));
608
4.16k
    cur->type = XML_ENTITY_DECL;
609
610
4.16k
    cur->etype = ent->etype;
611
4.16k
    if (ent->name != NULL) {
612
4.16k
  cur->name = xmlStrdup(ent->name);
613
4.16k
        if (cur->name == NULL)
614
1
            goto error;
615
4.16k
    }
616
4.15k
    if (ent->ExternalID != NULL) {
617
2.55k
  cur->ExternalID = xmlStrdup(ent->ExternalID);
618
2.55k
        if (cur->ExternalID == NULL)
619
1
            goto error;
620
2.55k
    }
621
4.15k
    if (ent->SystemID != NULL) {
622
2.29k
  cur->SystemID = xmlStrdup(ent->SystemID);
623
2.29k
        if (cur->SystemID == NULL)
624
1
            goto error;
625
2.29k
    }
626
4.15k
    if (ent->content != NULL) {
627
2.26k
  cur->content = xmlStrdup(ent->content);
628
2.26k
        if (cur->content == NULL)
629
1
            goto error;
630
2.26k
    }
631
4.15k
    if (ent->orig != NULL) {
632
579
  cur->orig = xmlStrdup(ent->orig);
633
579
        if (cur->orig == NULL)
634
1
            goto error;
635
579
    }
636
4.15k
    if (ent->URI != NULL) {
637
315
  cur->URI = xmlStrdup(ent->URI);
638
315
        if (cur->URI == NULL)
639
1
            goto error;
640
315
    }
641
    /* Handle XML_TEXT_NODE children for XML_ENTITY_DECL */
642
4.15k
    if (ent->children != NULL) {
643
332
        cur->children = xmlStaticCopyNodeList(ent->children, cur->doc, (xmlNodePtr)cur);
644
        /* Update last pointers */
645
332
        cur->last = cur->children;
646
810
        while (cur->last && cur->last->next) cur->last = cur->last->next;
647
332
    }
648
649
4.15k
    return(cur);
650
651
6
error:
652
6
    xmlFreeEntity(cur);
653
6
    return(NULL);
654
4.15k
}
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.59k
xmlCopyEntitiesTable(xmlEntitiesTable *table) {
666
2.59k
    return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper));
667
2.59k
}
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 */