catalog.c revision a9cce9cd0d7aff3ec318b5d8d376da131b6aaad4
1/** 2 * catalog.c: set of generic Catalog related routines 3 * 4 * Reference: SGML Open Technical Resolution TR9401:1997. 5 * http://www.jclark.com/sp/catalog.htm 6 * 7 * XML Catalogs Working Draft 06 August 2001 8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 9 * 10 * See Copyright for the status of this software. 11 * 12 * Daniel.Veillard@imag.fr 13 */ 14 15#define IN_LIBXML 16#include "libxml.h" 17 18#ifdef LIBXML_CATALOG_ENABLED 19#ifdef HAVE_SYS_TYPES_H 20#include <sys/types.h> 21#endif 22#ifdef HAVE_SYS_STAT_H 23#include <sys/stat.h> 24#endif 25#ifdef HAVE_UNISTD_H 26#include <unistd.h> 27#endif 28#ifdef HAVE_FCNTL_H 29#include <fcntl.h> 30#endif 31#ifdef HAVE_STDLIB_H 32#include <stdlib.h> 33#endif 34#include <string.h> 35#include <libxml/xmlmemory.h> 36#include <libxml/hash.h> 37#include <libxml/uri.h> 38#include <libxml/parserInternals.h> 39#include <libxml/catalog.h> 40#include <libxml/xmlerror.h> 41#include <libxml/threads.h> 42#include <libxml/globals.h> 43 44#define MAX_DELEGATE 50 45#define MAX_CATAL_DEPTH 50 46 47/** 48 * TODO: 49 * 50 * macro to flag unimplemented blocks 51 * XML_CATALOG_PREFER user env to select between system/public prefered 52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk> 53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with 54 *> values "system" and "public". I have made the default be "system" to 55 *> match yours. 56 */ 57#define TODO \ 58 xmlGenericError(xmlGenericErrorContext, \ 59 "Unimplemented block at %s:%d\n", \ 60 __FILE__, __LINE__); 61 62#define XML_URN_PUBID "urn:publicid:" 63#define XML_CATAL_BREAK ((xmlChar *) -1) 64#ifndef XML_XML_DEFAULT_CATALOG 65#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" 66#endif 67#ifndef XML_SGML_DEFAULT_CATALOG 68#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog" 69#endif 70 71static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename); 72 73/************************************************************************ 74 * * 75 * Types, all private * 76 * * 77 ************************************************************************/ 78 79typedef enum { 80 XML_CATA_REMOVED = -1, 81 XML_CATA_NONE = 0, 82 XML_CATA_CATALOG, 83 XML_CATA_BROKEN_CATALOG, 84 XML_CATA_NEXT_CATALOG, 85 XML_CATA_PUBLIC, 86 XML_CATA_SYSTEM, 87 XML_CATA_REWRITE_SYSTEM, 88 XML_CATA_DELEGATE_PUBLIC, 89 XML_CATA_DELEGATE_SYSTEM, 90 XML_CATA_URI, 91 XML_CATA_REWRITE_URI, 92 XML_CATA_DELEGATE_URI, 93 SGML_CATA_SYSTEM, 94 SGML_CATA_PUBLIC, 95 SGML_CATA_ENTITY, 96 SGML_CATA_PENTITY, 97 SGML_CATA_DOCTYPE, 98 SGML_CATA_LINKTYPE, 99 SGML_CATA_NOTATION, 100 SGML_CATA_DELEGATE, 101 SGML_CATA_BASE, 102 SGML_CATA_CATALOG, 103 SGML_CATA_DOCUMENT, 104 SGML_CATA_SGMLDECL 105} xmlCatalogEntryType; 106 107typedef struct _xmlCatalogEntry xmlCatalogEntry; 108typedef xmlCatalogEntry *xmlCatalogEntryPtr; 109struct _xmlCatalogEntry { 110 struct _xmlCatalogEntry *next; 111 struct _xmlCatalogEntry *parent; 112 struct _xmlCatalogEntry *children; 113 xmlCatalogEntryType type; 114 xmlChar *name; 115 xmlChar *value; 116 xmlChar *URL; /* The expanded URL using the base */ 117 xmlCatalogPrefer prefer; 118 int dealloc; 119 int depth; 120}; 121 122typedef enum { 123 XML_XML_CATALOG_TYPE = 1, 124 XML_SGML_CATALOG_TYPE 125} xmlCatalogType; 126 127#define XML_MAX_SGML_CATA_DEPTH 10 128struct _xmlCatalog { 129 xmlCatalogType type; /* either XML or SGML */ 130 131 /* 132 * SGML Catalogs are stored as a simple hash table of catalog entries 133 * Catalog stack to check against overflows when building the 134 * SGML catalog 135 */ 136 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */ 137 int catalNr; /* Number of current catal streams */ 138 int catalMax; /* Max number of catal streams */ 139 xmlHashTablePtr sgml; 140 141 /* 142 * XML Catalogs are stored as a tree of Catalog entries 143 */ 144 xmlCatalogPrefer prefer; 145 xmlCatalogEntryPtr xml; 146}; 147 148/************************************************************************ 149 * * 150 * Global variables * 151 * * 152 ************************************************************************/ 153 154/* 155 * Those are preferences 156 */ 157static int xmlDebugCatalogs = 0; /* used for debugging */ 158static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL; 159static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC; 160 161/* 162 * Hash table containing all the trees of XML catalogs parsed by 163 * the application. 164 */ 165static xmlHashTablePtr xmlCatalogXMLFiles = NULL; 166 167/* 168 * The default catalog in use by the application 169 */ 170static xmlCatalogPtr xmlDefaultCatalog = NULL; 171 172/* 173 * A mutex for modifying the shared global catalog(s) 174 * xmlDefaultCatalog tree. 175 * It also protects xmlCatalogXMLFiles 176 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile() 177 */ 178static xmlRMutexPtr xmlCatalogMutex = NULL; 179 180/* 181 * Whether the catalog support was initialized. 182 */ 183static int xmlCatalogInitialized = 0; 184 185 186/************************************************************************ 187 * * 188 * Allocation and Freeing * 189 * * 190 ************************************************************************/ 191 192/** 193 * xmlNewCatalogEntry: 194 * @type: type of entry 195 * @name: name of the entry 196 * @value: value of the entry 197 * @prefer: the PUBLIC vs. SYSTEM current preference value 198 * 199 * create a new Catalog entry, this type is shared both by XML and 200 * SGML catalogs, but the acceptable types values differs. 201 * 202 * Returns the xmlCatalogEntryPtr or NULL in case of error 203 */ 204static xmlCatalogEntryPtr 205xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name, 206 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) { 207 xmlCatalogEntryPtr ret; 208 209 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); 210 if (ret == NULL) { 211 xmlGenericError(xmlGenericErrorContext, 212 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry)); 213 return(NULL); 214 } 215 ret->next = NULL; 216 ret->parent = NULL; 217 ret->children = NULL; 218 ret->type = type; 219 if (name != NULL) 220 ret->name = xmlStrdup(name); 221 else 222 ret->name = NULL; 223 if (value != NULL) 224 ret->value = xmlStrdup(value); 225 else 226 ret->value = NULL; 227 if (URL == NULL) 228 URL = value; 229 if (URL != NULL) 230 ret->URL = xmlStrdup(URL); 231 else 232 ret->URL = NULL; 233 ret->prefer = prefer; 234 ret->dealloc = 0; 235 ret->depth = 0; 236 return(ret); 237} 238 239static void 240xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret); 241 242/** 243 * xmlFreeCatalogEntry: 244 * @ret: a Catalog entry 245 * 246 * Free the memory allocated to a Catalog entry 247 */ 248static void 249xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { 250 if (ret == NULL) 251 return; 252 /* 253 * Entries stored in the file hash must be deallocated 254 * only by the file hash cleaner ! 255 */ 256 if (ret->dealloc == 1) 257 return; 258 259 if (xmlDebugCatalogs) { 260 if (ret->name != NULL) 261 xmlGenericError(xmlGenericErrorContext, 262 "Free catalog entry %s\n", ret->name); 263 else if (ret->value != NULL) 264 xmlGenericError(xmlGenericErrorContext, 265 "Free catalog entry %s\n", ret->value); 266 else 267 xmlGenericError(xmlGenericErrorContext, 268 "Free catalog entry\n"); 269 } 270 271 if (ret->name != NULL) 272 xmlFree(ret->name); 273 if (ret->value != NULL) 274 xmlFree(ret->value); 275 if (ret->URL != NULL) 276 xmlFree(ret->URL); 277 xmlFree(ret); 278} 279 280/** 281 * xmlFreeCatalogEntryList: 282 * @ret: a Catalog entry list 283 * 284 * Free the memory allocated to a full chained list of Catalog entries 285 */ 286static void 287xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) { 288 xmlCatalogEntryPtr next; 289 290 while (ret != NULL) { 291 next = ret->next; 292 xmlFreeCatalogEntry(ret); 293 ret = next; 294 } 295} 296 297/** 298 * xmlFreeCatalogHashEntryList: 299 * @ret: a Catalog entry list 300 * 301 * Free the memory allocated to list of Catalog entries from the 302 * catalog file hash. 303 */ 304static void 305xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) { 306 xmlCatalogEntryPtr children, next; 307 308 if (catal == NULL) 309 return; 310 311 children = catal->children; 312 while (children != NULL) { 313 next = children->next; 314 children->dealloc = 0; 315 children->children = NULL; 316 xmlFreeCatalogEntry(children); 317 children = next; 318 } 319 catal->dealloc = 0; 320 xmlFreeCatalogEntry(catal); 321} 322 323/** 324 * xmlCreateNewCatalog: 325 * @type: type of catalog 326 * @prefer: the PUBLIC vs. SYSTEM current preference value 327 * 328 * create a new Catalog, this type is shared both by XML and 329 * SGML catalogs, but the acceptable types values differs. 330 * 331 * Returns the xmlCatalogPtr or NULL in case of error 332 */ 333static xmlCatalogPtr 334xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) { 335 xmlCatalogPtr ret; 336 337 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog)); 338 if (ret == NULL) { 339 xmlGenericError(xmlGenericErrorContext, 340 "malloc of %d byte failed\n", sizeof(xmlCatalog)); 341 return(NULL); 342 } 343 memset(ret, 0, sizeof(xmlCatalog)); 344 ret->type = type; 345 ret->catalNr = 0; 346 ret->catalMax = XML_MAX_SGML_CATA_DEPTH; 347 ret->prefer = prefer; 348 if (ret->type == XML_SGML_CATALOG_TYPE) 349 ret->sgml = xmlHashCreate(10); 350 return(ret); 351} 352 353/** 354 * xmlFreeCatalog: 355 * @catal: a Catalog entry 356 * 357 * Free the memory allocated to a Catalog 358 */ 359void 360xmlFreeCatalog(xmlCatalogPtr catal) { 361 if (catal == NULL) 362 return; 363 if (catal->xml != NULL) 364 xmlFreeCatalogEntryList(catal->xml); 365 if (catal->sgml != NULL) 366 xmlHashFree(catal->sgml, 367 (xmlHashDeallocator) xmlFreeCatalogEntry); 368 xmlFree(catal); 369} 370 371/************************************************************************ 372 * * 373 * Serializing Catalogs * 374 * * 375 ************************************************************************/ 376 377#ifdef LIBXML_OUTPUT_ENABLED 378/** 379 * xmlCatalogDumpEntry: 380 * @entry: the 381 * @out: the file. 382 * 383 * Serialize an SGML Catalog entry 384 */ 385static void 386xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { 387 if ((entry == NULL) || (out == NULL)) 388 return; 389 switch (entry->type) { 390 case SGML_CATA_ENTITY: 391 fprintf(out, "ENTITY "); break; 392 case SGML_CATA_PENTITY: 393 fprintf(out, "ENTITY %%"); break; 394 case SGML_CATA_DOCTYPE: 395 fprintf(out, "DOCTYPE "); break; 396 case SGML_CATA_LINKTYPE: 397 fprintf(out, "LINKTYPE "); break; 398 case SGML_CATA_NOTATION: 399 fprintf(out, "NOTATION "); break; 400 case SGML_CATA_PUBLIC: 401 fprintf(out, "PUBLIC "); break; 402 case SGML_CATA_SYSTEM: 403 fprintf(out, "SYSTEM "); break; 404 case SGML_CATA_DELEGATE: 405 fprintf(out, "DELEGATE "); break; 406 case SGML_CATA_BASE: 407 fprintf(out, "BASE "); break; 408 case SGML_CATA_CATALOG: 409 fprintf(out, "CATALOG "); break; 410 case SGML_CATA_DOCUMENT: 411 fprintf(out, "DOCUMENT "); break; 412 case SGML_CATA_SGMLDECL: 413 fprintf(out, "SGMLDECL "); break; 414 default: 415 return; 416 } 417 switch (entry->type) { 418 case SGML_CATA_ENTITY: 419 case SGML_CATA_PENTITY: 420 case SGML_CATA_DOCTYPE: 421 case SGML_CATA_LINKTYPE: 422 case SGML_CATA_NOTATION: 423 fprintf(out, "%s", (const char *) entry->name); break; 424 case SGML_CATA_PUBLIC: 425 case SGML_CATA_SYSTEM: 426 case SGML_CATA_SGMLDECL: 427 case SGML_CATA_DOCUMENT: 428 case SGML_CATA_CATALOG: 429 case SGML_CATA_BASE: 430 case SGML_CATA_DELEGATE: 431 fprintf(out, "\"%s\"", entry->name); break; 432 default: 433 break; 434 } 435 switch (entry->type) { 436 case SGML_CATA_ENTITY: 437 case SGML_CATA_PENTITY: 438 case SGML_CATA_DOCTYPE: 439 case SGML_CATA_LINKTYPE: 440 case SGML_CATA_NOTATION: 441 case SGML_CATA_PUBLIC: 442 case SGML_CATA_SYSTEM: 443 case SGML_CATA_DELEGATE: 444 fprintf(out, " \"%s\"", entry->value); break; 445 default: 446 break; 447 } 448 fprintf(out, "\n"); 449} 450 451static int 452xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { 453 int ret; 454 xmlDocPtr doc; 455 xmlNsPtr ns; 456 xmlDtdPtr dtd; 457 xmlNodePtr node, catalog; 458 xmlOutputBufferPtr buf; 459 xmlCatalogEntryPtr cur; 460 461 /* 462 * Rebuild a catalog 463 */ 464 doc = xmlNewDoc(NULL); 465 if (doc == NULL) 466 return(-1); 467 dtd = xmlNewDtd(doc, BAD_CAST "catalog", 468 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", 469BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); 470 471 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); 472 473 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL); 474 if (ns == NULL) { 475 xmlFreeDoc(doc); 476 return(-1); 477 } 478 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL); 479 if (catalog == NULL) { 480 xmlFreeNs(ns); 481 xmlFreeDoc(doc); 482 return(-1); 483 } 484 catalog->nsDef = ns; 485 xmlAddChild((xmlNodePtr) doc, catalog); 486 487 /* 488 * add all the catalog entries 489 */ 490 cur = catal; 491 while (cur != NULL) { 492 switch (cur->type) { 493 case XML_CATA_REMOVED: 494 break; 495 case XML_CATA_BROKEN_CATALOG: 496 case XML_CATA_CATALOG: 497 if (cur == catal) { 498 cur = cur->children; 499 continue; 500 } 501 break; 502 case XML_CATA_NEXT_CATALOG: 503 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL); 504 xmlSetProp(node, BAD_CAST "catalog", cur->value); 505 xmlAddChild(catalog, node); 506 break; 507 case XML_CATA_NONE: 508 break; 509 case XML_CATA_PUBLIC: 510 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL); 511 xmlSetProp(node, BAD_CAST "publicId", cur->name); 512 xmlSetProp(node, BAD_CAST "uri", cur->value); 513 xmlAddChild(catalog, node); 514 break; 515 case XML_CATA_SYSTEM: 516 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL); 517 xmlSetProp(node, BAD_CAST "systemId", cur->name); 518 xmlSetProp(node, BAD_CAST "uri", cur->value); 519 xmlAddChild(catalog, node); 520 break; 521 case XML_CATA_REWRITE_SYSTEM: 522 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL); 523 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); 524 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); 525 xmlAddChild(catalog, node); 526 break; 527 case XML_CATA_DELEGATE_PUBLIC: 528 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL); 529 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name); 530 xmlSetProp(node, BAD_CAST "catalog", cur->value); 531 xmlAddChild(catalog, node); 532 break; 533 case XML_CATA_DELEGATE_SYSTEM: 534 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL); 535 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); 536 xmlSetProp(node, BAD_CAST "catalog", cur->value); 537 xmlAddChild(catalog, node); 538 break; 539 case XML_CATA_URI: 540 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL); 541 xmlSetProp(node, BAD_CAST "name", cur->name); 542 xmlSetProp(node, BAD_CAST "uri", cur->value); 543 xmlAddChild(catalog, node); 544 break; 545 case XML_CATA_REWRITE_URI: 546 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL); 547 xmlSetProp(node, BAD_CAST "uriStartString", cur->name); 548 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); 549 xmlAddChild(catalog, node); 550 break; 551 case XML_CATA_DELEGATE_URI: 552 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL); 553 xmlSetProp(node, BAD_CAST "uriStartString", cur->name); 554 xmlSetProp(node, BAD_CAST "catalog", cur->value); 555 xmlAddChild(catalog, node); 556 break; 557 case SGML_CATA_SYSTEM: 558 case SGML_CATA_PUBLIC: 559 case SGML_CATA_ENTITY: 560 case SGML_CATA_PENTITY: 561 case SGML_CATA_DOCTYPE: 562 case SGML_CATA_LINKTYPE: 563 case SGML_CATA_NOTATION: 564 case SGML_CATA_DELEGATE: 565 case SGML_CATA_BASE: 566 case SGML_CATA_CATALOG: 567 case SGML_CATA_DOCUMENT: 568 case SGML_CATA_SGMLDECL: 569 break; 570 } 571 cur = cur->next; 572 } 573 574 /* 575 * reserialize it 576 */ 577 buf = xmlOutputBufferCreateFile(out, NULL); 578 if (buf == NULL) { 579 xmlFreeDoc(doc); 580 return(-1); 581 } 582 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1); 583 584 /* 585 * Free it 586 */ 587 xmlFreeDoc(doc); 588 589 return(ret); 590} 591#endif /* LIBXML_OUTPUT_ENABLED */ 592 593/************************************************************************ 594 * * 595 * Converting SGML Catalogs to XML * 596 * * 597 ************************************************************************/ 598 599/** 600 * xmlCatalogConvertEntry: 601 * @entry: the entry 602 * @catal: pointer to the catalog being converted 603 * 604 * Convert one entry from the catalog 605 */ 606static void 607xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) { 608 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) || 609 (catal->xml == NULL)) 610 return; 611 switch (entry->type) { 612 case SGML_CATA_ENTITY: 613 entry->type = XML_CATA_PUBLIC; 614 break; 615 case SGML_CATA_PENTITY: 616 entry->type = XML_CATA_PUBLIC; 617 break; 618 case SGML_CATA_DOCTYPE: 619 entry->type = XML_CATA_PUBLIC; 620 break; 621 case SGML_CATA_LINKTYPE: 622 entry->type = XML_CATA_PUBLIC; 623 break; 624 case SGML_CATA_NOTATION: 625 entry->type = XML_CATA_PUBLIC; 626 break; 627 case SGML_CATA_PUBLIC: 628 entry->type = XML_CATA_PUBLIC; 629 break; 630 case SGML_CATA_SYSTEM: 631 entry->type = XML_CATA_SYSTEM; 632 break; 633 case SGML_CATA_DELEGATE: 634 entry->type = XML_CATA_DELEGATE_PUBLIC; 635 break; 636 case SGML_CATA_CATALOG: 637 entry->type = XML_CATA_CATALOG; 638 break; 639 default: 640 xmlHashRemoveEntry(catal->sgml, entry->name, 641 (xmlHashDeallocator) xmlFreeCatalogEntry); 642 return; 643 } 644 /* 645 * Conversion successful, remove from the SGML catalog 646 * and add it to the default XML one 647 */ 648 xmlHashRemoveEntry(catal->sgml, entry->name, NULL); 649 entry->parent = catal->xml; 650 entry->next = NULL; 651 if (catal->xml->children == NULL) 652 catal->xml->children = entry; 653 else { 654 xmlCatalogEntryPtr prev; 655 656 prev = catal->xml->children; 657 while (prev->next != NULL) 658 prev = prev->next; 659 prev->next = entry; 660 } 661} 662 663/** 664 * xmlConvertSGMLCatalog: 665 * @catal: the catalog 666 * 667 * Convert all the SGML catalog entries as XML ones 668 * 669 * Returns the number of entries converted if successful, -1 otherwise 670 */ 671int 672xmlConvertSGMLCatalog(xmlCatalogPtr catal) { 673 674 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE)) 675 return(-1); 676 677 if (xmlDebugCatalogs) { 678 xmlGenericError(xmlGenericErrorContext, 679 "Converting SGML catalog to XML\n"); 680 } 681 xmlHashScan(catal->sgml, 682 (xmlHashScanner) xmlCatalogConvertEntry, 683 &catal); 684 return(0); 685} 686 687/************************************************************************ 688 * * 689 * Helper function * 690 * * 691 ************************************************************************/ 692 693/** 694 * xmlCatalogUnWrapURN: 695 * @urn: an "urn:publicid:" to unwrap 696 * 697 * Expand the URN into the equivalent Public Identifier 698 * 699 * Returns the new identifier or NULL, the string must be deallocated 700 * by the caller. 701 */ 702static xmlChar * 703xmlCatalogUnWrapURN(const xmlChar *urn) { 704 xmlChar result[2000]; 705 unsigned int i = 0; 706 707 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) 708 return(NULL); 709 urn += sizeof(XML_URN_PUBID) - 1; 710 711 while (*urn != 0) { 712 if (i > sizeof(result) - 3) 713 break; 714 if (*urn == '+') { 715 result[i++] = ' '; 716 urn++; 717 } else if (*urn == ':') { 718 result[i++] = '/'; 719 result[i++] = '/'; 720 urn++; 721 } else if (*urn == ';') { 722 result[i++] = ':'; 723 result[i++] = ':'; 724 urn++; 725 } else if (*urn == '%') { 726 if ((urn[1] == '2') && (urn[1] == 'B')) 727 result[i++] = '+'; 728 else if ((urn[1] == '3') && (urn[1] == 'A')) 729 result[i++] = ':'; 730 else if ((urn[1] == '2') && (urn[1] == 'F')) 731 result[i++] = '/'; 732 else if ((urn[1] == '3') && (urn[1] == 'B')) 733 result[i++] = ';'; 734 else if ((urn[1] == '2') && (urn[1] == '7')) 735 result[i++] = '\''; 736 else if ((urn[1] == '3') && (urn[1] == 'F')) 737 result[i++] = '?'; 738 else if ((urn[1] == '2') && (urn[1] == '3')) 739 result[i++] = '#'; 740 else if ((urn[1] == '2') && (urn[1] == '5')) 741 result[i++] = '%'; 742 else { 743 result[i++] = *urn; 744 urn++; 745 continue; 746 } 747 urn += 3; 748 } else { 749 result[i++] = *urn; 750 urn++; 751 } 752 } 753 result[i] = 0; 754 755 return(xmlStrdup(result)); 756} 757 758/** 759 * xmlParseCatalogFile: 760 * @filename: the filename 761 * 762 * parse an XML file and build a tree. It's like xmlParseFile() 763 * except it bypass all catalog lookups. 764 * 765 * Returns the resulting document tree or NULL in case of error 766 */ 767 768xmlDocPtr 769xmlParseCatalogFile(const char *filename) { 770 xmlDocPtr ret; 771 xmlParserCtxtPtr ctxt; 772 char *directory = NULL; 773 xmlParserInputPtr inputStream; 774 xmlParserInputBufferPtr buf; 775 776 ctxt = xmlNewParserCtxt(); 777 if (ctxt == NULL) { 778 if (xmlDefaultSAXHandler.error != NULL) { 779 xmlDefaultSAXHandler.error(NULL, "out of memory\n"); 780 } 781 return(NULL); 782 } 783 784 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE); 785 if (buf == NULL) { 786 xmlFreeParserCtxt(ctxt); 787 return(NULL); 788 } 789 790 inputStream = xmlNewInputStream(ctxt); 791 if (inputStream == NULL) { 792 xmlFreeParserCtxt(ctxt); 793 return(NULL); 794 } 795 796 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename); 797 inputStream->buf = buf; 798 inputStream->base = inputStream->buf->buffer->content; 799 inputStream->cur = inputStream->buf->buffer->content; 800 inputStream->end = 801 &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; 802 803 inputPush(ctxt, inputStream); 804 if ((ctxt->directory == NULL) && (directory == NULL)) 805 directory = xmlParserGetDirectory(filename); 806 if ((ctxt->directory == NULL) && (directory != NULL)) 807 ctxt->directory = directory; 808 ctxt->valid = 0; 809 ctxt->validate = 0; 810 ctxt->loadsubset = 0; 811 ctxt->pedantic = 0; 812 813 xmlParseDocument(ctxt); 814 815 if (ctxt->wellFormed) 816 ret = ctxt->myDoc; 817 else { 818 ret = NULL; 819 xmlFreeDoc(ctxt->myDoc); 820 ctxt->myDoc = NULL; 821 } 822 xmlFreeParserCtxt(ctxt); 823 824 return(ret); 825} 826 827/** 828 * xmlLoadFileContent: 829 * @filename: a file path 830 * 831 * Load a file content into memory. 832 * 833 * Returns a pointer to the 0 terminated string or NULL in case of error 834 */ 835static xmlChar * 836xmlLoadFileContent(const char *filename) 837{ 838#ifdef HAVE_STAT 839 int fd; 840#else 841 FILE *fd; 842#endif 843 int len; 844 long size; 845 846#ifdef HAVE_STAT 847 struct stat info; 848#endif 849 xmlChar *content; 850 851 if (filename == NULL) 852 return (NULL); 853 854#ifdef HAVE_STAT 855 if (stat(filename, &info) < 0) 856 return (NULL); 857#endif 858 859#ifdef HAVE_STAT 860 if ((fd = open(filename, O_RDONLY)) < 0) 861#else 862 if ((fd = fopen(filename, "rb")) == NULL) 863#endif 864 { 865 return (NULL); 866 } 867#ifdef HAVE_STAT 868 size = info.st_size; 869#else 870 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */ 871 fclose(fd); 872 return (NULL); 873 } 874#endif 875 content = xmlMallocAtomic(size + 10); 876 if (content == NULL) { 877 xmlGenericError(xmlGenericErrorContext, 878 "malloc of %d byte failed\n", size + 10); 879 return (NULL); 880 } 881#ifdef HAVE_STAT 882 len = read(fd, content, size); 883#else 884 len = fread(content, 1, size, fd); 885#endif 886 if (len < 0) { 887 xmlFree(content); 888 return (NULL); 889 } 890#ifdef HAVE_STAT 891 close(fd); 892#else 893 fclose(fd); 894#endif 895 content[len] = 0; 896 897 return(content); 898} 899 900/************************************************************************ 901 * * 902 * The XML Catalog parser * 903 * * 904 ************************************************************************/ 905 906static xmlCatalogEntryPtr 907xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename); 908static void 909xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, 910 xmlCatalogEntryPtr parent); 911static xmlChar * 912xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 913 const xmlChar *sysID); 914static xmlChar * 915xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI); 916 917 918/** 919 * xmlGetXMLCatalogEntryType: 920 * @name: the name 921 * 922 * lookup the internal type associated to an XML catalog entry name 923 * 924 * Returns the type associate with that name 925 */ 926static xmlCatalogEntryType 927xmlGetXMLCatalogEntryType(const xmlChar *name) { 928 xmlCatalogEntryType type = XML_CATA_NONE; 929 if (xmlStrEqual(name, (const xmlChar *) "system")) 930 type = XML_CATA_SYSTEM; 931 else if (xmlStrEqual(name, (const xmlChar *) "public")) 932 type = XML_CATA_PUBLIC; 933 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem")) 934 type = XML_CATA_REWRITE_SYSTEM; 935 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic")) 936 type = XML_CATA_DELEGATE_PUBLIC; 937 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem")) 938 type = XML_CATA_DELEGATE_SYSTEM; 939 else if (xmlStrEqual(name, (const xmlChar *) "uri")) 940 type = XML_CATA_URI; 941 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI")) 942 type = XML_CATA_REWRITE_URI; 943 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI")) 944 type = XML_CATA_DELEGATE_URI; 945 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog")) 946 type = XML_CATA_NEXT_CATALOG; 947 else if (xmlStrEqual(name, (const xmlChar *) "catalog")) 948 type = XML_CATA_CATALOG; 949 return(type); 950} 951 952/** 953 * xmlParseXMLCatalogOneNode: 954 * @cur: the XML node 955 * @type: the type of Catalog entry 956 * @name: the name of the node 957 * @attrName: the attribute holding the value 958 * @uriAttrName: the attribute holding the URI-Reference 959 * @prefer: the PUBLIC vs. SYSTEM current preference value 960 * 961 * Finishes the examination of an XML tree node of a catalog and build 962 * a Catalog entry from it. 963 * 964 * Returns the new Catalog entry node or NULL in case of error. 965 */ 966static xmlCatalogEntryPtr 967xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, 968 const xmlChar *name, const xmlChar *attrName, 969 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) { 970 int ok = 1; 971 xmlChar *uriValue; 972 xmlChar *nameValue = NULL; 973 xmlChar *base = NULL; 974 xmlChar *URL = NULL; 975 xmlCatalogEntryPtr ret = NULL; 976 977 if (attrName != NULL) { 978 nameValue = xmlGetProp(cur, attrName); 979 if (nameValue == NULL) { 980 xmlGenericError(xmlGenericErrorContext, 981 "%s entry lacks '%s'\n", name, attrName); 982 ok = 0; 983 } 984 } 985 uriValue = xmlGetProp(cur, uriAttrName); 986 if (uriValue == NULL) { 987 xmlGenericError(xmlGenericErrorContext, 988 "%s entry lacks '%s'\n", name, uriAttrName); 989 ok = 0; 990 } 991 if (!ok) { 992 if (nameValue != NULL) 993 xmlFree(nameValue); 994 if (uriValue != NULL) 995 xmlFree(uriValue); 996 return(NULL); 997 } 998 999 base = xmlNodeGetBase(cur->doc, cur); 1000 URL = xmlBuildURI(uriValue, base); 1001 if (URL != NULL) { 1002 if (xmlDebugCatalogs > 1) { 1003 if (nameValue != NULL) 1004 xmlGenericError(xmlGenericErrorContext, 1005 "Found %s: '%s' '%s'\n", name, nameValue, URL); 1006 else 1007 xmlGenericError(xmlGenericErrorContext, 1008 "Found %s: '%s'\n", name, URL); 1009 } 1010 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer); 1011 } else { 1012 xmlGenericError(xmlGenericErrorContext, 1013 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue); 1014 } 1015 if (nameValue != NULL) 1016 xmlFree(nameValue); 1017 if (uriValue != NULL) 1018 xmlFree(uriValue); 1019 if (base != NULL) 1020 xmlFree(base); 1021 if (URL != NULL) 1022 xmlFree(URL); 1023 return(ret); 1024} 1025 1026/** 1027 * xmlParseXMLCatalogNode: 1028 * @cur: the XML node 1029 * @prefer: the PUBLIC vs. SYSTEM current preference value 1030 * @parent: the parent Catalog entry 1031 * 1032 * Examines an XML tree node of a catalog and build 1033 * a Catalog entry from it adding it to its parent. The examination can 1034 * be recursive. 1035 */ 1036static void 1037xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, 1038 xmlCatalogEntryPtr parent) 1039{ 1040 xmlChar *uri = NULL; 1041 xmlChar *URL = NULL; 1042 xmlChar *base = NULL; 1043 xmlCatalogEntryPtr entry = NULL; 1044 1045 if (cur == NULL) 1046 return; 1047 if (xmlStrEqual(cur->name, BAD_CAST "group")) { 1048 xmlChar *prop; 1049 1050 prop = xmlGetProp(cur, BAD_CAST "prefer"); 1051 if (prop != NULL) { 1052 if (xmlStrEqual(prop, BAD_CAST "system")) { 1053 prefer = XML_CATA_PREFER_SYSTEM; 1054 } else if (xmlStrEqual(prop, BAD_CAST "public")) { 1055 prefer = XML_CATA_PREFER_PUBLIC; 1056 } else { 1057 xmlGenericError(xmlGenericErrorContext, 1058 "Invalid value for prefer: '%s'\n", prop); 1059 } 1060 xmlFree(prop); 1061 } 1062 /* 1063 * Recurse to propagate prefer to the subtree 1064 * (xml:base handling is automated) 1065 */ 1066 xmlParseXMLCatalogNodeList(cur->children, prefer, parent); 1067 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) { 1068 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC, 1069 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer); 1070 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) { 1071 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM, 1072 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer); 1073 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) { 1074 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM, 1075 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString", 1076 BAD_CAST "rewritePrefix", prefer); 1077 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) { 1078 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC, 1079 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString", 1080 BAD_CAST "catalog", prefer); 1081 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) { 1082 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM, 1083 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString", 1084 BAD_CAST "catalog", prefer); 1085 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) { 1086 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI, 1087 BAD_CAST "uri", BAD_CAST "name", 1088 BAD_CAST "uri", prefer); 1089 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) { 1090 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI, 1091 BAD_CAST "rewriteURI", BAD_CAST "uriStartString", 1092 BAD_CAST "rewritePrefix", prefer); 1093 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) { 1094 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI, 1095 BAD_CAST "delegateURI", BAD_CAST "uriStartString", 1096 BAD_CAST "catalog", prefer); 1097 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { 1098 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, 1099 BAD_CAST "nextCatalog", NULL, 1100 BAD_CAST "catalog", prefer); 1101 } 1102 if ((entry != NULL) && (parent != NULL)) { 1103 entry->parent = parent; 1104 if (parent->children == NULL) 1105 parent->children = entry; 1106 else { 1107 xmlCatalogEntryPtr prev; 1108 1109 prev = parent->children; 1110 while (prev->next != NULL) 1111 prev = prev->next; 1112 prev->next = entry; 1113 } 1114 } 1115 if (base != NULL) 1116 xmlFree(base); 1117 if (uri != NULL) 1118 xmlFree(uri); 1119 if (URL != NULL) 1120 xmlFree(URL); 1121} 1122 1123/** 1124 * xmlParseXMLCatalogNodeList: 1125 * @cur: the XML node list of siblings 1126 * @prefer: the PUBLIC vs. SYSTEM current preference value 1127 * @parent: the parent Catalog entry 1128 * 1129 * Examines a list of XML sibling nodes of a catalog and build 1130 * a list of Catalog entry from it adding it to the parent. 1131 * The examination will recurse to examine node subtrees. 1132 */ 1133static void 1134xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, 1135 xmlCatalogEntryPtr parent) { 1136 while (cur != NULL) { 1137 if ((cur->ns != NULL) && (cur->ns->href != NULL) && 1138 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { 1139 xmlParseXMLCatalogNode(cur, prefer, parent); 1140 } 1141 cur = cur->next; 1142 } 1143 /* TODO: sort the list according to REWRITE lengths and prefer value */ 1144} 1145 1146/** 1147 * xmlParseXMLCatalogFile: 1148 * @prefer: the PUBLIC vs. SYSTEM current preference value 1149 * @filename: the filename for the catalog 1150 * 1151 * Parses the catalog file to extract the XML tree and then analyze the 1152 * tree to build a list of Catalog entries corresponding to this catalog 1153 * 1154 * Returns the resulting Catalog entries list 1155 */ 1156static xmlCatalogEntryPtr 1157xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { 1158 xmlDocPtr doc; 1159 xmlNodePtr cur; 1160 xmlChar *prop; 1161 xmlCatalogEntryPtr parent = NULL; 1162 1163 if (filename == NULL) 1164 return(NULL); 1165 1166 doc = xmlParseCatalogFile((const char *) filename); 1167 if (doc == NULL) { 1168 if (xmlDebugCatalogs) 1169 xmlGenericError(xmlGenericErrorContext, 1170 "Failed to parse catalog %s\n", filename); 1171 return(NULL); 1172 } 1173 1174 if (xmlDebugCatalogs) 1175 xmlGenericError(xmlGenericErrorContext, 1176 "%d Parsing catalog %s\n", xmlGetThreadId(), filename); 1177 1178 cur = xmlDocGetRootElement(doc); 1179 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) && 1180 (cur->ns != NULL) && (cur->ns->href != NULL) && 1181 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { 1182 1183 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 1184 (const xmlChar *)filename, NULL, prefer); 1185 if (parent == NULL) { 1186 xmlFreeDoc(doc); 1187 return(NULL); 1188 } 1189 1190 prop = xmlGetProp(cur, BAD_CAST "prefer"); 1191 if (prop != NULL) { 1192 if (xmlStrEqual(prop, BAD_CAST "system")) { 1193 prefer = XML_CATA_PREFER_SYSTEM; 1194 } else if (xmlStrEqual(prop, BAD_CAST "public")) { 1195 prefer = XML_CATA_PREFER_PUBLIC; 1196 } else { 1197 xmlGenericError(xmlGenericErrorContext, 1198 "Invalid value for prefer: '%s'\n", 1199 prop); 1200 } 1201 xmlFree(prop); 1202 } 1203 cur = cur->children; 1204 xmlParseXMLCatalogNodeList(cur, prefer, parent); 1205 } else { 1206 xmlGenericError(xmlGenericErrorContext, 1207 "File %s is not an XML Catalog\n", filename); 1208 xmlFreeDoc(doc); 1209 return(NULL); 1210 } 1211 xmlFreeDoc(doc); 1212 return(parent); 1213} 1214 1215/** 1216 * xmlFetchXMLCatalogFile: 1217 * @catal: an existing but incomplete catalog entry 1218 * 1219 * Fetch and parse the subcatalog referenced by an entry 1220 * 1221 * Returns 0 in case of success, -1 otherwise 1222 */ 1223static int 1224xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { 1225 xmlCatalogEntryPtr doc; 1226 1227 if (catal == NULL) 1228 return(-1); 1229 if (catal->URL == NULL) 1230 return(-1); 1231 if (catal->children != NULL) 1232 return(-1); 1233 1234 /* 1235 * lock the whole catalog for modification 1236 */ 1237 xmlRMutexLock(xmlCatalogMutex); 1238 if (catal->children != NULL) { 1239 /* Okay someone else did it in the meantime */ 1240 xmlRMutexUnlock(xmlCatalogMutex); 1241 return(0); 1242 } 1243 1244 if (xmlCatalogXMLFiles != NULL) { 1245 doc = (xmlCatalogEntryPtr) 1246 xmlHashLookup(xmlCatalogXMLFiles, catal->URL); 1247 if (doc != NULL) { 1248 if (xmlDebugCatalogs) 1249 xmlGenericError(xmlGenericErrorContext, 1250 "Found %s in file hash\n", catal->URL); 1251 1252 if (catal->type == XML_CATA_CATALOG) 1253 catal->children = doc->children; 1254 else 1255 catal->children = doc; 1256 catal->dealloc = 0; 1257 xmlRMutexUnlock(xmlCatalogMutex); 1258 return(0); 1259 } 1260 if (xmlDebugCatalogs) 1261 xmlGenericError(xmlGenericErrorContext, 1262 "%s not found in file hash\n", catal->URL); 1263 } 1264 1265 /* 1266 * Fetch and parse. Note that xmlParseXMLCatalogFile does not 1267 * use the existing catalog, there is no recursion allowed at 1268 * that level. 1269 */ 1270 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL); 1271 if (doc == NULL) { 1272 catal->type = XML_CATA_BROKEN_CATALOG; 1273 xmlRMutexUnlock(xmlCatalogMutex); 1274 return(-1); 1275 } 1276 1277 if (catal->type == XML_CATA_CATALOG) 1278 catal->children = doc->children; 1279 else 1280 catal->children = doc; 1281 1282 doc->dealloc = 1; 1283 1284 if (xmlCatalogXMLFiles == NULL) 1285 xmlCatalogXMLFiles = xmlHashCreate(10); 1286 if (xmlCatalogXMLFiles != NULL) { 1287 if (xmlDebugCatalogs) 1288 xmlGenericError(xmlGenericErrorContext, 1289 "%s added to file hash\n", catal->URL); 1290 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); 1291 } 1292 xmlRMutexUnlock(xmlCatalogMutex); 1293 return(0); 1294} 1295 1296/************************************************************************ 1297 * * 1298 * XML Catalog handling * 1299 * * 1300 ************************************************************************/ 1301 1302/** 1303 * xmlAddXMLCatalog: 1304 * @catal: top of an XML catalog 1305 * @type: the type of record to add to the catalog 1306 * @orig: the system, public or prefix to match (or NULL) 1307 * @replace: the replacement value for the match 1308 * 1309 * Add an entry in the XML catalog, it may overwrite existing but 1310 * different entries. 1311 * 1312 * Returns 0 if successful, -1 otherwise 1313 */ 1314static int 1315xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, 1316 const xmlChar *orig, const xmlChar *replace) { 1317 xmlCatalogEntryPtr cur; 1318 xmlCatalogEntryType typ; 1319 int doregister = 0; 1320 1321 if ((catal == NULL) || 1322 ((catal->type != XML_CATA_CATALOG) && 1323 (catal->type != XML_CATA_BROKEN_CATALOG))) 1324 return(-1); 1325 if (catal->children == NULL) { 1326 xmlFetchXMLCatalogFile(catal); 1327 } 1328 if (catal->children == NULL) 1329 doregister = 1; 1330 1331 typ = xmlGetXMLCatalogEntryType(type); 1332 if (typ == XML_CATA_NONE) { 1333 if (xmlDebugCatalogs) 1334 xmlGenericError(xmlGenericErrorContext, 1335 "Failed to add unknown element %s to catalog\n", type); 1336 return(-1); 1337 } 1338 1339 cur = catal->children; 1340 /* 1341 * Might be a simple "update in place" 1342 */ 1343 if (cur != NULL) { 1344 while (cur != NULL) { 1345 if ((orig != NULL) && (cur->type == typ) && 1346 (xmlStrEqual(orig, cur->name))) { 1347 if (xmlDebugCatalogs) 1348 xmlGenericError(xmlGenericErrorContext, 1349 "Updating element %s to catalog\n", type); 1350 if (cur->value != NULL) 1351 xmlFree(cur->value); 1352 if (cur->URL != NULL) 1353 xmlFree(cur->URL); 1354 cur->value = xmlStrdup(replace); 1355 cur->URL = xmlStrdup(replace); 1356 return(0); 1357 } 1358 if (cur->next == NULL) 1359 break; 1360 cur = cur->next; 1361 } 1362 } 1363 if (xmlDebugCatalogs) 1364 xmlGenericError(xmlGenericErrorContext, 1365 "Adding element %s to catalog\n", type); 1366 if (cur == NULL) 1367 catal->children = xmlNewCatalogEntry(typ, orig, replace, 1368 NULL, catal->prefer); 1369 else 1370 cur->next = xmlNewCatalogEntry(typ, orig, replace, 1371 NULL, catal->prefer); 1372 if (doregister) { 1373 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL); 1374 if (cur != NULL) 1375 cur->children = catal->children; 1376 } 1377 1378 return(0); 1379} 1380 1381/** 1382 * xmlDelXMLCatalog: 1383 * @catal: top of an XML catalog 1384 * @value: the value to remove from the catalog 1385 * 1386 * Remove entries in the XML catalog where the value or the URI 1387 * is equal to @value 1388 * 1389 * Returns the number of entries removed if successful, -1 otherwise 1390 */ 1391static int 1392xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) { 1393 xmlCatalogEntryPtr cur; 1394 int ret = 0; 1395 1396 if ((catal == NULL) || 1397 ((catal->type != XML_CATA_CATALOG) && 1398 (catal->type != XML_CATA_BROKEN_CATALOG))) 1399 return(-1); 1400 if (value == NULL) 1401 return(-1); 1402 if (catal->children == NULL) { 1403 xmlFetchXMLCatalogFile(catal); 1404 } 1405 1406 /* 1407 * Scan the children 1408 */ 1409 cur = catal->children; 1410 while (cur != NULL) { 1411 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) || 1412 (xmlStrEqual(value, cur->value))) { 1413 if (xmlDebugCatalogs) { 1414 if (cur->name != NULL) 1415 xmlGenericError(xmlGenericErrorContext, 1416 "Removing element %s from catalog\n", cur->name); 1417 else 1418 xmlGenericError(xmlGenericErrorContext, 1419 "Removing element %s from catalog\n", cur->value); 1420 } 1421 cur->type = XML_CATA_REMOVED; 1422 } 1423 cur = cur->next; 1424 } 1425 return(ret); 1426} 1427 1428/** 1429 * xmlCatalogXMLResolve: 1430 * @catal: a catalog list 1431 * @pubId: the public ID string 1432 * @sysId: the system ID string 1433 * 1434 * Do a complete resolution lookup of an External Identifier for a 1435 * list of catalog entries. 1436 * 1437 * Implements (or tries to) 7.1. External Identifier Resolution 1438 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1439 * 1440 * Returns the URI of the resource or NULL if not found 1441 */ 1442static xmlChar * 1443xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 1444 const xmlChar *sysID) { 1445 xmlChar *ret = NULL; 1446 xmlCatalogEntryPtr cur; 1447 int haveDelegate = 0; 1448 int haveNext = 0; 1449 1450 /* 1451 * protection against loops 1452 */ 1453 if (catal->depth > MAX_CATAL_DEPTH) { 1454 if (catal->name != NULL) 1455 xmlGenericError(xmlGenericErrorContext, 1456 "Detected recursion in catalog %s\n", catal->name); 1457 else 1458 xmlGenericError(xmlGenericErrorContext, 1459 "Detected recursion in catalog\n"); 1460 return(NULL); 1461 } 1462 catal->depth++; 1463 1464 /* 1465 * First tries steps 2/ 3/ 4/ if a system ID is provided. 1466 */ 1467 if (sysID != NULL) { 1468 xmlCatalogEntryPtr rewrite = NULL; 1469 int lenrewrite = 0, len; 1470 cur = catal; 1471 haveDelegate = 0; 1472 while (cur != NULL) { 1473 switch (cur->type) { 1474 case XML_CATA_SYSTEM: 1475 if (xmlStrEqual(sysID, cur->name)) { 1476 if (xmlDebugCatalogs) 1477 xmlGenericError(xmlGenericErrorContext, 1478 "Found system match %s\n", cur->name); 1479 catal->depth--; 1480 return(xmlStrdup(cur->URL)); 1481 } 1482 break; 1483 case XML_CATA_REWRITE_SYSTEM: 1484 len = xmlStrlen(cur->name); 1485 if ((len > lenrewrite) && 1486 (!xmlStrncmp(sysID, cur->name, len))) { 1487 lenrewrite = len; 1488 rewrite = cur; 1489 } 1490 break; 1491 case XML_CATA_DELEGATE_SYSTEM: 1492 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name))) 1493 haveDelegate++; 1494 break; 1495 case XML_CATA_NEXT_CATALOG: 1496 haveNext++; 1497 break; 1498 default: 1499 break; 1500 } 1501 cur = cur->next; 1502 } 1503 if (rewrite != NULL) { 1504 if (xmlDebugCatalogs) 1505 xmlGenericError(xmlGenericErrorContext, 1506 "Using rewriting rule %s\n", rewrite->name); 1507 ret = xmlStrdup(rewrite->URL); 1508 if (ret != NULL) 1509 ret = xmlStrcat(ret, &sysID[lenrewrite]); 1510 catal->depth--; 1511 return(ret); 1512 } 1513 if (haveDelegate) { 1514 const xmlChar *delegates[MAX_DELEGATE]; 1515 int nbList = 0, i; 1516 1517 /* 1518 * Assume the entries have been sorted by decreasing substring 1519 * matches when the list was produced. 1520 */ 1521 cur = catal; 1522 while (cur != NULL) { 1523 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) && 1524 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) { 1525 for (i = 0;i < nbList;i++) 1526 if (xmlStrEqual(cur->URL, delegates[i])) 1527 break; 1528 if (i < nbList) { 1529 cur = cur->next; 1530 continue; 1531 } 1532 if (nbList < MAX_DELEGATE) 1533 delegates[nbList++] = cur->URL; 1534 1535 if (cur->children == NULL) { 1536 xmlFetchXMLCatalogFile(cur); 1537 } 1538 if (cur->children != NULL) { 1539 if (xmlDebugCatalogs) 1540 xmlGenericError(xmlGenericErrorContext, 1541 "Trying system delegate %s\n", cur->URL); 1542 ret = xmlCatalogListXMLResolve( 1543 cur->children, NULL, sysID); 1544 if (ret != NULL) { 1545 catal->depth--; 1546 return(ret); 1547 } 1548 } 1549 } 1550 cur = cur->next; 1551 } 1552 /* 1553 * Apply the cut algorithm explained in 4/ 1554 */ 1555 catal->depth--; 1556 return(XML_CATAL_BREAK); 1557 } 1558 } 1559 /* 1560 * Then tries 5/ 6/ if a public ID is provided 1561 */ 1562 if (pubID != NULL) { 1563 cur = catal; 1564 haveDelegate = 0; 1565 while (cur != NULL) { 1566 switch (cur->type) { 1567 case XML_CATA_PUBLIC: 1568 if (xmlStrEqual(pubID, cur->name)) { 1569 if (xmlDebugCatalogs) 1570 xmlGenericError(xmlGenericErrorContext, 1571 "Found public match %s\n", cur->name); 1572 catal->depth--; 1573 return(xmlStrdup(cur->URL)); 1574 } 1575 break; 1576 case XML_CATA_DELEGATE_PUBLIC: 1577 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) && 1578 (cur->prefer == XML_CATA_PREFER_PUBLIC)) 1579 haveDelegate++; 1580 break; 1581 case XML_CATA_NEXT_CATALOG: 1582 if (sysID == NULL) 1583 haveNext++; 1584 break; 1585 default: 1586 break; 1587 } 1588 cur = cur->next; 1589 } 1590 if (haveDelegate) { 1591 const xmlChar *delegates[MAX_DELEGATE]; 1592 int nbList = 0, i; 1593 1594 /* 1595 * Assume the entries have been sorted by decreasing substring 1596 * matches when the list was produced. 1597 */ 1598 cur = catal; 1599 while (cur != NULL) { 1600 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) && 1601 (cur->prefer == XML_CATA_PREFER_PUBLIC) && 1602 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) { 1603 1604 for (i = 0;i < nbList;i++) 1605 if (xmlStrEqual(cur->URL, delegates[i])) 1606 break; 1607 if (i < nbList) { 1608 cur = cur->next; 1609 continue; 1610 } 1611 if (nbList < MAX_DELEGATE) 1612 delegates[nbList++] = cur->URL; 1613 1614 if (cur->children == NULL) { 1615 xmlFetchXMLCatalogFile(cur); 1616 } 1617 if (cur->children != NULL) { 1618 if (xmlDebugCatalogs) 1619 xmlGenericError(xmlGenericErrorContext, 1620 "Trying public delegate %s\n", cur->URL); 1621 ret = xmlCatalogListXMLResolve( 1622 cur->children, pubID, NULL); 1623 if (ret != NULL) { 1624 catal->depth--; 1625 return(ret); 1626 } 1627 } 1628 } 1629 cur = cur->next; 1630 } 1631 /* 1632 * Apply the cut algorithm explained in 4/ 1633 */ 1634 catal->depth--; 1635 return(XML_CATAL_BREAK); 1636 } 1637 } 1638 if (haveNext) { 1639 cur = catal; 1640 while (cur != NULL) { 1641 if (cur->type == XML_CATA_NEXT_CATALOG) { 1642 if (cur->children == NULL) { 1643 xmlFetchXMLCatalogFile(cur); 1644 } 1645 if (cur->children != NULL) { 1646 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID); 1647 if (ret != NULL) { 1648 catal->depth--; 1649 return(ret); 1650 } 1651 } 1652 } 1653 cur = cur->next; 1654 } 1655 } 1656 1657 catal->depth--; 1658 return(NULL); 1659} 1660 1661/** 1662 * xmlCatalogXMLResolveURI: 1663 * @catal: a catalog list 1664 * @URI: the URI 1665 * @sysId: the system ID string 1666 * 1667 * Do a complete resolution lookup of an External Identifier for a 1668 * list of catalog entries. 1669 * 1670 * Implements (or tries to) 7.2.2. URI Resolution 1671 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1672 * 1673 * Returns the URI of the resource or NULL if not found 1674 */ 1675static xmlChar * 1676xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { 1677 xmlChar *ret = NULL; 1678 xmlCatalogEntryPtr cur; 1679 int haveDelegate = 0; 1680 int haveNext = 0; 1681 xmlCatalogEntryPtr rewrite = NULL; 1682 int lenrewrite = 0, len; 1683 1684 if (catal == NULL) 1685 return(NULL); 1686 1687 if (URI == NULL) 1688 return(NULL); 1689 1690 /* 1691 * First tries steps 2/ 3/ 4/ if a system ID is provided. 1692 */ 1693 cur = catal; 1694 haveDelegate = 0; 1695 while (cur != NULL) { 1696 switch (cur->type) { 1697 case XML_CATA_URI: 1698 if (xmlStrEqual(URI, cur->name)) { 1699 if (xmlDebugCatalogs) 1700 xmlGenericError(xmlGenericErrorContext, 1701 "Found URI match %s\n", cur->name); 1702 return(xmlStrdup(cur->URL)); 1703 } 1704 break; 1705 case XML_CATA_REWRITE_URI: 1706 len = xmlStrlen(cur->name); 1707 if ((len > lenrewrite) && 1708 (!xmlStrncmp(URI, cur->name, len))) { 1709 lenrewrite = len; 1710 rewrite = cur; 1711 } 1712 break; 1713 case XML_CATA_DELEGATE_URI: 1714 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name))) 1715 haveDelegate++; 1716 break; 1717 case XML_CATA_NEXT_CATALOG: 1718 haveNext++; 1719 break; 1720 default: 1721 break; 1722 } 1723 cur = cur->next; 1724 } 1725 if (rewrite != NULL) { 1726 if (xmlDebugCatalogs) 1727 xmlGenericError(xmlGenericErrorContext, 1728 "Using rewriting rule %s\n", rewrite->name); 1729 ret = xmlStrdup(rewrite->URL); 1730 if (ret != NULL) 1731 ret = xmlStrcat(ret, &URI[lenrewrite]); 1732 return(ret); 1733 } 1734 if (haveDelegate) { 1735 const xmlChar *delegates[MAX_DELEGATE]; 1736 int nbList = 0, i; 1737 1738 /* 1739 * Assume the entries have been sorted by decreasing substring 1740 * matches when the list was produced. 1741 */ 1742 cur = catal; 1743 while (cur != NULL) { 1744 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) || 1745 (cur->type == XML_CATA_DELEGATE_URI)) && 1746 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) { 1747 for (i = 0;i < nbList;i++) 1748 if (xmlStrEqual(cur->URL, delegates[i])) 1749 break; 1750 if (i < nbList) { 1751 cur = cur->next; 1752 continue; 1753 } 1754 if (nbList < MAX_DELEGATE) 1755 delegates[nbList++] = cur->URL; 1756 1757 if (cur->children == NULL) { 1758 xmlFetchXMLCatalogFile(cur); 1759 } 1760 if (cur->children != NULL) { 1761 if (xmlDebugCatalogs) 1762 xmlGenericError(xmlGenericErrorContext, 1763 "Trying URI delegate %s\n", cur->URL); 1764 ret = xmlCatalogListXMLResolveURI( 1765 cur->children, URI); 1766 if (ret != NULL) 1767 return(ret); 1768 } 1769 } 1770 cur = cur->next; 1771 } 1772 /* 1773 * Apply the cut algorithm explained in 4/ 1774 */ 1775 return(XML_CATAL_BREAK); 1776 } 1777 if (haveNext) { 1778 cur = catal; 1779 while (cur != NULL) { 1780 if (cur->type == XML_CATA_NEXT_CATALOG) { 1781 if (cur->children == NULL) { 1782 xmlFetchXMLCatalogFile(cur); 1783 } 1784 if (cur->children != NULL) { 1785 ret = xmlCatalogListXMLResolveURI(cur->children, URI); 1786 if (ret != NULL) 1787 return(ret); 1788 } 1789 } 1790 cur = cur->next; 1791 } 1792 } 1793 1794 return(NULL); 1795} 1796 1797/** 1798 * xmlCatalogListXMLResolve: 1799 * @catal: a catalog list 1800 * @pubId: the public ID string 1801 * @sysId: the system ID string 1802 * 1803 * Do a complete resolution lookup of an External Identifier for a 1804 * list of catalogs 1805 * 1806 * Implements (or tries to) 7.1. External Identifier Resolution 1807 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1808 * 1809 * Returns the URI of the resource or NULL if not found 1810 */ 1811static xmlChar * 1812xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 1813 const xmlChar *sysID) { 1814 xmlChar *ret = NULL; 1815 xmlChar *urnID = NULL; 1816 1817 if (catal == NULL) 1818 return(NULL); 1819 if ((pubID == NULL) && (sysID == NULL)) 1820 return(NULL); 1821 1822 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 1823 urnID = xmlCatalogUnWrapURN(pubID); 1824 if (xmlDebugCatalogs) { 1825 if (urnID == NULL) 1826 xmlGenericError(xmlGenericErrorContext, 1827 "Public URN ID %s expanded to NULL\n", pubID); 1828 else 1829 xmlGenericError(xmlGenericErrorContext, 1830 "Public URN ID expanded to %s\n", urnID); 1831 } 1832 ret = xmlCatalogListXMLResolve(catal, urnID, sysID); 1833 if (urnID != NULL) 1834 xmlFree(urnID); 1835 return(ret); 1836 } 1837 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 1838 urnID = xmlCatalogUnWrapURN(sysID); 1839 if (xmlDebugCatalogs) { 1840 if (urnID == NULL) 1841 xmlGenericError(xmlGenericErrorContext, 1842 "System URN ID %s expanded to NULL\n", sysID); 1843 else 1844 xmlGenericError(xmlGenericErrorContext, 1845 "System URN ID expanded to %s\n", urnID); 1846 } 1847 if (pubID == NULL) 1848 ret = xmlCatalogListXMLResolve(catal, urnID, NULL); 1849 else if (xmlStrEqual(pubID, urnID)) 1850 ret = xmlCatalogListXMLResolve(catal, pubID, NULL); 1851 else { 1852 ret = xmlCatalogListXMLResolve(catal, pubID, NULL); 1853 } 1854 if (urnID != NULL) 1855 xmlFree(urnID); 1856 return(ret); 1857 } 1858 while (catal != NULL) { 1859 if (catal->type == XML_CATA_CATALOG) { 1860 if (catal->children == NULL) { 1861 xmlFetchXMLCatalogFile(catal); 1862 } 1863 if (catal->children != NULL) { 1864 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID); 1865 if (ret != NULL) 1866 return(ret); 1867 } 1868 } 1869 catal = catal->next; 1870 } 1871 return(ret); 1872} 1873 1874/** 1875 * xmlCatalogListXMLResolveURI: 1876 * @catal: a catalog list 1877 * @URI: the URI 1878 * 1879 * Do a complete resolution lookup of an URI for a list of catalogs 1880 * 1881 * Implements (or tries to) 7.2. URI Resolution 1882 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1883 * 1884 * Returns the URI of the resource or NULL if not found 1885 */ 1886static xmlChar * 1887xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { 1888 xmlChar *ret = NULL; 1889 xmlChar *urnID = NULL; 1890 1891 if (catal == NULL) 1892 return(NULL); 1893 if (URI == NULL) 1894 return(NULL); 1895 1896 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 1897 urnID = xmlCatalogUnWrapURN(URI); 1898 if (xmlDebugCatalogs) { 1899 if (urnID == NULL) 1900 xmlGenericError(xmlGenericErrorContext, 1901 "URN ID %s expanded to NULL\n", URI); 1902 else 1903 xmlGenericError(xmlGenericErrorContext, 1904 "URN ID expanded to %s\n", urnID); 1905 } 1906 ret = xmlCatalogListXMLResolve(catal, urnID, NULL); 1907 if (urnID != NULL) 1908 xmlFree(urnID); 1909 return(ret); 1910 } 1911 while (catal != NULL) { 1912 if (catal->type == XML_CATA_CATALOG) { 1913 if (catal->children == NULL) { 1914 xmlFetchXMLCatalogFile(catal); 1915 } 1916 if (catal->children != NULL) { 1917 ret = xmlCatalogXMLResolveURI(catal->children, URI); 1918 if (ret != NULL) 1919 return(ret); 1920 } 1921 } 1922 catal = catal->next; 1923 } 1924 return(ret); 1925} 1926 1927/************************************************************************ 1928 * * 1929 * The SGML Catalog parser * 1930 * * 1931 ************************************************************************/ 1932 1933 1934#define RAW *cur 1935#define NEXT cur++; 1936#define SKIP(x) cur += x; 1937 1938#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT; 1939 1940/** 1941 * xmlParseSGMLCatalogComment: 1942 * @cur: the current character 1943 * 1944 * Skip a comment in an SGML catalog 1945 * 1946 * Returns new current character 1947 */ 1948static const xmlChar * 1949xmlParseSGMLCatalogComment(const xmlChar *cur) { 1950 if ((cur[0] != '-') || (cur[1] != '-')) 1951 return(cur); 1952 SKIP(2); 1953 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-')))) 1954 NEXT; 1955 if (cur[0] == 0) { 1956 return(NULL); 1957 } 1958 return(cur + 2); 1959} 1960 1961/** 1962 * xmlParseSGMLCatalogPubid: 1963 * @cur: the current character 1964 * @id: the return location 1965 * 1966 * Parse an SGML catalog ID 1967 * 1968 * Returns new current character and store the value in @id 1969 */ 1970static const xmlChar * 1971xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { 1972 xmlChar *buf = NULL; 1973 int len = 0; 1974 int size = 50; 1975 xmlChar stop; 1976 int count = 0; 1977 1978 *id = NULL; 1979 1980 if (RAW == '"') { 1981 NEXT; 1982 stop = '"'; 1983 } else if (RAW == '\'') { 1984 NEXT; 1985 stop = '\''; 1986 } else { 1987 stop = ' '; 1988 } 1989 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); 1990 if (buf == NULL) { 1991 xmlGenericError(xmlGenericErrorContext, 1992 "malloc of %d byte failed\n", size); 1993 return(NULL); 1994 } 1995 while (xmlIsPubidChar(*cur) || (*cur == '?')) { 1996 if ((*cur == stop) && (stop != ' ')) 1997 break; 1998 if ((stop == ' ') && (IS_BLANK(*cur))) 1999 break; 2000 if (len + 1 >= size) { 2001 size *= 2; 2002 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); 2003 if (buf == NULL) { 2004 xmlGenericError(xmlGenericErrorContext, 2005 "realloc of %d byte failed\n", size); 2006 return(NULL); 2007 } 2008 } 2009 buf[len++] = *cur; 2010 count++; 2011 NEXT; 2012 } 2013 buf[len] = 0; 2014 if (stop == ' ') { 2015 if (!IS_BLANK(*cur)) { 2016 xmlFree(buf); 2017 return(NULL); 2018 } 2019 } else { 2020 if (*cur != stop) { 2021 xmlFree(buf); 2022 return(NULL); 2023 } 2024 NEXT; 2025 } 2026 *id = buf; 2027 return(cur); 2028} 2029 2030/** 2031 * xmlParseSGMLCatalogName: 2032 * @cur: the current character 2033 * @name: the return location 2034 * 2035 * Parse an SGML catalog name 2036 * 2037 * Returns new current character and store the value in @name 2038 */ 2039static const xmlChar * 2040xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) { 2041 xmlChar buf[XML_MAX_NAMELEN + 5]; 2042 int len = 0; 2043 int c; 2044 2045 *name = NULL; 2046 2047 /* 2048 * Handler for more complex cases 2049 */ 2050 c = *cur; 2051 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) { 2052 return(NULL); 2053 } 2054 2055 while (((IS_LETTER(c)) || (IS_DIGIT(c)) || 2056 (c == '.') || (c == '-') || 2057 (c == '_') || (c == ':'))) { 2058 buf[len++] = c; 2059 cur++; 2060 c = *cur; 2061 if (len >= XML_MAX_NAMELEN) 2062 return(NULL); 2063 } 2064 *name = xmlStrndup(buf, len); 2065 return(cur); 2066} 2067 2068/** 2069 * xmlGetSGMLCatalogEntryType: 2070 * @name: the entry name 2071 * 2072 * Get the Catalog entry type for a given SGML Catalog name 2073 * 2074 * Returns Catalog entry type 2075 */ 2076static xmlCatalogEntryType 2077xmlGetSGMLCatalogEntryType(const xmlChar *name) { 2078 xmlCatalogEntryType type = XML_CATA_NONE; 2079 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) 2080 type = SGML_CATA_SYSTEM; 2081 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) 2082 type = SGML_CATA_PUBLIC; 2083 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2084 type = SGML_CATA_DELEGATE; 2085 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) 2086 type = SGML_CATA_ENTITY; 2087 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) 2088 type = SGML_CATA_DOCTYPE; 2089 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) 2090 type = SGML_CATA_LINKTYPE; 2091 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) 2092 type = SGML_CATA_NOTATION; 2093 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) 2094 type = SGML_CATA_SGMLDECL; 2095 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) 2096 type = SGML_CATA_DOCUMENT; 2097 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) 2098 type = SGML_CATA_CATALOG; 2099 else if (xmlStrEqual(name, (const xmlChar *) "BASE")) 2100 type = SGML_CATA_BASE; 2101 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2102 type = SGML_CATA_DELEGATE; 2103 return(type); 2104} 2105 2106/** 2107 * xmlParseSGMLCatalog: 2108 * @catal: the SGML Catalog 2109 * @value: the content of the SGML Catalog serialization 2110 * @file: the filepath for the catalog 2111 * @super: should this be handled as a Super Catalog in which case 2112 * parsing is not recursive 2113 * 2114 * Parse an SGML catalog content and fill up the @catal hash table with 2115 * the new entries found. 2116 * 2117 * Returns 0 in case of success, -1 in case of error. 2118 */ 2119static int 2120xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value, 2121 const char *file, int super) { 2122 const xmlChar *cur = value; 2123 xmlChar *base = NULL; 2124 int res; 2125 2126 if ((cur == NULL) || (file == NULL)) 2127 return(-1); 2128 base = xmlStrdup((const xmlChar *) file); 2129 2130 while ((cur != NULL) && (cur[0] != 0)) { 2131 SKIP_BLANKS; 2132 if (cur[0] == 0) 2133 break; 2134 if ((cur[0] == '-') && (cur[1] == '-')) { 2135 cur = xmlParseSGMLCatalogComment(cur); 2136 if (cur == NULL) { 2137 /* error */ 2138 break; 2139 } 2140 } else { 2141 xmlChar *sysid = NULL; 2142 xmlChar *name = NULL; 2143 xmlCatalogEntryType type = XML_CATA_NONE; 2144 2145 cur = xmlParseSGMLCatalogName(cur, &name); 2146 if (name == NULL) { 2147 /* error */ 2148 break; 2149 } 2150 if (!IS_BLANK(*cur)) { 2151 /* error */ 2152 break; 2153 } 2154 SKIP_BLANKS; 2155 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) 2156 type = SGML_CATA_SYSTEM; 2157 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) 2158 type = SGML_CATA_PUBLIC; 2159 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2160 type = SGML_CATA_DELEGATE; 2161 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) 2162 type = SGML_CATA_ENTITY; 2163 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) 2164 type = SGML_CATA_DOCTYPE; 2165 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) 2166 type = SGML_CATA_LINKTYPE; 2167 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) 2168 type = SGML_CATA_NOTATION; 2169 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) 2170 type = SGML_CATA_SGMLDECL; 2171 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) 2172 type = SGML_CATA_DOCUMENT; 2173 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) 2174 type = SGML_CATA_CATALOG; 2175 else if (xmlStrEqual(name, (const xmlChar *) "BASE")) 2176 type = SGML_CATA_BASE; 2177 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2178 type = SGML_CATA_DELEGATE; 2179 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) { 2180 xmlFree(name); 2181 cur = xmlParseSGMLCatalogName(cur, &name); 2182 if (name == NULL) { 2183 /* error */ 2184 break; 2185 } 2186 xmlFree(name); 2187 continue; 2188 } 2189 xmlFree(name); 2190 name = NULL; 2191 2192 switch(type) { 2193 case SGML_CATA_ENTITY: 2194 if (*cur == '%') 2195 type = SGML_CATA_PENTITY; 2196 case SGML_CATA_PENTITY: 2197 case SGML_CATA_DOCTYPE: 2198 case SGML_CATA_LINKTYPE: 2199 case SGML_CATA_NOTATION: 2200 cur = xmlParseSGMLCatalogName(cur, &name); 2201 if (cur == NULL) { 2202 /* error */ 2203 break; 2204 } 2205 if (!IS_BLANK(*cur)) { 2206 /* error */ 2207 break; 2208 } 2209 SKIP_BLANKS; 2210 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 2211 if (cur == NULL) { 2212 /* error */ 2213 break; 2214 } 2215 break; 2216 case SGML_CATA_PUBLIC: 2217 case SGML_CATA_SYSTEM: 2218 case SGML_CATA_DELEGATE: 2219 cur = xmlParseSGMLCatalogPubid(cur, &name); 2220 if (cur == NULL) { 2221 /* error */ 2222 break; 2223 } 2224 if (!IS_BLANK(*cur)) { 2225 /* error */ 2226 break; 2227 } 2228 SKIP_BLANKS; 2229 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 2230 if (cur == NULL) { 2231 /* error */ 2232 break; 2233 } 2234 break; 2235 case SGML_CATA_BASE: 2236 case SGML_CATA_CATALOG: 2237 case SGML_CATA_DOCUMENT: 2238 case SGML_CATA_SGMLDECL: 2239 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 2240 if (cur == NULL) { 2241 /* error */ 2242 break; 2243 } 2244 break; 2245 default: 2246 break; 2247 } 2248 if (cur == NULL) { 2249 if (name != NULL) 2250 xmlFree(name); 2251 if (sysid != NULL) 2252 xmlFree(sysid); 2253 break; 2254 } else if (type == SGML_CATA_BASE) { 2255 if (base != NULL) 2256 xmlFree(base); 2257 base = xmlStrdup(sysid); 2258 } else if ((type == SGML_CATA_PUBLIC) || 2259 (type == SGML_CATA_SYSTEM)) { 2260 xmlChar *filename; 2261 2262 filename = xmlBuildURI(sysid, base); 2263 if (filename != NULL) { 2264 xmlCatalogEntryPtr entry; 2265 2266 entry = xmlNewCatalogEntry(type, name, filename, 2267 NULL, XML_CATA_PREFER_NONE); 2268 res = xmlHashAddEntry(catal->sgml, name, entry); 2269 if (res < 0) { 2270 xmlFreeCatalogEntry(entry); 2271 } 2272 xmlFree(filename); 2273 } 2274 2275 } else if (type == SGML_CATA_CATALOG) { 2276 if (super) { 2277 xmlCatalogEntryPtr entry; 2278 2279 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL, 2280 XML_CATA_PREFER_NONE); 2281 res = xmlHashAddEntry(catal->sgml, sysid, entry); 2282 if (res < 0) { 2283 xmlFreeCatalogEntry(entry); 2284 } 2285 } else { 2286 xmlChar *filename; 2287 2288 filename = xmlBuildURI(sysid, base); 2289 if (filename != NULL) { 2290 xmlExpandCatalog(catal, (const char *)filename); 2291 xmlFree(filename); 2292 } 2293 } 2294 } 2295 /* 2296 * drop anything else we won't handle it 2297 */ 2298 if (name != NULL) 2299 xmlFree(name); 2300 if (sysid != NULL) 2301 xmlFree(sysid); 2302 } 2303 } 2304 if (base != NULL) 2305 xmlFree(base); 2306 if (cur == NULL) 2307 return(-1); 2308 return(0); 2309} 2310 2311/************************************************************************ 2312 * * 2313 * SGML Catalog handling * 2314 * * 2315 ************************************************************************/ 2316 2317/** 2318 * xmlCatalogGetSGMLPublic: 2319 * @catal: an SGML catalog hash 2320 * @pubId: the public ID string 2321 * 2322 * Try to lookup the system ID associated to a public ID 2323 * 2324 * Returns the system ID if found or NULL otherwise. 2325 */ 2326static const xmlChar * 2327xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) { 2328 xmlCatalogEntryPtr entry; 2329 2330 if (catal == NULL) 2331 return(NULL); 2332 2333 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID); 2334 if (entry == NULL) 2335 return(NULL); 2336 if (entry->type == SGML_CATA_PUBLIC) 2337 return(entry->URL); 2338 return(NULL); 2339} 2340 2341/** 2342 * xmlCatalogGetSGMLSystem: 2343 * @catal: an SGML catalog hash 2344 * @sysId: the public ID string 2345 * 2346 * Try to lookup the catalog local reference for a system ID 2347 * 2348 * Returns the system ID if found or NULL otherwise. 2349 */ 2350static const xmlChar * 2351xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) { 2352 xmlCatalogEntryPtr entry; 2353 2354 if (catal == NULL) 2355 return(NULL); 2356 2357 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID); 2358 if (entry == NULL) 2359 return(NULL); 2360 if (entry->type == SGML_CATA_SYSTEM) 2361 return(entry->URL); 2362 return(NULL); 2363} 2364 2365/** 2366 * xmlCatalogSGMLResolve: 2367 * @catal: the SGML catalog 2368 * @pubId: the public ID string 2369 * @sysId: the system ID string 2370 * 2371 * Do a complete resolution lookup of an External Identifier 2372 * 2373 * Returns the URI of the resource or NULL if not found 2374 */ 2375static const xmlChar * 2376xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID, 2377 const xmlChar *sysID) { 2378 const xmlChar *ret = NULL; 2379 2380 if (catal->sgml == NULL) 2381 return(NULL); 2382 2383 if (pubID != NULL) 2384 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID); 2385 if (ret != NULL) 2386 return(ret); 2387 if (sysID != NULL) 2388 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID); 2389 return(NULL); 2390} 2391 2392/************************************************************************ 2393 * * 2394 * Specific Public interfaces * 2395 * * 2396 ************************************************************************/ 2397 2398/** 2399 * xmlLoadSGMLSuperCatalog: 2400 * @filename: a file path 2401 * 2402 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE 2403 * references. This is only needed for manipulating SGML Super Catalogs 2404 * like adding and removing CATALOG or DELEGATE entries. 2405 * 2406 * Returns the catalog parsed or NULL in case of error 2407 */ 2408xmlCatalogPtr 2409xmlLoadSGMLSuperCatalog(const char *filename) 2410{ 2411 xmlChar *content; 2412 xmlCatalogPtr catal; 2413 int ret; 2414 2415 content = xmlLoadFileContent(filename); 2416 if (content == NULL) 2417 return(NULL); 2418 2419 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 2420 if (catal == NULL) { 2421 xmlFree(content); 2422 return(NULL); 2423 } 2424 2425 ret = xmlParseSGMLCatalog(catal, content, filename, 1); 2426 xmlFree(content); 2427 if (ret < 0) { 2428 xmlFreeCatalog(catal); 2429 return(NULL); 2430 } 2431 return (catal); 2432} 2433 2434/** 2435 * xmlLoadACatalog: 2436 * @filename: a file path 2437 * 2438 * Load the catalog and build the associated data structures. 2439 * This can be either an XML Catalog or an SGML Catalog 2440 * It will recurse in SGML CATALOG entries. On the other hand XML 2441 * Catalogs are not handled recursively. 2442 * 2443 * Returns the catalog parsed or NULL in case of error 2444 */ 2445xmlCatalogPtr 2446xmlLoadACatalog(const char *filename) 2447{ 2448 xmlChar *content; 2449 xmlChar *first; 2450 xmlCatalogPtr catal; 2451 int ret; 2452 2453 content = xmlLoadFileContent(filename); 2454 if (content == NULL) 2455 return(NULL); 2456 2457 2458 first = content; 2459 2460 while ((*first != 0) && (*first != '-') && (*first != '<') && 2461 (!(((*first >= 'A') && (*first <= 'Z')) || 2462 ((*first >= 'a') && (*first <= 'z'))))) 2463 first++; 2464 2465 if (*first != '<') { 2466 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 2467 if (catal == NULL) { 2468 xmlFree(content); 2469 return(NULL); 2470 } 2471 ret = xmlParseSGMLCatalog(catal, content, filename, 0); 2472 if (ret < 0) { 2473 xmlFreeCatalog(catal); 2474 xmlFree(content); 2475 return(NULL); 2476 } 2477 } else { 2478 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 2479 if (catal == NULL) { 2480 xmlFree(content); 2481 return(NULL); 2482 } 2483 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2484 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer); 2485 } 2486 xmlFree(content); 2487 return (catal); 2488} 2489 2490/** 2491 * xmlExpandCatalog: 2492 * @catal: a catalog 2493 * @filename: a file path 2494 * 2495 * Load the catalog and expand the existing catal structure. 2496 * This can be either an XML Catalog or an SGML Catalog 2497 * 2498 * Returns 0 in case of success, -1 in case of error 2499 */ 2500static int 2501xmlExpandCatalog(xmlCatalogPtr catal, const char *filename) 2502{ 2503 int ret; 2504 2505 if ((catal == NULL) || (filename == NULL)) 2506 return(-1); 2507 2508 2509 if (catal->type == XML_SGML_CATALOG_TYPE) { 2510 xmlChar *content; 2511 2512 content = xmlLoadFileContent(filename); 2513 if (content == NULL) 2514 return(-1); 2515 2516 ret = xmlParseSGMLCatalog(catal, content, filename, 0); 2517 if (ret < 0) { 2518 xmlFree(content); 2519 return(-1); 2520 } 2521 xmlFree(content); 2522 } else { 2523 xmlCatalogEntryPtr tmp, cur; 2524 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2525 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer); 2526 2527 cur = catal->xml; 2528 if (cur == NULL) { 2529 catal->xml = tmp; 2530 } else { 2531 while (cur->next != NULL) cur = cur->next; 2532 cur->next = tmp; 2533 } 2534 } 2535 return (0); 2536} 2537 2538/** 2539 * xmlACatalogResolveSystem: 2540 * @catal: a Catalog 2541 * @sysID: the public ID string 2542 * 2543 * Try to lookup the catalog resource for a system ID 2544 * 2545 * Returns the system ID if found or NULL otherwise, the value returned 2546 * must be freed by the caller. 2547 */ 2548xmlChar * 2549xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) { 2550 xmlChar *ret = NULL; 2551 2552 if ((sysID == NULL) || (catal == NULL)) 2553 return(NULL); 2554 2555 if (xmlDebugCatalogs) 2556 xmlGenericError(xmlGenericErrorContext, 2557 "Resolve sysID %s\n", sysID); 2558 2559 if (catal->type == XML_XML_CATALOG_TYPE) { 2560 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID); 2561 if (ret == XML_CATAL_BREAK) 2562 ret = NULL; 2563 } else { 2564 const xmlChar *sgml; 2565 2566 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID); 2567 if (sgml != NULL) 2568 ret = xmlStrdup(sgml); 2569 } 2570 return(ret); 2571} 2572 2573/** 2574 * xmlACatalogResolvePublic: 2575 * @catal: a Catalog 2576 * @pubID: the public ID string 2577 * 2578 * Try to lookup the system ID associated to a public ID in that catalog 2579 * 2580 * Returns the system ID if found or NULL otherwise, the value returned 2581 * must be freed by the caller. 2582 */ 2583xmlChar * 2584xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) { 2585 xmlChar *ret = NULL; 2586 2587 if ((pubID == NULL) || (catal == NULL)) 2588 return(NULL); 2589 2590 if (xmlDebugCatalogs) 2591 xmlGenericError(xmlGenericErrorContext, 2592 "Resolve pubID %s\n", pubID); 2593 2594 if (catal->type == XML_XML_CATALOG_TYPE) { 2595 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL); 2596 if (ret == XML_CATAL_BREAK) 2597 ret = NULL; 2598 } else { 2599 const xmlChar *sgml; 2600 2601 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID); 2602 if (sgml != NULL) 2603 ret = xmlStrdup(sgml); 2604 } 2605 return(ret); 2606} 2607 2608/** 2609 * xmlACatalogResolve: 2610 * @catal: a Catalog 2611 * @pubID: the public ID string 2612 * @sysID: the system ID string 2613 * 2614 * Do a complete resolution lookup of an External Identifier 2615 * 2616 * Returns the URI of the resource or NULL if not found, it must be freed 2617 * by the caller. 2618 */ 2619xmlChar * 2620xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID, 2621 const xmlChar * sysID) 2622{ 2623 xmlChar *ret = NULL; 2624 2625 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL)) 2626 return (NULL); 2627 2628 if (xmlDebugCatalogs) { 2629 if (pubID != NULL) { 2630 xmlGenericError(xmlGenericErrorContext, 2631 "Resolve: pubID %s\n", pubID); 2632 } else { 2633 xmlGenericError(xmlGenericErrorContext, 2634 "Resolve: sysID %s\n", sysID); 2635 } 2636 } 2637 2638 if (catal->type == XML_XML_CATALOG_TYPE) { 2639 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID); 2640 if (ret == XML_CATAL_BREAK) 2641 ret = NULL; 2642 } else { 2643 const xmlChar *sgml; 2644 2645 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID); 2646 if (sgml != NULL) 2647 ret = xmlStrdup(sgml); 2648 } 2649 return (ret); 2650} 2651 2652/** 2653 * xmlACatalogResolveURI: 2654 * @catal: a Catalog 2655 * @URI: the URI 2656 * 2657 * Do a complete resolution lookup of an URI 2658 * 2659 * Returns the URI of the resource or NULL if not found, it must be freed 2660 * by the caller. 2661 */ 2662xmlChar * 2663xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { 2664 xmlChar *ret = NULL; 2665 2666 if ((URI == NULL) || (catal == NULL)) 2667 return(NULL); 2668 2669 if (xmlDebugCatalogs) 2670 xmlGenericError(xmlGenericErrorContext, 2671 "Resolve URI %s\n", URI); 2672 2673 if (catal->type == XML_XML_CATALOG_TYPE) { 2674 ret = xmlCatalogListXMLResolveURI(catal->xml, URI); 2675 if (ret == XML_CATAL_BREAK) 2676 ret = NULL; 2677 } else { 2678 const xmlChar *sgml; 2679 2680 sgml = xmlCatalogSGMLResolve(catal, NULL, URI); 2681 if (sgml != NULL) 2682 sgml = xmlStrdup(sgml); 2683 } 2684 return(ret); 2685} 2686 2687#ifdef LIBXML_OUTPUT_ENABLED 2688/** 2689 * xmlACatalogDump: 2690 * @catal: a Catalog 2691 * @out: the file. 2692 * 2693 * Free up all the memory associated with catalogs 2694 */ 2695void 2696xmlACatalogDump(xmlCatalogPtr catal, FILE *out) { 2697 if ((out == NULL) || (catal == NULL)) 2698 return; 2699 2700 if (catal->type == XML_XML_CATALOG_TYPE) { 2701 xmlDumpXMLCatalog(out, catal->xml); 2702 } else { 2703 xmlHashScan(catal->sgml, 2704 (xmlHashScanner) xmlCatalogDumpEntry, out); 2705 } 2706} 2707#endif /* LIBXML_OUTPUT_ENABLED */ 2708 2709/** 2710 * xmlACatalogAdd: 2711 * @catal: a Catalog 2712 * @type: the type of record to add to the catalog 2713 * @orig: the system, public or prefix to match 2714 * @replace: the replacement value for the match 2715 * 2716 * Add an entry in the catalog, it may overwrite existing but 2717 * different entries. 2718 * 2719 * Returns 0 if successful, -1 otherwise 2720 */ 2721int 2722xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type, 2723 const xmlChar * orig, const xmlChar * replace) 2724{ 2725 int res = -1; 2726 2727 if (catal == NULL) 2728 return(-1); 2729 2730 if (catal->type == XML_XML_CATALOG_TYPE) { 2731 res = xmlAddXMLCatalog(catal->xml, type, orig, replace); 2732 } else { 2733 xmlCatalogEntryType cattype; 2734 2735 cattype = xmlGetSGMLCatalogEntryType(type); 2736 if (cattype != XML_CATA_NONE) { 2737 xmlCatalogEntryPtr entry; 2738 2739 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL, 2740 XML_CATA_PREFER_NONE); 2741 if (catal->sgml == NULL) 2742 catal->sgml = xmlHashCreate(10); 2743 res = xmlHashAddEntry(catal->sgml, orig, entry); 2744 } 2745 } 2746 return (res); 2747} 2748 2749/** 2750 * xmlACatalogRemove: 2751 * @catal: a Catalog 2752 * @value: the value to remove 2753 * 2754 * Remove an entry from the catalog 2755 * 2756 * Returns the number of entries removed if successful, -1 otherwise 2757 */ 2758int 2759xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) { 2760 int res = -1; 2761 2762 if ((catal == NULL) || (value == NULL)) 2763 return(-1); 2764 2765 if (catal->type == XML_XML_CATALOG_TYPE) { 2766 res = xmlDelXMLCatalog(catal->xml, value); 2767 } else { 2768 res = xmlHashRemoveEntry(catal->sgml, value, 2769 (xmlHashDeallocator) xmlFreeCatalogEntry); 2770 if (res == 0) 2771 res = 1; 2772 } 2773 return(res); 2774} 2775 2776/** 2777 * xmlNewCatalog: 2778 * @sgml: should this create an SGML catalog 2779 * 2780 * create a new Catalog. 2781 * 2782 * Returns the xmlCatalogPtr or NULL in case of error 2783 */ 2784xmlCatalogPtr 2785xmlNewCatalog(int sgml) { 2786 xmlCatalogPtr catal = NULL; 2787 2788 if (sgml) { 2789 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, 2790 xmlCatalogDefaultPrefer); 2791 if ((catal != NULL) && (catal->sgml == NULL)) 2792 catal->sgml = xmlHashCreate(10); 2793 } else 2794 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 2795 xmlCatalogDefaultPrefer); 2796 return(catal); 2797} 2798 2799/** 2800 * xmlCatalogIsEmpty: 2801 * @catal: should this create an SGML catalog 2802 * 2803 * Check is a catalog is empty 2804 * 2805 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error. 2806 */ 2807int 2808xmlCatalogIsEmpty(xmlCatalogPtr catal) { 2809 if (catal == NULL) 2810 return(-1); 2811 2812 if (catal->type == XML_XML_CATALOG_TYPE) { 2813 if (catal->xml == NULL) 2814 return(1); 2815 if ((catal->xml->type != XML_CATA_CATALOG) && 2816 (catal->xml->type != XML_CATA_BROKEN_CATALOG)) 2817 return(-1); 2818 if (catal->xml->children == NULL) 2819 return(1); 2820 return(0); 2821 } else { 2822 int res; 2823 2824 if (catal->sgml == NULL) 2825 return(1); 2826 res = xmlHashSize(catal->sgml); 2827 if (res == 0) 2828 return(1); 2829 if (res < 0) 2830 return(-1); 2831 } 2832 return(0); 2833} 2834 2835/************************************************************************ 2836 * * 2837 * Public interfaces manipulating the global shared default catalog * 2838 * * 2839 ************************************************************************/ 2840 2841/** 2842 * xmlInitializeCatalogData: 2843 * 2844 * Do the catalog initialization only of global data, doesn't try to load 2845 * any catalog actually. 2846 * this function is not thread safe, catalog initialization should 2847 * preferably be done once at startup 2848 */ 2849static void 2850xmlInitializeCatalogData(void) { 2851 if (xmlCatalogInitialized != 0) 2852 return; 2853 2854 if (getenv("XML_DEBUG_CATALOG")) 2855 xmlDebugCatalogs = 1; 2856 xmlCatalogMutex = xmlNewRMutex(); 2857 2858 xmlCatalogInitialized = 1; 2859} 2860/** 2861 * xmlInitializeCatalog: 2862 * 2863 * Do the catalog initialization. 2864 * this function is not thread safe, catalog initialization should 2865 * preferably be done once at startup 2866 */ 2867void 2868xmlInitializeCatalog(void) { 2869 if (xmlCatalogInitialized != 0) 2870 return; 2871 2872 xmlInitializeCatalogData(); 2873 xmlRMutexLock(xmlCatalogMutex); 2874 2875 if (getenv("XML_DEBUG_CATALOG")) 2876 xmlDebugCatalogs = 1; 2877 2878 if (xmlDefaultCatalog == NULL) { 2879 const char *catalogs; 2880 char *path; 2881 const char *cur, *paths; 2882 xmlCatalogPtr catal; 2883 xmlCatalogEntryPtr *nextent; 2884 2885 catalogs = (const char *) getenv("XML_CATALOG_FILES"); 2886 if (catalogs == NULL) 2887 catalogs = XML_XML_DEFAULT_CATALOG; 2888 2889 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 2890 xmlCatalogDefaultPrefer); 2891 if (catal != NULL) { 2892 /* the XML_CATALOG_FILES envvar is allowed to contain a 2893 space-separated list of entries. */ 2894 cur = catalogs; 2895 nextent = &catal->xml; 2896 while (*cur != '\0') { 2897 while (IS_BLANK(*cur)) 2898 cur++; 2899 if (*cur != 0) { 2900 paths = cur; 2901 while ((*cur != 0) && (!IS_BLANK(*cur))) 2902 cur++; 2903 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths); 2904 if (path != NULL) { 2905 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2906 NULL, BAD_CAST path, xmlCatalogDefaultPrefer); 2907 if (*nextent != NULL) 2908 nextent = &((*nextent)->next); 2909 xmlFree(path); 2910 } 2911 } 2912 } 2913 xmlDefaultCatalog = catal; 2914 } 2915 } 2916 2917 xmlRMutexUnlock(xmlCatalogMutex); 2918} 2919 2920 2921/** 2922 * xmlLoadCatalog: 2923 * @filename: a file path 2924 * 2925 * Load the catalog and makes its definitions effective for the default 2926 * external entity loader. It will recurse in SGML CATALOG entries. 2927 * this function is not thread safe, catalog initialization should 2928 * preferably be done once at startup 2929 * 2930 * Returns 0 in case of success -1 in case of error 2931 */ 2932int 2933xmlLoadCatalog(const char *filename) 2934{ 2935 int ret; 2936 xmlCatalogPtr catal; 2937 2938 if (!xmlCatalogInitialized) 2939 xmlInitializeCatalogData(); 2940 2941 xmlRMutexLock(xmlCatalogMutex); 2942 2943 if (xmlDefaultCatalog == NULL) { 2944 catal = xmlLoadACatalog(filename); 2945 if (catal == NULL) { 2946 xmlRMutexUnlock(xmlCatalogMutex); 2947 return(-1); 2948 } 2949 2950 xmlDefaultCatalog = catal; 2951 xmlRMutexUnlock(xmlCatalogMutex); 2952 return(0); 2953 } 2954 2955 ret = xmlExpandCatalog(xmlDefaultCatalog, filename); 2956 xmlRMutexUnlock(xmlCatalogMutex); 2957 return(ret); 2958} 2959 2960/** 2961 * xmlLoadCatalogs: 2962 * @pathss: a list of directories separated by a colon or a space. 2963 * 2964 * Load the catalogs and makes their definitions effective for the default 2965 * external entity loader. 2966 * this function is not thread safe, catalog initialization should 2967 * preferably be done once at startup 2968 */ 2969void 2970xmlLoadCatalogs(const char *pathss) { 2971 const char *cur; 2972 const char *paths; 2973 xmlChar *path; 2974 2975 if (pathss == NULL) 2976 return; 2977 2978 cur = pathss; 2979 while ((cur != NULL) && (*cur != 0)) { 2980 while (IS_BLANK(*cur)) cur++; 2981 if (*cur != 0) { 2982 paths = cur; 2983 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur))) 2984 cur++; 2985 path = xmlStrndup((const xmlChar *)paths, cur - paths); 2986 if (path != NULL) { 2987 xmlLoadCatalog((const char *) path); 2988 xmlFree(path); 2989 } 2990 } 2991 while (*cur == ':') 2992 cur++; 2993 } 2994} 2995 2996/** 2997 * xmlCatalogCleanup: 2998 * 2999 * Free up all the memory associated with catalogs 3000 */ 3001void 3002xmlCatalogCleanup(void) { 3003 if (xmlCatalogInitialized == 0) 3004 return; 3005 3006 xmlRMutexLock(xmlCatalogMutex); 3007 if (xmlDebugCatalogs) 3008 xmlGenericError(xmlGenericErrorContext, 3009 "Catalogs cleanup\n"); 3010 if (xmlCatalogXMLFiles != NULL) 3011 xmlHashFree(xmlCatalogXMLFiles, 3012 (xmlHashDeallocator)xmlFreeCatalogHashEntryList); 3013 xmlCatalogXMLFiles = NULL; 3014 if (xmlDefaultCatalog != NULL) 3015 xmlFreeCatalog(xmlDefaultCatalog); 3016 xmlDefaultCatalog = NULL; 3017 xmlDebugCatalogs = 0; 3018 xmlCatalogInitialized = 0; 3019 xmlRMutexUnlock(xmlCatalogMutex); 3020 xmlFreeRMutex(xmlCatalogMutex); 3021} 3022 3023/** 3024 * xmlCatalogResolveSystem: 3025 * @sysID: the public ID string 3026 * 3027 * Try to lookup the catalog resource for a system ID 3028 * 3029 * Returns the system ID if found or NULL otherwise, the value returned 3030 * must be freed by the caller. 3031 */ 3032xmlChar * 3033xmlCatalogResolveSystem(const xmlChar *sysID) { 3034 xmlChar *ret; 3035 3036 if (!xmlCatalogInitialized) 3037 xmlInitializeCatalog(); 3038 3039 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID); 3040 return(ret); 3041} 3042 3043/** 3044 * xmlCatalogResolvePublic: 3045 * @pubID: the public ID string 3046 * 3047 * Try to lookup the system ID associated to a public ID 3048 * 3049 * Returns the system ID if found or NULL otherwise, the value returned 3050 * must be freed by the caller. 3051 */ 3052xmlChar * 3053xmlCatalogResolvePublic(const xmlChar *pubID) { 3054 xmlChar *ret; 3055 3056 if (!xmlCatalogInitialized) 3057 xmlInitializeCatalog(); 3058 3059 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID); 3060 return(ret); 3061} 3062 3063/** 3064 * xmlCatalogResolve: 3065 * @pubID: the public ID string 3066 * @sysID: the system ID string 3067 * 3068 * Do a complete resolution lookup of an External Identifier 3069 * 3070 * Returns the URI of the resource or NULL if not found, it must be freed 3071 * by the caller. 3072 */ 3073xmlChar * 3074xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) { 3075 xmlChar *ret; 3076 3077 if (!xmlCatalogInitialized) 3078 xmlInitializeCatalog(); 3079 3080 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID); 3081 return(ret); 3082} 3083 3084/** 3085 * xmlCatalogResolveURI: 3086 * @URI: the URI 3087 * 3088 * Do a complete resolution lookup of an URI 3089 * 3090 * Returns the URI of the resource or NULL if not found, it must be freed 3091 * by the caller. 3092 */ 3093xmlChar * 3094xmlCatalogResolveURI(const xmlChar *URI) { 3095 xmlChar *ret; 3096 3097 if (!xmlCatalogInitialized) 3098 xmlInitializeCatalog(); 3099 3100 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI); 3101 return(ret); 3102} 3103 3104#ifdef LIBXML_OUTPUT_ENABLED 3105/** 3106 * xmlCatalogDump: 3107 * @out: the file. 3108 * 3109 * Free up all the memory associated with catalogs 3110 */ 3111void 3112xmlCatalogDump(FILE *out) { 3113 if (out == NULL) 3114 return; 3115 3116 if (!xmlCatalogInitialized) 3117 xmlInitializeCatalog(); 3118 3119 xmlACatalogDump(xmlDefaultCatalog, out); 3120} 3121#endif /* LIBXML_OUTPUT_ENABLED */ 3122 3123/** 3124 * xmlCatalogAdd: 3125 * @type: the type of record to add to the catalog 3126 * @orig: the system, public or prefix to match 3127 * @replace: the replacement value for the match 3128 * 3129 * Add an entry in the catalog, it may overwrite existing but 3130 * different entries. 3131 * If called before any other catalog routine, allows to override the 3132 * default shared catalog put in place by xmlInitializeCatalog(); 3133 * 3134 * Returns 0 if successful, -1 otherwise 3135 */ 3136int 3137xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { 3138 int res = -1; 3139 3140 if (!xmlCatalogInitialized) 3141 xmlInitializeCatalogData(); 3142 3143 xmlRMutexLock(xmlCatalogMutex); 3144 /* 3145 * Specific case where one want to override the default catalog 3146 * put in place by xmlInitializeCatalog(); 3147 */ 3148 if ((xmlDefaultCatalog == NULL) && 3149 (xmlStrEqual(type, BAD_CAST "catalog"))) { 3150 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 3151 xmlCatalogDefaultPrefer); 3152 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 3153 orig, NULL, xmlCatalogDefaultPrefer); 3154 3155 xmlRMutexUnlock(xmlCatalogMutex); 3156 return(0); 3157 } 3158 3159 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace); 3160 xmlRMutexUnlock(xmlCatalogMutex); 3161 return(res); 3162} 3163 3164/** 3165 * xmlCatalogRemove: 3166 * @value: the value to remove 3167 * 3168 * Remove an entry from the catalog 3169 * 3170 * Returns the number of entries removed if successful, -1 otherwise 3171 */ 3172int 3173xmlCatalogRemove(const xmlChar *value) { 3174 int res; 3175 3176 if (!xmlCatalogInitialized) 3177 xmlInitializeCatalog(); 3178 3179 xmlRMutexLock(xmlCatalogMutex); 3180 res = xmlACatalogRemove(xmlDefaultCatalog, value); 3181 xmlRMutexUnlock(xmlCatalogMutex); 3182 return(res); 3183} 3184 3185/** 3186 * xmlCatalogConvert: 3187 * 3188 * Convert all the SGML catalog entries as XML ones 3189 * 3190 * Returns the number of entries converted if successful, -1 otherwise 3191 */ 3192int 3193xmlCatalogConvert(void) { 3194 int res = -1; 3195 3196 if (!xmlCatalogInitialized) 3197 xmlInitializeCatalog(); 3198 3199 xmlRMutexLock(xmlCatalogMutex); 3200 res = xmlConvertSGMLCatalog(xmlDefaultCatalog); 3201 xmlRMutexUnlock(xmlCatalogMutex); 3202 return(res); 3203} 3204 3205/************************************************************************ 3206 * * 3207 * Public interface manipulating the common preferences * 3208 * * 3209 ************************************************************************/ 3210 3211/** 3212 * xmlCatalogGetDefaults: 3213 * 3214 * Used to get the user preference w.r.t. to what catalogs should 3215 * be accepted 3216 * 3217 * Returns the current xmlCatalogAllow value 3218 */ 3219xmlCatalogAllow 3220xmlCatalogGetDefaults(void) { 3221 return(xmlCatalogDefaultAllow); 3222} 3223 3224/** 3225 * xmlCatalogSetDefaults: 3226 * @allow: what catalogs should be accepted 3227 * 3228 * Used to set the user preference w.r.t. to what catalogs should 3229 * be accepted 3230 */ 3231void 3232xmlCatalogSetDefaults(xmlCatalogAllow allow) { 3233 if (xmlDebugCatalogs) { 3234 switch (allow) { 3235 case XML_CATA_ALLOW_NONE: 3236 xmlGenericError(xmlGenericErrorContext, 3237 "Disabling catalog usage\n"); 3238 break; 3239 case XML_CATA_ALLOW_GLOBAL: 3240 xmlGenericError(xmlGenericErrorContext, 3241 "Allowing only global catalogs\n"); 3242 break; 3243 case XML_CATA_ALLOW_DOCUMENT: 3244 xmlGenericError(xmlGenericErrorContext, 3245 "Allowing only catalogs from the document\n"); 3246 break; 3247 case XML_CATA_ALLOW_ALL: 3248 xmlGenericError(xmlGenericErrorContext, 3249 "Allowing all catalogs\n"); 3250 break; 3251 } 3252 } 3253 xmlCatalogDefaultAllow = allow; 3254} 3255 3256/** 3257 * xmlCatalogSetDefaultPrefer: 3258 * @prefer: the default preference for delegation 3259 * 3260 * Allows to set the preference between public and system for deletion 3261 * in XML Catalog resolution. C.f. section 4.1.1 of the spec 3262 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM 3263 * 3264 * Returns the previous value of the default preference for delegation 3265 */ 3266xmlCatalogPrefer 3267xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { 3268 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer; 3269 3270 if (prefer == XML_CATA_PREFER_NONE) 3271 return(ret); 3272 3273 if (xmlDebugCatalogs) { 3274 switch (prefer) { 3275 case XML_CATA_PREFER_PUBLIC: 3276 xmlGenericError(xmlGenericErrorContext, 3277 "Setting catalog preference to PUBLIC\n"); 3278 break; 3279 case XML_CATA_PREFER_SYSTEM: 3280 xmlGenericError(xmlGenericErrorContext, 3281 "Setting catalog preference to SYSTEM\n"); 3282 break; 3283 case XML_CATA_PREFER_NONE: 3284 break; 3285 } 3286 } 3287 xmlCatalogDefaultPrefer = prefer; 3288 return(ret); 3289} 3290 3291/** 3292 * xmlCatalogSetDebug: 3293 * @level: the debug level of catalogs required 3294 * 3295 * Used to set the debug level for catalog operation, 0 disable 3296 * debugging, 1 enable it 3297 * 3298 * Returns the previous value of the catalog debugging level 3299 */ 3300int 3301xmlCatalogSetDebug(int level) { 3302 int ret = xmlDebugCatalogs; 3303 3304 if (level <= 0) 3305 xmlDebugCatalogs = 0; 3306 else 3307 xmlDebugCatalogs = level; 3308 return(ret); 3309} 3310 3311/************************************************************************ 3312 * * 3313 * Minimal interfaces used for per-document catalogs by the parser * 3314 * * 3315 ************************************************************************/ 3316 3317/** 3318 * xmlCatalogFreeLocal: 3319 * @catalogs: a document's list of catalogs 3320 * 3321 * Free up the memory associated to the catalog list 3322 */ 3323void 3324xmlCatalogFreeLocal(void *catalogs) { 3325 xmlCatalogEntryPtr catal; 3326 3327 if (!xmlCatalogInitialized) 3328 xmlInitializeCatalog(); 3329 3330 catal = (xmlCatalogEntryPtr) catalogs; 3331 if (catal != NULL) 3332 xmlFreeCatalogEntryList(catal); 3333} 3334 3335 3336/** 3337 * xmlCatalogAddLocal: 3338 * @catalogs: a document's list of catalogs 3339 * @URL: the URL to a new local catalog 3340 * 3341 * Add the new entry to the catalog list 3342 * 3343 * Returns the updated list 3344 */ 3345void * 3346xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { 3347 xmlCatalogEntryPtr catal, add; 3348 3349 if (!xmlCatalogInitialized) 3350 xmlInitializeCatalog(); 3351 3352 if (URL == NULL) 3353 return(catalogs); 3354 3355 if (xmlDebugCatalogs) 3356 xmlGenericError(xmlGenericErrorContext, 3357 "Adding document catalog %s\n", URL); 3358 3359 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, 3360 xmlCatalogDefaultPrefer); 3361 if (add == NULL) 3362 return(catalogs); 3363 3364 catal = (xmlCatalogEntryPtr) catalogs; 3365 if (catal == NULL) 3366 return((void *) add); 3367 3368 while (catal->next != NULL) 3369 catal = catal->next; 3370 catal->next = add; 3371 return(catalogs); 3372} 3373 3374/** 3375 * xmlCatalogLocalResolve: 3376 * @catalogs: a document's list of catalogs 3377 * @pubID: the public ID string 3378 * @sysID: the system ID string 3379 * 3380 * Do a complete resolution lookup of an External Identifier using a 3381 * document's private catalog list 3382 * 3383 * Returns the URI of the resource or NULL if not found, it must be freed 3384 * by the caller. 3385 */ 3386xmlChar * 3387xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, 3388 const xmlChar *sysID) { 3389 xmlCatalogEntryPtr catal; 3390 xmlChar *ret; 3391 3392 if (!xmlCatalogInitialized) 3393 xmlInitializeCatalog(); 3394 3395 if ((pubID == NULL) && (sysID == NULL)) 3396 return(NULL); 3397 3398 if (xmlDebugCatalogs) { 3399 if (pubID != NULL) { 3400 xmlGenericError(xmlGenericErrorContext, 3401 "Local resolve: pubID %s\n", pubID); 3402 } else { 3403 xmlGenericError(xmlGenericErrorContext, 3404 "Local resolve: sysID %s\n", sysID); 3405 } 3406 } 3407 3408 catal = (xmlCatalogEntryPtr) catalogs; 3409 if (catal == NULL) 3410 return(NULL); 3411 ret = xmlCatalogListXMLResolve(catal, pubID, sysID); 3412 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 3413 return(ret); 3414 return(NULL); 3415} 3416 3417/** 3418 * xmlCatalogLocalResolveURI: 3419 * @catalogs: a document's list of catalogs 3420 * @URI: the URI 3421 * 3422 * Do a complete resolution lookup of an URI using a 3423 * document's private catalog list 3424 * 3425 * Returns the URI of the resource or NULL if not found, it must be freed 3426 * by the caller. 3427 */ 3428xmlChar * 3429xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { 3430 xmlCatalogEntryPtr catal; 3431 xmlChar *ret; 3432 3433 if (!xmlCatalogInitialized) 3434 xmlInitializeCatalog(); 3435 3436 if (URI == NULL) 3437 return(NULL); 3438 3439 if (xmlDebugCatalogs) 3440 xmlGenericError(xmlGenericErrorContext, 3441 "Resolve URI %s\n", URI); 3442 3443 catal = (xmlCatalogEntryPtr) catalogs; 3444 if (catal == NULL) 3445 return(NULL); 3446 ret = xmlCatalogListXMLResolveURI(catal, URI); 3447 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 3448 return(ret); 3449 return(NULL); 3450} 3451 3452/************************************************************************ 3453 * * 3454 * Deprecated interfaces * 3455 * * 3456 ************************************************************************/ 3457/** 3458 * xmlCatalogGetSystem: 3459 * @sysID: the system ID string 3460 * 3461 * Try to lookup the system ID associated to a public ID 3462 * DEPRECATED, use xmlCatalogResolveSystem() 3463 * 3464 * Returns the system ID if found or NULL otherwise. 3465 */ 3466const xmlChar * 3467xmlCatalogGetSystem(const xmlChar *sysID) { 3468 xmlChar *ret; 3469 static xmlChar result[1000]; 3470 static int msg = 0; 3471 3472 if (!xmlCatalogInitialized) 3473 xmlInitializeCatalog(); 3474 3475 if (msg == 0) { 3476 xmlGenericError(xmlGenericErrorContext, 3477 "Use of deprecated xmlCatalogGetSystem() call\n"); 3478 msg++; 3479 } 3480 3481 if (sysID == NULL) 3482 return(NULL); 3483 3484 /* 3485 * Check first the XML catalogs 3486 */ 3487 if (xmlDefaultCatalog != NULL) { 3488 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID); 3489 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 3490 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 3491 result[sizeof(result) - 1] = 0; 3492 return(result); 3493 } 3494 } 3495 3496 if (xmlDefaultCatalog != NULL) 3497 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID)); 3498 return(NULL); 3499} 3500 3501/** 3502 * xmlCatalogGetPublic: 3503 * @pubID: the public ID string 3504 * 3505 * Try to lookup the system ID associated to a public ID 3506 * DEPRECATED, use xmlCatalogResolvePublic() 3507 * 3508 * Returns the system ID if found or NULL otherwise. 3509 */ 3510const xmlChar * 3511xmlCatalogGetPublic(const xmlChar *pubID) { 3512 xmlChar *ret; 3513 static xmlChar result[1000]; 3514 static int msg = 0; 3515 3516 if (!xmlCatalogInitialized) 3517 xmlInitializeCatalog(); 3518 3519 if (msg == 0) { 3520 xmlGenericError(xmlGenericErrorContext, 3521 "Use of deprecated xmlCatalogGetPublic() call\n"); 3522 msg++; 3523 } 3524 3525 if (pubID == NULL) 3526 return(NULL); 3527 3528 /* 3529 * Check first the XML catalogs 3530 */ 3531 if (xmlDefaultCatalog != NULL) { 3532 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL); 3533 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 3534 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 3535 result[sizeof(result) - 1] = 0; 3536 return(result); 3537 } 3538 } 3539 3540 if (xmlDefaultCatalog != NULL) 3541 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID)); 3542 return(NULL); 3543} 3544 3545#endif /* LIBXML_CATALOG_ENABLED */ 3546