Coverage Report

Created: 2025-08-04 07:15

/src/libxml2-2.9.7/entities.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * entities.c : implementation for the XML entities handling
3
 *
4
 * See Copyright for the status of this software.
5
 *
6
 * daniel@veillard.com
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
#ifdef HAVE_STDLIB_H
19
#include <stdlib.h>
20
#endif
21
#include <libxml/xmlmemory.h>
22
#include <libxml/hash.h>
23
#include <libxml/entities.h>
24
#include <libxml/parser.h>
25
#include <libxml/parserInternals.h>
26
#include <libxml/xmlerror.h>
27
#include <libxml/globals.h>
28
#include <libxml/dict.h>
29
30
#include "save.h"
31
32
/*
33
 * The XML predefined entities.
34
 */
35
36
static xmlEntity xmlEntityLt = {
37
    NULL, XML_ENTITY_DECL, BAD_CAST "lt",
38
    NULL, NULL, NULL, NULL, NULL, NULL,
39
    BAD_CAST "<", BAD_CAST "<", 1,
40
    XML_INTERNAL_PREDEFINED_ENTITY,
41
    NULL, NULL, NULL, NULL, 0, 1
42
};
43
static xmlEntity xmlEntityGt = {
44
    NULL, XML_ENTITY_DECL, BAD_CAST "gt",
45
    NULL, NULL, NULL, NULL, NULL, NULL,
46
    BAD_CAST ">", BAD_CAST ">", 1,
47
    XML_INTERNAL_PREDEFINED_ENTITY,
48
    NULL, NULL, NULL, NULL, 0, 1
49
};
50
static xmlEntity xmlEntityAmp = {
51
    NULL, XML_ENTITY_DECL, BAD_CAST "amp",
52
    NULL, NULL, NULL, NULL, NULL, NULL,
53
    BAD_CAST "&", BAD_CAST "&", 1,
54
    XML_INTERNAL_PREDEFINED_ENTITY,
55
    NULL, NULL, NULL, NULL, 0, 1
56
};
57
static xmlEntity xmlEntityQuot = {
58
    NULL, XML_ENTITY_DECL, BAD_CAST "quot",
59
    NULL, NULL, NULL, NULL, NULL, NULL,
60
    BAD_CAST "\"", BAD_CAST "\"", 1,
61
    XML_INTERNAL_PREDEFINED_ENTITY,
62
    NULL, NULL, NULL, NULL, 0, 1
63
};
64
static xmlEntity xmlEntityApos = {
65
    NULL, XML_ENTITY_DECL, BAD_CAST "apos",
66
    NULL, NULL, NULL, NULL, NULL, NULL,
67
    BAD_CAST "'", BAD_CAST "'", 1,
68
    XML_INTERNAL_PREDEFINED_ENTITY,
69
    NULL, NULL, NULL, NULL, 0, 1
70
};
71
72
/**
73
 * xmlEntitiesErrMemory:
74
 * @extra:  extra informations
75
 *
76
 * Handle an out of memory condition
77
 */
78
static void
79
xmlEntitiesErrMemory(const char *extra)
80
0
{
81
0
    __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
82
0
}
83
84
/**
85
 * xmlEntitiesErr:
86
 * @code:  the error code
87
 * @msg:  the message
88
 *
89
 * Handle an out of memory condition
90
 */
91
static void LIBXML_ATTR_FORMAT(2,0)
92
xmlEntitiesErr(xmlParserErrors code, const char *msg)
93
0
{
94
0
    __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL);
95
0
}
96
97
/*
98
 * xmlFreeEntity : clean-up an entity record.
99
 */
100
static void
101
xmlFreeEntity(xmlEntityPtr entity)
102
0
{
103
0
    xmlDictPtr dict = NULL;
104
105
0
    if (entity == NULL)
106
0
        return;
107
108
0
    if (entity->doc != NULL)
109
0
        dict = entity->doc->dict;
110
111
112
0
    if ((entity->children) && (entity->owner == 1) &&
113
0
        (entity == (xmlEntityPtr) entity->children->parent))
114
0
        xmlFreeNodeList(entity->children);
115
0
    if (dict != NULL) {
116
0
        if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name)))
117
0
            xmlFree((char *) entity->name);
118
0
        if ((entity->ExternalID != NULL) &&
119
0
      (!xmlDictOwns(dict, entity->ExternalID)))
120
0
            xmlFree((char *) entity->ExternalID);
121
0
        if ((entity->SystemID != NULL) &&
122
0
      (!xmlDictOwns(dict, entity->SystemID)))
123
0
            xmlFree((char *) entity->SystemID);
124
0
        if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI)))
125
0
            xmlFree((char *) entity->URI);
126
0
        if ((entity->content != NULL)
127
0
            && (!xmlDictOwns(dict, entity->content)))
128
0
            xmlFree((char *) entity->content);
129
0
        if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig)))
130
0
            xmlFree((char *) entity->orig);
131
0
    } else {
132
0
        if (entity->name != NULL)
133
0
            xmlFree((char *) entity->name);
134
0
        if (entity->ExternalID != NULL)
135
0
            xmlFree((char *) entity->ExternalID);
136
0
        if (entity->SystemID != NULL)
137
0
            xmlFree((char *) entity->SystemID);
138
0
        if (entity->URI != NULL)
139
0
            xmlFree((char *) entity->URI);
140
0
        if (entity->content != NULL)
141
0
            xmlFree((char *) entity->content);
142
0
        if (entity->orig != NULL)
143
0
            xmlFree((char *) entity->orig);
144
0
    }
145
0
    xmlFree(entity);
146
0
}
147
148
/*
149
 * xmlCreateEntity:
150
 *
151
 * internal routine doing the entity node strutures allocations
152
 */
153
static xmlEntityPtr
154
xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
155
          const xmlChar *ExternalID, const xmlChar *SystemID,
156
0
          const xmlChar *content) {
157
0
    xmlEntityPtr ret;
158
159
0
    ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
160
0
    if (ret == NULL) {
161
0
        xmlEntitiesErrMemory("xmlCreateEntity: malloc failed");
162
0
  return(NULL);
163
0
    }
164
0
    memset(ret, 0, sizeof(xmlEntity));
165
0
    ret->type = XML_ENTITY_DECL;
166
0
    ret->checked = 0;
167
168
    /*
169
     * fill the structure.
170
     */
171
0
    ret->etype = (xmlEntityType) type;
172
0
    if (dict == NULL) {
173
0
  ret->name = xmlStrdup(name);
174
0
  if (ExternalID != NULL)
175
0
      ret->ExternalID = xmlStrdup(ExternalID);
176
0
  if (SystemID != NULL)
177
0
      ret->SystemID = xmlStrdup(SystemID);
178
0
    } else {
179
0
        ret->name = xmlDictLookup(dict, name, -1);
180
0
  if (ExternalID != NULL)
181
0
      ret->ExternalID = xmlDictLookup(dict, ExternalID, -1);
182
0
  if (SystemID != NULL)
183
0
      ret->SystemID = xmlDictLookup(dict, SystemID, -1);
184
0
    }
185
0
    if (content != NULL) {
186
0
        ret->length = xmlStrlen(content);
187
0
  if ((dict != NULL) && (ret->length < 5))
188
0
      ret->content = (xmlChar *)
189
0
                     xmlDictLookup(dict, content, ret->length);
190
0
  else
191
0
      ret->content = xmlStrndup(content, ret->length);
192
0
     } else {
193
0
        ret->length = 0;
194
0
        ret->content = NULL;
195
0
    }
196
0
    ret->URI = NULL; /* to be computed by the layer knowing
197
      the defining entity */
198
0
    ret->orig = NULL;
199
0
    ret->owner = 0;
200
201
0
    return(ret);
202
0
}
203
204
/*
205
 * xmlAddEntity : register a new entity for an entities table.
206
 */
207
static xmlEntityPtr
208
xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
209
    const xmlChar *ExternalID, const xmlChar *SystemID,
210
0
    const xmlChar *content) {
211
0
    xmlDictPtr dict = NULL;
212
0
    xmlEntitiesTablePtr table = NULL;
213
0
    xmlEntityPtr ret;
214
215
0
    if (name == NULL)
216
0
  return(NULL);
217
0
    if (dtd == NULL)
218
0
  return(NULL);
219
0
    if (dtd->doc != NULL)
220
0
        dict = dtd->doc->dict;
221
222
0
    switch (type) {
223
0
        case XML_INTERNAL_GENERAL_ENTITY:
224
0
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
225
0
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
226
0
      if (dtd->entities == NULL)
227
0
    dtd->entities = xmlHashCreateDict(0, dict);
228
0
      table = dtd->entities;
229
0
      break;
230
0
        case XML_INTERNAL_PARAMETER_ENTITY:
231
0
        case XML_EXTERNAL_PARAMETER_ENTITY:
232
0
      if (dtd->pentities == NULL)
233
0
    dtd->pentities = xmlHashCreateDict(0, dict);
234
0
      table = dtd->pentities;
235
0
      break;
236
0
        case XML_INTERNAL_PREDEFINED_ENTITY:
237
0
      return(NULL);
238
0
    }
239
0
    if (table == NULL)
240
0
  return(NULL);
241
0
    ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
242
0
    if (ret == NULL)
243
0
        return(NULL);
244
0
    ret->doc = dtd->doc;
245
246
0
    if (xmlHashAddEntry(table, name, ret)) {
247
  /*
248
   * entity was already defined at another level.
249
   */
250
0
        xmlFreeEntity(ret);
251
0
  return(NULL);
252
0
    }
253
0
    return(ret);
254
0
}
255
256
/**
257
 * xmlGetPredefinedEntity:
258
 * @name:  the entity name
259
 *
260
 * Check whether this name is an predefined entity.
261
 *
262
 * Returns NULL if not, otherwise the entity
263
 */
264
xmlEntityPtr
265
0
xmlGetPredefinedEntity(const xmlChar *name) {
266
0
    if (name == NULL) return(NULL);
267
0
    switch (name[0]) {
268
0
        case 'l':
269
0
      if (xmlStrEqual(name, BAD_CAST "lt"))
270
0
          return(&xmlEntityLt);
271
0
      break;
272
0
        case 'g':
273
0
      if (xmlStrEqual(name, BAD_CAST "gt"))
274
0
          return(&xmlEntityGt);
275
0
      break;
276
0
        case 'a':
277
0
      if (xmlStrEqual(name, BAD_CAST "amp"))
278
0
          return(&xmlEntityAmp);
279
0
      if (xmlStrEqual(name, BAD_CAST "apos"))
280
0
          return(&xmlEntityApos);
281
0
      break;
282
0
        case 'q':
283
0
      if (xmlStrEqual(name, BAD_CAST "quot"))
284
0
          return(&xmlEntityQuot);
285
0
      break;
286
0
  default:
287
0
      break;
288
0
    }
289
0
    return(NULL);
290
0
}
291
292
/**
293
 * xmlAddDtdEntity:
294
 * @doc:  the document
295
 * @name:  the entity name
296
 * @type:  the entity type XML_xxx_yyy_ENTITY
297
 * @ExternalID:  the entity external ID if available
298
 * @SystemID:  the entity system ID if available
299
 * @content:  the entity content
300
 *
301
 * Register a new entity for this document DTD external subset.
302
 *
303
 * Returns a pointer to the entity or NULL in case of error
304
 */
305
xmlEntityPtr
306
xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
307
          const xmlChar *ExternalID, const xmlChar *SystemID,
308
0
    const xmlChar *content) {
309
0
    xmlEntityPtr ret;
310
0
    xmlDtdPtr dtd;
311
312
0
    if (doc == NULL) {
313
0
  xmlEntitiesErr(XML_DTD_NO_DOC,
314
0
          "xmlAddDtdEntity: document is NULL");
315
0
  return(NULL);
316
0
    }
317
0
    if (doc->extSubset == NULL) {
318
0
  xmlEntitiesErr(XML_DTD_NO_DTD,
319
0
          "xmlAddDtdEntity: document without external subset");
320
0
  return(NULL);
321
0
    }
322
0
    dtd = doc->extSubset;
323
0
    ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
324
0
    if (ret == NULL) return(NULL);
325
326
    /*
327
     * Link it to the DTD
328
     */
329
0
    ret->parent = dtd;
330
0
    ret->doc = dtd->doc;
331
0
    if (dtd->last == NULL) {
332
0
  dtd->children = dtd->last = (xmlNodePtr) ret;
333
0
    } else {
334
0
        dtd->last->next = (xmlNodePtr) ret;
335
0
  ret->prev = dtd->last;
336
0
  dtd->last = (xmlNodePtr) ret;
337
0
    }
338
0
    return(ret);
339
0
}
340
341
/**
342
 * xmlAddDocEntity:
343
 * @doc:  the document
344
 * @name:  the entity name
345
 * @type:  the entity type XML_xxx_yyy_ENTITY
346
 * @ExternalID:  the entity external ID if available
347
 * @SystemID:  the entity system ID if available
348
 * @content:  the entity content
349
 *
350
 * Register a new entity for this document.
351
 *
352
 * Returns a pointer to the entity or NULL in case of error
353
 */
354
xmlEntityPtr
355
xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
356
          const xmlChar *ExternalID, const xmlChar *SystemID,
357
0
          const xmlChar *content) {
358
0
    xmlEntityPtr ret;
359
0
    xmlDtdPtr dtd;
360
361
0
    if (doc == NULL) {
362
0
  xmlEntitiesErr(XML_DTD_NO_DOC,
363
0
          "xmlAddDocEntity: document is NULL");
364
0
  return(NULL);
365
0
    }
366
0
    if (doc->intSubset == NULL) {
367
0
  xmlEntitiesErr(XML_DTD_NO_DTD,
368
0
          "xmlAddDocEntity: document without internal subset");
369
0
  return(NULL);
370
0
    }
371
0
    dtd = doc->intSubset;
372
0
    ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
373
0
    if (ret == NULL) return(NULL);
374
375
    /*
376
     * Link it to the DTD
377
     */
378
0
    ret->parent = dtd;
379
0
    ret->doc = dtd->doc;
380
0
    if (dtd->last == NULL) {
381
0
  dtd->children = dtd->last = (xmlNodePtr) ret;
382
0
    } else {
383
0
  dtd->last->next = (xmlNodePtr) ret;
384
0
  ret->prev = dtd->last;
385
0
  dtd->last = (xmlNodePtr) ret;
386
0
    }
387
0
    return(ret);
388
0
}
389
390
/**
391
 * xmlNewEntity:
392
 * @doc:  the document
393
 * @name:  the entity name
394
 * @type:  the entity type XML_xxx_yyy_ENTITY
395
 * @ExternalID:  the entity external ID if available
396
 * @SystemID:  the entity system ID if available
397
 * @content:  the entity content
398
 *
399
 * Create a new entity, this differs from xmlAddDocEntity() that if
400
 * the document is NULL or has no internal subset defined, then an
401
 * unlinked entity structure will be returned, it is then the responsability
402
 * of the caller to link it to the document later or free it when not needed
403
 * anymore.
404
 *
405
 * Returns a pointer to the entity or NULL in case of error
406
 */
407
xmlEntityPtr
408
xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type,
409
       const xmlChar *ExternalID, const xmlChar *SystemID,
410
0
       const xmlChar *content) {
411
0
    xmlEntityPtr ret;
412
0
    xmlDictPtr dict;
413
414
0
    if ((doc != NULL) && (doc->intSubset != NULL)) {
415
0
  return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
416
0
    }
417
0
    if (doc != NULL)
418
0
        dict = doc->dict;
419
0
    else
420
0
        dict = NULL;
421
0
    ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
422
0
    if (ret == NULL)
423
0
        return(NULL);
424
0
    ret->doc = doc;
425
0
    return(ret);
426
0
}
427
428
/**
429
 * xmlGetEntityFromTable:
430
 * @table:  an entity table
431
 * @name:  the entity name
432
 * @parameter:  look for parameter entities
433
 *
434
 * Do an entity lookup in the table.
435
 * returns the corresponding parameter entity, if found.
436
 *
437
 * Returns A pointer to the entity structure or NULL if not found.
438
 */
439
static xmlEntityPtr
440
0
xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
441
0
    return((xmlEntityPtr) xmlHashLookup(table, name));
442
0
}
443
444
/**
445
 * xmlGetParameterEntity:
446
 * @doc:  the document referencing the entity
447
 * @name:  the entity name
448
 *
449
 * Do an entity lookup in the internal and external subsets and
450
 * returns the corresponding parameter entity, if found.
451
 *
452
 * Returns A pointer to the entity structure or NULL if not found.
453
 */
454
xmlEntityPtr
455
0
xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
456
0
    xmlEntitiesTablePtr table;
457
0
    xmlEntityPtr ret;
458
459
0
    if (doc == NULL)
460
0
  return(NULL);
461
0
    if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
462
0
  table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
463
0
  ret = xmlGetEntityFromTable(table, name);
464
0
  if (ret != NULL)
465
0
      return(ret);
466
0
    }
467
0
    if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
468
0
  table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
469
0
  return(xmlGetEntityFromTable(table, name));
470
0
    }
471
0
    return(NULL);
472
0
}
473
474
/**
475
 * xmlGetDtdEntity:
476
 * @doc:  the document referencing the entity
477
 * @name:  the entity name
478
 *
479
 * Do an entity lookup in the DTD entity hash table and
480
 * returns the corresponding entity, if found.
481
 * Note: the first argument is the document node, not the DTD node.
482
 *
483
 * Returns A pointer to the entity structure or NULL if not found.
484
 */
485
xmlEntityPtr
486
0
xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
487
0
    xmlEntitiesTablePtr table;
488
489
0
    if (doc == NULL)
490
0
  return(NULL);
491
0
    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
492
0
  table = (xmlEntitiesTablePtr) doc->extSubset->entities;
493
0
  return(xmlGetEntityFromTable(table, name));
494
0
    }
495
0
    return(NULL);
496
0
}
497
498
/**
499
 * xmlGetDocEntity:
500
 * @doc:  the document referencing the entity
501
 * @name:  the entity name
502
 *
503
 * Do an entity lookup in the document entity hash table and
504
 * returns the corresponding entity, otherwise a lookup is done
505
 * in the predefined entities too.
506
 *
507
 * Returns A pointer to the entity structure or NULL if not found.
508
 */
509
xmlEntityPtr
510
0
xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) {
511
0
    xmlEntityPtr cur;
512
0
    xmlEntitiesTablePtr table;
513
514
0
    if (doc != NULL) {
515
0
  if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
516
0
      table = (xmlEntitiesTablePtr) doc->intSubset->entities;
517
0
      cur = xmlGetEntityFromTable(table, name);
518
0
      if (cur != NULL)
519
0
    return(cur);
520
0
  }
521
0
  if (doc->standalone != 1) {
522
0
      if ((doc->extSubset != NULL) &&
523
0
    (doc->extSubset->entities != NULL)) {
524
0
    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
525
0
    cur = xmlGetEntityFromTable(table, name);
526
0
    if (cur != NULL)
527
0
        return(cur);
528
0
      }
529
0
  }
530
0
    }
531
0
    return(xmlGetPredefinedEntity(name));
532
0
}
533
534
/*
535
 * Macro used to grow the current buffer.
536
 */
537
0
#define growBufferReentrant() {           \
538
0
    xmlChar *tmp;                                                       \
539
0
    size_t new_size = buffer_size * 2;                                  \
540
0
    if (new_size < buffer_size) goto mem_error;                         \
541
0
    tmp = (xmlChar *) xmlRealloc(buffer, new_size);                 \
542
0
    if (tmp == NULL) goto mem_error;                                    \
543
0
    buffer = tmp;             \
544
0
    buffer_size = new_size;           \
545
0
}
546
547
/**
548
 * xmlEncodeEntitiesInternal:
549
 * @doc:  the document containing the string
550
 * @input:  A string to convert to XML.
551
 * @attr: are we handling an atrbute value
552
 *
553
 * Do a global encoding of a string, replacing the predefined entities
554
 * and non ASCII values with their entities and CharRef counterparts.
555
 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
556
 * must be deallocated.
557
 *
558
 * Returns A newly allocated string with the substitution done.
559
 */
560
static xmlChar *
561
0
xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
562
0
    const xmlChar *cur = input;
563
0
    xmlChar *buffer = NULL;
564
0
    xmlChar *out = NULL;
565
0
    size_t buffer_size = 0;
566
0
    int html = 0;
567
568
0
    if (input == NULL) return(NULL);
569
0
    if (doc != NULL)
570
0
        html = (doc->type == XML_HTML_DOCUMENT_NODE);
571
572
    /*
573
     * allocate an translation buffer.
574
     */
575
0
    buffer_size = 1000;
576
0
    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
577
0
    if (buffer == NULL) {
578
0
        xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed");
579
0
  return(NULL);
580
0
    }
581
0
    out = buffer;
582
583
0
    while (*cur != '\0') {
584
0
        size_t indx = out - buffer;
585
0
        if (indx + 100 > buffer_size) {
586
587
0
      growBufferReentrant();
588
0
      out = &buffer[indx];
589
0
  }
590
591
  /*
592
   * By default one have to encode at least '<', '>', '"' and '&' !
593
   */
594
0
  if (*cur == '<') {
595
0
      const xmlChar *end;
596
597
      /*
598
       * Special handling of server side include in HTML attributes
599
       */
600
0
      if (html && attr &&
601
0
          (cur[1] == '!') && (cur[2] == '-') && (cur[3] == '-') &&
602
0
          ((end = xmlStrstr(cur, BAD_CAST "-->")) != NULL)) {
603
0
          while (cur != end) {
604
0
        *out++ = *cur++;
605
0
        indx = out - buffer;
606
0
        if (indx + 100 > buffer_size) {
607
0
      growBufferReentrant();
608
0
      out = &buffer[indx];
609
0
        }
610
0
    }
611
0
    *out++ = *cur++;
612
0
    *out++ = *cur++;
613
0
    *out++ = *cur++;
614
0
    continue;
615
0
      }
616
0
      *out++ = '&';
617
0
      *out++ = 'l';
618
0
      *out++ = 't';
619
0
      *out++ = ';';
620
0
  } else if (*cur == '>') {
621
0
      *out++ = '&';
622
0
      *out++ = 'g';
623
0
      *out++ = 't';
624
0
      *out++ = ';';
625
0
  } else if (*cur == '&') {
626
      /*
627
       * Special handling of &{...} construct from HTML 4, see
628
       * http://www.w3.org/TR/html401/appendix/notes.html#h-B.7.1
629
       */
630
0
      if (html && attr && (cur[1] == '{') &&
631
0
          (strchr((const char *) cur, '}'))) {
632
0
          while (*cur != '}') {
633
0
        *out++ = *cur++;
634
0
        indx = out - buffer;
635
0
        if (indx + 100 > buffer_size) {
636
0
      growBufferReentrant();
637
0
      out = &buffer[indx];
638
0
        }
639
0
    }
640
0
    *out++ = *cur++;
641
0
    continue;
642
0
      }
643
0
      *out++ = '&';
644
0
      *out++ = 'a';
645
0
      *out++ = 'm';
646
0
      *out++ = 'p';
647
0
      *out++ = ';';
648
0
  } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
649
0
      (*cur == '\n') || (*cur == '\t') || ((html) && (*cur == '\r'))) {
650
      /*
651
       * default case, just copy !
652
       */
653
0
      *out++ = *cur;
654
0
  } else if (*cur >= 0x80) {
655
0
      if (((doc != NULL) && (doc->encoding != NULL)) || (html)) {
656
    /*
657
     * Bjørn Reese <br@sseusa.com> provided the patch
658
          xmlChar xc;
659
          xc = (*cur & 0x3F) << 6;
660
          if (cur[1] != 0) {
661
        xc += *(++cur) & 0x3F;
662
        *out++ = xc;
663
          } else
664
     */
665
0
    *out++ = *cur;
666
0
      } else {
667
    /*
668
     * We assume we have UTF-8 input.
669
     */
670
0
    char buf[11], *ptr;
671
0
    int val = 0, l = 1;
672
673
0
    if (*cur < 0xC0) {
674
0
        xmlEntitiesErr(XML_CHECK_NOT_UTF8,
675
0
          "xmlEncodeEntities: input not UTF-8");
676
0
        if (doc != NULL)
677
0
      doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
678
0
        snprintf(buf, sizeof(buf), "&#%d;", *cur);
679
0
        buf[sizeof(buf) - 1] = 0;
680
0
        ptr = buf;
681
0
        while (*ptr != 0) *out++ = *ptr++;
682
0
        cur++;
683
0
        continue;
684
0
    } else if (*cur < 0xE0) {
685
0
                    val = (cur[0]) & 0x1F;
686
0
        val <<= 6;
687
0
        val |= (cur[1]) & 0x3F;
688
0
        l = 2;
689
0
    } else if (*cur < 0xF0) {
690
0
                    val = (cur[0]) & 0x0F;
691
0
        val <<= 6;
692
0
        val |= (cur[1]) & 0x3F;
693
0
        val <<= 6;
694
0
        val |= (cur[2]) & 0x3F;
695
0
        l = 3;
696
0
    } else if (*cur < 0xF8) {
697
0
                    val = (cur[0]) & 0x07;
698
0
        val <<= 6;
699
0
        val |= (cur[1]) & 0x3F;
700
0
        val <<= 6;
701
0
        val |= (cur[2]) & 0x3F;
702
0
        val <<= 6;
703
0
        val |= (cur[3]) & 0x3F;
704
0
        l = 4;
705
0
    }
706
0
    if ((l == 1) || (!IS_CHAR(val))) {
707
0
        xmlEntitiesErr(XML_ERR_INVALID_CHAR,
708
0
      "xmlEncodeEntities: char out of range\n");
709
0
        if (doc != NULL)
710
0
      doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
711
0
        snprintf(buf, sizeof(buf), "&#%d;", *cur);
712
0
        buf[sizeof(buf) - 1] = 0;
713
0
        ptr = buf;
714
0
        while (*ptr != 0) *out++ = *ptr++;
715
0
        cur++;
716
0
        continue;
717
0
    }
718
    /*
719
     * We could do multiple things here. Just save as a char ref
720
     */
721
0
    snprintf(buf, sizeof(buf), "&#x%X;", val);
722
0
    buf[sizeof(buf) - 1] = 0;
723
0
    ptr = buf;
724
0
    while (*ptr != 0) *out++ = *ptr++;
725
0
    cur += l;
726
0
    continue;
727
0
      }
728
0
  } else if (IS_BYTE_CHAR(*cur)) {
729
0
      char buf[11], *ptr;
730
731
0
      snprintf(buf, sizeof(buf), "&#%d;", *cur);
732
0
      buf[sizeof(buf) - 1] = 0;
733
0
            ptr = buf;
734
0
      while (*ptr != 0) *out++ = *ptr++;
735
0
  }
736
0
  cur++;
737
0
    }
738
0
    *out = 0;
739
0
    return(buffer);
740
741
0
mem_error:
742
0
    xmlEntitiesErrMemory("xmlEncodeEntities: realloc failed");
743
0
    xmlFree(buffer);
744
0
    return(NULL);
745
0
}
746
747
/**
748
 * xmlEncodeAttributeEntities:
749
 * @doc:  the document containing the string
750
 * @input:  A string to convert to XML.
751
 *
752
 * Do a global encoding of a string, replacing the predefined entities
753
 * and non ASCII values with their entities and CharRef counterparts for
754
 * attribute values.
755
 *
756
 * Returns A newly allocated string with the substitution done.
757
 */
758
xmlChar *
759
0
xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input) {
760
0
    return xmlEncodeEntitiesInternal(doc, input, 1);
761
0
}
762
763
/**
764
 * xmlEncodeEntitiesReentrant:
765
 * @doc:  the document containing the string
766
 * @input:  A string to convert to XML.
767
 *
768
 * Do a global encoding of a string, replacing the predefined entities
769
 * and non ASCII values with their entities and CharRef counterparts.
770
 * Contrary to xmlEncodeEntities, this routine is reentrant, and result
771
 * must be deallocated.
772
 *
773
 * Returns A newly allocated string with the substitution done.
774
 */
775
xmlChar *
776
0
xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
777
0
    return xmlEncodeEntitiesInternal(doc, input, 0);
778
0
}
779
780
/**
781
 * xmlEncodeSpecialChars:
782
 * @doc:  the document containing the string
783
 * @input:  A string to convert to XML.
784
 *
785
 * Do a global encoding of a string, replacing the predefined entities
786
 * this routine is reentrant, and result must be deallocated.
787
 *
788
 * Returns A newly allocated string with the substitution done.
789
 */
790
xmlChar *
791
0
xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) {
792
0
    const xmlChar *cur = input;
793
0
    xmlChar *buffer = NULL;
794
0
    xmlChar *out = NULL;
795
0
    size_t buffer_size = 0;
796
0
    if (input == NULL) return(NULL);
797
798
    /*
799
     * allocate an translation buffer.
800
     */
801
0
    buffer_size = 1000;
802
0
    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
803
0
    if (buffer == NULL) {
804
0
        xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed");
805
0
  return(NULL);
806
0
    }
807
0
    out = buffer;
808
809
0
    while (*cur != '\0') {
810
0
        size_t indx = out - buffer;
811
0
        if (indx + 10 > buffer_size) {
812
813
0
      growBufferReentrant();
814
0
      out = &buffer[indx];
815
0
  }
816
817
  /*
818
   * By default one have to encode at least '<', '>', '"' and '&' !
819
   */
820
0
  if (*cur == '<') {
821
0
      *out++ = '&';
822
0
      *out++ = 'l';
823
0
      *out++ = 't';
824
0
      *out++ = ';';
825
0
  } else if (*cur == '>') {
826
0
      *out++ = '&';
827
0
      *out++ = 'g';
828
0
      *out++ = 't';
829
0
      *out++ = ';';
830
0
  } else if (*cur == '&') {
831
0
      *out++ = '&';
832
0
      *out++ = 'a';
833
0
      *out++ = 'm';
834
0
      *out++ = 'p';
835
0
      *out++ = ';';
836
0
  } else if (*cur == '"') {
837
0
      *out++ = '&';
838
0
      *out++ = 'q';
839
0
      *out++ = 'u';
840
0
      *out++ = 'o';
841
0
      *out++ = 't';
842
0
      *out++ = ';';
843
0
  } else if (*cur == '\r') {
844
0
      *out++ = '&';
845
0
      *out++ = '#';
846
0
      *out++ = '1';
847
0
      *out++ = '3';
848
0
      *out++ = ';';
849
0
  } else {
850
      /*
851
       * Works because on UTF-8, all extended sequences cannot
852
       * result in bytes in the ASCII range.
853
       */
854
0
      *out++ = *cur;
855
0
  }
856
0
  cur++;
857
0
    }
858
0
    *out = 0;
859
0
    return(buffer);
860
861
0
mem_error:
862
0
    xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed");
863
0
    xmlFree(buffer);
864
0
    return(NULL);
865
0
}
866
867
/**
868
 * xmlCreateEntitiesTable:
869
 *
870
 * create and initialize an empty entities hash table.
871
 * This really doesn't make sense and should be deprecated
872
 *
873
 * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
874
 */
875
xmlEntitiesTablePtr
876
0
xmlCreateEntitiesTable(void) {
877
0
    return((xmlEntitiesTablePtr) xmlHashCreate(0));
878
0
}
879
880
/**
881
 * xmlFreeEntityWrapper:
882
 * @entity:  An entity
883
 * @name:  its name
884
 *
885
 * Deallocate the memory used by an entities in the hash table.
886
 */
887
static void
888
xmlFreeEntityWrapper(xmlEntityPtr entity,
889
0
                 const xmlChar *name ATTRIBUTE_UNUSED) {
890
0
    if (entity != NULL)
891
0
  xmlFreeEntity(entity);
892
0
}
893
894
/**
895
 * xmlFreeEntitiesTable:
896
 * @table:  An entity table
897
 *
898
 * Deallocate the memory used by an entities hash table.
899
 */
900
void
901
0
xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
902
0
    xmlHashFree(table, (xmlHashDeallocator) xmlFreeEntityWrapper);
903
0
}
904
905
#ifdef LIBXML_TREE_ENABLED
906
/**
907
 * xmlCopyEntity:
908
 * @ent:  An entity
909
 *
910
 * Build a copy of an entity
911
 *
912
 * Returns the new xmlEntitiesPtr or NULL in case of error.
913
 */
914
static xmlEntityPtr
915
0
xmlCopyEntity(xmlEntityPtr ent) {
916
0
    xmlEntityPtr cur;
917
918
0
    cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
919
0
    if (cur == NULL) {
920
0
        xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed");
921
0
  return(NULL);
922
0
    }
923
0
    memset(cur, 0, sizeof(xmlEntity));
924
0
    cur->type = XML_ENTITY_DECL;
925
926
0
    cur->etype = ent->etype;
927
0
    if (ent->name != NULL)
928
0
  cur->name = xmlStrdup(ent->name);
929
0
    if (ent->ExternalID != NULL)
930
0
  cur->ExternalID = xmlStrdup(ent->ExternalID);
931
0
    if (ent->SystemID != NULL)
932
0
  cur->SystemID = xmlStrdup(ent->SystemID);
933
0
    if (ent->content != NULL)
934
0
  cur->content = xmlStrdup(ent->content);
935
0
    if (ent->orig != NULL)
936
0
  cur->orig = xmlStrdup(ent->orig);
937
0
    if (ent->URI != NULL)
938
0
  cur->URI = xmlStrdup(ent->URI);
939
0
    return(cur);
940
0
}
941
942
/**
943
 * xmlCopyEntitiesTable:
944
 * @table:  An entity table
945
 *
946
 * Build a copy of an entity table.
947
 *
948
 * Returns the new xmlEntitiesTablePtr or NULL in case of error.
949
 */
950
xmlEntitiesTablePtr
951
0
xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
952
0
    return(xmlHashCopy(table, (xmlHashCopier) xmlCopyEntity));
953
0
}
954
#endif /* LIBXML_TREE_ENABLED */
955
956
#ifdef LIBXML_OUTPUT_ENABLED
957
958
/**
959
 * xmlDumpEntityContent:
960
 * @buf:  An XML buffer.
961
 * @content:  The entity content.
962
 *
963
 * This will dump the quoted string value, taking care of the special
964
 * treatment required by %
965
 */
966
static void
967
0
xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) {
968
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
969
0
    if (xmlStrchr(content, '%')) {
970
0
        const xmlChar * base, *cur;
971
972
0
  xmlBufferCCat(buf, "\"");
973
0
  base = cur = content;
974
0
  while (*cur != 0) {
975
0
      if (*cur == '"') {
976
0
    if (base != cur)
977
0
        xmlBufferAdd(buf, base, cur - base);
978
0
    xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
979
0
    cur++;
980
0
    base = cur;
981
0
      } else if (*cur == '%') {
982
0
    if (base != cur)
983
0
        xmlBufferAdd(buf, base, cur - base);
984
0
    xmlBufferAdd(buf, BAD_CAST "&#x25;", 6);
985
0
    cur++;
986
0
    base = cur;
987
0
      } else {
988
0
    cur++;
989
0
      }
990
0
  }
991
0
  if (base != cur)
992
0
      xmlBufferAdd(buf, base, cur - base);
993
0
  xmlBufferCCat(buf, "\"");
994
0
    } else {
995
0
        xmlBufferWriteQuotedString(buf, content);
996
0
    }
997
0
}
998
999
/**
1000
 * xmlDumpEntityDecl:
1001
 * @buf:  An XML buffer.
1002
 * @ent:  An entity table
1003
 *
1004
 * This will dump the content of the entity table as an XML DTD definition
1005
 */
1006
void
1007
0
xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
1008
0
    if ((buf == NULL) || (ent == NULL)) return;
1009
0
    switch (ent->etype) {
1010
0
  case XML_INTERNAL_GENERAL_ENTITY:
1011
0
      xmlBufferWriteChar(buf, "<!ENTITY ");
1012
0
      xmlBufferWriteCHAR(buf, ent->name);
1013
0
      xmlBufferWriteChar(buf, " ");
1014
0
      if (ent->orig != NULL)
1015
0
    xmlBufferWriteQuotedString(buf, ent->orig);
1016
0
      else
1017
0
    xmlDumpEntityContent(buf, ent->content);
1018
0
      xmlBufferWriteChar(buf, ">\n");
1019
0
      break;
1020
0
  case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1021
0
      xmlBufferWriteChar(buf, "<!ENTITY ");
1022
0
      xmlBufferWriteCHAR(buf, ent->name);
1023
0
      if (ent->ExternalID != NULL) {
1024
0
     xmlBufferWriteChar(buf, " PUBLIC ");
1025
0
     xmlBufferWriteQuotedString(buf, ent->ExternalID);
1026
0
     xmlBufferWriteChar(buf, " ");
1027
0
     xmlBufferWriteQuotedString(buf, ent->SystemID);
1028
0
      } else {
1029
0
     xmlBufferWriteChar(buf, " SYSTEM ");
1030
0
     xmlBufferWriteQuotedString(buf, ent->SystemID);
1031
0
      }
1032
0
      xmlBufferWriteChar(buf, ">\n");
1033
0
      break;
1034
0
  case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1035
0
      xmlBufferWriteChar(buf, "<!ENTITY ");
1036
0
      xmlBufferWriteCHAR(buf, ent->name);
1037
0
      if (ent->ExternalID != NULL) {
1038
0
     xmlBufferWriteChar(buf, " PUBLIC ");
1039
0
     xmlBufferWriteQuotedString(buf, ent->ExternalID);
1040
0
     xmlBufferWriteChar(buf, " ");
1041
0
     xmlBufferWriteQuotedString(buf, ent->SystemID);
1042
0
      } else {
1043
0
     xmlBufferWriteChar(buf, " SYSTEM ");
1044
0
     xmlBufferWriteQuotedString(buf, ent->SystemID);
1045
0
      }
1046
0
      if (ent->content != NULL) { /* Should be true ! */
1047
0
    xmlBufferWriteChar(buf, " NDATA ");
1048
0
    if (ent->orig != NULL)
1049
0
        xmlBufferWriteCHAR(buf, ent->orig);
1050
0
    else
1051
0
        xmlBufferWriteCHAR(buf, ent->content);
1052
0
      }
1053
0
      xmlBufferWriteChar(buf, ">\n");
1054
0
      break;
1055
0
  case XML_INTERNAL_PARAMETER_ENTITY:
1056
0
      xmlBufferWriteChar(buf, "<!ENTITY % ");
1057
0
      xmlBufferWriteCHAR(buf, ent->name);
1058
0
      xmlBufferWriteChar(buf, " ");
1059
0
      if (ent->orig == NULL)
1060
0
    xmlDumpEntityContent(buf, ent->content);
1061
0
      else
1062
0
    xmlBufferWriteQuotedString(buf, ent->orig);
1063
0
      xmlBufferWriteChar(buf, ">\n");
1064
0
      break;
1065
0
  case XML_EXTERNAL_PARAMETER_ENTITY:
1066
0
      xmlBufferWriteChar(buf, "<!ENTITY % ");
1067
0
      xmlBufferWriteCHAR(buf, ent->name);
1068
0
      if (ent->ExternalID != NULL) {
1069
0
     xmlBufferWriteChar(buf, " PUBLIC ");
1070
0
     xmlBufferWriteQuotedString(buf, ent->ExternalID);
1071
0
     xmlBufferWriteChar(buf, " ");
1072
0
     xmlBufferWriteQuotedString(buf, ent->SystemID);
1073
0
      } else {
1074
0
     xmlBufferWriteChar(buf, " SYSTEM ");
1075
0
     xmlBufferWriteQuotedString(buf, ent->SystemID);
1076
0
      }
1077
0
      xmlBufferWriteChar(buf, ">\n");
1078
0
      break;
1079
0
  default:
1080
0
      xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY,
1081
0
    "xmlDumpEntitiesDecl: internal: unknown type entity type");
1082
0
    }
1083
0
}
1084
1085
/**
1086
 * xmlDumpEntityDeclScan:
1087
 * @ent:  An entity table
1088
 * @buf:  An XML buffer.
1089
 *
1090
 * When using the hash table scan function, arguments need to be reversed
1091
 */
1092
static void
1093
0
xmlDumpEntityDeclScan(xmlEntityPtr ent, xmlBufferPtr buf) {
1094
0
    xmlDumpEntityDecl(buf, ent);
1095
0
}
1096
1097
/**
1098
 * xmlDumpEntitiesTable:
1099
 * @buf:  An XML buffer.
1100
 * @table:  An entity table
1101
 *
1102
 * This will dump the content of the entity table as an XML DTD definition
1103
 */
1104
void
1105
0
xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
1106
0
    xmlHashScan(table, (xmlHashScanner)xmlDumpEntityDeclScan, buf);
1107
0
}
1108
#endif /* LIBXML_OUTPUT_ENABLED */
1109
#define bottom_entities
1110
#include "elfgcchack.h"