~ubuntu-branches/ubuntu/saucy/libxml2/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/0004-Fix-entities-local-buffers-size-problems.patch/entities.c

  • Committer: Package Import Robot
  • Author(s): Aron Xu, Daniel Veillard
  • Date: 2012-07-19 17:11:09 UTC
  • mfrom: (43.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20120719171109-ehl65767otr4mdwj
Tags: 2.8.0+dfsg1-5
[ Daniel Veillard ]
* Fix parser local buffers size problems
* Fix entities local buffers size problems
CVE-2012-2807, Closes: #679280.

Show diffs side-by-side

added added

removed removed

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