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 { 81 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); 82 } 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 { 94 __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL); 95 } 96 97 /* 98 * xmlFreeEntity : clean-up an entity record. 99 */ 100 static void 101 xmlFreeEntity(xmlEntityPtr entity) 102 { 103 xmlDictPtr dict = NULL; 104 105 if (entity == NULL) 106 return; 107 108 if (entity->doc != NULL) 109 dict = entity->doc->dict; 110 111 112 if ((entity->children) && (entity->owner == 1) && 113 (entity == (xmlEntityPtr) entity->children->parent)) 114 xmlFreeNodeList(entity->children); 115 if (dict != NULL) { 116 if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name))) 117 xmlFree((char *) entity->name); 118 if ((entity->ExternalID != NULL) && 119 (!xmlDictOwns(dict, entity->ExternalID))) 120 xmlFree((char *) entity->ExternalID); 121 if ((entity->SystemID != NULL) && 122 (!xmlDictOwns(dict, entity->SystemID))) 123 xmlFree((char *) entity->SystemID); 124 if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI))) 125 xmlFree((char *) entity->URI); 126 if ((entity->content != NULL) 127 && (!xmlDictOwns(dict, entity->content))) 128 xmlFree((char *) entity->content); 129 if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig))) 130 xmlFree((char *) entity->orig); 131 } else { 132 if (entity->name != NULL) 133 xmlFree((char *) entity->name); 134 if (entity->ExternalID != NULL) 135 xmlFree((char *) entity->ExternalID); 136 if (entity->SystemID != NULL) 137 xmlFree((char *) entity->SystemID); 138 if (entity->URI != NULL) 139 xmlFree((char *) entity->URI); 140 if (entity->content != NULL) 141 xmlFree((char *) entity->content); 142 if (entity->orig != NULL) 143 xmlFree((char *) entity->orig); 144 } 145 xmlFree(entity); 146 } 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 const xmlChar *content) { 157 xmlEntityPtr ret; 158 159 ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); 160 if (ret == NULL) { 161 xmlEntitiesErrMemory("xmlCreateEntity: malloc failed"); 162 return(NULL); 163 } 164 memset(ret, 0, sizeof(xmlEntity)); 165 ret->type = XML_ENTITY_DECL; 166 ret->checked = 0; 167 168 /* 169 * fill the structure. 170 */ 171 ret->etype = (xmlEntityType) type; 172 if (dict == NULL) { 173 ret->name = xmlStrdup(name); 174 if (ExternalID != NULL) 175 ret->ExternalID = xmlStrdup(ExternalID); 176 if (SystemID != NULL) 177 ret->SystemID = xmlStrdup(SystemID); 178 } else { 179 ret->name = xmlDictLookup(dict, name, -1); 180 if (ExternalID != NULL) 181 ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); 182 if (SystemID != NULL) 183 ret->SystemID = xmlDictLookup(dict, SystemID, -1); 184 } 185 if (content != NULL) { 186 ret->length = xmlStrlen(content); 187 if ((dict != NULL) && (ret->length < 5)) 188 ret->content = (xmlChar *) 189 xmlDictLookup(dict, content, ret->length); 190 else 191 ret->content = xmlStrndup(content, ret->length); 192 } else { 193 ret->length = 0; 194 ret->content = NULL; 195 } 196 ret->URI = NULL; /* to be computed by the layer knowing 197 the defining entity */ 198 ret->orig = NULL; 199 ret->owner = 0; 200 201 return(ret); 202 } 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 const xmlChar *content) { 211 xmlDictPtr dict = NULL; 212 xmlEntitiesTablePtr table = NULL; 213 xmlEntityPtr ret; 214 215 if (name == NULL) 216 return(NULL); 217 if (dtd == NULL) 218 return(NULL); 219 if (dtd->doc != NULL) 220 dict = dtd->doc->dict; 221 222 switch (type) { 223 case XML_INTERNAL_GENERAL_ENTITY: 224 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 225 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 226 if (dtd->entities == NULL) 227 dtd->entities = xmlHashCreateDict(0, dict); 228 table = dtd->entities; 229 break; 230 case XML_INTERNAL_PARAMETER_ENTITY: 231 case XML_EXTERNAL_PARAMETER_ENTITY: 232 if (dtd->pentities == NULL) 233 dtd->pentities = xmlHashCreateDict(0, dict); 234 table = dtd->pentities; 235 break; 236 case XML_INTERNAL_PREDEFINED_ENTITY: 237 return(NULL); 238 } 239 if (table == NULL) 240 return(NULL); 241 ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); 242 if (ret == NULL) 243 return(NULL); 244 ret->doc = dtd->doc; 245 246 if (xmlHashAddEntry(table, name, ret)) { 247 /* 248 * entity was already defined at another level. 249 */ 250 xmlFreeEntity(ret); 251 return(NULL); 252 } 253 return(ret); 254 } 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 xmlGetPredefinedEntity(const xmlChar *name) { 266 if (name == NULL) return(NULL); 267 switch (name[0]) { 268 case 'l': 269 if (xmlStrEqual(name, BAD_CAST "lt")) 270 return(&xmlEntityLt); 271 break; 272 case 'g': 273 if (xmlStrEqual(name, BAD_CAST "gt")) 274 return(&xmlEntityGt); 275 break; 276 case 'a': 277 if (xmlStrEqual(name, BAD_CAST "amp")) 278 return(&xmlEntityAmp); 279 if (xmlStrEqual(name, BAD_CAST "apos")) 280 return(&xmlEntityApos); 281 break; 282 case 'q': 283 if (xmlStrEqual(name, BAD_CAST "quot")) 284 return(&xmlEntityQuot); 285 break; 286 default: 287 break; 288 } 289 return(NULL); 290 } 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 const xmlChar *content) { 309 xmlEntityPtr ret; 310 xmlDtdPtr dtd; 311 312 if (doc == NULL) { 313 xmlEntitiesErr(XML_DTD_NO_DOC, 314 "xmlAddDtdEntity: document is NULL"); 315 return(NULL); 316 } 317 if (doc->extSubset == NULL) { 318 xmlEntitiesErr(XML_DTD_NO_DTD, 319 "xmlAddDtdEntity: document without external subset"); 320 return(NULL); 321 } 322 dtd = doc->extSubset; 323 ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content); 324 if (ret == NULL) return(NULL); 325 326 /* 327 * Link it to the DTD 328 */ 329 ret->parent = dtd; 330 ret->doc = dtd->doc; 331 if (dtd->last == NULL) { 332 dtd->children = dtd->last = (xmlNodePtr) ret; 333 } else { 334 dtd->last->next = (xmlNodePtr) ret; 335 ret->prev = dtd->last; 336 dtd->last = (xmlNodePtr) ret; 337 } 338 return(ret); 339 } 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 const xmlChar *content) { 358 xmlEntityPtr ret; 359 xmlDtdPtr dtd; 360 361 if (doc == NULL) { 362 xmlEntitiesErr(XML_DTD_NO_DOC, 363 "xmlAddDocEntity: document is NULL"); 364 return(NULL); 365 } 366 if (doc->intSubset == NULL) { 367 xmlEntitiesErr(XML_DTD_NO_DTD, 368 "xmlAddDocEntity: document without internal subset"); 369 return(NULL); 370 } 371 dtd = doc->intSubset; 372 ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content); 373 if (ret == NULL) return(NULL); 374 375 /* 376 * Link it to the DTD 377 */ 378 ret->parent = dtd; 379 ret->doc = dtd->doc; 380 if (dtd->last == NULL) { 381 dtd->children = dtd->last = (xmlNodePtr) ret; 382 } else { 383 dtd->last->next = (xmlNodePtr) ret; 384 ret->prev = dtd->last; 385 dtd->last = (xmlNodePtr) ret; 386 } 387 return(ret); 388 } 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 const xmlChar *content) { 411 xmlEntityPtr ret; 412 xmlDictPtr dict; 413 414 if ((doc != NULL) && (doc->intSubset != NULL)) { 415 return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content)); 416 } 417 if (doc != NULL) 418 dict = doc->dict; 419 else 420 dict = NULL; 421 ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); 422 if (ret == NULL) 423 return(NULL); 424 ret->doc = doc; 425 return(ret); 426 } 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 xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) { 441 return((xmlEntityPtr) xmlHashLookup(table, name)); 442 } 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 xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) { 456 xmlEntitiesTablePtr table; 457 xmlEntityPtr ret; 458 459 if (doc == NULL) 460 return(NULL); 461 if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) { 462 table = (xmlEntitiesTablePtr) doc->intSubset->pentities; 463 ret = xmlGetEntityFromTable(table, name); 464 if (ret != NULL) 465 return(ret); 466 } 467 if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) { 468 table = (xmlEntitiesTablePtr) doc->extSubset->pentities; 469 return(xmlGetEntityFromTable(table, name)); 470 } 471 return(NULL); 472 } 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 xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) { 487 xmlEntitiesTablePtr table; 488 489 if (doc == NULL) 490 return(NULL); 491 if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { 492 table = (xmlEntitiesTablePtr) doc->extSubset->entities; 493 return(xmlGetEntityFromTable(table, name)); 494 } 495 return(NULL); 496 } 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 xmlGetDocEntity(const xmlDoc *doc, const xmlChar *name) { 511 xmlEntityPtr cur; 512 xmlEntitiesTablePtr table; 513 514 if (doc != NULL) { 515 if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) { 516 table = (xmlEntitiesTablePtr) doc->intSubset->entities; 517 cur = xmlGetEntityFromTable(table, name); 518 if (cur != NULL) 519 return(cur); 520 } 521 if (doc->standalone != 1) { 522 if ((doc->extSubset != NULL) && 523 (doc->extSubset->entities != NULL)) { 524 table = (xmlEntitiesTablePtr) doc->extSubset->entities; 525 cur = xmlGetEntityFromTable(table, name); 526 if (cur != NULL) 527 return(cur); 528 } 529 } 530 } 531 return(xmlGetPredefinedEntity(name)); 532 } 533 534 /* 535 * Macro used to grow the current buffer. 536 */ 537 #define growBufferReentrant() { \ 538 xmlChar *tmp; \ 539 size_t new_size = buffer_size * 2; \ 540 if (new_size < buffer_size) goto mem_error; \ 541 tmp = (xmlChar *) xmlRealloc(buffer, new_size); \ 542 if (tmp == NULL) goto mem_error; \ 543 buffer = tmp; \ 544 buffer_size = new_size; \ 545 } 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 xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { 562 const xmlChar *cur = input; 563 xmlChar *buffer = NULL; 564 xmlChar *out = NULL; 565 size_t buffer_size = 0; 566 int html = 0; 567 568 if (input == NULL) return(NULL); 569 if (doc != NULL) 570 html = (doc->type == XML_HTML_DOCUMENT_NODE); 571 572 /* 573 * allocate an translation buffer. 574 */ 575 buffer_size = 1000; 576 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar)); 577 if (buffer == NULL) { 578 xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed"); 579 return(NULL); 580 } 581 out = buffer; 582 583 while (*cur != '\0') { 584 size_t indx = out - buffer; 585 if (indx + 100 > buffer_size) { 586 587 growBufferReentrant(); 588 out = &buffer[indx]; 589 } 590 591 /* 592 * By default one have to encode at least '<', '>', '"' and '&' ! 593 */ 594 if (*cur == '<') { 595 const xmlChar *end; 596 597 /* 598 * Special handling of server side include in HTML attributes 599 */ 600 if (html && attr && 601 (cur[1] == '!') && (cur[2] == '-') && (cur[3] == '-') && 602 ((end = xmlStrstr(cur, BAD_CAST "-->")) != NULL)) { 603 while (cur != end) { 604 *out++ = *cur++; 605 indx = out - buffer; 606 if (indx + 100 > buffer_size) { 607 growBufferReentrant(); 608 out = &buffer[indx]; 609 } 610 } 611 *out++ = *cur++; 612 *out++ = *cur++; 613 *out++ = *cur++; 614 continue; 615 } 616 *out++ = '&'; 617 *out++ = 'l'; 618 *out++ = 't'; 619 *out++ = ';'; 620 } else if (*cur == '>') { 621 *out++ = '&'; 622 *out++ = 'g'; 623 *out++ = 't'; 624 *out++ = ';'; 625 } 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 if (html && attr && (cur[1] == '{') && 631 (strchr((const char *) cur, '}'))) { 632 while (*cur != '}') { 633 *out++ = *cur++; 634 indx = out - buffer; 635 if (indx + 100 > buffer_size) { 636 growBufferReentrant(); 637 out = &buffer[indx]; 638 } 639 } 640 *out++ = *cur++; 641 continue; 642 } 643 *out++ = '&'; 644 *out++ = 'a'; 645 *out++ = 'm'; 646 *out++ = 'p'; 647 *out++ = ';'; 648 } else if (((*cur >= 0x20) && (*cur < 0x80)) || 649 (*cur == '\n') || (*cur == '\t') || ((html) && (*cur == '\r'))) { 650 /* 651 * default case, just copy ! 652 */ 653 *out++ = *cur; 654 } else if (*cur >= 0x80) { 655 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 *out++ = *cur; 666 } else { 667 /* 668 * We assume we have UTF-8 input. 669 */ 670 char buf[11], *ptr; 671 int val = 0, l = 1; 672 673 if (*cur < 0xC0) { 674 xmlEntitiesErr(XML_CHECK_NOT_UTF8, 675 "xmlEncodeEntities: input not UTF-8"); 676 if (doc != NULL) 677 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 678 snprintf(buf, sizeof(buf), "&#%d;", *cur); 679 buf[sizeof(buf) - 1] = 0; 680 ptr = buf; 681 while (*ptr != 0) *out++ = *ptr++; 682 cur++; 683 continue; 684 } else if (*cur < 0xE0) { 685 val = (cur[0]) & 0x1F; 686 val <<= 6; 687 val |= (cur[1]) & 0x3F; 688 l = 2; 689 } else if (*cur < 0xF0) { 690 val = (cur[0]) & 0x0F; 691 val <<= 6; 692 val |= (cur[1]) & 0x3F; 693 val <<= 6; 694 val |= (cur[2]) & 0x3F; 695 l = 3; 696 } else if (*cur < 0xF8) { 697 val = (cur[0]) & 0x07; 698 val <<= 6; 699 val |= (cur[1]) & 0x3F; 700 val <<= 6; 701 val |= (cur[2]) & 0x3F; 702 val <<= 6; 703 val |= (cur[3]) & 0x3F; 704 l = 4; 705 } 706 if ((l == 1) || (!IS_CHAR(val))) { 707 xmlEntitiesErr(XML_ERR_INVALID_CHAR, 708 "xmlEncodeEntities: char out of range\n"); 709 if (doc != NULL) 710 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 711 snprintf(buf, sizeof(buf), "&#%d;", *cur); 712 buf[sizeof(buf) - 1] = 0; 713 ptr = buf; 714 while (*ptr != 0) *out++ = *ptr++; 715 cur++; 716 continue; 717 } 718 /* 719 * We could do multiple things here. Just save as a char ref 720 */ 721 snprintf(buf, sizeof(buf), "&#x%X;", val); 722 buf[sizeof(buf) - 1] = 0; 723 ptr = buf; 724 while (*ptr != 0) *out++ = *ptr++; 725 cur += l; 726 continue; 727 } 728 } else if (IS_BYTE_CHAR(*cur)) { 729 char buf[11], *ptr; 730 731 snprintf(buf, sizeof(buf), "&#%d;", *cur); 732 buf[sizeof(buf) - 1] = 0; 733 ptr = buf; 734 while (*ptr != 0) *out++ = *ptr++; 735 } 736 cur++; 737 } 738 *out = 0; 739 return(buffer); 740 741 mem_error: 742 xmlEntitiesErrMemory("xmlEncodeEntities: realloc failed"); 743 xmlFree(buffer); 744 return(NULL); 745 } 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 xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input) { 760 return xmlEncodeEntitiesInternal(doc, input, 1); 761 } 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 xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) { 777 return xmlEncodeEntitiesInternal(doc, input, 0); 778 } 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 xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) { 792 const xmlChar *cur = input; 793 xmlChar *buffer = NULL; 794 xmlChar *out = NULL; 795 size_t buffer_size = 0; 796 if (input == NULL) return(NULL); 797 798 /* 799 * allocate an translation buffer. 800 */ 801 buffer_size = 1000; 802 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar)); 803 if (buffer == NULL) { 804 xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed"); 805 return(NULL); 806 } 807 out = buffer; 808 809 while (*cur != '\0') { 810 size_t indx = out - buffer; 811 if (indx + 10 > buffer_size) { 812 813 growBufferReentrant(); 814 out = &buffer[indx]; 815 } 816 817 /* 818 * By default one have to encode at least '<', '>', '"' and '&' ! 819 */ 820 if (*cur == '<') { 821 *out++ = '&'; 822 *out++ = 'l'; 823 *out++ = 't'; 824 *out++ = ';'; 825 } else if (*cur == '>') { 826 *out++ = '&'; 827 *out++ = 'g'; 828 *out++ = 't'; 829 *out++ = ';'; 830 } else if (*cur == '&') { 831 *out++ = '&'; 832 *out++ = 'a'; 833 *out++ = 'm'; 834 *out++ = 'p'; 835 *out++ = ';'; 836 } else if (*cur == '"') { 837 *out++ = '&'; 838 *out++ = 'q'; 839 *out++ = 'u'; 840 *out++ = 'o'; 841 *out++ = 't'; 842 *out++ = ';'; 843 } else if (*cur == '\r') { 844 *out++ = '&'; 845 *out++ = '#'; 846 *out++ = '1'; 847 *out++ = '3'; 848 *out++ = ';'; 849 } else { 850 /* 851 * Works because on UTF-8, all extended sequences cannot 852 * result in bytes in the ASCII range. 853 */ 854 *out++ = *cur; 855 } 856 cur++; 857 } 858 *out = 0; 859 return(buffer); 860 861 mem_error: 862 xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed"); 863 xmlFree(buffer); 864 return(NULL); 865 } 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 xmlCreateEntitiesTable(void) { 877 return((xmlEntitiesTablePtr) xmlHashCreate(0)); 878 } 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(void *entity, const xmlChar *name ATTRIBUTE_UNUSED) { 889 if (entity != NULL) 890 xmlFreeEntity((xmlEntityPtr) entity); 891 } 892 893 /** 894 * xmlFreeEntitiesTable: 895 * @table: An entity table 896 * 897 * Deallocate the memory used by an entities hash table. 898 */ 899 void 900 xmlFreeEntitiesTable(xmlEntitiesTablePtr table) { 901 xmlHashFree(table, xmlFreeEntityWrapper); 902 } 903 904 #ifdef LIBXML_TREE_ENABLED 905 /** 906 * xmlCopyEntity: 907 * @ent: An entity 908 * 909 * Build a copy of an entity 910 * 911 * Returns the new xmlEntitiesPtr or NULL in case of error. 912 */ 913 static void * 914 xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { 915 xmlEntityPtr ent = (xmlEntityPtr) payload; 916 xmlEntityPtr cur; 917 918 cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); 919 if (cur == NULL) { 920 xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed"); 921 return(NULL); 922 } 923 memset(cur, 0, sizeof(xmlEntity)); 924 cur->type = XML_ENTITY_DECL; 925 926 cur->etype = ent->etype; 927 if (ent->name != NULL) 928 cur->name = xmlStrdup(ent->name); 929 if (ent->ExternalID != NULL) 930 cur->ExternalID = xmlStrdup(ent->ExternalID); 931 if (ent->SystemID != NULL) 932 cur->SystemID = xmlStrdup(ent->SystemID); 933 if (ent->content != NULL) 934 cur->content = xmlStrdup(ent->content); 935 if (ent->orig != NULL) 936 cur->orig = xmlStrdup(ent->orig); 937 if (ent->URI != NULL) 938 cur->URI = xmlStrdup(ent->URI); 939 return(cur); 940 } 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 xmlCopyEntitiesTable(xmlEntitiesTablePtr table) { 952 return(xmlHashCopy(table, xmlCopyEntity)); 953 } 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 xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) { 968 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 969 if (xmlStrchr(content, '%')) { 970 const xmlChar * base, *cur; 971 972 xmlBufferCCat(buf, "\""); 973 base = cur = content; 974 while (*cur != 0) { 975 if (*cur == '"') { 976 if (base != cur) 977 xmlBufferAdd(buf, base, cur - base); 978 xmlBufferAdd(buf, BAD_CAST """, 6); 979 cur++; 980 base = cur; 981 } else if (*cur == '%') { 982 if (base != cur) 983 xmlBufferAdd(buf, base, cur - base); 984 xmlBufferAdd(buf, BAD_CAST "%", 6); 985 cur++; 986 base = cur; 987 } else { 988 cur++; 989 } 990 } 991 if (base != cur) 992 xmlBufferAdd(buf, base, cur - base); 993 xmlBufferCCat(buf, "\""); 994 } else { 995 xmlBufferWriteQuotedString(buf, content); 996 } 997 } 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 xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) { 1008 if ((buf == NULL) || (ent == NULL)) return; 1009 switch (ent->etype) { 1010 case XML_INTERNAL_GENERAL_ENTITY: 1011 xmlBufferWriteChar(buf, "<!ENTITY "); 1012 xmlBufferWriteCHAR(buf, ent->name); 1013 xmlBufferWriteChar(buf, " "); 1014 if (ent->orig != NULL) 1015 xmlBufferWriteQuotedString(buf, ent->orig); 1016 else 1017 xmlDumpEntityContent(buf, ent->content); 1018 xmlBufferWriteChar(buf, ">\n"); 1019 break; 1020 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 1021 xmlBufferWriteChar(buf, "<!ENTITY "); 1022 xmlBufferWriteCHAR(buf, ent->name); 1023 if (ent->ExternalID != NULL) { 1024 xmlBufferWriteChar(buf, " PUBLIC "); 1025 xmlBufferWriteQuotedString(buf, ent->ExternalID); 1026 xmlBufferWriteChar(buf, " "); 1027 xmlBufferWriteQuotedString(buf, ent->SystemID); 1028 } else { 1029 xmlBufferWriteChar(buf, " SYSTEM "); 1030 xmlBufferWriteQuotedString(buf, ent->SystemID); 1031 } 1032 xmlBufferWriteChar(buf, ">\n"); 1033 break; 1034 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 1035 xmlBufferWriteChar(buf, "<!ENTITY "); 1036 xmlBufferWriteCHAR(buf, ent->name); 1037 if (ent->ExternalID != NULL) { 1038 xmlBufferWriteChar(buf, " PUBLIC "); 1039 xmlBufferWriteQuotedString(buf, ent->ExternalID); 1040 xmlBufferWriteChar(buf, " "); 1041 xmlBufferWriteQuotedString(buf, ent->SystemID); 1042 } else { 1043 xmlBufferWriteChar(buf, " SYSTEM "); 1044 xmlBufferWriteQuotedString(buf, ent->SystemID); 1045 } 1046 if (ent->content != NULL) { /* Should be true ! */ 1047 xmlBufferWriteChar(buf, " NDATA "); 1048 if (ent->orig != NULL) 1049 xmlBufferWriteCHAR(buf, ent->orig); 1050 else 1051 xmlBufferWriteCHAR(buf, ent->content); 1052 } 1053 xmlBufferWriteChar(buf, ">\n"); 1054 break; 1055 case XML_INTERNAL_PARAMETER_ENTITY: 1056 xmlBufferWriteChar(buf, "<!ENTITY % "); 1057 xmlBufferWriteCHAR(buf, ent->name); 1058 xmlBufferWriteChar(buf, " "); 1059 if (ent->orig == NULL) 1060 xmlDumpEntityContent(buf, ent->content); 1061 else 1062 xmlBufferWriteQuotedString(buf, ent->orig); 1063 xmlBufferWriteChar(buf, ">\n"); 1064 break; 1065 case XML_EXTERNAL_PARAMETER_ENTITY: 1066 xmlBufferWriteChar(buf, "<!ENTITY % "); 1067 xmlBufferWriteCHAR(buf, ent->name); 1068 if (ent->ExternalID != NULL) { 1069 xmlBufferWriteChar(buf, " PUBLIC "); 1070 xmlBufferWriteQuotedString(buf, ent->ExternalID); 1071 xmlBufferWriteChar(buf, " "); 1072 xmlBufferWriteQuotedString(buf, ent->SystemID); 1073 } else { 1074 xmlBufferWriteChar(buf, " SYSTEM "); 1075 xmlBufferWriteQuotedString(buf, ent->SystemID); 1076 } 1077 xmlBufferWriteChar(buf, ">\n"); 1078 break; 1079 default: 1080 xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY, 1081 "xmlDumpEntitiesDecl: internal: unknown type entity type"); 1082 } 1083 } 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 xmlDumpEntityDeclScan(void *ent, void *buf, 1094 const xmlChar *name ATTRIBUTE_UNUSED) { 1095 xmlDumpEntityDecl((xmlBufferPtr) buf, (xmlEntityPtr) ent); 1096 } 1097 1098 /** 1099 * xmlDumpEntitiesTable: 1100 * @buf: An XML buffer. 1101 * @table: An entity table 1102 * 1103 * This will dump the content of the entity table as an XML DTD definition 1104 */ 1105 void 1106 xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) { 1107 xmlHashScan(table, xmlDumpEntityDeclScan, buf); 1108 } 1109 #endif /* LIBXML_OUTPUT_ENABLED */ 1110 #define bottom_entities 1111 #include "elfgcchack.h" 1112