catalog.c revision 5aad832aa34d21fca4696eb5a3bf203521f6a7f2
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 { 855 return (NULL); 856 } 857#ifdef HAVE_STAT 858 size = info.st_size; 859#else 860 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */ 861 fclose(fd); 862 return (NULL); 863 } 864#endif 865 content = xmlMalloc(size + 10); 866 if (content == NULL) { 867 xmlGenericError(xmlGenericErrorContext, 868 "malloc of %d byte failed\n", size + 10); 869 return (NULL); 870 } 871#ifdef HAVE_STAT 872 len = read(fd, content, size); 873#else 874 len = fread(content, 1, size, fd); 875#endif 876 if (len < 0) { 877 xmlFree(content); 878 return (NULL); 879 } 880#ifdef HAVE_STAT 881 close(fd); 882#else 883 fclose(fd); 884#endif 885 content[len] = 0; 886 887 return(content); 888} 889 890/************************************************************************ 891 * * 892 * The XML Catalog parser * 893 * * 894 ************************************************************************/ 895 896static xmlCatalogEntryPtr 897xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename); 898static void 899xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, 900 xmlCatalogEntryPtr parent); 901static xmlChar * 902xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 903 const xmlChar *sysID); 904static xmlChar * 905xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI); 906 907 908/** 909 * xmlGetXMLCatalogEntryType: 910 * @name: the name 911 * 912 * lookup the internal type associated to an XML catalog entry name 913 * 914 * Returns the type associate with that name 915 */ 916static xmlCatalogEntryType 917xmlGetXMLCatalogEntryType(const xmlChar *name) { 918 xmlCatalogEntryType type = XML_CATA_NONE; 919 if (xmlStrEqual(name, (const xmlChar *) "system")) 920 type = XML_CATA_SYSTEM; 921 else if (xmlStrEqual(name, (const xmlChar *) "public")) 922 type = XML_CATA_PUBLIC; 923 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem")) 924 type = XML_CATA_REWRITE_SYSTEM; 925 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic")) 926 type = XML_CATA_DELEGATE_PUBLIC; 927 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem")) 928 type = XML_CATA_DELEGATE_SYSTEM; 929 else if (xmlStrEqual(name, (const xmlChar *) "uri")) 930 type = XML_CATA_URI; 931 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI")) 932 type = XML_CATA_REWRITE_URI; 933 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI")) 934 type = XML_CATA_DELEGATE_URI; 935 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog")) 936 type = XML_CATA_NEXT_CATALOG; 937 else if (xmlStrEqual(name, (const xmlChar *) "catalog")) 938 type = XML_CATA_CATALOG; 939 return(type); 940} 941 942/** 943 * xmlParseXMLCatalogOneNode: 944 * @cur: the XML node 945 * @type: the type of Catalog entry 946 * @name: the name of the node 947 * @attrName: the attribute holding the value 948 * @uriAttrName: the attribute holding the URI-Reference 949 * @prefer: the PUBLIC vs. SYSTEM current preference value 950 * 951 * Finishes the examination of an XML tree node of a catalog and build 952 * a Catalog entry from it. 953 * 954 * Returns the new Catalog entry node or NULL in case of error. 955 */ 956static xmlCatalogEntryPtr 957xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, 958 const xmlChar *name, const xmlChar *attrName, 959 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) { 960 int ok = 1; 961 xmlChar *uriValue; 962 xmlChar *nameValue = NULL; 963 xmlChar *base = NULL; 964 xmlChar *URL = NULL; 965 xmlCatalogEntryPtr ret = NULL; 966 967 if (attrName != NULL) { 968 nameValue = xmlGetProp(cur, attrName); 969 if (nameValue == NULL) { 970 xmlGenericError(xmlGenericErrorContext, 971 "%s entry lacks '%s'\n", name, attrName); 972 ok = 0; 973 } 974 } 975 uriValue = xmlGetProp(cur, uriAttrName); 976 if (uriValue == NULL) { 977 xmlGenericError(xmlGenericErrorContext, 978 "%s entry lacks '%s'\n", name, uriAttrName); 979 ok = 0; 980 } 981 if (!ok) { 982 if (nameValue != NULL) 983 xmlFree(nameValue); 984 if (uriValue != NULL) 985 xmlFree(uriValue); 986 return(NULL); 987 } 988 989 base = xmlNodeGetBase(cur->doc, cur); 990 URL = xmlBuildURI(uriValue, base); 991 if (URL != NULL) { 992 if (xmlDebugCatalogs > 1) { 993 if (nameValue != NULL) 994 xmlGenericError(xmlGenericErrorContext, 995 "Found %s: '%s' '%s'\n", name, nameValue, URL); 996 else 997 xmlGenericError(xmlGenericErrorContext, 998 "Found %s: '%s'\n", name, URL); 999 } 1000 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer); 1001 } else { 1002 xmlGenericError(xmlGenericErrorContext, 1003 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue); 1004 } 1005 if (nameValue != NULL) 1006 xmlFree(nameValue); 1007 if (uriValue != NULL) 1008 xmlFree(uriValue); 1009 if (base != NULL) 1010 xmlFree(base); 1011 if (URL != NULL) 1012 xmlFree(URL); 1013 return(ret); 1014} 1015 1016/** 1017 * xmlParseXMLCatalogNode: 1018 * @cur: the XML node 1019 * @prefer: the PUBLIC vs. SYSTEM current preference value 1020 * @parent: the parent Catalog entry 1021 * 1022 * Examines an XML tree node of a catalog and build 1023 * a Catalog entry from it adding it to its parent. The examination can 1024 * be recursive. 1025 */ 1026static void 1027xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, 1028 xmlCatalogEntryPtr parent) 1029{ 1030 xmlChar *uri = NULL; 1031 xmlChar *URL = NULL; 1032 xmlChar *base = NULL; 1033 xmlCatalogEntryPtr entry = NULL; 1034 1035 if (cur == NULL) 1036 return; 1037 if (xmlStrEqual(cur->name, BAD_CAST "group")) { 1038 xmlChar *prop; 1039 1040 prop = xmlGetProp(cur, BAD_CAST "prefer"); 1041 if (prop != NULL) { 1042 if (xmlStrEqual(prop, BAD_CAST "system")) { 1043 prefer = XML_CATA_PREFER_SYSTEM; 1044 } else if (xmlStrEqual(prop, BAD_CAST "public")) { 1045 prefer = XML_CATA_PREFER_PUBLIC; 1046 } else { 1047 xmlGenericError(xmlGenericErrorContext, 1048 "Invalid value for prefer: '%s'\n", prop); 1049 } 1050 xmlFree(prop); 1051 } 1052 /* 1053 * Recurse to propagate prefer to the subtree 1054 * (xml:base handling is automated) 1055 */ 1056 xmlParseXMLCatalogNodeList(cur->children, prefer, parent); 1057 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) { 1058 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC, 1059 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer); 1060 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) { 1061 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM, 1062 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer); 1063 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) { 1064 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM, 1065 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString", 1066 BAD_CAST "rewritePrefix", prefer); 1067 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) { 1068 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC, 1069 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString", 1070 BAD_CAST "catalog", prefer); 1071 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) { 1072 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM, 1073 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString", 1074 BAD_CAST "catalog", prefer); 1075 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) { 1076 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI, 1077 BAD_CAST "uri", BAD_CAST "name", 1078 BAD_CAST "uri", prefer); 1079 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) { 1080 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI, 1081 BAD_CAST "rewriteURI", BAD_CAST "uriStartString", 1082 BAD_CAST "rewritePrefix", prefer); 1083 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) { 1084 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI, 1085 BAD_CAST "delegateURI", BAD_CAST "uriStartString", 1086 BAD_CAST "catalog", prefer); 1087 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { 1088 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, 1089 BAD_CAST "nextCatalog", NULL, 1090 BAD_CAST "catalog", prefer); 1091 } 1092 if ((entry != NULL) && (parent != NULL)) { 1093 entry->parent = parent; 1094 if (parent->children == NULL) 1095 parent->children = entry; 1096 else { 1097 xmlCatalogEntryPtr prev; 1098 1099 prev = parent->children; 1100 while (prev->next != NULL) 1101 prev = prev->next; 1102 prev->next = entry; 1103 } 1104 } 1105 if (base != NULL) 1106 xmlFree(base); 1107 if (uri != NULL) 1108 xmlFree(uri); 1109 if (URL != NULL) 1110 xmlFree(URL); 1111} 1112 1113/** 1114 * xmlParseXMLCatalogNodeList: 1115 * @cur: the XML node list of siblings 1116 * @prefer: the PUBLIC vs. SYSTEM current preference value 1117 * @parent: the parent Catalog entry 1118 * 1119 * Examines a list of XML sibling nodes of a catalog and build 1120 * a list of Catalog entry from it adding it to the parent. 1121 * The examination will recurse to examine node subtrees. 1122 */ 1123static void 1124xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, 1125 xmlCatalogEntryPtr parent) { 1126 while (cur != NULL) { 1127 if ((cur->ns != NULL) && (cur->ns->href != NULL) && 1128 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { 1129 xmlParseXMLCatalogNode(cur, prefer, parent); 1130 } 1131 cur = cur->next; 1132 } 1133 /* TODO: sort the list according to REWRITE lengths and prefer value */ 1134} 1135 1136/** 1137 * xmlParseXMLCatalogFile: 1138 * @prefer: the PUBLIC vs. SYSTEM current preference value 1139 * @filename: the filename for the catalog 1140 * 1141 * Parses the catalog file to extract the XML tree and then analyze the 1142 * tree to build a list of Catalog entries corresponding to this catalog 1143 * 1144 * Returns the resulting Catalog entries list 1145 */ 1146static xmlCatalogEntryPtr 1147xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { 1148 xmlDocPtr doc; 1149 xmlNodePtr cur; 1150 xmlChar *prop; 1151 xmlCatalogEntryPtr parent = NULL; 1152 1153 if (filename == NULL) 1154 return(NULL); 1155 1156 doc = xmlParseCatalogFile((const char *) filename); 1157 if (doc == NULL) { 1158 if (xmlDebugCatalogs) 1159 xmlGenericError(xmlGenericErrorContext, 1160 "Failed to parse catalog %s\n", filename); 1161 return(NULL); 1162 } 1163 1164 if (xmlDebugCatalogs) 1165 xmlGenericError(xmlGenericErrorContext, 1166 "%d Parsing catalog %s\n", xmlGetThreadId(), filename); 1167 1168 cur = xmlDocGetRootElement(doc); 1169 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) && 1170 (cur->ns != NULL) && (cur->ns->href != NULL) && 1171 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { 1172 1173 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 1174 (const xmlChar *)filename, NULL, prefer); 1175 if (parent == NULL) { 1176 xmlFreeDoc(doc); 1177 return(NULL); 1178 } 1179 1180 prop = xmlGetProp(cur, BAD_CAST "prefer"); 1181 if (prop != NULL) { 1182 if (xmlStrEqual(prop, BAD_CAST "system")) { 1183 prefer = XML_CATA_PREFER_SYSTEM; 1184 } else if (xmlStrEqual(prop, BAD_CAST "public")) { 1185 prefer = XML_CATA_PREFER_PUBLIC; 1186 } else { 1187 xmlGenericError(xmlGenericErrorContext, 1188 "Invalid value for prefer: '%s'\n", 1189 prop); 1190 } 1191 xmlFree(prop); 1192 } 1193 cur = cur->children; 1194 xmlParseXMLCatalogNodeList(cur, prefer, parent); 1195 } else { 1196 xmlGenericError(xmlGenericErrorContext, 1197 "File %s is not an XML Catalog\n", filename); 1198 xmlFreeDoc(doc); 1199 return(NULL); 1200 } 1201 xmlFreeDoc(doc); 1202 return(parent); 1203} 1204 1205/** 1206 * xmlFetchXMLCatalogFile: 1207 * @catal: an existing but incomplete catalog entry 1208 * 1209 * Fetch and parse the subcatalog referenced by an entry 1210 * 1211 * Returns 0 in case of success, -1 otherwise 1212 */ 1213static int 1214xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { 1215 xmlCatalogEntryPtr doc; 1216 1217 if (catal == NULL) 1218 return(-1); 1219 if (catal->URL == NULL) 1220 return(-1); 1221 if (catal->children != NULL) 1222 return(-1); 1223 1224 /* 1225 * lock the whole catalog for modification 1226 */ 1227 xmlRMutexLock(xmlCatalogMutex); 1228 if (catal->children != NULL) { 1229 /* Okay someone else did it in the meantime */ 1230 xmlRMutexUnlock(xmlCatalogMutex); 1231 return(0); 1232 } 1233 1234 if (xmlCatalogXMLFiles != NULL) { 1235 doc = (xmlCatalogEntryPtr) 1236 xmlHashLookup(xmlCatalogXMLFiles, catal->URL); 1237 if (doc != NULL) { 1238 if (xmlDebugCatalogs) 1239 xmlGenericError(xmlGenericErrorContext, 1240 "Found %s in file hash\n", catal->URL); 1241 1242 if (catal->type == XML_CATA_CATALOG) 1243 catal->children = doc->children; 1244 else 1245 catal->children = doc; 1246 catal->dealloc = 0; 1247 xmlRMutexUnlock(xmlCatalogMutex); 1248 return(0); 1249 } 1250 if (xmlDebugCatalogs) 1251 xmlGenericError(xmlGenericErrorContext, 1252 "%s not found in file hash\n", catal->URL); 1253 } 1254 1255 /* 1256 * Fetch and parse. Note that xmlParseXMLCatalogFile does not 1257 * use the existing catalog, there is no recursion allowed at 1258 * that level. 1259 */ 1260 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL); 1261 if (doc == NULL) { 1262 catal->type = XML_CATA_BROKEN_CATALOG; 1263 xmlRMutexUnlock(xmlCatalogMutex); 1264 return(-1); 1265 } 1266 1267 if (catal->type == XML_CATA_CATALOG) 1268 catal->children = doc->children; 1269 else 1270 catal->children = doc; 1271 1272 doc->dealloc = 1; 1273 1274 if (xmlCatalogXMLFiles == NULL) 1275 xmlCatalogXMLFiles = xmlHashCreate(10); 1276 if (xmlCatalogXMLFiles != NULL) { 1277 if (xmlDebugCatalogs) 1278 xmlGenericError(xmlGenericErrorContext, 1279 "%s added to file hash\n", catal->URL); 1280 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); 1281 } 1282 xmlRMutexUnlock(xmlCatalogMutex); 1283 return(0); 1284} 1285 1286/************************************************************************ 1287 * * 1288 * XML Catalog handling * 1289 * * 1290 ************************************************************************/ 1291 1292/** 1293 * xmlAddXMLCatalog: 1294 * @catal: top of an XML catalog 1295 * @type: the type of record to add to the catalog 1296 * @orig: the system, public or prefix to match (or NULL) 1297 * @replace: the replacement value for the match 1298 * 1299 * Add an entry in the XML catalog, it may overwrite existing but 1300 * different entries. 1301 * 1302 * Returns 0 if successful, -1 otherwise 1303 */ 1304static int 1305xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, 1306 const xmlChar *orig, const xmlChar *replace) { 1307 xmlCatalogEntryPtr cur; 1308 xmlCatalogEntryType typ; 1309 int doregister = 0; 1310 1311 if ((catal == NULL) || 1312 ((catal->type != XML_CATA_CATALOG) && 1313 (catal->type != XML_CATA_BROKEN_CATALOG))) 1314 return(-1); 1315 if (catal->children == NULL) { 1316 xmlFetchXMLCatalogFile(catal); 1317 } 1318 if (catal->children == NULL) 1319 doregister = 1; 1320 1321 typ = xmlGetXMLCatalogEntryType(type); 1322 if (typ == XML_CATA_NONE) { 1323 if (xmlDebugCatalogs) 1324 xmlGenericError(xmlGenericErrorContext, 1325 "Failed to add unknown element %s to catalog\n", type); 1326 return(-1); 1327 } 1328 1329 cur = catal->children; 1330 /* 1331 * Might be a simple "update in place" 1332 */ 1333 if (cur != NULL) { 1334 while (cur != NULL) { 1335 if ((orig != NULL) && (cur->type == typ) && 1336 (xmlStrEqual(orig, cur->name))) { 1337 if (xmlDebugCatalogs) 1338 xmlGenericError(xmlGenericErrorContext, 1339 "Updating element %s to catalog\n", type); 1340 if (cur->value != NULL) 1341 xmlFree(cur->value); 1342 if (cur->URL != NULL) 1343 xmlFree(cur->URL); 1344 cur->value = xmlStrdup(replace); 1345 cur->URL = xmlStrdup(replace); 1346 return(0); 1347 } 1348 if (cur->next == NULL) 1349 break; 1350 cur = cur->next; 1351 } 1352 } 1353 if (xmlDebugCatalogs) 1354 xmlGenericError(xmlGenericErrorContext, 1355 "Adding element %s to catalog\n", type); 1356 if (cur == NULL) 1357 catal->children = xmlNewCatalogEntry(typ, orig, replace, 1358 NULL, catal->prefer); 1359 else 1360 cur->next = xmlNewCatalogEntry(typ, orig, replace, 1361 NULL, catal->prefer); 1362 if (doregister) { 1363 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL); 1364 if (cur != NULL) 1365 cur->children = catal->children; 1366 } 1367 1368 return(0); 1369} 1370 1371/** 1372 * xmlDelXMLCatalog: 1373 * @catal: top of an XML catalog 1374 * @value: the value to remove from the catalog 1375 * 1376 * Remove entries in the XML catalog where the value or the URI 1377 * is equal to @value 1378 * 1379 * Returns the number of entries removed if successful, -1 otherwise 1380 */ 1381static int 1382xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) { 1383 xmlCatalogEntryPtr cur; 1384 int ret = 0; 1385 1386 if ((catal == NULL) || 1387 ((catal->type != XML_CATA_CATALOG) && 1388 (catal->type != XML_CATA_BROKEN_CATALOG))) 1389 return(-1); 1390 if (value == NULL) 1391 return(-1); 1392 if (catal->children == NULL) { 1393 xmlFetchXMLCatalogFile(catal); 1394 } 1395 1396 /* 1397 * Scan the children 1398 */ 1399 cur = catal->children; 1400 while (cur != NULL) { 1401 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) || 1402 (xmlStrEqual(value, cur->value))) { 1403 if (xmlDebugCatalogs) { 1404 if (cur->name != NULL) 1405 xmlGenericError(xmlGenericErrorContext, 1406 "Removing element %s from catalog\n", cur->name); 1407 else 1408 xmlGenericError(xmlGenericErrorContext, 1409 "Removing element %s from catalog\n", cur->value); 1410 } 1411 cur->type = XML_CATA_REMOVED; 1412 } 1413 cur = cur->next; 1414 } 1415 return(ret); 1416} 1417 1418/** 1419 * xmlCatalogXMLResolve: 1420 * @catal: a catalog list 1421 * @pubId: the public ID string 1422 * @sysId: the system ID string 1423 * 1424 * Do a complete resolution lookup of an External Identifier for a 1425 * list of catalog entries. 1426 * 1427 * Implements (or tries to) 7.1. External Identifier Resolution 1428 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1429 * 1430 * Returns the URI of the resource or NULL if not found 1431 */ 1432static xmlChar * 1433xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 1434 const xmlChar *sysID) { 1435 xmlChar *ret = NULL; 1436 xmlCatalogEntryPtr cur; 1437 int haveDelegate = 0; 1438 int haveNext = 0; 1439 1440 /* 1441 * First tries steps 2/ 3/ 4/ if a system ID is provided. 1442 */ 1443 if (sysID != NULL) { 1444 xmlCatalogEntryPtr rewrite = NULL; 1445 int lenrewrite = 0, len; 1446 cur = catal; 1447 haveDelegate = 0; 1448 while (cur != NULL) { 1449 switch (cur->type) { 1450 case XML_CATA_SYSTEM: 1451 if (xmlStrEqual(sysID, cur->name)) { 1452 if (xmlDebugCatalogs) 1453 xmlGenericError(xmlGenericErrorContext, 1454 "Found system match %s\n", cur->name); 1455 return(xmlStrdup(cur->URL)); 1456 } 1457 break; 1458 case XML_CATA_REWRITE_SYSTEM: 1459 len = xmlStrlen(cur->name); 1460 if ((len > lenrewrite) && 1461 (!xmlStrncmp(sysID, cur->name, len))) { 1462 lenrewrite = len; 1463 rewrite = cur; 1464 } 1465 break; 1466 case XML_CATA_DELEGATE_SYSTEM: 1467 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name))) 1468 haveDelegate++; 1469 break; 1470 case XML_CATA_NEXT_CATALOG: 1471 haveNext++; 1472 break; 1473 default: 1474 break; 1475 } 1476 cur = cur->next; 1477 } 1478 if (rewrite != NULL) { 1479 if (xmlDebugCatalogs) 1480 xmlGenericError(xmlGenericErrorContext, 1481 "Using rewriting rule %s\n", rewrite->name); 1482 ret = xmlStrdup(rewrite->URL); 1483 if (ret != NULL) 1484 ret = xmlStrcat(ret, &sysID[lenrewrite]); 1485 return(ret); 1486 } 1487 if (haveDelegate) { 1488 const xmlChar *delegates[MAX_DELEGATE]; 1489 int nbList = 0, i; 1490 1491 /* 1492 * Assume the entries have been sorted by decreasing substring 1493 * matches when the list was produced. 1494 */ 1495 cur = catal; 1496 while (cur != NULL) { 1497 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) && 1498 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) { 1499 for (i = 0;i < nbList;i++) 1500 if (xmlStrEqual(cur->URL, delegates[i])) 1501 break; 1502 if (i < nbList) { 1503 cur = cur->next; 1504 continue; 1505 } 1506 if (nbList < MAX_DELEGATE) 1507 delegates[nbList++] = cur->URL; 1508 1509 if (cur->children == NULL) { 1510 xmlFetchXMLCatalogFile(cur); 1511 } 1512 if (cur->children != NULL) { 1513 if (xmlDebugCatalogs) 1514 xmlGenericError(xmlGenericErrorContext, 1515 "Trying system delegate %s\n", cur->URL); 1516 ret = xmlCatalogListXMLResolve( 1517 cur->children, NULL, sysID); 1518 if (ret != NULL) 1519 return(ret); 1520 } 1521 } 1522 cur = cur->next; 1523 } 1524 /* 1525 * Apply the cut algorithm explained in 4/ 1526 */ 1527 return(XML_CATAL_BREAK); 1528 } 1529 } 1530 /* 1531 * Then tries 5/ 6/ if a public ID is provided 1532 */ 1533 if (pubID != NULL) { 1534 cur = catal; 1535 haveDelegate = 0; 1536 while (cur != NULL) { 1537 switch (cur->type) { 1538 case XML_CATA_PUBLIC: 1539 if (xmlStrEqual(pubID, cur->name)) { 1540 if (xmlDebugCatalogs) 1541 xmlGenericError(xmlGenericErrorContext, 1542 "Found public match %s\n", cur->name); 1543 return(xmlStrdup(cur->URL)); 1544 } 1545 break; 1546 case XML_CATA_DELEGATE_PUBLIC: 1547 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) && 1548 (cur->prefer == XML_CATA_PREFER_PUBLIC)) 1549 haveDelegate++; 1550 break; 1551 case XML_CATA_NEXT_CATALOG: 1552 if (sysID == NULL) 1553 haveNext++; 1554 break; 1555 default: 1556 break; 1557 } 1558 cur = cur->next; 1559 } 1560 if (haveDelegate) { 1561 const xmlChar *delegates[MAX_DELEGATE]; 1562 int nbList = 0, i; 1563 1564 /* 1565 * Assume the entries have been sorted by decreasing substring 1566 * matches when the list was produced. 1567 */ 1568 cur = catal; 1569 while (cur != NULL) { 1570 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) && 1571 (cur->prefer == XML_CATA_PREFER_PUBLIC) && 1572 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) { 1573 1574 for (i = 0;i < nbList;i++) 1575 if (xmlStrEqual(cur->URL, delegates[i])) 1576 break; 1577 if (i < nbList) { 1578 cur = cur->next; 1579 continue; 1580 } 1581 if (nbList < MAX_DELEGATE) 1582 delegates[nbList++] = cur->URL; 1583 1584 if (cur->children == NULL) { 1585 xmlFetchXMLCatalogFile(cur); 1586 } 1587 if (cur->children != NULL) { 1588 if (xmlDebugCatalogs) 1589 xmlGenericError(xmlGenericErrorContext, 1590 "Trying public delegate %s\n", cur->URL); 1591 ret = xmlCatalogListXMLResolve( 1592 cur->children, pubID, NULL); 1593 if (ret != NULL) 1594 return(ret); 1595 } 1596 } 1597 cur = cur->next; 1598 } 1599 /* 1600 * Apply the cut algorithm explained in 4/ 1601 */ 1602 return(XML_CATAL_BREAK); 1603 } 1604 } 1605 if (haveNext) { 1606 cur = catal; 1607 while (cur != NULL) { 1608 if (cur->type == XML_CATA_NEXT_CATALOG) { 1609 if (cur->children == NULL) { 1610 xmlFetchXMLCatalogFile(cur); 1611 } 1612 if (cur->children != NULL) { 1613 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID); 1614 if (ret != NULL) 1615 return(ret); 1616 } 1617 } 1618 cur = cur->next; 1619 } 1620 } 1621 1622 return(NULL); 1623} 1624 1625/** 1626 * xmlCatalogXMLResolveURI: 1627 * @catal: a catalog list 1628 * @URI: the URI 1629 * @sysId: the system ID string 1630 * 1631 * Do a complete resolution lookup of an External Identifier for a 1632 * list of catalog entries. 1633 * 1634 * Implements (or tries to) 7.2.2. URI Resolution 1635 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1636 * 1637 * Returns the URI of the resource or NULL if not found 1638 */ 1639static xmlChar * 1640xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { 1641 xmlChar *ret = NULL; 1642 xmlCatalogEntryPtr cur; 1643 int haveDelegate = 0; 1644 int haveNext = 0; 1645 xmlCatalogEntryPtr rewrite = NULL; 1646 int lenrewrite = 0, len; 1647 1648 if (catal == NULL) 1649 return(NULL); 1650 1651 if (URI == NULL) 1652 return(NULL); 1653 1654 /* 1655 * First tries steps 2/ 3/ 4/ if a system ID is provided. 1656 */ 1657 cur = catal; 1658 haveDelegate = 0; 1659 while (cur != NULL) { 1660 switch (cur->type) { 1661 case XML_CATA_URI: 1662 if (xmlStrEqual(URI, cur->name)) { 1663 if (xmlDebugCatalogs) 1664 xmlGenericError(xmlGenericErrorContext, 1665 "Found URI match %s\n", cur->name); 1666 return(xmlStrdup(cur->URL)); 1667 } 1668 break; 1669 case XML_CATA_REWRITE_URI: 1670 len = xmlStrlen(cur->name); 1671 if ((len > lenrewrite) && 1672 (!xmlStrncmp(URI, cur->name, len))) { 1673 lenrewrite = len; 1674 rewrite = cur; 1675 } 1676 break; 1677 case XML_CATA_DELEGATE_URI: 1678 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name))) 1679 haveDelegate++; 1680 break; 1681 case XML_CATA_NEXT_CATALOG: 1682 haveNext++; 1683 break; 1684 default: 1685 break; 1686 } 1687 cur = cur->next; 1688 } 1689 if (rewrite != NULL) { 1690 if (xmlDebugCatalogs) 1691 xmlGenericError(xmlGenericErrorContext, 1692 "Using rewriting rule %s\n", rewrite->name); 1693 ret = xmlStrdup(rewrite->URL); 1694 if (ret != NULL) 1695 ret = xmlStrcat(ret, &URI[lenrewrite]); 1696 return(ret); 1697 } 1698 if (haveDelegate) { 1699 const xmlChar *delegates[MAX_DELEGATE]; 1700 int nbList = 0, i; 1701 1702 /* 1703 * Assume the entries have been sorted by decreasing substring 1704 * matches when the list was produced. 1705 */ 1706 cur = catal; 1707 while (cur != NULL) { 1708 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) && 1709 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) { 1710 for (i = 0;i < nbList;i++) 1711 if (xmlStrEqual(cur->URL, delegates[i])) 1712 break; 1713 if (i < nbList) { 1714 cur = cur->next; 1715 continue; 1716 } 1717 if (nbList < MAX_DELEGATE) 1718 delegates[nbList++] = cur->URL; 1719 1720 if (cur->children == NULL) { 1721 xmlFetchXMLCatalogFile(cur); 1722 } 1723 if (cur->children != NULL) { 1724 if (xmlDebugCatalogs) 1725 xmlGenericError(xmlGenericErrorContext, 1726 "Trying URI delegate %s\n", cur->URL); 1727 ret = xmlCatalogListXMLResolveURI( 1728 cur->children, URI); 1729 if (ret != NULL) 1730 return(ret); 1731 } 1732 } 1733 cur = cur->next; 1734 } 1735 /* 1736 * Apply the cut algorithm explained in 4/ 1737 */ 1738 return(XML_CATAL_BREAK); 1739 } 1740 if (haveNext) { 1741 cur = catal; 1742 while (cur != NULL) { 1743 if (cur->type == XML_CATA_NEXT_CATALOG) { 1744 if (cur->children == NULL) { 1745 xmlFetchXMLCatalogFile(cur); 1746 } 1747 if (cur->children != NULL) { 1748 ret = xmlCatalogListXMLResolveURI(cur->children, URI); 1749 if (ret != NULL) 1750 return(ret); 1751 } 1752 } 1753 cur = cur->next; 1754 } 1755 } 1756 1757 return(NULL); 1758} 1759 1760/** 1761 * xmlCatalogListXMLResolve: 1762 * @catal: a catalog list 1763 * @pubId: the public ID string 1764 * @sysId: the system ID string 1765 * 1766 * Do a complete resolution lookup of an External Identifier for a 1767 * list of catalogs 1768 * 1769 * Implements (or tries to) 7.1. External Identifier Resolution 1770 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1771 * 1772 * Returns the URI of the resource or NULL if not found 1773 */ 1774static xmlChar * 1775xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 1776 const xmlChar *sysID) { 1777 xmlChar *ret = NULL; 1778 xmlChar *urnID = NULL; 1779 1780 if (catal == NULL) 1781 return(NULL); 1782 if ((pubID == NULL) && (sysID == NULL)) 1783 return(NULL); 1784 1785 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 1786 urnID = xmlCatalogUnWrapURN(pubID); 1787 if (xmlDebugCatalogs) { 1788 if (urnID == NULL) 1789 xmlGenericError(xmlGenericErrorContext, 1790 "Public URN ID %s expanded to NULL\n", pubID); 1791 else 1792 xmlGenericError(xmlGenericErrorContext, 1793 "Public URN ID expanded to %s\n", urnID); 1794 } 1795 ret = xmlCatalogListXMLResolve(catal, urnID, sysID); 1796 if (urnID != NULL) 1797 xmlFree(urnID); 1798 return(ret); 1799 } 1800 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 1801 urnID = xmlCatalogUnWrapURN(sysID); 1802 if (xmlDebugCatalogs) { 1803 if (urnID == NULL) 1804 xmlGenericError(xmlGenericErrorContext, 1805 "System URN ID %s expanded to NULL\n", sysID); 1806 else 1807 xmlGenericError(xmlGenericErrorContext, 1808 "System URN ID expanded to %s\n", urnID); 1809 } 1810 if (pubID == NULL) 1811 ret = xmlCatalogListXMLResolve(catal, urnID, NULL); 1812 else if (xmlStrEqual(pubID, urnID)) 1813 ret = xmlCatalogListXMLResolve(catal, pubID, NULL); 1814 else { 1815 ret = xmlCatalogListXMLResolve(catal, pubID, NULL); 1816 } 1817 if (urnID != NULL) 1818 xmlFree(urnID); 1819 return(ret); 1820 } 1821 while (catal != NULL) { 1822 if (catal->type == XML_CATA_CATALOG) { 1823 if (catal->children == NULL) { 1824 xmlFetchXMLCatalogFile(catal); 1825 } 1826 if (catal->children != NULL) { 1827 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID); 1828 if (ret != NULL) 1829 return(ret); 1830 } 1831 } 1832 catal = catal->next; 1833 } 1834 return(ret); 1835} 1836 1837/** 1838 * xmlCatalogListXMLResolveURI: 1839 * @catal: a catalog list 1840 * @URI: the URI 1841 * 1842 * Do a complete resolution lookup of an URI for a list of catalogs 1843 * 1844 * Implements (or tries to) 7.2. URI Resolution 1845 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 1846 * 1847 * Returns the URI of the resource or NULL if not found 1848 */ 1849static xmlChar * 1850xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { 1851 xmlChar *ret = NULL; 1852 xmlChar *urnID = NULL; 1853 1854 if (catal == NULL) 1855 return(NULL); 1856 if (URI == NULL) 1857 return(NULL); 1858 1859 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 1860 urnID = xmlCatalogUnWrapURN(URI); 1861 if (xmlDebugCatalogs) { 1862 if (urnID == NULL) 1863 xmlGenericError(xmlGenericErrorContext, 1864 "URN ID %s expanded to NULL\n", URI); 1865 else 1866 xmlGenericError(xmlGenericErrorContext, 1867 "URN ID expanded to %s\n", urnID); 1868 } 1869 ret = xmlCatalogListXMLResolve(catal, urnID, NULL); 1870 if (urnID != NULL) 1871 xmlFree(urnID); 1872 return(ret); 1873 } 1874 while (catal != NULL) { 1875 if (catal->type == XML_CATA_CATALOG) { 1876 if (catal->children == NULL) { 1877 xmlFetchXMLCatalogFile(catal); 1878 } 1879 if (catal->children != NULL) { 1880 ret = xmlCatalogXMLResolveURI(catal->children, URI); 1881 if (ret != NULL) 1882 return(ret); 1883 } 1884 } 1885 catal = catal->next; 1886 } 1887 return(ret); 1888} 1889 1890/************************************************************************ 1891 * * 1892 * The SGML Catalog parser * 1893 * * 1894 ************************************************************************/ 1895 1896 1897#define RAW *cur 1898#define NEXT cur++; 1899#define SKIP(x) cur += x; 1900 1901#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT; 1902 1903/** 1904 * xmlParseSGMLCatalogComment: 1905 * @cur: the current character 1906 * 1907 * Skip a comment in an SGML catalog 1908 * 1909 * Returns new current character 1910 */ 1911static const xmlChar * 1912xmlParseSGMLCatalogComment(const xmlChar *cur) { 1913 if ((cur[0] != '-') || (cur[1] != '-')) 1914 return(cur); 1915 SKIP(2); 1916 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-')))) 1917 NEXT; 1918 if (cur[0] == 0) { 1919 return(NULL); 1920 } 1921 return(cur + 2); 1922} 1923 1924/** 1925 * xmlParseSGMLCatalogPubid: 1926 * @cur: the current character 1927 * @id: the return location 1928 * 1929 * Parse an SGML catalog ID 1930 * 1931 * Returns new current character and store the value in @id 1932 */ 1933static const xmlChar * 1934xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { 1935 xmlChar *buf = NULL; 1936 int len = 0; 1937 int size = 50; 1938 xmlChar stop; 1939 int count = 0; 1940 1941 *id = NULL; 1942 1943 if (RAW == '"') { 1944 NEXT; 1945 stop = '"'; 1946 } else if (RAW == '\'') { 1947 NEXT; 1948 stop = '\''; 1949 } else { 1950 stop = ' '; 1951 } 1952 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar)); 1953 if (buf == NULL) { 1954 xmlGenericError(xmlGenericErrorContext, 1955 "malloc of %d byte failed\n", size); 1956 return(NULL); 1957 } 1958 while (xmlIsPubidChar(*cur) || (*cur == '?')) { 1959 if ((*cur == stop) && (stop != ' ')) 1960 break; 1961 if ((stop == ' ') && (IS_BLANK(*cur))) 1962 break; 1963 if (len + 1 >= size) { 1964 size *= 2; 1965 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); 1966 if (buf == NULL) { 1967 xmlGenericError(xmlGenericErrorContext, 1968 "realloc of %d byte failed\n", size); 1969 return(NULL); 1970 } 1971 } 1972 buf[len++] = *cur; 1973 count++; 1974 NEXT; 1975 } 1976 buf[len] = 0; 1977 if (stop == ' ') { 1978 if (!IS_BLANK(*cur)) { 1979 xmlFree(buf); 1980 return(NULL); 1981 } 1982 } else { 1983 if (*cur != stop) { 1984 xmlFree(buf); 1985 return(NULL); 1986 } 1987 NEXT; 1988 } 1989 *id = buf; 1990 return(cur); 1991} 1992 1993/** 1994 * xmlParseSGMLCatalogName: 1995 * @cur: the current character 1996 * @name: the return location 1997 * 1998 * Parse an SGML catalog name 1999 * 2000 * Returns new current character and store the value in @name 2001 */ 2002static const xmlChar * 2003xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) { 2004 xmlChar buf[XML_MAX_NAMELEN + 5]; 2005 int len = 0; 2006 int c; 2007 2008 *name = NULL; 2009 2010 /* 2011 * Handler for more complex cases 2012 */ 2013 c = *cur; 2014 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) { 2015 return(NULL); 2016 } 2017 2018 while (((IS_LETTER(c)) || (IS_DIGIT(c)) || 2019 (c == '.') || (c == '-') || 2020 (c == '_') || (c == ':'))) { 2021 buf[len++] = c; 2022 cur++; 2023 c = *cur; 2024 if (len >= XML_MAX_NAMELEN) 2025 return(NULL); 2026 } 2027 *name = xmlStrndup(buf, len); 2028 return(cur); 2029} 2030 2031/** 2032 * xmlGetSGMLCatalogEntryType: 2033 * @name: the entry name 2034 * 2035 * Get the Catalog entry type for a given SGML Catalog name 2036 * 2037 * Returns Catalog entry type 2038 */ 2039static xmlCatalogEntryType 2040xmlGetSGMLCatalogEntryType(const xmlChar *name) { 2041 xmlCatalogEntryType type = XML_CATA_NONE; 2042 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) 2043 type = SGML_CATA_SYSTEM; 2044 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) 2045 type = SGML_CATA_PUBLIC; 2046 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2047 type = SGML_CATA_DELEGATE; 2048 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) 2049 type = SGML_CATA_ENTITY; 2050 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) 2051 type = SGML_CATA_DOCTYPE; 2052 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) 2053 type = SGML_CATA_LINKTYPE; 2054 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) 2055 type = SGML_CATA_NOTATION; 2056 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) 2057 type = SGML_CATA_SGMLDECL; 2058 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) 2059 type = SGML_CATA_DOCUMENT; 2060 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) 2061 type = SGML_CATA_CATALOG; 2062 else if (xmlStrEqual(name, (const xmlChar *) "BASE")) 2063 type = SGML_CATA_BASE; 2064 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2065 type = SGML_CATA_DELEGATE; 2066 return(type); 2067} 2068 2069/** 2070 * xmlParseSGMLCatalog: 2071 * @catal: the SGML Catalog 2072 * @value: the content of the SGML Catalog serialization 2073 * @file: the filepath for the catalog 2074 * @super: should this be handled as a Super Catalog in which case 2075 * parsing is not recursive 2076 * 2077 * Parse an SGML catalog content and fill up the @catal hash table with 2078 * the new entries found. 2079 * 2080 * Returns 0 in case of success, -1 in case of error. 2081 */ 2082static int 2083xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value, 2084 const char *file, int super) { 2085 const xmlChar *cur = value; 2086 xmlChar *base = NULL; 2087 int res; 2088 2089 if ((cur == NULL) || (file == NULL)) 2090 return(-1); 2091 base = xmlStrdup((const xmlChar *) file); 2092 2093 while ((cur != NULL) && (cur[0] != 0)) { 2094 SKIP_BLANKS; 2095 if (cur[0] == 0) 2096 break; 2097 if ((cur[0] == '-') && (cur[1] == '-')) { 2098 cur = xmlParseSGMLCatalogComment(cur); 2099 if (cur == NULL) { 2100 /* error */ 2101 break; 2102 } 2103 } else { 2104 xmlChar *sysid = NULL; 2105 xmlChar *name = NULL; 2106 xmlCatalogEntryType type = XML_CATA_NONE; 2107 2108 cur = xmlParseSGMLCatalogName(cur, &name); 2109 if (name == NULL) { 2110 /* error */ 2111 break; 2112 } 2113 if (!IS_BLANK(*cur)) { 2114 /* error */ 2115 break; 2116 } 2117 SKIP_BLANKS; 2118 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) 2119 type = SGML_CATA_SYSTEM; 2120 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) 2121 type = SGML_CATA_PUBLIC; 2122 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2123 type = SGML_CATA_DELEGATE; 2124 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) 2125 type = SGML_CATA_ENTITY; 2126 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) 2127 type = SGML_CATA_DOCTYPE; 2128 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) 2129 type = SGML_CATA_LINKTYPE; 2130 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) 2131 type = SGML_CATA_NOTATION; 2132 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) 2133 type = SGML_CATA_SGMLDECL; 2134 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) 2135 type = SGML_CATA_DOCUMENT; 2136 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) 2137 type = SGML_CATA_CATALOG; 2138 else if (xmlStrEqual(name, (const xmlChar *) "BASE")) 2139 type = SGML_CATA_BASE; 2140 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 2141 type = SGML_CATA_DELEGATE; 2142 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) { 2143 xmlFree(name); 2144 cur = xmlParseSGMLCatalogName(cur, &name); 2145 if (name == NULL) { 2146 /* error */ 2147 break; 2148 } 2149 xmlFree(name); 2150 continue; 2151 } 2152 xmlFree(name); 2153 name = NULL; 2154 2155 switch(type) { 2156 case SGML_CATA_ENTITY: 2157 if (*cur == '%') 2158 type = SGML_CATA_PENTITY; 2159 case SGML_CATA_PENTITY: 2160 case SGML_CATA_DOCTYPE: 2161 case SGML_CATA_LINKTYPE: 2162 case SGML_CATA_NOTATION: 2163 cur = xmlParseSGMLCatalogName(cur, &name); 2164 if (cur == NULL) { 2165 /* error */ 2166 break; 2167 } 2168 if (!IS_BLANK(*cur)) { 2169 /* error */ 2170 break; 2171 } 2172 SKIP_BLANKS; 2173 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 2174 if (cur == NULL) { 2175 /* error */ 2176 break; 2177 } 2178 break; 2179 case SGML_CATA_PUBLIC: 2180 case SGML_CATA_SYSTEM: 2181 case SGML_CATA_DELEGATE: 2182 cur = xmlParseSGMLCatalogPubid(cur, &name); 2183 if (cur == NULL) { 2184 /* error */ 2185 break; 2186 } 2187 if (!IS_BLANK(*cur)) { 2188 /* error */ 2189 break; 2190 } 2191 SKIP_BLANKS; 2192 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 2193 if (cur == NULL) { 2194 /* error */ 2195 break; 2196 } 2197 break; 2198 case SGML_CATA_BASE: 2199 case SGML_CATA_CATALOG: 2200 case SGML_CATA_DOCUMENT: 2201 case SGML_CATA_SGMLDECL: 2202 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 2203 if (cur == NULL) { 2204 /* error */ 2205 break; 2206 } 2207 break; 2208 default: 2209 break; 2210 } 2211 if (cur == NULL) { 2212 if (name != NULL) 2213 xmlFree(name); 2214 if (sysid != NULL) 2215 xmlFree(sysid); 2216 break; 2217 } else if (type == SGML_CATA_BASE) { 2218 if (base != NULL) 2219 xmlFree(base); 2220 base = xmlStrdup(sysid); 2221 } else if ((type == SGML_CATA_PUBLIC) || 2222 (type == SGML_CATA_SYSTEM)) { 2223 xmlChar *filename; 2224 2225 filename = xmlBuildURI(sysid, base); 2226 if (filename != NULL) { 2227 xmlCatalogEntryPtr entry; 2228 2229 entry = xmlNewCatalogEntry(type, name, filename, 2230 NULL, XML_CATA_PREFER_NONE); 2231 res = xmlHashAddEntry(catal->sgml, name, entry); 2232 if (res < 0) { 2233 xmlFreeCatalogEntry(entry); 2234 } 2235 xmlFree(filename); 2236 } 2237 2238 } else if (type == SGML_CATA_CATALOG) { 2239 if (super) { 2240 xmlCatalogEntryPtr entry; 2241 2242 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL, 2243 XML_CATA_PREFER_NONE); 2244 res = xmlHashAddEntry(catal->sgml, sysid, entry); 2245 if (res < 0) { 2246 xmlFreeCatalogEntry(entry); 2247 } 2248 } else { 2249 xmlChar *filename; 2250 2251 filename = xmlBuildURI(sysid, base); 2252 if (filename != NULL) { 2253 xmlExpandCatalog(catal, (const char *)filename); 2254 xmlFree(filename); 2255 } 2256 } 2257 } 2258 /* 2259 * drop anything else we won't handle it 2260 */ 2261 if (name != NULL) 2262 xmlFree(name); 2263 if (sysid != NULL) 2264 xmlFree(sysid); 2265 } 2266 } 2267 if (base != NULL) 2268 xmlFree(base); 2269 if (cur == NULL) 2270 return(-1); 2271 return(0); 2272} 2273 2274/************************************************************************ 2275 * * 2276 * SGML Catalog handling * 2277 * * 2278 ************************************************************************/ 2279 2280/** 2281 * xmlCatalogGetSGMLPublic: 2282 * @catal: an SGML catalog hash 2283 * @pubId: the public ID string 2284 * 2285 * Try to lookup the system ID associated to a public ID 2286 * 2287 * Returns the system ID if found or NULL otherwise. 2288 */ 2289static const xmlChar * 2290xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) { 2291 xmlCatalogEntryPtr entry; 2292 2293 if (catal == NULL) 2294 return(NULL); 2295 2296 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID); 2297 if (entry == NULL) 2298 return(NULL); 2299 if (entry->type == SGML_CATA_PUBLIC) 2300 return(entry->URL); 2301 return(NULL); 2302} 2303 2304/** 2305 * xmlCatalogGetSGMLSystem: 2306 * @catal: an SGML catalog hash 2307 * @sysId: the public ID string 2308 * 2309 * Try to lookup the catalog local reference for a system ID 2310 * 2311 * Returns the system ID if found or NULL otherwise. 2312 */ 2313static const xmlChar * 2314xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) { 2315 xmlCatalogEntryPtr entry; 2316 2317 if (catal == NULL) 2318 return(NULL); 2319 2320 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID); 2321 if (entry == NULL) 2322 return(NULL); 2323 if (entry->type == SGML_CATA_SYSTEM) 2324 return(entry->URL); 2325 return(NULL); 2326} 2327 2328/** 2329 * xmlCatalogSGMLResolve: 2330 * @catal: the SGML catalog 2331 * @pubId: the public ID string 2332 * @sysId: the system ID string 2333 * 2334 * Do a complete resolution lookup of an External Identifier 2335 * 2336 * Returns the URI of the resource or NULL if not found 2337 */ 2338static const xmlChar * 2339xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID, 2340 const xmlChar *sysID) { 2341 const xmlChar *ret = NULL; 2342 2343 if (catal->sgml == NULL) 2344 return(NULL); 2345 2346 if (pubID != NULL) 2347 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID); 2348 if (ret != NULL) 2349 return(ret); 2350 if (sysID != NULL) 2351 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID); 2352 return(NULL); 2353} 2354 2355/************************************************************************ 2356 * * 2357 * Specific Public interfaces * 2358 * * 2359 ************************************************************************/ 2360 2361/** 2362 * xmlLoadSGMLSuperCatalog: 2363 * @filename: a file path 2364 * 2365 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE 2366 * references. This is only needed for manipulating SGML Super Catalogs 2367 * like adding and removing CATALOG or DELEGATE entries. 2368 * 2369 * Returns the catalog parsed or NULL in case of error 2370 */ 2371xmlCatalogPtr 2372xmlLoadSGMLSuperCatalog(const char *filename) 2373{ 2374 xmlChar *content; 2375 xmlCatalogPtr catal; 2376 int ret; 2377 2378 content = xmlLoadFileContent(filename); 2379 if (content == NULL) 2380 return(NULL); 2381 2382 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 2383 if (catal == NULL) { 2384 xmlFree(content); 2385 return(NULL); 2386 } 2387 2388 ret = xmlParseSGMLCatalog(catal, content, filename, 1); 2389 xmlFree(content); 2390 if (ret < 0) { 2391 xmlFreeCatalog(catal); 2392 return(NULL); 2393 } 2394 return (catal); 2395} 2396 2397/** 2398 * xmlLoadACatalog: 2399 * @filename: a file path 2400 * 2401 * Load the catalog and build the associated data structures. 2402 * This can be either an XML Catalog or an SGML Catalog 2403 * It will recurse in SGML CATALOG entries. On the other hand XML 2404 * Catalogs are not handled recursively. 2405 * 2406 * Returns the catalog parsed or NULL in case of error 2407 */ 2408xmlCatalogPtr 2409xmlLoadACatalog(const char *filename) 2410{ 2411 xmlChar *content; 2412 xmlChar *first; 2413 xmlCatalogPtr catal; 2414 int ret; 2415 2416 content = xmlLoadFileContent(filename); 2417 if (content == NULL) 2418 return(NULL); 2419 2420 2421 first = content; 2422 2423 while ((*first != 0) && (*first != '-') && (*first != '<') && 2424 (!(((*first >= 'A') && (*first <= 'Z')) || 2425 ((*first >= 'a') && (*first <= 'z'))))) 2426 first++; 2427 2428 if (*first != '<') { 2429 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 2430 if (catal == NULL) { 2431 xmlFree(content); 2432 return(NULL); 2433 } 2434 ret = xmlParseSGMLCatalog(catal, content, filename, 0); 2435 if (ret < 0) { 2436 xmlFreeCatalog(catal); 2437 xmlFree(content); 2438 return(NULL); 2439 } 2440 } else { 2441 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 2442 if (catal == NULL) { 2443 xmlFree(content); 2444 return(NULL); 2445 } 2446 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2447 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer); 2448 } 2449 xmlFree(content); 2450 return (catal); 2451} 2452 2453/** 2454 * xmlExpandCatalog: 2455 * @catal: a catalog 2456 * @filename: a file path 2457 * 2458 * Load the catalog and expand the existing catal structure. 2459 * This can be either an XML Catalog or an SGML Catalog 2460 * 2461 * Returns 0 in case of success, -1 in case of error 2462 */ 2463static int 2464xmlExpandCatalog(xmlCatalogPtr catal, const char *filename) 2465{ 2466 int ret; 2467 2468 if ((catal == NULL) || (filename == NULL)) 2469 return(-1); 2470 2471 2472 if (catal->type == XML_SGML_CATALOG_TYPE) { 2473 xmlChar *content; 2474 2475 content = xmlLoadFileContent(filename); 2476 if (content == NULL) 2477 return(-1); 2478 2479 ret = xmlParseSGMLCatalog(catal, content, filename, 0); 2480 if (ret < 0) { 2481 xmlFree(content); 2482 return(-1); 2483 } 2484 xmlFree(content); 2485 } else { 2486 xmlCatalogEntryPtr tmp, cur; 2487 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2488 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer); 2489 2490 cur = catal->xml; 2491 if (cur == NULL) { 2492 catal->xml = tmp; 2493 } else { 2494 while (cur->next != NULL) cur = cur->next; 2495 cur->next = tmp; 2496 } 2497 } 2498 return (0); 2499} 2500 2501/** 2502 * xmlACatalogResolveSystem: 2503 * @catal: a Catalog 2504 * @sysID: the public ID string 2505 * 2506 * Try to lookup the catalog resource for a system ID 2507 * 2508 * Returns the system ID if found or NULL otherwise, the value returned 2509 * must be freed by the caller. 2510 */ 2511xmlChar * 2512xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) { 2513 xmlChar *ret = NULL; 2514 2515 if ((sysID == NULL) || (catal == NULL)) 2516 return(NULL); 2517 2518 if (xmlDebugCatalogs) 2519 xmlGenericError(xmlGenericErrorContext, 2520 "Resolve sysID %s\n", sysID); 2521 2522 if (catal->type == XML_XML_CATALOG_TYPE) { 2523 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID); 2524 if (ret == XML_CATAL_BREAK) 2525 ret = NULL; 2526 } else { 2527 const xmlChar *sgml; 2528 2529 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID); 2530 if (sgml != NULL) 2531 ret = xmlStrdup(sgml); 2532 } 2533 return(ret); 2534} 2535 2536/** 2537 * xmlACatalogResolvePublic: 2538 * @catal: a Catalog 2539 * @pubID: the public ID string 2540 * 2541 * Try to lookup the system ID associated to a public ID in that catalog 2542 * 2543 * Returns the system ID if found or NULL otherwise, the value returned 2544 * must be freed by the caller. 2545 */ 2546xmlChar * 2547xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) { 2548 xmlChar *ret = NULL; 2549 2550 if ((pubID == NULL) || (catal == NULL)) 2551 return(NULL); 2552 2553 if (xmlDebugCatalogs) 2554 xmlGenericError(xmlGenericErrorContext, 2555 "Resolve pubID %s\n", pubID); 2556 2557 if (catal->type == XML_XML_CATALOG_TYPE) { 2558 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL); 2559 if (ret == XML_CATAL_BREAK) 2560 ret = NULL; 2561 } else { 2562 const xmlChar *sgml; 2563 2564 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID); 2565 if (sgml != NULL) 2566 ret = xmlStrdup(sgml); 2567 } 2568 return(ret); 2569} 2570 2571/** 2572 * xmlACatalogResolve: 2573 * @catal: a Catalog 2574 * @pubID: the public ID string 2575 * @sysID: the system ID string 2576 * 2577 * Do a complete resolution lookup of an External Identifier 2578 * 2579 * Returns the URI of the resource or NULL if not found, it must be freed 2580 * by the caller. 2581 */ 2582xmlChar * 2583xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID, 2584 const xmlChar * sysID) 2585{ 2586 xmlChar *ret = NULL; 2587 2588 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL)) 2589 return (NULL); 2590 2591 if (xmlDebugCatalogs) { 2592 if (pubID != NULL) { 2593 xmlGenericError(xmlGenericErrorContext, 2594 "Resolve: pubID %s\n", pubID); 2595 } else { 2596 xmlGenericError(xmlGenericErrorContext, 2597 "Resolve: sysID %s\n", sysID); 2598 } 2599 } 2600 2601 if (catal->type == XML_XML_CATALOG_TYPE) { 2602 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID); 2603 if (ret == XML_CATAL_BREAK) 2604 ret = NULL; 2605 } else { 2606 const xmlChar *sgml; 2607 2608 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID); 2609 if (sgml != NULL) 2610 ret = xmlStrdup(sgml); 2611 } 2612 return (ret); 2613} 2614 2615/** 2616 * xmlACatalogResolveURI: 2617 * @catal: a Catalog 2618 * @URI: the URI 2619 * 2620 * Do a complete resolution lookup of an URI 2621 * 2622 * Returns the URI of the resource or NULL if not found, it must be freed 2623 * by the caller. 2624 */ 2625xmlChar * 2626xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { 2627 xmlChar *ret = NULL; 2628 2629 if ((URI == NULL) || (catal == NULL)) 2630 return(NULL); 2631 2632 if (xmlDebugCatalogs) 2633 xmlGenericError(xmlGenericErrorContext, 2634 "Resolve URI %s\n", URI); 2635 2636 if (catal->type == XML_XML_CATALOG_TYPE) { 2637 ret = xmlCatalogListXMLResolveURI(catal->xml, URI); 2638 if (ret == XML_CATAL_BREAK) 2639 ret = NULL; 2640 } else { 2641 const xmlChar *sgml; 2642 2643 sgml = xmlCatalogSGMLResolve(catal, NULL, URI); 2644 if (sgml != NULL) 2645 sgml = xmlStrdup(sgml); 2646 } 2647 return(ret); 2648} 2649 2650/** 2651 * xmlACatalogDump: 2652 * @catal: a Catalog 2653 * @out: the file. 2654 * 2655 * Free up all the memory associated with catalogs 2656 */ 2657void 2658xmlACatalogDump(xmlCatalogPtr catal, FILE *out) { 2659 if ((out == NULL) || (catal == NULL)) 2660 return; 2661 2662 if (catal->type == XML_XML_CATALOG_TYPE) { 2663 xmlDumpXMLCatalog(out, catal->xml); 2664 } else { 2665 xmlHashScan(catal->sgml, 2666 (xmlHashScanner) xmlCatalogDumpEntry, out); 2667 } 2668} 2669 2670/** 2671 * xmlACatalogAdd: 2672 * @catal: a Catalog 2673 * @type: the type of record to add to the catalog 2674 * @orig: the system, public or prefix to match 2675 * @replace: the replacement value for the match 2676 * 2677 * Add an entry in the catalog, it may overwrite existing but 2678 * different entries. 2679 * 2680 * Returns 0 if successful, -1 otherwise 2681 */ 2682int 2683xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type, 2684 const xmlChar * orig, const xmlChar * replace) 2685{ 2686 int res = -1; 2687 2688 if (catal == NULL) 2689 return(-1); 2690 2691 if (catal->type == XML_XML_CATALOG_TYPE) { 2692 res = xmlAddXMLCatalog(catal->xml, type, orig, replace); 2693 } else { 2694 xmlCatalogEntryType cattype; 2695 2696 cattype = xmlGetSGMLCatalogEntryType(type); 2697 if (cattype != XML_CATA_NONE) { 2698 xmlCatalogEntryPtr entry; 2699 2700 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL, 2701 XML_CATA_PREFER_NONE); 2702 if (catal->sgml == NULL) 2703 catal->sgml = xmlHashCreate(10); 2704 res = xmlHashAddEntry(catal->sgml, orig, entry); 2705 } 2706 } 2707 return (res); 2708} 2709 2710/** 2711 * xmlACatalogRemove: 2712 * @catal: a Catalog 2713 * @value: the value to remove 2714 * 2715 * Remove an entry from the catalog 2716 * 2717 * Returns the number of entries removed if successful, -1 otherwise 2718 */ 2719int 2720xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) { 2721 int res = -1; 2722 2723 if ((catal == NULL) || (value == NULL)) 2724 return(-1); 2725 2726 if (catal->type == XML_XML_CATALOG_TYPE) { 2727 res = xmlDelXMLCatalog(catal->xml, value); 2728 } else { 2729 res = xmlHashRemoveEntry(catal->sgml, value, 2730 (xmlHashDeallocator) xmlFreeCatalogEntry); 2731 if (res == 0) 2732 res = 1; 2733 } 2734 return(res); 2735} 2736 2737/** 2738 * xmlNewCatalog: 2739 * @sgml: should this create an SGML catalog 2740 * 2741 * create a new Catalog. 2742 * 2743 * Returns the xmlCatalogPtr or NULL in case of error 2744 */ 2745xmlCatalogPtr 2746xmlNewCatalog(int sgml) { 2747 xmlCatalogPtr catal = NULL; 2748 2749 if (sgml) { 2750 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, 2751 xmlCatalogDefaultPrefer); 2752 if ((catal != NULL) && (catal->sgml == NULL)) 2753 catal->sgml = xmlHashCreate(10); 2754 } else 2755 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 2756 xmlCatalogDefaultPrefer); 2757 return(catal); 2758} 2759 2760/** 2761 * xmlCatalogIsEmpty: 2762 * @catal: should this create an SGML catalog 2763 * 2764 * Check is a catalog is empty 2765 * 2766 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error. 2767 */ 2768int 2769xmlCatalogIsEmpty(xmlCatalogPtr catal) { 2770 if (catal == NULL) 2771 return(-1); 2772 2773 if (catal->type == XML_XML_CATALOG_TYPE) { 2774 if (catal->xml == NULL) 2775 return(1); 2776 if ((catal->xml->type != XML_CATA_CATALOG) && 2777 (catal->xml->type != XML_CATA_BROKEN_CATALOG)) 2778 return(-1); 2779 if (catal->xml->children == NULL) 2780 return(1); 2781 return(0); 2782 } else { 2783 int res; 2784 2785 if (catal->sgml == NULL) 2786 return(1); 2787 res = xmlHashSize(catal->sgml); 2788 if (res == 0) 2789 return(1); 2790 if (res < 0) 2791 return(-1); 2792 } 2793 return(0); 2794} 2795 2796/************************************************************************ 2797 * * 2798 * Public interfaces manipulating the global shared default catalog * 2799 * * 2800 ************************************************************************/ 2801 2802/** 2803 * xmlInitializeCatalogData: 2804 * 2805 * Do the catalog initialization only of global data, doesn't try to load 2806 * any catalog actually. 2807 * this function is not thread safe, catalog initialization should 2808 * preferably be done once at startup 2809 */ 2810static void 2811xmlInitializeCatalogData(void) { 2812 if (xmlCatalogInitialized != 0) 2813 return; 2814 2815 if (getenv("XML_DEBUG_CATALOG")) 2816 xmlDebugCatalogs = 1; 2817 xmlCatalogMutex = xmlNewRMutex(); 2818 2819 xmlCatalogInitialized = 1; 2820} 2821/** 2822 * xmlInitializeCatalog: 2823 * 2824 * Do the catalog initialization. 2825 * this function is not thread safe, catalog initialization should 2826 * preferably be done once at startup 2827 */ 2828void 2829xmlInitializeCatalog(void) { 2830 if (xmlCatalogInitialized != 0) 2831 return; 2832 2833 xmlInitializeCatalogData(); 2834 xmlRMutexLock(xmlCatalogMutex); 2835 2836 if (getenv("XML_DEBUG_CATALOG")) 2837 xmlDebugCatalogs = 1; 2838 2839 if (xmlDefaultCatalog == NULL) { 2840 const char *catalogs; 2841 char *path; 2842 const char *cur, *paths; 2843 xmlCatalogPtr catal; 2844 xmlCatalogEntryPtr *nextent; 2845 2846 catalogs = (const char *) getenv("XML_CATALOG_FILES"); 2847 if (catalogs == NULL) 2848 catalogs = XML_XML_DEFAULT_CATALOG; 2849 2850 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 2851 xmlCatalogDefaultPrefer); 2852 if (catal != NULL) { 2853 /* the XML_CATALOG_FILES envvar is allowed to contain a 2854 space-separated list of entries. */ 2855 cur = catalogs; 2856 nextent = &catal->xml; 2857 while (*cur != '\0') { 2858 while (IS_BLANK(*cur)) 2859 cur++; 2860 if (*cur != 0) { 2861 paths = cur; 2862 while ((*cur != 0) && (!IS_BLANK(*cur))) 2863 cur++; 2864 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths); 2865 if (path != NULL) { 2866 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 2867 NULL, BAD_CAST path, xmlCatalogDefaultPrefer); 2868 if (*nextent != NULL) 2869 nextent = &((*nextent)->next); 2870 xmlFree(path); 2871 } 2872 } 2873 } 2874 xmlDefaultCatalog = catal; 2875 } 2876 } 2877 2878 xmlRMutexUnlock(xmlCatalogMutex); 2879} 2880 2881 2882/** 2883 * xmlLoadCatalog: 2884 * @filename: a file path 2885 * 2886 * Load the catalog and makes its definitions effective for the default 2887 * external entity loader. It will recurse in SGML CATALOG entries. 2888 * this function is not thread safe, catalog initialization should 2889 * preferably be done once at startup 2890 * 2891 * Returns 0 in case of success -1 in case of error 2892 */ 2893int 2894xmlLoadCatalog(const char *filename) 2895{ 2896 int ret; 2897 xmlCatalogPtr catal; 2898 2899 if (!xmlCatalogInitialized) 2900 xmlInitializeCatalogData(); 2901 2902 xmlRMutexLock(xmlCatalogMutex); 2903 2904 if (xmlDefaultCatalog == NULL) { 2905 catal = xmlLoadACatalog(filename); 2906 if (catal == NULL) 2907 return(-1); 2908 2909 xmlDefaultCatalog = catal; 2910 xmlRMutexUnlock(xmlCatalogMutex); 2911 return(0); 2912 } 2913 2914 ret = xmlExpandCatalog(xmlDefaultCatalog, filename); 2915 xmlRMutexUnlock(xmlCatalogMutex); 2916 return(ret); 2917} 2918 2919/** 2920 * xmlLoadCatalogs: 2921 * @pathss: a list of directories separated by a colon or a space. 2922 * 2923 * Load the catalogs and makes their definitions effective for the default 2924 * external entity loader. 2925 * this function is not thread safe, catalog initialization should 2926 * preferably be done once at startup 2927 */ 2928void 2929xmlLoadCatalogs(const char *pathss) { 2930 const char *cur; 2931 const char *paths; 2932 xmlChar *path; 2933 2934 if (pathss == NULL) 2935 return; 2936 2937 cur = pathss; 2938 while ((cur != NULL) && (*cur != 0)) { 2939 while (IS_BLANK(*cur)) cur++; 2940 if (*cur != 0) { 2941 paths = cur; 2942 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur))) 2943 cur++; 2944 path = xmlStrndup((const xmlChar *)paths, cur - paths); 2945 if (path != NULL) { 2946 xmlLoadCatalog((const char *) path); 2947 xmlFree(path); 2948 } 2949 } 2950 while (*cur == ':') 2951 cur++; 2952 } 2953} 2954 2955/** 2956 * xmlCatalogCleanup: 2957 * 2958 * Free up all the memory associated with catalogs 2959 */ 2960void 2961xmlCatalogCleanup(void) { 2962 if (xmlCatalogInitialized == 0) 2963 return; 2964 2965 xmlRMutexLock(xmlCatalogMutex); 2966 if (xmlDebugCatalogs) 2967 xmlGenericError(xmlGenericErrorContext, 2968 "Catalogs cleanup\n"); 2969 if (xmlCatalogXMLFiles != NULL) 2970 xmlHashFree(xmlCatalogXMLFiles, 2971 (xmlHashDeallocator)xmlFreeCatalogHashEntryList); 2972 xmlCatalogXMLFiles = NULL; 2973 if (xmlDefaultCatalog != NULL) 2974 xmlFreeCatalog(xmlDefaultCatalog); 2975 xmlDefaultCatalog = NULL; 2976 xmlDebugCatalogs = 0; 2977 xmlCatalogInitialized = 0; 2978 xmlRMutexUnlock(xmlCatalogMutex); 2979 xmlFreeRMutex(xmlCatalogMutex); 2980} 2981 2982/** 2983 * xmlCatalogResolveSystem: 2984 * @sysID: the public ID string 2985 * 2986 * Try to lookup the catalog resource for a system ID 2987 * 2988 * Returns the system ID if found or NULL otherwise, the value returned 2989 * must be freed by the caller. 2990 */ 2991xmlChar * 2992xmlCatalogResolveSystem(const xmlChar *sysID) { 2993 xmlChar *ret; 2994 2995 if (!xmlCatalogInitialized) 2996 xmlInitializeCatalog(); 2997 2998 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID); 2999 return(ret); 3000} 3001 3002/** 3003 * xmlCatalogResolvePublic: 3004 * @pubID: the public ID string 3005 * 3006 * Try to lookup the system ID associated to a public ID 3007 * 3008 * Returns the system ID if found or NULL otherwise, the value returned 3009 * must be freed by the caller. 3010 */ 3011xmlChar * 3012xmlCatalogResolvePublic(const xmlChar *pubID) { 3013 xmlChar *ret; 3014 3015 if (!xmlCatalogInitialized) 3016 xmlInitializeCatalog(); 3017 3018 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID); 3019 return(ret); 3020} 3021 3022/** 3023 * xmlCatalogResolve: 3024 * @pubID: the public ID string 3025 * @sysID: the system ID string 3026 * 3027 * Do a complete resolution lookup of an External Identifier 3028 * 3029 * Returns the URI of the resource or NULL if not found, it must be freed 3030 * by the caller. 3031 */ 3032xmlChar * 3033xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) { 3034 xmlChar *ret; 3035 3036 if (!xmlCatalogInitialized) 3037 xmlInitializeCatalog(); 3038 3039 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID); 3040 return(ret); 3041} 3042 3043/** 3044 * xmlCatalogResolveURI: 3045 * @URI: the URI 3046 * 3047 * Do a complete resolution lookup of an URI 3048 * 3049 * Returns the URI of the resource or NULL if not found, it must be freed 3050 * by the caller. 3051 */ 3052xmlChar * 3053xmlCatalogResolveURI(const xmlChar *URI) { 3054 xmlChar *ret; 3055 3056 if (!xmlCatalogInitialized) 3057 xmlInitializeCatalog(); 3058 3059 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI); 3060 return(ret); 3061} 3062 3063/** 3064 * xmlCatalogDump: 3065 * @out: the file. 3066 * 3067 * Free up all the memory associated with catalogs 3068 */ 3069void 3070xmlCatalogDump(FILE *out) { 3071 if (out == NULL) 3072 return; 3073 3074 if (!xmlCatalogInitialized) 3075 xmlInitializeCatalog(); 3076 3077 xmlACatalogDump(xmlDefaultCatalog, out); 3078} 3079 3080/** 3081 * xmlCatalogAdd: 3082 * @type: the type of record to add to the catalog 3083 * @orig: the system, public or prefix to match 3084 * @replace: the replacement value for the match 3085 * 3086 * Add an entry in the catalog, it may overwrite existing but 3087 * different entries. 3088 * If called before any other catalog routine, allows to override the 3089 * default shared catalog put in place by xmlInitializeCatalog(); 3090 * 3091 * Returns 0 if successful, -1 otherwise 3092 */ 3093int 3094xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { 3095 int res = -1; 3096 3097 if (!xmlCatalogInitialized) 3098 xmlInitializeCatalogData(); 3099 3100 xmlRMutexLock(xmlCatalogMutex); 3101 /* 3102 * Specific case where one want to override the default catalog 3103 * put in place by xmlInitializeCatalog(); 3104 */ 3105 if ((xmlDefaultCatalog == NULL) && 3106 (xmlStrEqual(type, BAD_CAST "catalog"))) { 3107 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 3108 xmlCatalogDefaultPrefer); 3109 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 3110 orig, NULL, xmlCatalogDefaultPrefer); 3111 3112 xmlRMutexUnlock(xmlCatalogMutex); 3113 return(0); 3114 } 3115 3116 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace); 3117 xmlRMutexUnlock(xmlCatalogMutex); 3118 return(res); 3119} 3120 3121/** 3122 * xmlCatalogRemove: 3123 * @value: the value to remove 3124 * 3125 * Remove an entry from the catalog 3126 * 3127 * Returns the number of entries removed if successful, -1 otherwise 3128 */ 3129int 3130xmlCatalogRemove(const xmlChar *value) { 3131 int res; 3132 3133 if (!xmlCatalogInitialized) 3134 xmlInitializeCatalog(); 3135 3136 xmlRMutexLock(xmlCatalogMutex); 3137 res = xmlACatalogRemove(xmlDefaultCatalog, value); 3138 xmlRMutexUnlock(xmlCatalogMutex); 3139 return(res); 3140} 3141 3142/** 3143 * xmlCatalogConvert: 3144 * 3145 * Convert all the SGML catalog entries as XML ones 3146 * 3147 * Returns the number of entries converted if successful, -1 otherwise 3148 */ 3149int 3150xmlCatalogConvert(void) { 3151 int res = -1; 3152 3153 if (!xmlCatalogInitialized) 3154 xmlInitializeCatalog(); 3155 3156 xmlRMutexLock(xmlCatalogMutex); 3157 res = xmlConvertSGMLCatalog(xmlDefaultCatalog); 3158 xmlRMutexUnlock(xmlCatalogMutex); 3159 return(res); 3160} 3161 3162/************************************************************************ 3163 * * 3164 * Public interface manipulating the common preferences * 3165 * * 3166 ************************************************************************/ 3167 3168/** 3169 * xmlCatalogGetDefaults: 3170 * 3171 * Used to get the user preference w.r.t. to what catalogs should 3172 * be accepted 3173 * 3174 * Returns the current xmlCatalogAllow value 3175 */ 3176xmlCatalogAllow 3177xmlCatalogGetDefaults(void) { 3178 return(xmlCatalogDefaultAllow); 3179} 3180 3181/** 3182 * xmlCatalogSetDefaults: 3183 * @allow: what catalogs should be accepted 3184 * 3185 * Used to set the user preference w.r.t. to what catalogs should 3186 * be accepted 3187 */ 3188void 3189xmlCatalogSetDefaults(xmlCatalogAllow allow) { 3190 if (xmlDebugCatalogs) { 3191 switch (allow) { 3192 case XML_CATA_ALLOW_NONE: 3193 xmlGenericError(xmlGenericErrorContext, 3194 "Disabling catalog usage\n"); 3195 break; 3196 case XML_CATA_ALLOW_GLOBAL: 3197 xmlGenericError(xmlGenericErrorContext, 3198 "Allowing only global catalogs\n"); 3199 break; 3200 case XML_CATA_ALLOW_DOCUMENT: 3201 xmlGenericError(xmlGenericErrorContext, 3202 "Allowing only catalogs from the document\n"); 3203 break; 3204 case XML_CATA_ALLOW_ALL: 3205 xmlGenericError(xmlGenericErrorContext, 3206 "Allowing all catalogs\n"); 3207 break; 3208 } 3209 } 3210 xmlCatalogDefaultAllow = allow; 3211} 3212 3213/** 3214 * xmlCatalogSetDefaultPrefer: 3215 * @prefer: the default preference for delegation 3216 * 3217 * Allows to set the preference between public and system for deletion 3218 * in XML Catalog resolution. C.f. section 4.1.1 of the spec 3219 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM 3220 * 3221 * Returns the previous value of the default preference for delegation 3222 */ 3223xmlCatalogPrefer 3224xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { 3225 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer; 3226 3227 if (prefer == XML_CATA_PREFER_NONE) 3228 return(ret); 3229 3230 if (xmlDebugCatalogs) { 3231 switch (prefer) { 3232 case XML_CATA_PREFER_PUBLIC: 3233 xmlGenericError(xmlGenericErrorContext, 3234 "Setting catalog preference to PUBLIC\n"); 3235 break; 3236 case XML_CATA_PREFER_SYSTEM: 3237 xmlGenericError(xmlGenericErrorContext, 3238 "Setting catalog preference to SYSTEM\n"); 3239 break; 3240 case XML_CATA_PREFER_NONE: 3241 break; 3242 } 3243 } 3244 xmlCatalogDefaultPrefer = prefer; 3245 return(ret); 3246} 3247 3248/** 3249 * xmlCatalogSetDebug: 3250 * @level: the debug level of catalogs required 3251 * 3252 * Used to set the debug level for catalog operation, 0 disable 3253 * debugging, 1 enable it 3254 * 3255 * Returns the previous value of the catalog debugging level 3256 */ 3257int 3258xmlCatalogSetDebug(int level) { 3259 int ret = xmlDebugCatalogs; 3260 3261 if (level <= 0) 3262 xmlDebugCatalogs = 0; 3263 else 3264 xmlDebugCatalogs = level; 3265 return(ret); 3266} 3267 3268/************************************************************************ 3269 * * 3270 * Minimal interfaces used for per-document catalogs by the parser * 3271 * * 3272 ************************************************************************/ 3273 3274/** 3275 * xmlCatalogFreeLocal: 3276 * @catalogs: a document's list of catalogs 3277 * 3278 * Free up the memory associated to the catalog list 3279 */ 3280void 3281xmlCatalogFreeLocal(void *catalogs) { 3282 xmlCatalogEntryPtr catal; 3283 3284 if (!xmlCatalogInitialized) 3285 xmlInitializeCatalog(); 3286 3287 catal = (xmlCatalogEntryPtr) catalogs; 3288 if (catal != NULL) 3289 xmlFreeCatalogEntryList(catal); 3290} 3291 3292 3293/** 3294 * xmlCatalogAddLocal: 3295 * @catalogs: a document's list of catalogs 3296 * @URL: the URL to a new local catalog 3297 * 3298 * Add the new entry to the catalog list 3299 * 3300 * Returns the updated list 3301 */ 3302void * 3303xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { 3304 xmlCatalogEntryPtr catal, add; 3305 3306 if (!xmlCatalogInitialized) 3307 xmlInitializeCatalog(); 3308 3309 if (URL == NULL) 3310 return(catalogs); 3311 3312 if (xmlDebugCatalogs) 3313 xmlGenericError(xmlGenericErrorContext, 3314 "Adding document catalog %s\n", URL); 3315 3316 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, 3317 xmlCatalogDefaultPrefer); 3318 if (add == NULL) 3319 return(catalogs); 3320 3321 catal = (xmlCatalogEntryPtr) catalogs; 3322 if (catal == NULL) 3323 return((void *) add); 3324 3325 while (catal->next != NULL) 3326 catal = catal->next; 3327 catal->next = add; 3328 return(catalogs); 3329} 3330 3331/** 3332 * xmlCatalogLocalResolve: 3333 * @catalogs: a document's list of catalogs 3334 * @pubID: the public ID string 3335 * @sysID: the system ID string 3336 * 3337 * Do a complete resolution lookup of an External Identifier using a 3338 * document's private catalog list 3339 * 3340 * Returns the URI of the resource or NULL if not found, it must be freed 3341 * by the caller. 3342 */ 3343xmlChar * 3344xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, 3345 const xmlChar *sysID) { 3346 xmlCatalogEntryPtr catal; 3347 xmlChar *ret; 3348 3349 if (!xmlCatalogInitialized) 3350 xmlInitializeCatalog(); 3351 3352 if ((pubID == NULL) && (sysID == NULL)) 3353 return(NULL); 3354 3355 if (xmlDebugCatalogs) { 3356 if (pubID != NULL) { 3357 xmlGenericError(xmlGenericErrorContext, 3358 "Local resolve: pubID %s\n", pubID); 3359 } else { 3360 xmlGenericError(xmlGenericErrorContext, 3361 "Local resolve: sysID %s\n", sysID); 3362 } 3363 } 3364 3365 catal = (xmlCatalogEntryPtr) catalogs; 3366 if (catal == NULL) 3367 return(NULL); 3368 ret = xmlCatalogListXMLResolve(catal, pubID, sysID); 3369 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 3370 return(ret); 3371 return(NULL); 3372} 3373 3374/** 3375 * xmlCatalogLocalResolveURI: 3376 * @catalogs: a document's list of catalogs 3377 * @URI: the URI 3378 * 3379 * Do a complete resolution lookup of an URI using a 3380 * document's private catalog list 3381 * 3382 * Returns the URI of the resource or NULL if not found, it must be freed 3383 * by the caller. 3384 */ 3385xmlChar * 3386xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { 3387 xmlCatalogEntryPtr catal; 3388 xmlChar *ret; 3389 3390 if (!xmlCatalogInitialized) 3391 xmlInitializeCatalog(); 3392 3393 if (URI == NULL) 3394 return(NULL); 3395 3396 if (xmlDebugCatalogs) 3397 xmlGenericError(xmlGenericErrorContext, 3398 "Resolve URI %s\n", URI); 3399 3400 catal = (xmlCatalogEntryPtr) catalogs; 3401 if (catal == NULL) 3402 return(NULL); 3403 ret = xmlCatalogListXMLResolveURI(catal, URI); 3404 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 3405 return(ret); 3406 return(NULL); 3407} 3408 3409/************************************************************************ 3410 * * 3411 * Deprecated interfaces * 3412 * * 3413 ************************************************************************/ 3414/** 3415 * xmlCatalogGetSystem: 3416 * @sysID: the system ID string 3417 * 3418 * Try to lookup the system ID associated to a public ID 3419 * DEPRECATED, use xmlCatalogResolveSystem() 3420 * 3421 * Returns the system ID if found or NULL otherwise. 3422 */ 3423const xmlChar * 3424xmlCatalogGetSystem(const xmlChar *sysID) { 3425 xmlChar *ret; 3426 static xmlChar result[1000]; 3427 static int msg = 0; 3428 3429 if (!xmlCatalogInitialized) 3430 xmlInitializeCatalog(); 3431 3432 if (msg == 0) { 3433 xmlGenericError(xmlGenericErrorContext, 3434 "Use of deprecated xmlCatalogGetSystem() call\n"); 3435 msg++; 3436 } 3437 3438 if (sysID == NULL) 3439 return(NULL); 3440 3441 /* 3442 * Check first the XML catalogs 3443 */ 3444 if (xmlDefaultCatalog != NULL) { 3445 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID); 3446 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 3447 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 3448 result[sizeof(result) - 1] = 0; 3449 return(result); 3450 } 3451 } 3452 3453 if (xmlDefaultCatalog != NULL) 3454 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID)); 3455 return(NULL); 3456} 3457 3458/** 3459 * xmlCatalogGetPublic: 3460 * @pubID: the public ID string 3461 * 3462 * Try to lookup the system ID associated to a public ID 3463 * DEPRECATED, use xmlCatalogResolvePublic() 3464 * 3465 * Returns the system ID if found or NULL otherwise. 3466 */ 3467const xmlChar * 3468xmlCatalogGetPublic(const xmlChar *pubID) { 3469 xmlChar *ret; 3470 static xmlChar result[1000]; 3471 static int msg = 0; 3472 3473 if (!xmlCatalogInitialized) 3474 xmlInitializeCatalog(); 3475 3476 if (msg == 0) { 3477 xmlGenericError(xmlGenericErrorContext, 3478 "Use of deprecated xmlCatalogGetPublic() call\n"); 3479 msg++; 3480 } 3481 3482 if (pubID == NULL) 3483 return(NULL); 3484 3485 /* 3486 * Check first the XML catalogs 3487 */ 3488 if (xmlDefaultCatalog != NULL) { 3489 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL); 3490 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 3491 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 3492 result[sizeof(result) - 1] = 0; 3493 return(result); 3494 } 3495 } 3496 3497 if (xmlDefaultCatalog != NULL) 3498 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID)); 3499 return(NULL); 3500} 3501 3502#endif /* LIBXML_CATALOG_ENABLED */ 3503