Coverage Report

Created: 2026-04-27 07:05

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
11.9k
{
86
11.9k
    xmlDictPtr dict = NULL;
87
88
11.9k
    if (entity == NULL)
89
0
        return;
90
91
11.9k
    if (entity->doc != NULL)
92
11.9k
        dict = entity->doc->dict;
93
94
95
11.9k
    if ((entity->children) &&
96
823
        (entity == (xmlEntityPtr) entity->children->parent))
97
823
        xmlFreeNodeList(entity->children);
98
11.9k
    if ((entity->name != NULL) &&
99
11.9k
        ((dict == NULL) || (!xmlDictOwns(dict, entity->name))))
100
11.9k
        xmlFree((char *) entity->name);
101
11.9k
    if (entity->ExternalID != NULL)
102
245
        xmlFree((char *) entity->ExternalID);
103
11.9k
    if (entity->SystemID != NULL)
104
560
        xmlFree((char *) entity->SystemID);
105
11.9k
    if (entity->URI != NULL)
106
156
        xmlFree((char *) entity->URI);
107
11.9k
    if (entity->content != NULL)
108
10.6k
        xmlFree((char *) entity->content);
109
11.9k
    if (entity->orig != NULL)
110
7.19k
        xmlFree((char *) entity->orig);
111
11.9k
    xmlFree(entity);
112
11.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
11.9k
          const xmlChar *content) {
121
11.9k
    xmlEntityPtr ret;
122
123
11.9k
    ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
124
11.9k
    if (ret == NULL)
125
0
  return(NULL);
126
11.9k
    memset(ret, 0, sizeof(xmlEntity));
127
11.9k
    ret->doc = doc;
128
11.9k
    ret->type = XML_ENTITY_DECL;
129
130
    /*
131
     * fill the structure.
132
     */
133
11.9k
    ret->etype = (xmlEntityType) type;
134
11.9k
    if ((doc == NULL) || (doc->dict == NULL))
135
11.9k
  ret->name = xmlStrdup(name);
136
0
    else
137
0
        ret->name = xmlDictLookup(doc->dict, name, -1);
138
11.9k
    if (ret->name == NULL)
139
0
        goto error;
140
11.9k
    if (publicId != NULL) {
141
245
        ret->ExternalID = xmlStrdup(publicId);
142
245
        if (ret->ExternalID == NULL)
143
0
            goto error;
144
245
    }
145
11.9k
    if (systemId != NULL) {
146
560
        ret->SystemID = xmlStrdup(systemId);
147
560
        if (ret->SystemID == NULL)
148
0
            goto error;
149
560
    }
150
11.9k
    if (content != NULL) {
151
10.6k
        ret->length = xmlStrlen(content);
152
10.6k
  ret->content = xmlStrndup(content, ret->length);
153
10.6k
        if (ret->content == NULL)
154
0
            goto error;
155
10.6k
     } else {
156
1.28k
        ret->length = 0;
157
1.28k
        ret->content = NULL;
158
1.28k
    }
159
11.9k
    ret->URI = NULL; /* to be computed by the layer knowing
160
      the defining entity */
161
11.9k
    ret->orig = NULL;
162
163
11.9k
    return(ret);
164
165
0
error:
166
0
    xmlFreeEntity(ret);
167
0
    return(NULL);
168
11.9k
}
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
14.0k
    const xmlChar *content, xmlEntity **out) {
189
14.0k
    xmlDtdPtr dtd;
190
14.0k
    xmlDictPtr dict = NULL;
191
14.0k
    xmlEntitiesTablePtr table = NULL;
192
14.0k
    xmlEntityPtr ret, predef;
193
14.0k
    int res;
194
195
14.0k
    if (out != NULL)
196
14.0k
        *out = NULL;
197
14.0k
    if ((doc == NULL) || (name == NULL))
198
0
  return(XML_ERR_ARGUMENT);
199
14.0k
    dict = doc->dict;
200
201
14.0k
    if (extSubset)
202
0
        dtd = doc->extSubset;
203
14.0k
    else
204
14.0k
        dtd = doc->intSubset;
205
14.0k
    if (dtd == NULL)
206
0
        return(XML_DTD_NO_DTD);
207
208
14.0k
    switch (type) {
209
10.2k
        case XML_INTERNAL_GENERAL_ENTITY:
210
11.4k
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
211
11.6k
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
212
11.6k
            predef = xmlGetPredefinedEntity(name);
213
11.6k
            if (predef != NULL) {
214
3.82k
                int valid = 0;
215
216
                /* 4.6 Predefined Entities */
217
3.82k
                if ((type == XML_INTERNAL_GENERAL_ENTITY) &&
218
3.61k
                    (content != NULL)) {
219
3.61k
                    int c = predef->content[0];
220
221
3.61k
                    if (((content[0] == c) && (content[1] == 0)) &&
222
663
                        ((c == '>') || (c == '\'') || (c == '"'))) {
223
468
                        valid = 1;
224
3.14k
                    } else if ((content[0] == '&') && (content[1] == '#')) {
225
1.68k
                        if (content[2] == 'x') {
226
1.27k
                            xmlChar *hex = BAD_CAST "0123456789ABCDEF";
227
1.27k
                            xmlChar ref[] = "00;";
228
229
1.27k
                            ref[0] = hex[c / 16 % 16];
230
1.27k
                            ref[1] = hex[c % 16];
231
1.27k
                            if (xmlStrcasecmp(&content[3], ref) == 0)
232
1.03k
                                valid = 1;
233
1.27k
                        } else {
234
410
                            xmlChar ref[] = "00;";
235
236
410
                            ref[0] = '0' + c / 10 % 10;
237
410
                            ref[1] = '0' + c % 10;
238
410
                            if (xmlStrEqual(&content[2], ref))
239
194
                                valid = 1;
240
410
                        }
241
1.68k
                    }
242
3.61k
                }
243
3.82k
                if (!valid)
244
2.12k
                    return(XML_ERR_REDECL_PREDEF_ENTITY);
245
3.82k
            }
246
9.52k
      if (dtd->entities == NULL) {
247
3.04k
    dtd->entities = xmlHashCreateDict(0, dict);
248
3.04k
                if (dtd->entities == NULL)
249
0
                    return(XML_ERR_NO_MEMORY);
250
3.04k
            }
251
9.52k
      table = dtd->entities;
252
9.52k
      break;
253
2.32k
        case XML_INTERNAL_PARAMETER_ENTITY:
254
2.40k
        case XML_EXTERNAL_PARAMETER_ENTITY:
255
2.40k
      if (dtd->pentities == NULL) {
256
1.94k
    dtd->pentities = xmlHashCreateDict(0, dict);
257
1.94k
                if (dtd->pentities == NULL)
258
0
                    return(XML_ERR_NO_MEMORY);
259
1.94k
            }
260
2.40k
      table = dtd->pentities;
261
2.40k
      break;
262
0
        default:
263
0
      return(XML_ERR_ARGUMENT);
264
14.0k
    }
265
11.9k
    ret = xmlCreateEntity(dtd->doc, name, type, publicId, systemId, content);
266
11.9k
    if (ret == NULL)
267
0
        return(XML_ERR_NO_MEMORY);
268
269
11.9k
    res = xmlHashAdd(table, name, ret);
270
11.9k
    if (res < 0) {
271
0
        xmlFreeEntity(ret);
272
0
        return(XML_ERR_NO_MEMORY);
273
11.9k
    } else if (res == 0) {
274
  /*
275
   * entity was already defined at another level.
276
   */
277
4.25k
        xmlFreeEntity(ret);
278
4.25k
  return(XML_WAR_ENTITY_REDEFINED);
279
4.25k
    }
280
281
    /*
282
     * Link it to the DTD
283
     */
284
7.67k
    ret->parent = dtd;
285
7.67k
    ret->doc = dtd->doc;
286
7.67k
    if (dtd->last == NULL) {
287
4.84k
  dtd->children = dtd->last = (xmlNodePtr) ret;
288
4.84k
    } else {
289
2.83k
  dtd->last->next = (xmlNodePtr) ret;
290
2.83k
  ret->prev = dtd->last;
291
2.83k
  dtd->last = (xmlNodePtr) ret;
292
2.83k
    }
293
294
7.67k
    if (out != NULL)
295
7.67k
        *out = ret;
296
7.67k
    return(0);
297
11.9k
}
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.56M
xmlGetPredefinedEntity(const xmlChar *name) {
307
1.56M
    if (name == NULL) return(NULL);
308
1.56M
    switch (name[0]) {
309
97.3k
        case 'l':
310
97.3k
      if (xmlStrEqual(name, BAD_CAST "lt"))
311
34.1k
          return(&xmlEntityLt);
312
63.1k
      break;
313
63.1k
        case 'g':
314
1.26k
      if (xmlStrEqual(name, BAD_CAST "gt"))
315
736
          return(&xmlEntityGt);
316
524
      break;
317
259k
        case 'a':
318
259k
      if (xmlStrEqual(name, BAD_CAST "amp"))
319
5.27k
          return(&xmlEntityAmp);
320
254k
      if (xmlStrEqual(name, BAD_CAST "apos"))
321
444
          return(&xmlEntityApos);
322
253k
      break;
323
328k
        case 'q':
324
328k
      if (xmlStrEqual(name, BAD_CAST "quot"))
325
772
          return(&xmlEntityQuot);
326
327k
      break;
327
878k
  default:
328
878k
      break;
329
1.56M
    }
330
1.52M
    return(NULL);
331
1.56M
}
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
0
    const xmlChar *content) {
350
0
    xmlEntityPtr ret;
351
352
0
    xmlAddEntity(doc, 1, name, type, publicId, systemId, content, &ret);
353
0
    return(ret);
354
0
}
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
0
          const xmlChar *content) {
373
0
    xmlEntityPtr ret;
374
375
0
    xmlAddEntity(doc, 0, name, type, publicId, systemId, content, &ret);
376
0
    return(ret);
377
0
}
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
0
       const xmlChar *content) {
399
0
    if ((doc != NULL) && (doc->intSubset != NULL)) {
400
0
  return(xmlAddDocEntity(doc, name, type, publicId, systemId, content));
401
0
    }
402
0
    if (name == NULL)
403
0
        return(NULL);
404
0
    return(xmlCreateEntity(doc, name, type, publicId, systemId, content));
405
0
}
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
713k
xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
416
713k
    return((xmlEntityPtr) xmlHashLookup(table, name));
417
713k
}
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
46.8k
xmlGetParameterEntity(xmlDoc *doc, const xmlChar *name) {
429
46.8k
    xmlEntitiesTablePtr table;
430
46.8k
    xmlEntityPtr ret;
431
432
46.8k
    if (doc == NULL)
433
217
  return(NULL);
434
46.6k
    if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
435
45.8k
  table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
436
45.8k
  ret = xmlGetEntityFromTable(table, name);
437
45.8k
  if (ret != NULL)
438
44.7k
      return(ret);
439
45.8k
    }
440
1.93k
    if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
441
0
  table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
442
0
  return(xmlGetEntityFromTable(table, name));
443
0
    }
444
1.93k
    return(NULL);
445
1.93k
}
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
0
xmlGetDtdEntity(xmlDoc *doc, const xmlChar *name) {
456
0
    xmlEntitiesTablePtr table;
457
458
0
    if (doc == NULL)
459
0
  return(NULL);
460
0
    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
461
0
  table = (xmlEntitiesTablePtr) doc->extSubset->entities;
462
0
  return(xmlGetEntityFromTable(table, name));
463
0
    }
464
0
    return(NULL);
465
0
}
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
748k
xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) {
477
748k
    xmlEntityPtr cur;
478
748k
    xmlEntitiesTablePtr table;
479
480
748k
    if (doc != NULL) {
481
740k
  if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
482
650k
      table = (xmlEntitiesTablePtr) doc->intSubset->entities;
483
650k
      cur = xmlGetEntityFromTable(table, name);
484
650k
      if (cur != NULL)
485
603k
    return(cur);
486
650k
  }
487
137k
  if (doc->standalone != 1) {
488
137k
      if ((doc->extSubset != NULL) &&
489
17.8k
    (doc->extSubset->entities != NULL)) {
490
16.9k
    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
491
16.9k
    cur = xmlGetEntityFromTable(table, name);
492
16.9k
    if (cur != NULL)
493
0
        return(cur);
494
16.9k
      }
495
137k
  }
496
137k
    }
497
145k
    return(xmlGetPredefinedEntity(name));
498
748k
}
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
0
xmlEncodeEntitiesReentrant(xmlDoc *doc, const xmlChar *input) {
523
0
    int flags = 0;
524
525
0
    if (input == NULL)
526
0
        return(NULL);
527
528
0
    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE))
529
0
        flags |= XML_ESCAPE_HTML;
530
0
    else if ((doc == NULL) || (doc->encoding == NULL))
531
0
        flags |= XML_ESCAPE_NON_ASCII;
532
533
0
    return(xmlEscapeText(input, flags));
534
0
}
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
0
                      const xmlChar *input) {
550
0
    if (input == NULL)
551
0
        return(NULL);
552
553
0
    return(xmlEscapeText(input, XML_ESCAPE_QUOT));
554
0
}
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
7.67k
xmlFreeEntityWrapper(void *entity, const xmlChar *name ATTRIBUTE_UNUSED) {
576
7.67k
    if (entity != NULL)
577
7.67k
  xmlFreeEntity((xmlEntityPtr) entity);
578
7.67k
}
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
4.99k
xmlFreeEntitiesTable(xmlEntitiesTable *table) {
589
4.99k
    xmlHashFree(table, xmlFreeEntityWrapper);
590
4.99k
}
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
0
xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
601
0
    xmlEntityPtr ent = (xmlEntityPtr) payload;
602
0
    xmlEntityPtr cur;
603
604
0
    cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
605
0
    if (cur == NULL)
606
0
  return(NULL);
607
0
    memset(cur, 0, sizeof(xmlEntity));
608
0
    cur->type = XML_ENTITY_DECL;
609
610
0
    cur->etype = ent->etype;
611
0
    if (ent->name != NULL) {
612
0
  cur->name = xmlStrdup(ent->name);
613
0
        if (cur->name == NULL)
614
0
            goto error;
615
0
    }
616
0
    if (ent->ExternalID != NULL) {
617
0
  cur->ExternalID = xmlStrdup(ent->ExternalID);
618
0
        if (cur->ExternalID == NULL)
619
0
            goto error;
620
0
    }
621
0
    if (ent->SystemID != NULL) {
622
0
  cur->SystemID = xmlStrdup(ent->SystemID);
623
0
        if (cur->SystemID == NULL)
624
0
            goto error;
625
0
    }
626
0
    if (ent->content != NULL) {
627
0
  cur->content = xmlStrdup(ent->content);
628
0
        if (cur->content == NULL)
629
0
            goto error;
630
0
    }
631
0
    if (ent->orig != NULL) {
632
0
  cur->orig = xmlStrdup(ent->orig);
633
0
        if (cur->orig == NULL)
634
0
            goto error;
635
0
    }
636
0
    if (ent->URI != NULL) {
637
0
  cur->URI = xmlStrdup(ent->URI);
638
0
        if (cur->URI == NULL)
639
0
            goto error;
640
0
    }
641
    /* Handle XML_TEXT_NODE children for XML_ENTITY_DECL */
642
0
    if (ent->children != NULL) {
643
0
        cur->children = xmlStaticCopyNodeList(ent->children, cur->doc, (xmlNodePtr)cur);
644
        /* Update last pointers */
645
0
        cur->last = cur->children;
646
0
        while (cur->last && cur->last->next) cur->last = cur->last->next;
647
0
    }
648
649
0
    return(cur);
650
651
0
error:
652
0
    xmlFreeEntity(cur);
653
0
    return(NULL);
654
0
}
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
0
xmlCopyEntitiesTable(xmlEntitiesTable *table) {
666
0
    return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper));
667
0
}
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
0
xmlDumpEntityDecl(xmlBuffer *buf, xmlEntity *ent) {
682
0
    xmlSaveCtxtPtr save;
683
684
0
    if ((buf == NULL) || (ent == NULL))
685
0
        return;
686
687
0
    save = xmlSaveToBuffer(buf, NULL, 0);
688
0
    xmlSaveTree(save, (xmlNodePtr) ent);
689
0
    if (xmlSaveFinish(save) != XML_ERR_OK)
690
0
        xmlFree(xmlBufferDetach(buf));
691
0
}
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
0
                      const xmlChar *name ATTRIBUTE_UNUSED) {
704
0
    xmlSaveTree(save, ent);
705
0
}
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
0
xmlDumpEntitiesTable(xmlBuffer *buf, xmlEntitiesTable *table) {
718
0
    xmlSaveCtxtPtr save;
719
720
0
    if ((buf == NULL) || (table == NULL))
721
0
        return;
722
723
0
    save = xmlSaveToBuffer(buf, NULL, 0);
724
0
    xmlHashScan(table, xmlDumpEntityDeclScan, save);
725
0
    if (xmlSaveFinish(save) != XML_ERR_OK)
726
0
        xmlFree(xmlBufferDetach(buf));
727
0
}
728
#endif /* LIBXML_OUTPUT_ENABLED */