catalog.c revision 76e95df05556c9610b564b14cf578c8f9e34c9c1
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 entry 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 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) - 3) 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[1] == 'B')) 767 result[i++] = '+'; 768 else if ((urn[1] == '3') && (urn[1] == 'A')) 769 result[i++] = ':'; 770 else if ((urn[1] == '2') && (urn[1] == 'F')) 771 result[i++] = '/'; 772 else if ((urn[1] == '3') && (urn[1] == 'B')) 773 result[i++] = ';'; 774 else if ((urn[1] == '2') && (urn[1] == '7')) 775 result[i++] = '\''; 776 else if ((urn[1] == '3') && (urn[1] == 'F')) 777 result[i++] = '?'; 778 else if ((urn[1] == '2') && (urn[1] == '3')) 779 result[i++] = '#'; 780 else if ((urn[1] == '2') && (urn[1] == '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 associate 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, NULL); 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(*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 system ID associated to a public ID 2361 * 2362 * Returns the system ID 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 public ID string 2383 * 2384 * Try to lookup the catalog local reference for a system ID 2385 * 2386 * Returns the system ID 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 public ID string 2580 * 2581 * Try to lookup the catalog resource for a system ID 2582 * 2583 * Returns the system ID 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 system ID associated to a public ID in that catalog 2617 * 2618 * Returns the system ID 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) { 2668 xmlGenericError(xmlGenericErrorContext, 2669 "Resolve: pubID %s\n", pubID); 2670 } else { 2671 xmlGenericError(xmlGenericErrorContext, 2672 "Resolve: sysID %s\n", sysID); 2673 } 2674 } 2675 2676 if (catal->type == XML_XML_CATALOG_TYPE) { 2677 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID); 2678 if (ret == XML_CATAL_BREAK) 2679 ret = NULL; 2680 } else { 2681 const xmlChar *sgml; 2682 2683 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID); 2684 if (sgml != NULL) 2685 ret = xmlStrdup(sgml); 2686 } 2687 return (ret); 2688} 2689 2690/** 2691 * xmlACatalogResolveURI: 2692 * @catal: a Catalog 2693 * @URI: the URI 2694 * 2695 * Do a complete resolution lookup of an URI 2696 * 2697 * Returns the URI of the resource or NULL if not found, it must be freed 2698 * by the caller. 2699 */ 2700xmlChar * 2701xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { 2702 xmlChar *ret = NULL; 2703 2704 if ((URI == NULL) || (catal == NULL)) 2705 return(NULL); 2706 2707 if (xmlDebugCatalogs) 2708 xmlGenericError(xmlGenericErrorContext, 2709 "Resolve URI %s\n", URI); 2710 2711 if (catal->type == XML_XML_CATALOG_TYPE) { 2712 ret = xmlCatalogListXMLResolveURI(catal->xml, URI); 2713 if (ret == XML_CATAL_BREAK) 2714 ret = NULL; 2715 } else { 2716 const xmlChar *sgml; 2717 2718 sgml = xmlCatalogSGMLResolve(catal, NULL, URI); 2719 if (sgml != NULL) 2720 sgml = xmlStrdup(sgml); 2721 } 2722 return(ret); 2723} 2724 2725#ifdef LIBXML_OUTPUT_ENABLED 2726/** 2727 * xmlACatalogDump: 2728 * @catal: a Catalog 2729 * @out: the file. 2730 * 2731 * Free up all the memory associated with catalogs 2732 */ 2733void 2734xmlACatalogDump(xmlCatalogPtr catal, FILE *out) { 2735 if ((out == NULL) || (catal == NULL)) 2736 return; 2737 2738 if (catal->type == XML_XML_CATALOG_TYPE) { 2739 xmlDumpXMLCatalog(out, catal->xml); 2740 } else { 2741 xmlHashScan(catal->sgml, 2742 (xmlHashScanner) xmlCatalogDumpEntry, out); 2743 } 2744} 2745#endif /* LIBXML_OUTPUT_ENABLED */ 2746 2747/** 2748 * xmlACatalogAdd: 2749 * @catal: a Catalog 2750 * @type: the type of record to add to the catalog 2751 * @orig: the system, public or prefix to match 2752 * @replace: the replacement value for the match 2753 * 2754 * Add an entry in the catalog, it may overwrite existing but 2755 * different entries. 2756 * 2757 * Returns 0 if successful, -1 otherwise 2758 */ 2759int 2760xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type, 2761 const xmlChar * orig, const xmlChar * replace) 2762{ 2763 int res = -1; 2764 2765 if (catal == NULL) 2766 return(-1); 2767 2768 if (catal->type == XML_XML_CATALOG_TYPE) { 2769 res = xmlAddXMLCatalog(catal->xml, type, orig, replace); 2770 } else { 2771 xmlCatalogEntryType cattype; 2772 2773 cattype = xmlGetSGMLCatalogEntryType(type); 2774 if (cattype != XML_CATA_NONE) { 2775 xmlCatalogEntryPtr entry; 2776 2777 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL, 2778 XML_CATA_PREFER_NONE); 2779 if (catal->sgml == NULL) 2780 catal->sgml = xmlHashCreate(10); 2781 res = xmlHashAddEntry(catal->sgml, orig, entry); 2782 } 2783 } 2784 return (res); 2785} 2786 2787/** 2788 * xmlACatalogRemove: 2789 * @catal: a Catalog 2790 * @value: the value to remove 2791 * 2792 * Remove an entry from the catalog 2793 * 2794 * Returns the number of entries removed if successful, -1 otherwise 2795 */ 2796int 2797xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) { 2798 int res = -1; 2799 2800 if ((catal == NULL) || (value == NULL)) 2801 return(-1); 2802 2803 if (catal->type == XML_XML_CATALOG_TYPE) { 2804 res = xmlDelXMLCatalog(catal->xml, value); 2805 } else { 2806 res = xmlHashRemoveEntry(catal->sgml, value, 2807 (xmlHashDeallocator) xmlFreeCatalogEntry); 2808 if (res == 0) 2809 res = 1; 2810 } 2811 return(res); 2812} 2813 2814/** 2815 * xmlNewCatalog: 2816 * @sgml: should this create an SGML catalog 2817 * 2818 * create a new Catalog. 2819 * 2820 * Returns the xmlCatalogPtr or NULL in case of error 2821 */ 2822xmlCatalogPtr 2823xmlNewCatalog(int sgml) { 2824 xmlCatalogPtr catal = NULL; 2825 2826 if (sgml) { 2827 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, 2828 xmlCatalogDefaultPrefer); 2829 if ((catal != NULL) && (catal->sgml == NULL)) 2830 catal->sgml = xmlHashCreate(10); 2831 } else 2832 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 2833 xmlCatalogDefaultPrefer); 2834 return(catal); 2835} 2836 2837/** 2838 * xmlCatalogIsEmpty: 2839 * @catal: should this create an SGML catalog 2840 * 2841 * Check is a catalog is empty 2842 * 2843 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error. 2844 */ 2845int 2846xmlCatalogIsEmpty(xmlCatalogPtr catal) { 2847 if (catal == NULL) 2848 return(-1); 2849 2850 if (catal->type == XML_XML_CATALOG_TYPE) { 2851 if (catal->xml == NULL) 2852 return(1); 2853 if ((catal->xml->type != XML_CATA_CATALOG) && 2854 (catal->xml->type != XML_CATA_BROKEN_CATALOG)) 2855 return(-1); 2856 if (catal->xml->children == NULL) 2857 return(1); 2858 return(0); 2859 } else { 2860 int res; 2861 2862 if (catal->sgml == NULL) 2863 return(1); 2864 res = xmlHashSize(catal->sgml); 2865 if (res == 0) 2866 return(1); 2867 if (res < 0) 2868 return(-1); 2869 } 2870 return(0); 2871} 2872 2873/************************************************************************ 2874 * * 2875 * Public interfaces manipulating the global shared default catalog * 2876 * * 2877 ************************************************************************/ 2878 2879/** 2880 * xmlInitializeCatalogData: 2881 * 2882 * Do the catalog initialization only of global data, doesn't try to load 2883 * any catalog actually. 2884 * this function is not thread safe, catalog initialization should 2885 * preferably be done once at startup 2886 */ 2887static void 2888xmlInitializeCatalogData(void) { 2889 if (xmlCatalogInitialized != 0) 2890 return; 2891 2892 if (getenv("XML_DEBUG_CATALOG")) 2893 xmlDebugCatalogs = 1; 2894 xmlCatalogMutex = xmlNewRMutex(); 2895 2896 xmlCatalogInitialized = 1; 2897} 2898/** 2899 * xmlInitializeCatalog: 2900 * 2901 * Do the catalog initialization. 2902 * this function is not thread safe, catalog initialization should 2903 * preferably be done once at startup 2904 */ 2905void 2906xmlInitializeCatalog(void) { 2907 if (xmlCatalogInitialized != 0) 2908 return; 2909 2910 xmlInitializeCatalogData(); 2911 xmlRMutexLock(xmlCatalogMutex); 2912 2913 if (getenv("XML_DEBUG_CATALOG")) 2914 xmlDebugCatalogs = 1; 2915 2916 if (xmlDefaultCatalog == NULL) { 2917 const char *catalogs; 2918 char *path; 2919 const char *cur, *paths; 2920 xmlCatalogPtr catal; 2921 xmlCatalogEntryPtr *nextent; 2922 2923 catalogs = (const char *) getenv("XML_CATALOG_FILES"); 2924 if (catalogs == NULL) 2925 catalogs = XML_XML_DEFAULT_CATALOG; 2926 2927 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 2928 xmlCatalogDefaultPrefer); 2929 if (catal != NULL) { 2930 /* the XML_CATALOG_FILES envvar is allowed to contain a 2931 space-separated list of entries. */ 2932 cur = catalogs; 2933 nextent = &catal->xml; 2934 while (*cur != '\0') { 2935 while (xmlIsBlank_ch(*cur)) 2936 cur++; 2937 if (*cur != 0) { 2938 paths = cur; 2939 while ((*cur != 0) && (!xmlIsBlank_ch(*cur))) 2940 cur++; 2941 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths); 2942 if (path != NULL) { 2943 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2944 NULL, BAD_CAST path, xmlCatalogDefaultPrefer); 2945 if (*nextent != NULL) 2946 nextent = &((*nextent)->next); 2947 xmlFree(path); 2948 } 2949 } 2950 } 2951 xmlDefaultCatalog = catal; 2952 } 2953 } 2954 2955 xmlRMutexUnlock(xmlCatalogMutex); 2956} 2957 2958 2959/** 2960 * xmlLoadCatalog: 2961 * @filename: a file path 2962 * 2963 * Load the catalog and makes its definitions effective for the default 2964 * external entity loader. It will recurse in SGML CATALOG entries. 2965 * this function is not thread safe, catalog initialization should 2966 * preferably be done once at startup 2967 * 2968 * Returns 0 in case of success -1 in case of error 2969 */ 2970int 2971xmlLoadCatalog(const char *filename) 2972{ 2973 int ret; 2974 xmlCatalogPtr catal; 2975 2976 if (!xmlCatalogInitialized) 2977 xmlInitializeCatalogData(); 2978 2979 xmlRMutexLock(xmlCatalogMutex); 2980 2981 if (xmlDefaultCatalog == NULL) { 2982 catal = xmlLoadACatalog(filename); 2983 if (catal == NULL) { 2984 xmlRMutexUnlock(xmlCatalogMutex); 2985 return(-1); 2986 } 2987 2988 xmlDefaultCatalog = catal; 2989 xmlRMutexUnlock(xmlCatalogMutex); 2990 return(0); 2991 } 2992 2993 ret = xmlExpandCatalog(xmlDefaultCatalog, filename); 2994 xmlRMutexUnlock(xmlCatalogMutex); 2995 return(ret); 2996} 2997 2998/** 2999 * xmlLoadCatalogs: 3000 * @pathss: a list of directories separated by a colon or a space. 3001 * 3002 * Load the catalogs and makes their definitions effective for the default 3003 * external entity loader. 3004 * this function is not thread safe, catalog initialization should 3005 * preferably be done once at startup 3006 */ 3007void 3008xmlLoadCatalogs(const char *pathss) { 3009 const char *cur; 3010 const char *paths; 3011 xmlChar *path; 3012 3013 if (pathss == NULL) 3014 return; 3015 3016 cur = pathss; 3017 while ((cur != NULL) && (*cur != 0)) { 3018 while (xmlIsBlank_ch(*cur)) cur++; 3019 if (*cur != 0) { 3020 paths = cur; 3021 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur))) 3022 cur++; 3023 path = xmlStrndup((const xmlChar *)paths, cur - paths); 3024 if (path != NULL) { 3025 xmlLoadCatalog((const char *) path); 3026 xmlFree(path); 3027 } 3028 } 3029 while (*cur == ':') 3030 cur++; 3031 } 3032} 3033 3034/** 3035 * xmlCatalogCleanup: 3036 * 3037 * Free up all the memory associated with catalogs 3038 */ 3039void 3040xmlCatalogCleanup(void) { 3041 if (xmlCatalogInitialized == 0) 3042 return; 3043 3044 xmlRMutexLock(xmlCatalogMutex); 3045 if (xmlDebugCatalogs) 3046 xmlGenericError(xmlGenericErrorContext, 3047 "Catalogs cleanup\n"); 3048 if (xmlCatalogXMLFiles != NULL) 3049 xmlHashFree(xmlCatalogXMLFiles, 3050 (xmlHashDeallocator)xmlFreeCatalogHashEntryList); 3051 xmlCatalogXMLFiles = NULL; 3052 if (xmlDefaultCatalog != NULL) 3053 xmlFreeCatalog(xmlDefaultCatalog); 3054 xmlDefaultCatalog = NULL; 3055 xmlDebugCatalogs = 0; 3056 xmlCatalogInitialized = 0; 3057 xmlRMutexUnlock(xmlCatalogMutex); 3058 xmlFreeRMutex(xmlCatalogMutex); 3059} 3060 3061/** 3062 * xmlCatalogResolveSystem: 3063 * @sysID: the public ID string 3064 * 3065 * Try to lookup the catalog resource for a system ID 3066 * 3067 * Returns the system ID if found or NULL otherwise, the value returned 3068 * must be freed by the caller. 3069 */ 3070xmlChar * 3071xmlCatalogResolveSystem(const xmlChar *sysID) { 3072 xmlChar *ret; 3073 3074 if (!xmlCatalogInitialized) 3075 xmlInitializeCatalog(); 3076 3077 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID); 3078 return(ret); 3079} 3080 3081/** 3082 * xmlCatalogResolvePublic: 3083 * @pubID: the public ID string 3084 * 3085 * Try to lookup the system ID associated to a public ID 3086 * 3087 * Returns the system ID if found or NULL otherwise, the value returned 3088 * must be freed by the caller. 3089 */ 3090xmlChar * 3091xmlCatalogResolvePublic(const xmlChar *pubID) { 3092 xmlChar *ret; 3093 3094 if (!xmlCatalogInitialized) 3095 xmlInitializeCatalog(); 3096 3097 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID); 3098 return(ret); 3099} 3100 3101/** 3102 * xmlCatalogResolve: 3103 * @pubID: the public ID string 3104 * @sysID: the system ID string 3105 * 3106 * Do a complete resolution lookup of an External Identifier 3107 * 3108 * Returns the URI of the resource or NULL if not found, it must be freed 3109 * by the caller. 3110 */ 3111xmlChar * 3112xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) { 3113 xmlChar *ret; 3114 3115 if (!xmlCatalogInitialized) 3116 xmlInitializeCatalog(); 3117 3118 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID); 3119 return(ret); 3120} 3121 3122/** 3123 * xmlCatalogResolveURI: 3124 * @URI: the URI 3125 * 3126 * Do a complete resolution lookup of an URI 3127 * 3128 * Returns the URI of the resource or NULL if not found, it must be freed 3129 * by the caller. 3130 */ 3131xmlChar * 3132xmlCatalogResolveURI(const xmlChar *URI) { 3133 xmlChar *ret; 3134 3135 if (!xmlCatalogInitialized) 3136 xmlInitializeCatalog(); 3137 3138 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI); 3139 return(ret); 3140} 3141 3142#ifdef LIBXML_OUTPUT_ENABLED 3143/** 3144 * xmlCatalogDump: 3145 * @out: the file. 3146 * 3147 * Free up all the memory associated with catalogs 3148 */ 3149void 3150xmlCatalogDump(FILE *out) { 3151 if (out == NULL) 3152 return; 3153 3154 if (!xmlCatalogInitialized) 3155 xmlInitializeCatalog(); 3156 3157 xmlACatalogDump(xmlDefaultCatalog, out); 3158} 3159#endif /* LIBXML_OUTPUT_ENABLED */ 3160 3161/** 3162 * xmlCatalogAdd: 3163 * @type: the type of record to add to the catalog 3164 * @orig: the system, public or prefix to match 3165 * @replace: the replacement value for the match 3166 * 3167 * Add an entry in the catalog, it may overwrite existing but 3168 * different entries. 3169 * If called before any other catalog routine, allows to override the 3170 * default shared catalog put in place by xmlInitializeCatalog(); 3171 * 3172 * Returns 0 if successful, -1 otherwise 3173 */ 3174int 3175xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { 3176 int res = -1; 3177 3178 if (!xmlCatalogInitialized) 3179 xmlInitializeCatalogData(); 3180 3181 xmlRMutexLock(xmlCatalogMutex); 3182 /* 3183 * Specific case where one want to override the default catalog 3184 * put in place by xmlInitializeCatalog(); 3185 */ 3186 if ((xmlDefaultCatalog == NULL) && 3187 (xmlStrEqual(type, BAD_CAST "catalog"))) { 3188 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 3189 xmlCatalogDefaultPrefer); 3190 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 3191 orig, NULL, xmlCatalogDefaultPrefer); 3192 3193 xmlRMutexUnlock(xmlCatalogMutex); 3194 return(0); 3195 } 3196 3197 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace); 3198 xmlRMutexUnlock(xmlCatalogMutex); 3199 return(res); 3200} 3201 3202/** 3203 * xmlCatalogRemove: 3204 * @value: the value to remove 3205 * 3206 * Remove an entry from the catalog 3207 * 3208 * Returns the number of entries removed if successful, -1 otherwise 3209 */ 3210int 3211xmlCatalogRemove(const xmlChar *value) { 3212 int res; 3213 3214 if (!xmlCatalogInitialized) 3215 xmlInitializeCatalog(); 3216 3217 xmlRMutexLock(xmlCatalogMutex); 3218 res = xmlACatalogRemove(xmlDefaultCatalog, value); 3219 xmlRMutexUnlock(xmlCatalogMutex); 3220 return(res); 3221} 3222 3223/** 3224 * xmlCatalogConvert: 3225 * 3226 * Convert all the SGML catalog entries as XML ones 3227 * 3228 * Returns the number of entries converted if successful, -1 otherwise 3229 */ 3230int 3231xmlCatalogConvert(void) { 3232 int res = -1; 3233 3234 if (!xmlCatalogInitialized) 3235 xmlInitializeCatalog(); 3236 3237 xmlRMutexLock(xmlCatalogMutex); 3238 res = xmlConvertSGMLCatalog(xmlDefaultCatalog); 3239 xmlRMutexUnlock(xmlCatalogMutex); 3240 return(res); 3241} 3242 3243/************************************************************************ 3244 * * 3245 * Public interface manipulating the common preferences * 3246 * * 3247 ************************************************************************/ 3248 3249/** 3250 * xmlCatalogGetDefaults: 3251 * 3252 * Used to get the user preference w.r.t. to what catalogs should 3253 * be accepted 3254 * 3255 * Returns the current xmlCatalogAllow value 3256 */ 3257xmlCatalogAllow 3258xmlCatalogGetDefaults(void) { 3259 return(xmlCatalogDefaultAllow); 3260} 3261 3262/** 3263 * xmlCatalogSetDefaults: 3264 * @allow: what catalogs should be accepted 3265 * 3266 * Used to set the user preference w.r.t. to what catalogs should 3267 * be accepted 3268 */ 3269void 3270xmlCatalogSetDefaults(xmlCatalogAllow allow) { 3271 if (xmlDebugCatalogs) { 3272 switch (allow) { 3273 case XML_CATA_ALLOW_NONE: 3274 xmlGenericError(xmlGenericErrorContext, 3275 "Disabling catalog usage\n"); 3276 break; 3277 case XML_CATA_ALLOW_GLOBAL: 3278 xmlGenericError(xmlGenericErrorContext, 3279 "Allowing only global catalogs\n"); 3280 break; 3281 case XML_CATA_ALLOW_DOCUMENT: 3282 xmlGenericError(xmlGenericErrorContext, 3283 "Allowing only catalogs from the document\n"); 3284 break; 3285 case XML_CATA_ALLOW_ALL: 3286 xmlGenericError(xmlGenericErrorContext, 3287 "Allowing all catalogs\n"); 3288 break; 3289 } 3290 } 3291 xmlCatalogDefaultAllow = allow; 3292} 3293 3294/** 3295 * xmlCatalogSetDefaultPrefer: 3296 * @prefer: the default preference for delegation 3297 * 3298 * Allows to set the preference between public and system for deletion 3299 * in XML Catalog resolution. C.f. section 4.1.1 of the spec 3300 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM 3301 * 3302 * Returns the previous value of the default preference for delegation 3303 */ 3304xmlCatalogPrefer 3305xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { 3306 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer; 3307 3308 if (prefer == XML_CATA_PREFER_NONE) 3309 return(ret); 3310 3311 if (xmlDebugCatalogs) { 3312 switch (prefer) { 3313 case XML_CATA_PREFER_PUBLIC: 3314 xmlGenericError(xmlGenericErrorContext, 3315 "Setting catalog preference to PUBLIC\n"); 3316 break; 3317 case XML_CATA_PREFER_SYSTEM: 3318 xmlGenericError(xmlGenericErrorContext, 3319 "Setting catalog preference to SYSTEM\n"); 3320 break; 3321 case XML_CATA_PREFER_NONE: 3322 break; 3323 } 3324 } 3325 xmlCatalogDefaultPrefer = prefer; 3326 return(ret); 3327} 3328 3329/** 3330 * xmlCatalogSetDebug: 3331 * @level: the debug level of catalogs required 3332 * 3333 * Used to set the debug level for catalog operation, 0 disable 3334 * debugging, 1 enable it 3335 * 3336 * Returns the previous value of the catalog debugging level 3337 */ 3338int 3339xmlCatalogSetDebug(int level) { 3340 int ret = xmlDebugCatalogs; 3341 3342 if (level <= 0) 3343 xmlDebugCatalogs = 0; 3344 else 3345 xmlDebugCatalogs = level; 3346 return(ret); 3347} 3348 3349/************************************************************************ 3350 * * 3351 * Minimal interfaces used for per-document catalogs by the parser * 3352 * * 3353 ************************************************************************/ 3354 3355/** 3356 * xmlCatalogFreeLocal: 3357 * @catalogs: a document's list of catalogs 3358 * 3359 * Free up the memory associated to the catalog list 3360 */ 3361void 3362xmlCatalogFreeLocal(void *catalogs) { 3363 xmlCatalogEntryPtr catal; 3364 3365 if (!xmlCatalogInitialized) 3366 xmlInitializeCatalog(); 3367 3368 catal = (xmlCatalogEntryPtr) catalogs; 3369 if (catal != NULL) 3370 xmlFreeCatalogEntryList(catal); 3371} 3372 3373 3374/** 3375 * xmlCatalogAddLocal: 3376 * @catalogs: a document's list of catalogs 3377 * @URL: the URL to a new local catalog 3378 * 3379 * Add the new entry to the catalog list 3380 * 3381 * Returns the updated list 3382 */ 3383void * 3384xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { 3385 xmlCatalogEntryPtr catal, add; 3386 3387 if (!xmlCatalogInitialized) 3388 xmlInitializeCatalog(); 3389 3390 if (URL == NULL) 3391 return(catalogs); 3392 3393 if (xmlDebugCatalogs) 3394 xmlGenericError(xmlGenericErrorContext, 3395 "Adding document catalog %s\n", URL); 3396 3397 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, 3398 xmlCatalogDefaultPrefer); 3399 if (add == NULL) 3400 return(catalogs); 3401 3402 catal = (xmlCatalogEntryPtr) catalogs; 3403 if (catal == NULL) 3404 return((void *) add); 3405 3406 while (catal->next != NULL) 3407 catal = catal->next; 3408 catal->next = add; 3409 return(catalogs); 3410} 3411 3412/** 3413 * xmlCatalogLocalResolve: 3414 * @catalogs: a document's list of catalogs 3415 * @pubID: the public ID string 3416 * @sysID: the system ID string 3417 * 3418 * Do a complete resolution lookup of an External Identifier using a 3419 * document's private catalog list 3420 * 3421 * Returns the URI of the resource or NULL if not found, it must be freed 3422 * by the caller. 3423 */ 3424xmlChar * 3425xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, 3426 const xmlChar *sysID) { 3427 xmlCatalogEntryPtr catal; 3428 xmlChar *ret; 3429 3430 if (!xmlCatalogInitialized) 3431 xmlInitializeCatalog(); 3432 3433 if ((pubID == NULL) && (sysID == NULL)) 3434 return(NULL); 3435 3436 if (xmlDebugCatalogs) { 3437 if (pubID != NULL) { 3438 xmlGenericError(xmlGenericErrorContext, 3439 "Local resolve: pubID %s\n", pubID); 3440 } else { 3441 xmlGenericError(xmlGenericErrorContext, 3442 "Local resolve: sysID %s\n", sysID); 3443 } 3444 } 3445 3446 catal = (xmlCatalogEntryPtr) catalogs; 3447 if (catal == NULL) 3448 return(NULL); 3449 ret = xmlCatalogListXMLResolve(catal, pubID, sysID); 3450 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 3451 return(ret); 3452 return(NULL); 3453} 3454 3455/** 3456 * xmlCatalogLocalResolveURI: 3457 * @catalogs: a document's list of catalogs 3458 * @URI: the URI 3459 * 3460 * Do a complete resolution lookup of an URI using a 3461 * document's private catalog list 3462 * 3463 * Returns the URI of the resource or NULL if not found, it must be freed 3464 * by the caller. 3465 */ 3466xmlChar * 3467xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { 3468 xmlCatalogEntryPtr catal; 3469 xmlChar *ret; 3470 3471 if (!xmlCatalogInitialized) 3472 xmlInitializeCatalog(); 3473 3474 if (URI == NULL) 3475 return(NULL); 3476 3477 if (xmlDebugCatalogs) 3478 xmlGenericError(xmlGenericErrorContext, 3479 "Resolve URI %s\n", URI); 3480 3481 catal = (xmlCatalogEntryPtr) catalogs; 3482 if (catal == NULL) 3483 return(NULL); 3484 ret = xmlCatalogListXMLResolveURI(catal, URI); 3485 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 3486 return(ret); 3487 return(NULL); 3488} 3489 3490/************************************************************************ 3491 * * 3492 * Deprecated interfaces * 3493 * * 3494 ************************************************************************/ 3495/** 3496 * xmlCatalogGetSystem: 3497 * @sysID: the system ID string 3498 * 3499 * Try to lookup the system ID associated to a public ID 3500 * DEPRECATED, use xmlCatalogResolveSystem() 3501 * 3502 * Returns the system ID if found or NULL otherwise. 3503 */ 3504const xmlChar * 3505xmlCatalogGetSystem(const xmlChar *sysID) { 3506 xmlChar *ret; 3507 static xmlChar result[1000]; 3508 static int msg = 0; 3509 3510 if (!xmlCatalogInitialized) 3511 xmlInitializeCatalog(); 3512 3513 if (msg == 0) { 3514 xmlGenericError(xmlGenericErrorContext, 3515 "Use of deprecated xmlCatalogGetSystem() call\n"); 3516 msg++; 3517 } 3518 3519 if (sysID == NULL) 3520 return(NULL); 3521 3522 /* 3523 * Check first the XML catalogs 3524 */ 3525 if (xmlDefaultCatalog != NULL) { 3526 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID); 3527 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 3528 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 3529 result[sizeof(result) - 1] = 0; 3530 return(result); 3531 } 3532 } 3533 3534 if (xmlDefaultCatalog != NULL) 3535 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID)); 3536 return(NULL); 3537} 3538 3539/** 3540 * xmlCatalogGetPublic: 3541 * @pubID: the public ID string 3542 * 3543 * Try to lookup the system ID associated to a public ID 3544 * DEPRECATED, use xmlCatalogResolvePublic() 3545 * 3546 * Returns the system ID if found or NULL otherwise. 3547 */ 3548const xmlChar * 3549xmlCatalogGetPublic(const xmlChar *pubID) { 3550 xmlChar *ret; 3551 static xmlChar result[1000]; 3552 static int msg = 0; 3553 3554 if (!xmlCatalogInitialized) 3555 xmlInitializeCatalog(); 3556 3557 if (msg == 0) { 3558 xmlGenericError(xmlGenericErrorContext, 3559 "Use of deprecated xmlCatalogGetPublic() call\n"); 3560 msg++; 3561 } 3562 3563 if (pubID == NULL) 3564 return(NULL); 3565 3566 /* 3567 * Check first the XML catalogs 3568 */ 3569 if (xmlDefaultCatalog != NULL) { 3570 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL); 3571 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 3572 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 3573 result[sizeof(result) - 1] = 0; 3574 return(result); 3575 } 3576 } 3577 3578 if (xmlDefaultCatalog != NULL) 3579 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID)); 3580 return(NULL); 3581} 3582 3583#endif /* LIBXML_CATALOG_ENABLED */ 3584