1 /* 2 * entities.c : implementation for the XML entities handling 3 * 4 * See Copyright for the status of this software. 5 * 6 * daniel (at) 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 * Bjrn Reese <br (at) 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 """, 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 "%", 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" 1023