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