Coverage Report

Created: 2025-07-18 06:08

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