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