1 Star 0 Fork 9

yang/libxml2_backup

forked from openKylin/libxml2 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
catalog.c 96.92 KB
一键复制 编辑 原始数据 按行查看 历史
openKylinBot 提交于 2022-05-14 01:30 . Import Upstream version 2.9.10+dfsg
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828
/**
* catalog.c: set of generic Catalog related routines
*
* Reference: SGML Open Technical Resolution TR9401:1997.
* http://www.jclark.com/sp/catalog.htm
*
* XML Catalogs Working Draft 06 August 2001
* http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* See Copyright for the status of this software.
*
* Daniel.Veillard@imag.fr
*/
#define IN_LIBXML
#include "libxml.h"
#ifdef LIBXML_CATALOG_ENABLED
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/hash.h>
#include <libxml/uri.h>
#include <libxml/parserInternals.h>
#include <libxml/catalog.h>
#include <libxml/xmlerror.h>
#include <libxml/threads.h>
#include <libxml/globals.h>
#include "buf.h"
#define MAX_DELEGATE 50
#define MAX_CATAL_DEPTH 50
#ifdef _WIN32
# define PATH_SEPARATOR ';'
#else
# define PATH_SEPARATOR ':'
#endif
/**
* TODO:
*
* macro to flag unimplemented blocks
* XML_CATALOG_PREFER user env to select between system/public preferred
* option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
*> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
*> values "system" and "public". I have made the default be "system" to
*> match yours.
*/
#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#define XML_URN_PUBID "urn:publicid:"
#define XML_CATAL_BREAK ((xmlChar *) -1)
#ifndef XML_XML_DEFAULT_CATALOG
#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
#endif
#ifndef XML_SGML_DEFAULT_CATALOG
#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
#endif
#if defined(_WIN32) && defined(_MSC_VER)
#undef XML_XML_DEFAULT_CATALOG
static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
#if defined(_WIN32_WCE)
/* Windows CE don't have a A variant */
#define GetModuleHandleA GetModuleHandle
#define GetModuleFileNameA GetModuleFileName
#else
#if !defined(_WINDOWS_)
void* __stdcall GetModuleHandleA(const char*);
unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
#endif
#endif
#endif
static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
/************************************************************************
* *
* Types, all private *
* *
************************************************************************/
typedef enum {
XML_CATA_REMOVED = -1,
XML_CATA_NONE = 0,
XML_CATA_CATALOG,
XML_CATA_BROKEN_CATALOG,
XML_CATA_NEXT_CATALOG,
XML_CATA_GROUP,
XML_CATA_PUBLIC,
XML_CATA_SYSTEM,
XML_CATA_REWRITE_SYSTEM,
XML_CATA_DELEGATE_PUBLIC,
XML_CATA_DELEGATE_SYSTEM,
XML_CATA_URI,
XML_CATA_REWRITE_URI,
XML_CATA_DELEGATE_URI,
SGML_CATA_SYSTEM,
SGML_CATA_PUBLIC,
SGML_CATA_ENTITY,
SGML_CATA_PENTITY,
SGML_CATA_DOCTYPE,
SGML_CATA_LINKTYPE,
SGML_CATA_NOTATION,
SGML_CATA_DELEGATE,
SGML_CATA_BASE,
SGML_CATA_CATALOG,
SGML_CATA_DOCUMENT,
SGML_CATA_SGMLDECL
} xmlCatalogEntryType;
typedef struct _xmlCatalogEntry xmlCatalogEntry;
typedef xmlCatalogEntry *xmlCatalogEntryPtr;
struct _xmlCatalogEntry {
struct _xmlCatalogEntry *next;
struct _xmlCatalogEntry *parent;
struct _xmlCatalogEntry *children;
xmlCatalogEntryType type;
xmlChar *name;
xmlChar *value;
xmlChar *URL; /* The expanded URL using the base */
xmlCatalogPrefer prefer;
int dealloc;
int depth;
struct _xmlCatalogEntry *group;
};
typedef enum {
XML_XML_CATALOG_TYPE = 1,
XML_SGML_CATALOG_TYPE
} xmlCatalogType;
#define XML_MAX_SGML_CATA_DEPTH 10
struct _xmlCatalog {
xmlCatalogType type; /* either XML or SGML */
/*
* SGML Catalogs are stored as a simple hash table of catalog entries
* Catalog stack to check against overflows when building the
* SGML catalog
*/
char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
int catalNr; /* Number of current catal streams */
int catalMax; /* Max number of catal streams */
xmlHashTablePtr sgml;
/*
* XML Catalogs are stored as a tree of Catalog entries
*/
xmlCatalogPrefer prefer;
xmlCatalogEntryPtr xml;
};
/************************************************************************
* *
* Global variables *
* *
************************************************************************/
/*
* Those are preferences
*/
static int xmlDebugCatalogs = 0; /* used for debugging */
static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
/*
* Hash table containing all the trees of XML catalogs parsed by
* the application.
*/
static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
/*
* The default catalog in use by the application
*/
static xmlCatalogPtr xmlDefaultCatalog = NULL;
/*
* A mutex for modifying the shared global catalog(s)
* xmlDefaultCatalog tree.
* It also protects xmlCatalogXMLFiles
* The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
*/
static xmlRMutexPtr xmlCatalogMutex = NULL;
/*
* Whether the catalog support was initialized.
*/
static int xmlCatalogInitialized = 0;
/************************************************************************
* *
* Catalog error handlers *
* *
************************************************************************/
/**
* xmlCatalogErrMemory:
* @extra: extra informations
*
* Handle an out of memory condition
*/
static void
xmlCatalogErrMemory(const char *extra)
{
__xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
extra, NULL, NULL, 0, 0,
"Memory allocation failed : %s\n", extra);
}
/**
* xmlCatalogErr:
* @catal: the Catalog entry
* @node: the context node
* @msg: the error message
* @extra: extra informations
*
* Handle a catalog error
*/
static void LIBXML_ATTR_FORMAT(4,0)
xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
const char *msg, const xmlChar *str1, const xmlChar *str2,
const xmlChar *str3)
{
__xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
error, XML_ERR_ERROR, NULL, 0,
(const char *) str1, (const char *) str2,
(const char *) str3, 0, 0,
msg, str1, str2, str3);
}
/************************************************************************
* *
* Allocation and Freeing *
* *
************************************************************************/
/**
* xmlNewCatalogEntry:
* @type: type of entry
* @name: name of the entry
* @value: value of the entry
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @group: for members of a group, the group entry
*
* create a new Catalog entry, this type is shared both by XML and
* SGML catalogs, but the acceptable types values differs.
*
* Returns the xmlCatalogEntryPtr or NULL in case of error
*/
static xmlCatalogEntryPtr
xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr group) {
xmlCatalogEntryPtr ret;
xmlChar *normid = NULL;
ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
if (ret == NULL) {
xmlCatalogErrMemory("allocating catalog entry");
return(NULL);
}
ret->next = NULL;
ret->parent = NULL;
ret->children = NULL;
ret->type = type;
if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
normid = xmlCatalogNormalizePublic(name);
if (normid != NULL)
name = (*normid != 0 ? normid : NULL);
}
if (name != NULL)
ret->name = xmlStrdup(name);
else
ret->name = NULL;
if (normid != NULL)
xmlFree(normid);
if (value != NULL)
ret->value = xmlStrdup(value);
else
ret->value = NULL;
if (URL == NULL)
URL = value;
if (URL != NULL)
ret->URL = xmlStrdup(URL);
else
ret->URL = NULL;
ret->prefer = prefer;
ret->dealloc = 0;
ret->depth = 0;
ret->group = group;
return(ret);
}
static void
xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
/**
* xmlFreeCatalogEntry:
* @payload: a Catalog entry
*
* Free the memory allocated to a Catalog entry
*/
static void
xmlFreeCatalogEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr ret = (xmlCatalogEntryPtr) payload;
if (ret == NULL)
return;
/*
* Entries stored in the file hash must be deallocated
* only by the file hash cleaner !
*/
if (ret->dealloc == 1)
return;
if (xmlDebugCatalogs) {
if (ret->name != NULL)
xmlGenericError(xmlGenericErrorContext,
"Free catalog entry %s\n", ret->name);
else if (ret->value != NULL)
xmlGenericError(xmlGenericErrorContext,
"Free catalog entry %s\n", ret->value);
else
xmlGenericError(xmlGenericErrorContext,
"Free catalog entry\n");
}
if (ret->name != NULL)
xmlFree(ret->name);
if (ret->value != NULL)
xmlFree(ret->value);
if (ret->URL != NULL)
xmlFree(ret->URL);
xmlFree(ret);
}
/**
* xmlFreeCatalogEntryList:
* @ret: a Catalog entry list
*
* Free the memory allocated to a full chained list of Catalog entries
*/
static void
xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
xmlCatalogEntryPtr next;
while (ret != NULL) {
next = ret->next;
xmlFreeCatalogEntry(ret, NULL);
ret = next;
}
}
/**
* xmlFreeCatalogHashEntryList:
* @payload: a Catalog entry list
*
* Free the memory allocated to list of Catalog entries from the
* catalog file hash.
*/
static void
xmlFreeCatalogHashEntryList(void *payload,
const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr catal = (xmlCatalogEntryPtr) payload;
xmlCatalogEntryPtr children, next;
if (catal == NULL)
return;
children = catal->children;
while (children != NULL) {
next = children->next;
children->dealloc = 0;
children->children = NULL;
xmlFreeCatalogEntry(children, NULL);
children = next;
}
catal->dealloc = 0;
xmlFreeCatalogEntry(catal, NULL);
}
/**
* xmlCreateNewCatalog:
* @type: type of catalog
* @prefer: the PUBLIC vs. SYSTEM current preference value
*
* create a new Catalog, this type is shared both by XML and
* SGML catalogs, but the acceptable types values differs.
*
* Returns the xmlCatalogPtr or NULL in case of error
*/
static xmlCatalogPtr
xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
xmlCatalogPtr ret;
ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
if (ret == NULL) {
xmlCatalogErrMemory("allocating catalog");
return(NULL);
}
memset(ret, 0, sizeof(xmlCatalog));
ret->type = type;
ret->catalNr = 0;
ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
ret->prefer = prefer;
if (ret->type == XML_SGML_CATALOG_TYPE)
ret->sgml = xmlHashCreate(10);
return(ret);
}
/**
* xmlFreeCatalog:
* @catal: a Catalog
*
* Free the memory allocated to a Catalog
*/
void
xmlFreeCatalog(xmlCatalogPtr catal) {
if (catal == NULL)
return;
if (catal->xml != NULL)
xmlFreeCatalogEntryList(catal->xml);
if (catal->sgml != NULL)
xmlHashFree(catal->sgml, xmlFreeCatalogEntry);
xmlFree(catal);
}
/************************************************************************
* *
* Serializing Catalogs *
* *
************************************************************************/
#ifdef LIBXML_OUTPUT_ENABLED
/**
* xmlCatalogDumpEntry:
* @entry: the catalog entry
* @out: the file.
*
* Serialize an SGML Catalog entry
*/
static void
xmlCatalogDumpEntry(void *payload, void *data,
const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
FILE *out = (FILE *) data;
if ((entry == NULL) || (out == NULL))
return;
switch (entry->type) {
case SGML_CATA_ENTITY:
fprintf(out, "ENTITY "); break;
case SGML_CATA_PENTITY:
fprintf(out, "ENTITY %%"); break;
case SGML_CATA_DOCTYPE:
fprintf(out, "DOCTYPE "); break;
case SGML_CATA_LINKTYPE:
fprintf(out, "LINKTYPE "); break;
case SGML_CATA_NOTATION:
fprintf(out, "NOTATION "); break;
case SGML_CATA_PUBLIC:
fprintf(out, "PUBLIC "); break;
case SGML_CATA_SYSTEM:
fprintf(out, "SYSTEM "); break;
case SGML_CATA_DELEGATE:
fprintf(out, "DELEGATE "); break;
case SGML_CATA_BASE:
fprintf(out, "BASE "); break;
case SGML_CATA_CATALOG:
fprintf(out, "CATALOG "); break;
case SGML_CATA_DOCUMENT:
fprintf(out, "DOCUMENT "); break;
case SGML_CATA_SGMLDECL:
fprintf(out, "SGMLDECL "); break;
default:
return;
}
switch (entry->type) {
case SGML_CATA_ENTITY:
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
fprintf(out, "%s", (const char *) entry->name); break;
case SGML_CATA_PUBLIC:
case SGML_CATA_SYSTEM:
case SGML_CATA_SGMLDECL:
case SGML_CATA_DOCUMENT:
case SGML_CATA_CATALOG:
case SGML_CATA_BASE:
case SGML_CATA_DELEGATE:
fprintf(out, "\"%s\"", entry->name); break;
default:
break;
}
switch (entry->type) {
case SGML_CATA_ENTITY:
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
case SGML_CATA_PUBLIC:
case SGML_CATA_SYSTEM:
case SGML_CATA_DELEGATE:
fprintf(out, " \"%s\"", entry->value); break;
default:
break;
}
fprintf(out, "\n");
}
/**
* xmlDumpXMLCatalogNode:
* @catal: top catalog entry
* @catalog: pointer to the xml tree
* @doc: the containing document
* @ns: the current namespace
* @cgroup: group node for group members
*
* Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
* for group entries
*/
static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
xmlNodePtr node;
xmlCatalogEntryPtr cur;
/*
* add all the catalog entries
*/
cur = catal;
while (cur != NULL) {
if (cur->group == cgroup) {
switch (cur->type) {
case XML_CATA_REMOVED:
break;
case XML_CATA_BROKEN_CATALOG:
case XML_CATA_CATALOG:
if (cur == catal) {
cur = cur->children;
continue;
}
break;
case XML_CATA_NEXT_CATALOG:
node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_NONE:
break;
case XML_CATA_GROUP:
node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
xmlSetProp(node, BAD_CAST "id", cur->name);
if (cur->value != NULL) {
xmlNsPtr xns;
xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
if (xns != NULL)
xmlSetNsProp(node, xns, BAD_CAST "base",
cur->value);
}
switch (cur->prefer) {
case XML_CATA_PREFER_NONE:
break;
case XML_CATA_PREFER_PUBLIC:
xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
break;
case XML_CATA_PREFER_SYSTEM:
xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
break;
}
xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
xmlAddChild(catalog, node);
break;
case XML_CATA_PUBLIC:
node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
xmlSetProp(node, BAD_CAST "publicId", cur->name);
xmlSetProp(node, BAD_CAST "uri", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_SYSTEM:
node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
xmlSetProp(node, BAD_CAST "systemId", cur->name);
xmlSetProp(node, BAD_CAST "uri", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_REWRITE_SYSTEM:
node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_DELEGATE_PUBLIC:
node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_DELEGATE_SYSTEM:
node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_URI:
node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
xmlSetProp(node, BAD_CAST "name", cur->name);
xmlSetProp(node, BAD_CAST "uri", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_REWRITE_URI:
node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_DELEGATE_URI:
node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case SGML_CATA_SYSTEM:
case SGML_CATA_PUBLIC:
case SGML_CATA_ENTITY:
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
case SGML_CATA_DELEGATE:
case SGML_CATA_BASE:
case SGML_CATA_CATALOG:
case SGML_CATA_DOCUMENT:
case SGML_CATA_SGMLDECL:
break;
}
}
cur = cur->next;
}
}
static int
xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
int ret;
xmlDocPtr doc;
xmlNsPtr ns;
xmlDtdPtr dtd;
xmlNodePtr catalog;
xmlOutputBufferPtr buf;
/*
* Rebuild a catalog
*/
doc = xmlNewDoc(NULL);
if (doc == NULL)
return(-1);
dtd = xmlNewDtd(doc, BAD_CAST "catalog",
BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
if (ns == NULL) {
xmlFreeDoc(doc);
return(-1);
}
catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
if (catalog == NULL) {
xmlFreeNs(ns);
xmlFreeDoc(doc);
return(-1);
}
catalog->nsDef = ns;
xmlAddChild((xmlNodePtr) doc, catalog);
xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
/*
* reserialize it
*/
buf = xmlOutputBufferCreateFile(out, NULL);
if (buf == NULL) {
xmlFreeDoc(doc);
return(-1);
}
ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
/*
* Free it
*/
xmlFreeDoc(doc);
return(ret);
}
#endif /* LIBXML_OUTPUT_ENABLED */
/************************************************************************
* *
* Converting SGML Catalogs to XML *
* *
************************************************************************/
/**
* xmlCatalogConvertEntry:
* @entry: the entry
* @catal: pointer to the catalog being converted
*
* Convert one entry from the catalog
*/
static void
xmlCatalogConvertEntry(void *payload, void *data,
const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
xmlCatalogPtr catal = (xmlCatalogPtr) data;
if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
(catal->xml == NULL))
return;
switch (entry->type) {
case SGML_CATA_ENTITY:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_PENTITY:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_DOCTYPE:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_LINKTYPE:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_NOTATION:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_PUBLIC:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_SYSTEM:
entry->type = XML_CATA_SYSTEM;
break;
case SGML_CATA_DELEGATE:
entry->type = XML_CATA_DELEGATE_PUBLIC;
break;
case SGML_CATA_CATALOG:
entry->type = XML_CATA_CATALOG;
break;
default:
xmlHashRemoveEntry(catal->sgml, entry->name, xmlFreeCatalogEntry);
return;
}
/*
* Conversion successful, remove from the SGML catalog
* and add it to the default XML one
*/
xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
entry->parent = catal->xml;
entry->next = NULL;
if (catal->xml->children == NULL)
catal->xml->children = entry;
else {
xmlCatalogEntryPtr prev;
prev = catal->xml->children;
while (prev->next != NULL)
prev = prev->next;
prev->next = entry;
}
}
/**
* xmlConvertSGMLCatalog:
* @catal: the catalog
*
* Convert all the SGML catalog entries as XML ones
*
* Returns the number of entries converted if successful, -1 otherwise
*/
int
xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
return(-1);
if (xmlDebugCatalogs) {
xmlGenericError(xmlGenericErrorContext,
"Converting SGML catalog to XML\n");
}
xmlHashScan(catal->sgml, xmlCatalogConvertEntry, &catal);
return(0);
}
/************************************************************************
* *
* Helper function *
* *
************************************************************************/
/**
* xmlCatalogUnWrapURN:
* @urn: an "urn:publicid:" to unwrap
*
* Expand the URN into the equivalent Public Identifier
*
* Returns the new identifier or NULL, the string must be deallocated
* by the caller.
*/
static xmlChar *
xmlCatalogUnWrapURN(const xmlChar *urn) {
xmlChar result[2000];
unsigned int i = 0;
if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
return(NULL);
urn += sizeof(XML_URN_PUBID) - 1;
while (*urn != 0) {
if (i > sizeof(result) - 4)
break;
if (*urn == '+') {
result[i++] = ' ';
urn++;
} else if (*urn == ':') {
result[i++] = '/';
result[i++] = '/';
urn++;
} else if (*urn == ';') {
result[i++] = ':';
result[i++] = ':';
urn++;
} else if (*urn == '%') {
if ((urn[1] == '2') && (urn[2] == 'B'))
result[i++] = '+';
else if ((urn[1] == '3') && (urn[2] == 'A'))
result[i++] = ':';
else if ((urn[1] == '2') && (urn[2] == 'F'))
result[i++] = '/';
else if ((urn[1] == '3') && (urn[2] == 'B'))
result[i++] = ';';
else if ((urn[1] == '2') && (urn[2] == '7'))
result[i++] = '\'';
else if ((urn[1] == '3') && (urn[2] == 'F'))
result[i++] = '?';
else if ((urn[1] == '2') && (urn[2] == '3'))
result[i++] = '#';
else if ((urn[1] == '2') && (urn[2] == '5'))
result[i++] = '%';
else {
result[i++] = *urn;
urn++;
continue;
}
urn += 3;
} else {
result[i++] = *urn;
urn++;
}
}
result[i] = 0;
return(xmlStrdup(result));
}
/**
* xmlParseCatalogFile:
* @filename: the filename
*
* parse an XML file and build a tree. It's like xmlParseFile()
* except it bypass all catalog lookups.
*
* Returns the resulting document tree or NULL in case of error
*/
xmlDocPtr
xmlParseCatalogFile(const char *filename) {
xmlDocPtr ret;
xmlParserCtxtPtr ctxt;
char *directory = NULL;
xmlParserInputPtr inputStream;
xmlParserInputBufferPtr buf;
ctxt = xmlNewParserCtxt();
if (ctxt == NULL) {
#ifdef LIBXML_SAX1_ENABLED
if (xmlDefaultSAXHandler.error != NULL) {
xmlDefaultSAXHandler.error(NULL, "out of memory\n");
}
#endif
return(NULL);
}
buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
if (buf == NULL) {
xmlFreeParserCtxt(ctxt);
return(NULL);
}
inputStream = xmlNewInputStream(ctxt);
if (inputStream == NULL) {
xmlFreeParserCtxt(ctxt);
return(NULL);
}
inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
inputStream->buf = buf;
xmlBufResetInput(buf->buffer, inputStream);
inputPush(ctxt, inputStream);
if ((ctxt->directory == NULL) && (directory == NULL))
directory = xmlParserGetDirectory(filename);
if ((ctxt->directory == NULL) && (directory != NULL))
ctxt->directory = directory;
ctxt->valid = 0;
ctxt->validate = 0;
ctxt->loadsubset = 0;
ctxt->pedantic = 0;
ctxt->dictNames = 1;
xmlParseDocument(ctxt);
if (ctxt->wellFormed)
ret = ctxt->myDoc;
else {
ret = NULL;
xmlFreeDoc(ctxt->myDoc);
ctxt->myDoc = NULL;
}
xmlFreeParserCtxt(ctxt);
return(ret);
}
/**
* xmlLoadFileContent:
* @filename: a file path
*
* Load a file content into memory.
*
* Returns a pointer to the 0 terminated string or NULL in case of error
*/
static xmlChar *
xmlLoadFileContent(const char *filename)
{
#ifdef HAVE_STAT
int fd;
#else
FILE *fd;
#endif
int len;
long size;
#ifdef HAVE_STAT
struct stat info;
#endif
xmlChar *content;
if (filename == NULL)
return (NULL);
#ifdef HAVE_STAT
if (stat(filename, &info) < 0)
return (NULL);
#endif
#ifdef HAVE_STAT
if ((fd = open(filename, O_RDONLY)) < 0)
#else
if ((fd = fopen(filename, "rb")) == NULL)
#endif
{
return (NULL);
}
#ifdef HAVE_STAT
size = info.st_size;
#else
if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
fclose(fd);
return (NULL);
}
#endif
content = (xmlChar*)xmlMallocAtomic(size + 10);
if (content == NULL) {
xmlCatalogErrMemory("allocating catalog data");
#ifdef HAVE_STAT
close(fd);
#else
fclose(fd);
#endif
return (NULL);
}
#ifdef HAVE_STAT
len = read(fd, content, size);
close(fd);
#else
len = fread(content, 1, size, fd);
fclose(fd);
#endif
if (len < 0) {
xmlFree(content);
return (NULL);
}
content[len] = 0;
return(content);
}
/**
* xmlCatalogNormalizePublic:
* @pubID: the public ID string
*
* Normalizes the Public Identifier
*
* Implements 6.2. Public Identifier Normalization
* from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* Returns the new string or NULL, the string must be deallocated
* by the caller.
*/
static xmlChar *
xmlCatalogNormalizePublic(const xmlChar *pubID)
{
int ok = 1;
int white;
const xmlChar *p;
xmlChar *ret;
xmlChar *q;
if (pubID == NULL)
return(NULL);
white = 1;
for (p = pubID;*p != 0 && ok;p++) {
if (!xmlIsBlank_ch(*p))
white = 0;
else if (*p == 0x20 && !white)
white = 1;
else
ok = 0;
}
if (ok && !white) /* is normalized */
return(NULL);
ret = xmlStrdup(pubID);
q = ret;
white = 0;
for (p = pubID;*p != 0;p++) {
if (xmlIsBlank_ch(*p)) {
if (q != ret)
white = 1;
} else {
if (white) {
*(q++) = 0x20;
white = 0;
}
*(q++) = *p;
}
}
*q = 0;
return(ret);
}
/************************************************************************
* *
* The XML Catalog parser *
* *
************************************************************************/
static xmlCatalogEntryPtr
xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
static void
xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
static xmlChar *
xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
const xmlChar *sysID);
static xmlChar *
xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
/**
* xmlGetXMLCatalogEntryType:
* @name: the name
*
* lookup the internal type associated to an XML catalog entry name
*
* Returns the type associated with that name
*/
static xmlCatalogEntryType
xmlGetXMLCatalogEntryType(const xmlChar *name) {
xmlCatalogEntryType type = XML_CATA_NONE;
if (xmlStrEqual(name, (const xmlChar *) "system"))
type = XML_CATA_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "public"))
type = XML_CATA_PUBLIC;
else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
type = XML_CATA_REWRITE_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
type = XML_CATA_DELEGATE_PUBLIC;
else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
type = XML_CATA_DELEGATE_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "uri"))
type = XML_CATA_URI;
else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
type = XML_CATA_REWRITE_URI;
else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
type = XML_CATA_DELEGATE_URI;
else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
type = XML_CATA_NEXT_CATALOG;
else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
type = XML_CATA_CATALOG;
return(type);
}
/**
* xmlParseXMLCatalogOneNode:
* @cur: the XML node
* @type: the type of Catalog entry
* @name: the name of the node
* @attrName: the attribute holding the value
* @uriAttrName: the attribute holding the URI-Reference
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @cgroup: the group which includes this node
*
* Finishes the examination of an XML tree node of a catalog and build
* a Catalog entry from it.
*
* Returns the new Catalog entry node or NULL in case of error.
*/
static xmlCatalogEntryPtr
xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
const xmlChar *name, const xmlChar *attrName,
const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr cgroup) {
int ok = 1;
xmlChar *uriValue;
xmlChar *nameValue = NULL;
xmlChar *base = NULL;
xmlChar *URL = NULL;
xmlCatalogEntryPtr ret = NULL;
if (attrName != NULL) {
nameValue = xmlGetProp(cur, attrName);
if (nameValue == NULL) {
xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
"%s entry lacks '%s'\n", name, attrName, NULL);
ok = 0;
}
}
uriValue = xmlGetProp(cur, uriAttrName);
if (uriValue == NULL) {
xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
"%s entry lacks '%s'\n", name, uriAttrName, NULL);
ok = 0;
}
if (!ok) {
if (nameValue != NULL)
xmlFree(nameValue);
if (uriValue != NULL)
xmlFree(uriValue);
return(NULL);
}
base = xmlNodeGetBase(cur->doc, cur);
URL = xmlBuildURI(uriValue, base);
if (URL != NULL) {
if (xmlDebugCatalogs > 1) {
if (nameValue != NULL)
xmlGenericError(xmlGenericErrorContext,
"Found %s: '%s' '%s'\n", name, nameValue, URL);
else
xmlGenericError(xmlGenericErrorContext,
"Found %s: '%s'\n", name, URL);
}
ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
} else {
xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
"%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
}
if (nameValue != NULL)
xmlFree(nameValue);
if (uriValue != NULL)
xmlFree(uriValue);
if (base != NULL)
xmlFree(base);
if (URL != NULL)
xmlFree(URL);
return(ret);
}
/**
* xmlParseXMLCatalogNode:
* @cur: the XML node
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @parent: the parent Catalog entry
* @cgroup: the group which includes this node
*
* Examines an XML tree node of a catalog and build
* a Catalog entry from it adding it to its parent. The examination can
* be recursive.
*/
static void
xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
{
xmlChar *base = NULL;
xmlCatalogEntryPtr entry = NULL;
if (cur == NULL)
return;
if (xmlStrEqual(cur->name, BAD_CAST "group")) {
xmlChar *prop;
xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
prop = xmlGetProp(cur, BAD_CAST "prefer");
if (prop != NULL) {
if (xmlStrEqual(prop, BAD_CAST "system")) {
prefer = XML_CATA_PREFER_SYSTEM;
} else if (xmlStrEqual(prop, BAD_CAST "public")) {
prefer = XML_CATA_PREFER_PUBLIC;
} else {
xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
"Invalid value for prefer: '%s'\n",
prop, NULL, NULL);
}
xmlFree(prop);
pref = prefer;
}
prop = xmlGetProp(cur, BAD_CAST "id");
base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
xmlFree(prop);
} else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
BAD_CAST "rewritePrefix", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
BAD_CAST "catalog", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
BAD_CAST "catalog", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
BAD_CAST "uri", BAD_CAST "name",
BAD_CAST "uri", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
BAD_CAST "rewritePrefix", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
BAD_CAST "delegateURI", BAD_CAST "uriStartString",
BAD_CAST "catalog", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
BAD_CAST "nextCatalog", NULL,
BAD_CAST "catalog", prefer, cgroup);
}
if (entry != NULL) {
if (parent != NULL) {
entry->parent = parent;
if (parent->children == NULL)
parent->children = entry;
else {
xmlCatalogEntryPtr prev;
prev = parent->children;
while (prev->next != NULL)
prev = prev->next;
prev->next = entry;
}
}
if (entry->type == XML_CATA_GROUP) {
/*
* Recurse to propagate prefer to the subtree
* (xml:base handling is automated)
*/
xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
}
}
if (base != NULL)
xmlFree(base);
}
/**
* xmlParseXMLCatalogNodeList:
* @cur: the XML node list of siblings
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @parent: the parent Catalog entry
* @cgroup: the group which includes this list
*
* Examines a list of XML sibling nodes of a catalog and build
* a list of Catalog entry from it adding it to the parent.
* The examination will recurse to examine node subtrees.
*/
static void
xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
while (cur != NULL) {
if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
}
cur = cur->next;
}
/* TODO: sort the list according to REWRITE lengths and prefer value */
}
/**
* xmlParseXMLCatalogFile:
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @filename: the filename for the catalog
*
* Parses the catalog file to extract the XML tree and then analyze the
* tree to build a list of Catalog entries corresponding to this catalog
*
* Returns the resulting Catalog entries list
*/
static xmlCatalogEntryPtr
xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
xmlDocPtr doc;
xmlNodePtr cur;
xmlChar *prop;
xmlCatalogEntryPtr parent = NULL;
if (filename == NULL)
return(NULL);
doc = xmlParseCatalogFile((const char *) filename);
if (doc == NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Failed to parse catalog %s\n", filename);
return(NULL);
}
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"%d Parsing catalog %s\n", xmlGetThreadId(), filename);
cur = xmlDocGetRootElement(doc);
if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
(cur->ns != NULL) && (cur->ns->href != NULL) &&
(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
(const xmlChar *)filename, NULL, prefer, NULL);
if (parent == NULL) {
xmlFreeDoc(doc);
return(NULL);
}
prop = xmlGetProp(cur, BAD_CAST "prefer");
if (prop != NULL) {
if (xmlStrEqual(prop, BAD_CAST "system")) {
prefer = XML_CATA_PREFER_SYSTEM;
} else if (xmlStrEqual(prop, BAD_CAST "public")) {
prefer = XML_CATA_PREFER_PUBLIC;
} else {
xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
"Invalid value for prefer: '%s'\n",
prop, NULL, NULL);
}
xmlFree(prop);
}
cur = cur->children;
xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
} else {
xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
"File %s is not an XML Catalog\n",
filename, NULL, NULL);
xmlFreeDoc(doc);
return(NULL);
}
xmlFreeDoc(doc);
return(parent);
}
/**
* xmlFetchXMLCatalogFile:
* @catal: an existing but incomplete catalog entry
*
* Fetch and parse the subcatalog referenced by an entry
*
* Returns 0 in case of success, -1 otherwise
*/
static int
xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
xmlCatalogEntryPtr doc;
if (catal == NULL)
return(-1);
if (catal->URL == NULL)
return(-1);
/*
* lock the whole catalog for modification
*/
xmlRMutexLock(xmlCatalogMutex);
if (catal->children != NULL) {
/* Okay someone else did it in the meantime */
xmlRMutexUnlock(xmlCatalogMutex);
return(0);
}
if (xmlCatalogXMLFiles != NULL) {
doc = (xmlCatalogEntryPtr)
xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
if (doc != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Found %s in file hash\n", catal->URL);
if (catal->type == XML_CATA_CATALOG)
catal->children = doc->children;
else
catal->children = doc;
catal->dealloc = 0;
xmlRMutexUnlock(xmlCatalogMutex);
return(0);
}
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"%s not found in file hash\n", catal->URL);
}
/*
* Fetch and parse. Note that xmlParseXMLCatalogFile does not
* use the existing catalog, there is no recursion allowed at
* that level.
*/
doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
if (doc == NULL) {
catal->type = XML_CATA_BROKEN_CATALOG;
xmlRMutexUnlock(xmlCatalogMutex);
return(-1);
}
if (catal->type == XML_CATA_CATALOG)
catal->children = doc->children;
else
catal->children = doc;
doc->dealloc = 1;
if (xmlCatalogXMLFiles == NULL)
xmlCatalogXMLFiles = xmlHashCreate(10);
if (xmlCatalogXMLFiles != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"%s added to file hash\n", catal->URL);
xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
}
xmlRMutexUnlock(xmlCatalogMutex);
return(0);
}
/************************************************************************
* *
* XML Catalog handling *
* *
************************************************************************/
/**
* xmlAddXMLCatalog:
* @catal: top of an XML catalog
* @type: the type of record to add to the catalog
* @orig: the system, public or prefix to match (or NULL)
* @replace: the replacement value for the match
*
* Add an entry in the XML catalog, it may overwrite existing but
* different entries.
*
* Returns 0 if successful, -1 otherwise
*/
static int
xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
const xmlChar *orig, const xmlChar *replace) {
xmlCatalogEntryPtr cur;
xmlCatalogEntryType typ;
int doregister = 0;
if ((catal == NULL) ||
((catal->type != XML_CATA_CATALOG) &&
(catal->type != XML_CATA_BROKEN_CATALOG)))
return(-1);
if (catal->children == NULL) {
xmlFetchXMLCatalogFile(catal);
}
if (catal->children == NULL)
doregister = 1;
typ = xmlGetXMLCatalogEntryType(type);
if (typ == XML_CATA_NONE) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Failed to add unknown element %s to catalog\n", type);
return(-1);
}
cur = catal->children;
/*
* Might be a simple "update in place"
*/
if (cur != NULL) {
while (cur != NULL) {
if ((orig != NULL) && (cur->type == typ) &&
(xmlStrEqual(orig, cur->name))) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Updating element %s to catalog\n", type);
if (cur->value != NULL)
xmlFree(cur->value);
if (cur->URL != NULL)
xmlFree(cur->URL);
cur->value = xmlStrdup(replace);
cur->URL = xmlStrdup(replace);
return(0);
}
if (cur->next == NULL)
break;
cur = cur->next;
}
}
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Adding element %s to catalog\n", type);
if (cur == NULL)
catal->children = xmlNewCatalogEntry(typ, orig, replace,
NULL, catal->prefer, NULL);
else
cur->next = xmlNewCatalogEntry(typ, orig, replace,
NULL, catal->prefer, NULL);
if (doregister) {
catal->type = XML_CATA_CATALOG;
cur = (xmlCatalogEntryPtr)xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
if (cur != NULL)
cur->children = catal->children;
}
return(0);
}
/**
* xmlDelXMLCatalog:
* @catal: top of an XML catalog
* @value: the value to remove from the catalog
*
* Remove entries in the XML catalog where the value or the URI
* is equal to @value
*
* Returns the number of entries removed if successful, -1 otherwise
*/
static int
xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
xmlCatalogEntryPtr cur;
int ret = 0;
if ((catal == NULL) ||
((catal->type != XML_CATA_CATALOG) &&
(catal->type != XML_CATA_BROKEN_CATALOG)))
return(-1);
if (value == NULL)
return(-1);
if (catal->children == NULL) {
xmlFetchXMLCatalogFile(catal);
}
/*
* Scan the children
*/
cur = catal->children;
while (cur != NULL) {
if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
(xmlStrEqual(value, cur->value))) {
if (xmlDebugCatalogs) {
if (cur->name != NULL)
xmlGenericError(xmlGenericErrorContext,
"Removing element %s from catalog\n", cur->name);
else
xmlGenericError(xmlGenericErrorContext,
"Removing element %s from catalog\n", cur->value);
}
cur->type = XML_CATA_REMOVED;
}
cur = cur->next;
}
return(ret);
}
/**
* xmlCatalogXMLResolve:
* @catal: a catalog list
* @pubID: the public ID string
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier for a
* list of catalog entries.
*
* Implements (or tries to) 7.1. External Identifier Resolution
* from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* Returns the URI of the resource or NULL if not found
*/
static xmlChar *
xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
const xmlChar *sysID) {
xmlChar *ret = NULL;
xmlCatalogEntryPtr cur;
int haveDelegate = 0;
int haveNext = 0;
/*
* protection against loops
*/
if (catal->depth > MAX_CATAL_DEPTH) {
xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
"Detected recursion in catalog %s\n",
catal->name, NULL, NULL);
return(NULL);
}
catal->depth++;
/*
* First tries steps 2/ 3/ 4/ if a system ID is provided.
*/
if (sysID != NULL) {
xmlCatalogEntryPtr rewrite = NULL;
int lenrewrite = 0, len;
cur = catal;
haveDelegate = 0;
while (cur != NULL) {
switch (cur->type) {
case XML_CATA_SYSTEM:
if (xmlStrEqual(sysID, cur->name)) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Found system match %s, using %s\n",
cur->name, cur->URL);
catal->depth--;
return(xmlStrdup(cur->URL));
}
break;
case XML_CATA_REWRITE_SYSTEM:
len = xmlStrlen(cur->name);
if ((len > lenrewrite) &&
(!xmlStrncmp(sysID, cur->name, len))) {
lenrewrite = len;
rewrite = cur;
}
break;
case XML_CATA_DELEGATE_SYSTEM:
if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
haveDelegate++;
break;
case XML_CATA_NEXT_CATALOG:
haveNext++;
break;
default:
break;
}
cur = cur->next;
}
if (rewrite != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Using rewriting rule %s\n", rewrite->name);
ret = xmlStrdup(rewrite->URL);
if (ret != NULL)
ret = xmlStrcat(ret, &sysID[lenrewrite]);
catal->depth--;
return(ret);
}
if (haveDelegate) {
const xmlChar *delegates[MAX_DELEGATE];
int nbList = 0, i;
/*
* Assume the entries have been sorted by decreasing substring
* matches when the list was produced.
*/
cur = catal;
while (cur != NULL) {
if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
(!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
for (i = 0;i < nbList;i++)
if (xmlStrEqual(cur->URL, delegates[i]))
break;
if (i < nbList) {
cur = cur->next;
continue;
}
if (nbList < MAX_DELEGATE)
delegates[nbList++] = cur->URL;
if (cur->children == NULL) {
xmlFetchXMLCatalogFile(cur);
}
if (cur->children != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Trying system delegate %s\n", cur->URL);
ret = xmlCatalogListXMLResolve(
cur->children, NULL, sysID);
if (ret != NULL) {
catal->depth--;
return(ret);
}
}
}
cur = cur->next;
}
/*
* Apply the cut algorithm explained in 4/
*/
catal->depth--;
return(XML_CATAL_BREAK);
}
}
/*
* Then tries 5/ 6/ if a public ID is provided
*/
if (pubID != NULL) {
cur = catal;
haveDelegate = 0;
while (cur != NULL) {
switch (cur->type) {
case XML_CATA_PUBLIC:
if (xmlStrEqual(pubID, cur->name)) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Found public match %s\n", cur->name);
catal->depth--;
return(xmlStrdup(cur->URL));
}
break;
case XML_CATA_DELEGATE_PUBLIC:
if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
(cur->prefer == XML_CATA_PREFER_PUBLIC))
haveDelegate++;
break;
case XML_CATA_NEXT_CATALOG:
if (sysID == NULL)
haveNext++;
break;
default:
break;
}
cur = cur->next;
}
if (haveDelegate) {
const xmlChar *delegates[MAX_DELEGATE];
int nbList = 0, i;
/*
* Assume the entries have been sorted by decreasing substring
* matches when the list was produced.
*/
cur = catal;
while (cur != NULL) {
if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
(cur->prefer == XML_CATA_PREFER_PUBLIC) &&
(!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
for (i = 0;i < nbList;i++)
if (xmlStrEqual(cur->URL, delegates[i]))
break;
if (i < nbList) {
cur = cur->next;
continue;
}
if (nbList < MAX_DELEGATE)
delegates[nbList++] = cur->URL;
if (cur->children == NULL) {
xmlFetchXMLCatalogFile(cur);
}
if (cur->children != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Trying public delegate %s\n", cur->URL);
ret = xmlCatalogListXMLResolve(
cur->children, pubID, NULL);
if (ret != NULL) {
catal->depth--;
return(ret);
}
}
}
cur = cur->next;
}
/*
* Apply the cut algorithm explained in 4/
*/
catal->depth--;
return(XML_CATAL_BREAK);
}
}
if (haveNext) {
cur = catal;
while (cur != NULL) {
if (cur->type == XML_CATA_NEXT_CATALOG) {
if (cur->children == NULL) {
xmlFetchXMLCatalogFile(cur);
}
if (cur->children != NULL) {
ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
if (ret != NULL) {
catal->depth--;
return(ret);
} else if (catal->depth > MAX_CATAL_DEPTH) {
return(NULL);
}
}
}
cur = cur->next;
}
}
catal->depth--;
return(NULL);
}
/**
* xmlCatalogXMLResolveURI:
* @catal: a catalog list
* @URI: the URI
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier for a
* list of catalog entries.
*
* Implements (or tries to) 7.2.2. URI Resolution
* from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* Returns the URI of the resource or NULL if not found
*/
static xmlChar *
xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
xmlChar *ret = NULL;
xmlCatalogEntryPtr cur;
int haveDelegate = 0;
int haveNext = 0;
xmlCatalogEntryPtr rewrite = NULL;
int lenrewrite = 0, len;
if (catal == NULL)
return(NULL);
if (URI == NULL)
return(NULL);
if (catal->depth > MAX_CATAL_DEPTH) {
xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
"Detected recursion in catalog %s\n",
catal->name, NULL, NULL);
return(NULL);
}
/*
* First tries steps 2/ 3/ 4/ if a system ID is provided.
*/
cur = catal;
haveDelegate = 0;
while (cur != NULL) {
switch (cur->type) {
case XML_CATA_URI:
if (xmlStrEqual(URI, cur->name)) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Found URI match %s\n", cur->name);
return(xmlStrdup(cur->URL));
}
break;
case XML_CATA_REWRITE_URI:
len = xmlStrlen(cur->name);
if ((len > lenrewrite) &&
(!xmlStrncmp(URI, cur->name, len))) {
lenrewrite = len;
rewrite = cur;
}
break;
case XML_CATA_DELEGATE_URI:
if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
haveDelegate++;
break;
case XML_CATA_NEXT_CATALOG:
haveNext++;
break;
default:
break;
}
cur = cur->next;
}
if (rewrite != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Using rewriting rule %s\n", rewrite->name);
ret = xmlStrdup(rewrite->URL);
if (ret != NULL)
ret = xmlStrcat(ret, &URI[lenrewrite]);
return(ret);
}
if (haveDelegate) {
const xmlChar *delegates[MAX_DELEGATE];
int nbList = 0, i;
/*
* Assume the entries have been sorted by decreasing substring
* matches when the list was produced.
*/
cur = catal;
while (cur != NULL) {
if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
(cur->type == XML_CATA_DELEGATE_URI)) &&
(!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
for (i = 0;i < nbList;i++)
if (xmlStrEqual(cur->URL, delegates[i]))
break;
if (i < nbList) {
cur = cur->next;
continue;
}
if (nbList < MAX_DELEGATE)
delegates[nbList++] = cur->URL;
if (cur->children == NULL) {
xmlFetchXMLCatalogFile(cur);
}
if (cur->children != NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Trying URI delegate %s\n", cur->URL);
ret = xmlCatalogListXMLResolveURI(
cur->children, URI);
if (ret != NULL)
return(ret);
}
}
cur = cur->next;
}
/*
* Apply the cut algorithm explained in 4/
*/
return(XML_CATAL_BREAK);
}
if (haveNext) {
cur = catal;
while (cur != NULL) {
if (cur->type == XML_CATA_NEXT_CATALOG) {
if (cur->children == NULL) {
xmlFetchXMLCatalogFile(cur);
}
if (cur->children != NULL) {
ret = xmlCatalogListXMLResolveURI(cur->children, URI);
if (ret != NULL)
return(ret);
}
}
cur = cur->next;
}
}
return(NULL);
}
/**
* xmlCatalogListXMLResolve:
* @catal: a catalog list
* @pubID: the public ID string
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier for a
* list of catalogs
*
* Implements (or tries to) 7.1. External Identifier Resolution
* from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* Returns the URI of the resource or NULL if not found
*/
static xmlChar *
xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
const xmlChar *sysID) {
xmlChar *ret = NULL;
xmlChar *urnID = NULL;
xmlChar *normid;
if (catal == NULL)
return(NULL);
if ((pubID == NULL) && (sysID == NULL))
return(NULL);
normid = xmlCatalogNormalizePublic(pubID);
if (normid != NULL)
pubID = (*normid != 0 ? normid : NULL);
if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
urnID = xmlCatalogUnWrapURN(pubID);
if (xmlDebugCatalogs) {
if (urnID == NULL)
xmlGenericError(xmlGenericErrorContext,
"Public URN ID %s expanded to NULL\n", pubID);
else
xmlGenericError(xmlGenericErrorContext,
"Public URN ID expanded to %s\n", urnID);
}
ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
if (urnID != NULL)
xmlFree(urnID);
if (normid != NULL)
xmlFree(normid);
return(ret);
}
if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
urnID = xmlCatalogUnWrapURN(sysID);
if (xmlDebugCatalogs) {
if (urnID == NULL)
xmlGenericError(xmlGenericErrorContext,
"System URN ID %s expanded to NULL\n", sysID);
else
xmlGenericError(xmlGenericErrorContext,
"System URN ID expanded to %s\n", urnID);
}
if (pubID == NULL)
ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
else if (xmlStrEqual(pubID, urnID))
ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
else {
ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
}
if (urnID != NULL)
xmlFree(urnID);
if (normid != NULL)
xmlFree(normid);
return(ret);
}
while (catal != NULL) {
if (catal->type == XML_CATA_CATALOG) {
if (catal->children == NULL) {
xmlFetchXMLCatalogFile(catal);
}
if (catal->children != NULL) {
ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
if (ret != NULL) {
break;
} else if ((catal->children != NULL) &&
(catal->children->depth > MAX_CATAL_DEPTH)) {
ret = NULL;
break;
}
}
}
catal = catal->next;
}
if (normid != NULL)
xmlFree(normid);
return(ret);
}
/**
* xmlCatalogListXMLResolveURI:
* @catal: a catalog list
* @URI: the URI
*
* Do a complete resolution lookup of an URI for a list of catalogs
*
* Implements (or tries to) 7.2. URI Resolution
* from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* Returns the URI of the resource or NULL if not found
*/
static xmlChar *
xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
xmlChar *ret = NULL;
xmlChar *urnID = NULL;
if (catal == NULL)
return(NULL);
if (URI == NULL)
return(NULL);
if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
urnID = xmlCatalogUnWrapURN(URI);
if (xmlDebugCatalogs) {
if (urnID == NULL)
xmlGenericError(xmlGenericErrorContext,
"URN ID %s expanded to NULL\n", URI);
else
xmlGenericError(xmlGenericErrorContext,
"URN ID expanded to %s\n", urnID);
}
ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
if (urnID != NULL)
xmlFree(urnID);
return(ret);
}
while (catal != NULL) {
if (catal->type == XML_CATA_CATALOG) {
if (catal->children == NULL) {
xmlFetchXMLCatalogFile(catal);
}
if (catal->children != NULL) {
ret = xmlCatalogXMLResolveURI(catal->children, URI);
if (ret != NULL)
return(ret);
}
}
catal = catal->next;
}
return(ret);
}
/************************************************************************
* *
* The SGML Catalog parser *
* *
************************************************************************/
#define RAW *cur
#define NEXT cur++;
#define SKIP(x) cur += x;
#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
/**
* xmlParseSGMLCatalogComment:
* @cur: the current character
*
* Skip a comment in an SGML catalog
*
* Returns new current character
*/
static const xmlChar *
xmlParseSGMLCatalogComment(const xmlChar *cur) {
if ((cur[0] != '-') || (cur[1] != '-'))
return(cur);
SKIP(2);
while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
NEXT;
if (cur[0] == 0) {
return(NULL);
}
return(cur + 2);
}
/**
* xmlParseSGMLCatalogPubid:
* @cur: the current character
* @id: the return location
*
* Parse an SGML catalog ID
*
* Returns new current character and store the value in @id
*/
static const xmlChar *
xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
xmlChar *buf = NULL, *tmp;
int len = 0;
int size = 50;
xmlChar stop;
int count = 0;
*id = NULL;
if (RAW == '"') {
NEXT;
stop = '"';
} else if (RAW == '\'') {
NEXT;
stop = '\'';
} else {
stop = ' ';
}
buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
if (buf == NULL) {
xmlCatalogErrMemory("allocating public ID");
return(NULL);
}
while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
if ((*cur == stop) && (stop != ' '))
break;
if ((stop == ' ') && (IS_BLANK_CH(*cur)))
break;
if (len + 1 >= size) {
size *= 2;
tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
if (tmp == NULL) {
xmlCatalogErrMemory("allocating public ID");
xmlFree(buf);
return(NULL);
}
buf = tmp;
}
buf[len++] = *cur;
count++;
NEXT;
}
buf[len] = 0;
if (stop == ' ') {
if (!IS_BLANK_CH(*cur)) {
xmlFree(buf);
return(NULL);
}
} else {
if (*cur != stop) {
xmlFree(buf);
return(NULL);
}
NEXT;
}
*id = buf;
return(cur);
}
/**
* xmlParseSGMLCatalogName:
* @cur: the current character
* @name: the return location
*
* Parse an SGML catalog name
*
* Returns new current character and store the value in @name
*/
static const xmlChar *
xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
xmlChar buf[XML_MAX_NAMELEN + 5];
int len = 0;
int c;
*name = NULL;
/*
* Handler for more complex cases
*/
c = *cur;
if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
return(NULL);
}
while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
(c == '.') || (c == '-') ||
(c == '_') || (c == ':'))) {
buf[len++] = c;
cur++;
c = *cur;
if (len >= XML_MAX_NAMELEN)
return(NULL);
}
*name = xmlStrndup(buf, len);
return(cur);
}
/**
* xmlGetSGMLCatalogEntryType:
* @name: the entry name
*
* Get the Catalog entry type for a given SGML Catalog name
*
* Returns Catalog entry type
*/
static xmlCatalogEntryType
xmlGetSGMLCatalogEntryType(const xmlChar *name) {
xmlCatalogEntryType type = XML_CATA_NONE;
if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
type = SGML_CATA_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
type = SGML_CATA_PUBLIC;
else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
type = SGML_CATA_DELEGATE;
else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
type = SGML_CATA_ENTITY;
else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
type = SGML_CATA_DOCTYPE;
else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
type = SGML_CATA_LINKTYPE;
else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
type = SGML_CATA_NOTATION;
else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
type = SGML_CATA_SGMLDECL;
else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
type = SGML_CATA_DOCUMENT;
else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
type = SGML_CATA_CATALOG;
else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
type = SGML_CATA_BASE;
return(type);
}
/**
* xmlParseSGMLCatalog:
* @catal: the SGML Catalog
* @value: the content of the SGML Catalog serialization
* @file: the filepath for the catalog
* @super: should this be handled as a Super Catalog in which case
* parsing is not recursive
*
* Parse an SGML catalog content and fill up the @catal hash table with
* the new entries found.
*
* Returns 0 in case of success, -1 in case of error.
*/
static int
xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
const char *file, int super) {
const xmlChar *cur = value;
xmlChar *base = NULL;
int res;
if ((cur == NULL) || (file == NULL))
return(-1);
base = xmlStrdup((const xmlChar *) file);
while ((cur != NULL) && (cur[0] != 0)) {
SKIP_BLANKS;
if (cur[0] == 0)
break;
if ((cur[0] == '-') && (cur[1] == '-')) {
cur = xmlParseSGMLCatalogComment(cur);
if (cur == NULL) {
/* error */
break;
}
} else {
xmlChar *sysid = NULL;
xmlChar *name = NULL;
xmlCatalogEntryType type = XML_CATA_NONE;
cur = xmlParseSGMLCatalogName(cur, &name);
if (name == NULL) {
/* error */
break;
}
if (!IS_BLANK_CH(*cur)) {
/* error */
break;
}
SKIP_BLANKS;
if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
type = SGML_CATA_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
type = SGML_CATA_PUBLIC;
else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
type = SGML_CATA_DELEGATE;
else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
type = SGML_CATA_ENTITY;
else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
type = SGML_CATA_DOCTYPE;
else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
type = SGML_CATA_LINKTYPE;
else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
type = SGML_CATA_NOTATION;
else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
type = SGML_CATA_SGMLDECL;
else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
type = SGML_CATA_DOCUMENT;
else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
type = SGML_CATA_CATALOG;
else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
type = SGML_CATA_BASE;
else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
xmlFree(name);
cur = xmlParseSGMLCatalogName(cur, &name);
if (name == NULL) {
/* error */
break;
}
xmlFree(name);
continue;
}
xmlFree(name);
name = NULL;
switch(type) {
case SGML_CATA_ENTITY:
if (*cur == '%')
type = SGML_CATA_PENTITY;
/* Falls through. */
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
cur = xmlParseSGMLCatalogName(cur, &name);
if (cur == NULL) {
/* error */
break;
}
if (!IS_BLANK_CH(*cur)) {
/* error */
break;
}
SKIP_BLANKS;
cur = xmlParseSGMLCatalogPubid(cur, &sysid);
if (cur == NULL) {
/* error */
break;
}
break;
case SGML_CATA_PUBLIC:
case SGML_CATA_SYSTEM:
case SGML_CATA_DELEGATE:
cur = xmlParseSGMLCatalogPubid(cur, &name);
if (cur == NULL) {
/* error */
break;
}
if (type != SGML_CATA_SYSTEM) {
xmlChar *normid;
normid = xmlCatalogNormalizePublic(name);
if (normid != NULL) {
if (name != NULL)
xmlFree(name);
if (*normid != 0)
name = normid;
else {
xmlFree(normid);
name = NULL;
}
}
}
if (!IS_BLANK_CH(*cur)) {
/* error */
break;
}
SKIP_BLANKS;
cur = xmlParseSGMLCatalogPubid(cur, &sysid);
if (cur == NULL) {
/* error */
break;
}
break;
case SGML_CATA_BASE:
case SGML_CATA_CATALOG:
case SGML_CATA_DOCUMENT:
case SGML_CATA_SGMLDECL:
cur = xmlParseSGMLCatalogPubid(cur, &sysid);
if (cur == NULL) {
/* error */
break;
}
break;
default:
break;
}
if (cur == NULL) {
if (name != NULL)
xmlFree(name);
if (sysid != NULL)
xmlFree(sysid);
break;
} else if (type == SGML_CATA_BASE) {
if (base != NULL)
xmlFree(base);
base = xmlStrdup(sysid);
} else if ((type == SGML_CATA_PUBLIC) ||
(type == SGML_CATA_SYSTEM)) {
xmlChar *filename;
filename = xmlBuildURI(sysid, base);
if (filename != NULL) {
xmlCatalogEntryPtr entry;
entry = xmlNewCatalogEntry(type, name, filename,
NULL, XML_CATA_PREFER_NONE, NULL);
res = xmlHashAddEntry(catal->sgml, name, entry);
if (res < 0) {
xmlFreeCatalogEntry(entry, NULL);
}
xmlFree(filename);
}
} else if (type == SGML_CATA_CATALOG) {
if (super) {
xmlCatalogEntryPtr entry;
entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
XML_CATA_PREFER_NONE, NULL);
res = xmlHashAddEntry(catal->sgml, sysid, entry);
if (res < 0) {
xmlFreeCatalogEntry(entry, NULL);
}
} else {
xmlChar *filename;
filename = xmlBuildURI(sysid, base);
if (filename != NULL) {
xmlExpandCatalog(catal, (const char *)filename);
xmlFree(filename);
}
}
}
/*
* drop anything else we won't handle it
*/
if (name != NULL)
xmlFree(name);
if (sysid != NULL)
xmlFree(sysid);
}
}
if (base != NULL)
xmlFree(base);
if (cur == NULL)
return(-1);
return(0);
}
/************************************************************************
* *
* SGML Catalog handling *
* *
************************************************************************/
/**
* xmlCatalogGetSGMLPublic:
* @catal: an SGML catalog hash
* @pubID: the public ID string
*
* Try to lookup the catalog local reference associated to a public ID
*
* Returns the local resource if found or NULL otherwise.
*/
static const xmlChar *
xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
xmlCatalogEntryPtr entry;
xmlChar *normid;
if (catal == NULL)
return(NULL);
normid = xmlCatalogNormalizePublic(pubID);
if (normid != NULL)
pubID = (*normid != 0 ? normid : NULL);
entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
if (entry == NULL) {
if (normid != NULL)
xmlFree(normid);
return(NULL);
}
if (entry->type == SGML_CATA_PUBLIC) {
if (normid != NULL)
xmlFree(normid);
return(entry->URL);
}
if (normid != NULL)
xmlFree(normid);
return(NULL);
}
/**
* xmlCatalogGetSGMLSystem:
* @catal: an SGML catalog hash
* @sysID: the system ID string
*
* Try to lookup the catalog local reference for a system ID
*
* Returns the local resource if found or NULL otherwise.
*/
static const xmlChar *
xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
xmlCatalogEntryPtr entry;
if (catal == NULL)
return(NULL);
entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
if (entry == NULL)
return(NULL);
if (entry->type == SGML_CATA_SYSTEM)
return(entry->URL);
return(NULL);
}
/**
* xmlCatalogSGMLResolve:
* @catal: the SGML catalog
* @pubID: the public ID string
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier
*
* Returns the URI of the resource or NULL if not found
*/
static const xmlChar *
xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
const xmlChar *sysID) {
const xmlChar *ret = NULL;
if (catal->sgml == NULL)
return(NULL);
if (pubID != NULL)
ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
if (ret != NULL)
return(ret);
if (sysID != NULL)
ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
if (ret != NULL)
return(ret);
return(NULL);
}
/************************************************************************
* *
* Specific Public interfaces *
* *
************************************************************************/
/**
* xmlLoadSGMLSuperCatalog:
* @filename: a file path
*
* Load an SGML super catalog. It won't expand CATALOG or DELEGATE
* references. This is only needed for manipulating SGML Super Catalogs
* like adding and removing CATALOG or DELEGATE entries.
*
* Returns the catalog parsed or NULL in case of error
*/
xmlCatalogPtr
xmlLoadSGMLSuperCatalog(const char *filename)
{
xmlChar *content;
xmlCatalogPtr catal;
int ret;
content = xmlLoadFileContent(filename);
if (content == NULL)
return(NULL);
catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
if (catal == NULL) {
xmlFree(content);
return(NULL);
}
ret = xmlParseSGMLCatalog(catal, content, filename, 1);
xmlFree(content);
if (ret < 0) {
xmlFreeCatalog(catal);
return(NULL);
}
return (catal);
}
/**
* xmlLoadACatalog:
* @filename: a file path
*
* Load the catalog and build the associated data structures.
* This can be either an XML Catalog or an SGML Catalog
* It will recurse in SGML CATALOG entries. On the other hand XML
* Catalogs are not handled recursively.
*
* Returns the catalog parsed or NULL in case of error
*/
xmlCatalogPtr
xmlLoadACatalog(const char *filename)
{
xmlChar *content;
xmlChar *first;
xmlCatalogPtr catal;
int ret;
content = xmlLoadFileContent(filename);
if (content == NULL)
return(NULL);
first = content;
while ((*first != 0) && (*first != '-') && (*first != '<') &&
(!(((*first >= 'A') && (*first <= 'Z')) ||
((*first >= 'a') && (*first <= 'z')))))
first++;
if (*first != '<') {
catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
if (catal == NULL) {
xmlFree(content);
return(NULL);
}
ret = xmlParseSGMLCatalog(catal, content, filename, 0);
if (ret < 0) {
xmlFreeCatalog(catal);
xmlFree(content);
return(NULL);
}
} else {
catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
if (catal == NULL) {
xmlFree(content);
return(NULL);
}
catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
}
xmlFree(content);
return (catal);
}
/**
* xmlExpandCatalog:
* @catal: a catalog
* @filename: a file path
*
* Load the catalog and expand the existing catal structure.
* This can be either an XML Catalog or an SGML Catalog
*
* Returns 0 in case of success, -1 in case of error
*/
static int
xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
{
int ret;
if ((catal == NULL) || (filename == NULL))
return(-1);
if (catal->type == XML_SGML_CATALOG_TYPE) {
xmlChar *content;
content = xmlLoadFileContent(filename);
if (content == NULL)
return(-1);
ret = xmlParseSGMLCatalog(catal, content, filename, 0);
if (ret < 0) {
xmlFree(content);
return(-1);
}
xmlFree(content);
} else {
xmlCatalogEntryPtr tmp, cur;
tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
cur = catal->xml;
if (cur == NULL) {
catal->xml = tmp;
} else {
while (cur->next != NULL) cur = cur->next;
cur->next = tmp;
}
}
return (0);
}
/**
* xmlACatalogResolveSystem:
* @catal: a Catalog
* @sysID: the system ID string
*
* Try to lookup the catalog resource for a system ID
*
* Returns the resource if found or NULL otherwise, the value returned
* must be freed by the caller.
*/
xmlChar *
xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
xmlChar *ret = NULL;
if ((sysID == NULL) || (catal == NULL))
return(NULL);
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Resolve sysID %s\n", sysID);
if (catal->type == XML_XML_CATALOG_TYPE) {
ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
if (ret == XML_CATAL_BREAK)
ret = NULL;
} else {
const xmlChar *sgml;
sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
if (sgml != NULL)
ret = xmlStrdup(sgml);
}
return(ret);
}
/**
* xmlACatalogResolvePublic:
* @catal: a Catalog
* @pubID: the public ID string
*
* Try to lookup the catalog local reference associated to a public ID in that catalog
*
* Returns the local resource if found or NULL otherwise, the value returned
* must be freed by the caller.
*/
xmlChar *
xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
xmlChar *ret = NULL;
if ((pubID == NULL) || (catal == NULL))
return(NULL);
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Resolve pubID %s\n", pubID);
if (catal->type == XML_XML_CATALOG_TYPE) {
ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
if (ret == XML_CATAL_BREAK)
ret = NULL;
} else {
const xmlChar *sgml;
sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
if (sgml != NULL)
ret = xmlStrdup(sgml);
}
return(ret);
}
/**
* xmlACatalogResolve:
* @catal: a Catalog
* @pubID: the public ID string
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier
*
* Returns the URI of the resource or NULL if not found, it must be freed
* by the caller.
*/
xmlChar *
xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
const xmlChar * sysID)
{
xmlChar *ret = NULL;
if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
return (NULL);
if (xmlDebugCatalogs) {
if ((pubID != NULL) && (sysID != NULL)) {
xmlGenericError(xmlGenericErrorContext,
"Resolve: pubID %s sysID %s\n", pubID, sysID);
} else if (pubID != NULL) {
xmlGenericError(xmlGenericErrorContext,
"Resolve: pubID %s\n", pubID);
} else {
xmlGenericError(xmlGenericErrorContext,
"Resolve: sysID %s\n", sysID);
}
}
if (catal->type == XML_XML_CATALOG_TYPE) {
ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
if (ret == XML_CATAL_BREAK)
ret = NULL;
} else {
const xmlChar *sgml;
sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
if (sgml != NULL)
ret = xmlStrdup(sgml);
}
return (ret);
}
/**
* xmlACatalogResolveURI:
* @catal: a Catalog
* @URI: the URI
*
* Do a complete resolution lookup of an URI
*
* Returns the URI of the resource or NULL if not found, it must be freed
* by the caller.
*/
xmlChar *
xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
xmlChar *ret = NULL;
if ((URI == NULL) || (catal == NULL))
return(NULL);
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Resolve URI %s\n", URI);
if (catal->type == XML_XML_CATALOG_TYPE) {
ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
if (ret == XML_CATAL_BREAK)
ret = NULL;
} else {
const xmlChar *sgml;
sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
if (sgml != NULL)
ret = xmlStrdup(sgml);
}
return(ret);
}
#ifdef LIBXML_OUTPUT_ENABLED
/**
* xmlACatalogDump:
* @catal: a Catalog
* @out: the file.
*
* Dump the given catalog to the given file.
*/
void
xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
if ((out == NULL) || (catal == NULL))
return;
if (catal->type == XML_XML_CATALOG_TYPE) {
xmlDumpXMLCatalog(out, catal->xml);
} else {
xmlHashScan(catal->sgml, xmlCatalogDumpEntry, out);
}
}
#endif /* LIBXML_OUTPUT_ENABLED */
/**
* xmlACatalogAdd:
* @catal: a Catalog
* @type: the type of record to add to the catalog
* @orig: the system, public or prefix to match
* @replace: the replacement value for the match
*
* Add an entry in the catalog, it may overwrite existing but
* different entries.
*
* Returns 0 if successful, -1 otherwise
*/
int
xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
const xmlChar * orig, const xmlChar * replace)
{
int res = -1;
if (catal == NULL)
return(-1);
if (catal->type == XML_XML_CATALOG_TYPE) {
res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
} else {
xmlCatalogEntryType cattype;
cattype = xmlGetSGMLCatalogEntryType(type);
if (cattype != XML_CATA_NONE) {
xmlCatalogEntryPtr entry;
entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
XML_CATA_PREFER_NONE, NULL);
if (catal->sgml == NULL)
catal->sgml = xmlHashCreate(10);
res = xmlHashAddEntry(catal->sgml, orig, entry);
}
}
return (res);
}
/**
* xmlACatalogRemove:
* @catal: a Catalog
* @value: the value to remove
*
* Remove an entry from the catalog
*
* Returns the number of entries removed if successful, -1 otherwise
*/
int
xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
int res = -1;
if ((catal == NULL) || (value == NULL))
return(-1);
if (catal->type == XML_XML_CATALOG_TYPE) {
res = xmlDelXMLCatalog(catal->xml, value);
} else {
res = xmlHashRemoveEntry(catal->sgml, value, xmlFreeCatalogEntry);
if (res == 0)
res = 1;
}
return(res);
}
/**
* xmlNewCatalog:
* @sgml: should this create an SGML catalog
*
* create a new Catalog.
*
* Returns the xmlCatalogPtr or NULL in case of error
*/
xmlCatalogPtr
xmlNewCatalog(int sgml) {
xmlCatalogPtr catal = NULL;
if (sgml) {
catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
xmlCatalogDefaultPrefer);
if ((catal != NULL) && (catal->sgml == NULL))
catal->sgml = xmlHashCreate(10);
} else
catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
xmlCatalogDefaultPrefer);
return(catal);
}
/**
* xmlCatalogIsEmpty:
* @catal: should this create an SGML catalog
*
* Check is a catalog is empty
*
* Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
*/
int
xmlCatalogIsEmpty(xmlCatalogPtr catal) {
if (catal == NULL)
return(-1);
if (catal->type == XML_XML_CATALOG_TYPE) {
if (catal->xml == NULL)
return(1);
if ((catal->xml->type != XML_CATA_CATALOG) &&
(catal->xml->type != XML_CATA_BROKEN_CATALOG))
return(-1);
if (catal->xml->children == NULL)
return(1);
return(0);
} else {
int res;
if (catal->sgml == NULL)
return(1);
res = xmlHashSize(catal->sgml);
if (res == 0)
return(1);
if (res < 0)
return(-1);
}
return(0);
}
/************************************************************************
* *
* Public interfaces manipulating the global shared default catalog *
* *
************************************************************************/
/**
* xmlInitializeCatalogData:
*
* Do the catalog initialization only of global data, doesn't try to load
* any catalog actually.
* this function is not thread safe, catalog initialization should
* preferably be done once at startup
*/
static void
xmlInitializeCatalogData(void) {
if (xmlCatalogInitialized != 0)
return;
if (getenv("XML_DEBUG_CATALOG"))
xmlDebugCatalogs = 1;
xmlCatalogMutex = xmlNewRMutex();
xmlCatalogInitialized = 1;
}
/**
* xmlInitializeCatalog:
*
* Do the catalog initialization.
* this function is not thread safe, catalog initialization should
* preferably be done once at startup
*/
void
xmlInitializeCatalog(void) {
if (xmlCatalogInitialized != 0)
return;
xmlInitializeCatalogData();
xmlRMutexLock(xmlCatalogMutex);
if (getenv("XML_DEBUG_CATALOG"))
xmlDebugCatalogs = 1;
if (xmlDefaultCatalog == NULL) {
const char *catalogs;
char *path;
const char *cur, *paths;
xmlCatalogPtr catal;
xmlCatalogEntryPtr *nextent;
catalogs = (const char *) getenv("XML_CATALOG_FILES");
if (catalogs == NULL)
#if defined(_WIN32) && defined(_MSC_VER)
{
void* hmodule;
hmodule = GetModuleHandleA("libxml2.dll");
if (hmodule == NULL)
hmodule = GetModuleHandleA(NULL);
if (hmodule != NULL) {
char buf[256];
unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
if (len != 0) {
char* p = &(buf[len]);
while (*p != '\\' && p > buf)
p--;
if (p != buf) {
xmlChar* uri;
strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
uri = xmlCanonicPath((const xmlChar*)buf);
if (uri != NULL) {
strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
xmlFree(uri);
}
}
}
}
catalogs = XML_XML_DEFAULT_CATALOG;
}
#else
catalogs = XML_XML_DEFAULT_CATALOG;
#endif
catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
xmlCatalogDefaultPrefer);
if (catal != NULL) {
/* the XML_CATALOG_FILES envvar is allowed to contain a
space-separated list of entries. */
cur = catalogs;
nextent = &catal->xml;
while (*cur != '\0') {
while (xmlIsBlank_ch(*cur))
cur++;
if (*cur != 0) {
paths = cur;
while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
cur++;
path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
if (path != NULL) {
*nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
if (*nextent != NULL)
nextent = &((*nextent)->next);
xmlFree(path);
}
}
}
xmlDefaultCatalog = catal;
}
}
xmlRMutexUnlock(xmlCatalogMutex);
}
/**
* xmlLoadCatalog:
* @filename: a file path
*
* Load the catalog and makes its definitions effective for the default
* external entity loader. It will recurse in SGML CATALOG entries.
* this function is not thread safe, catalog initialization should
* preferably be done once at startup
*
* Returns 0 in case of success -1 in case of error
*/
int
xmlLoadCatalog(const char *filename)
{
int ret;
xmlCatalogPtr catal;
if (!xmlCatalogInitialized)
xmlInitializeCatalogData();
xmlRMutexLock(xmlCatalogMutex);
if (xmlDefaultCatalog == NULL) {
catal = xmlLoadACatalog(filename);
if (catal == NULL) {
xmlRMutexUnlock(xmlCatalogMutex);
return(-1);
}
xmlDefaultCatalog = catal;
xmlRMutexUnlock(xmlCatalogMutex);
return(0);
}
ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
xmlRMutexUnlock(xmlCatalogMutex);
return(ret);
}
/**
* xmlLoadCatalogs:
* @pathss: a list of directories separated by a colon or a space.
*
* Load the catalogs and makes their definitions effective for the default
* external entity loader.
* this function is not thread safe, catalog initialization should
* preferably be done once at startup
*/
void
xmlLoadCatalogs(const char *pathss) {
const char *cur;
const char *paths;
xmlChar *path;
#ifdef _WIN32
int i, iLen;
#endif
if (pathss == NULL)
return;
cur = pathss;
while (*cur != 0) {
while (xmlIsBlank_ch(*cur)) cur++;
if (*cur != 0) {
paths = cur;
while ((*cur != 0) && (*cur != PATH_SEPARATOR) && (!xmlIsBlank_ch(*cur)))
cur++;
path = xmlStrndup((const xmlChar *)paths, cur - paths);
#ifdef _WIN32
iLen = strlen((const char*)path);
for(i = 0; i < iLen; i++) {
if(path[i] == '\\') {
path[i] = '/';
}
}
#endif
if (path != NULL) {
xmlLoadCatalog((const char *) path);
xmlFree(path);
}
}
while (*cur == PATH_SEPARATOR)
cur++;
}
}
/**
* xmlCatalogCleanup:
*
* Free up all the memory associated with catalogs
*/
void
xmlCatalogCleanup(void) {
if (xmlCatalogInitialized == 0)
return;
xmlRMutexLock(xmlCatalogMutex);
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Catalogs cleanup\n");
if (xmlCatalogXMLFiles != NULL)
xmlHashFree(xmlCatalogXMLFiles, xmlFreeCatalogHashEntryList);
xmlCatalogXMLFiles = NULL;
if (xmlDefaultCatalog != NULL)
xmlFreeCatalog(xmlDefaultCatalog);
xmlDefaultCatalog = NULL;
xmlDebugCatalogs = 0;
xmlCatalogInitialized = 0;
xmlRMutexUnlock(xmlCatalogMutex);
xmlFreeRMutex(xmlCatalogMutex);
}
/**
* xmlCatalogResolveSystem:
* @sysID: the system ID string
*
* Try to lookup the catalog resource for a system ID
*
* Returns the resource if found or NULL otherwise, the value returned
* must be freed by the caller.
*/
xmlChar *
xmlCatalogResolveSystem(const xmlChar *sysID) {
xmlChar *ret;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
return(ret);
}
/**
* xmlCatalogResolvePublic:
* @pubID: the public ID string
*
* Try to lookup the catalog reference associated to a public ID
*
* Returns the resource if found or NULL otherwise, the value returned
* must be freed by the caller.
*/
xmlChar *
xmlCatalogResolvePublic(const xmlChar *pubID) {
xmlChar *ret;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
return(ret);
}
/**
* xmlCatalogResolve:
* @pubID: the public ID string
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier
*
* Returns the URI of the resource or NULL if not found, it must be freed
* by the caller.
*/
xmlChar *
xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
xmlChar *ret;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
return(ret);
}
/**
* xmlCatalogResolveURI:
* @URI: the URI
*
* Do a complete resolution lookup of an URI
*
* Returns the URI of the resource or NULL if not found, it must be freed
* by the caller.
*/
xmlChar *
xmlCatalogResolveURI(const xmlChar *URI) {
xmlChar *ret;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
return(ret);
}
#ifdef LIBXML_OUTPUT_ENABLED
/**
* xmlCatalogDump:
* @out: the file.
*
* Dump all the global catalog content to the given file.
*/
void
xmlCatalogDump(FILE *out) {
if (out == NULL)
return;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
xmlACatalogDump(xmlDefaultCatalog, out);
}
#endif /* LIBXML_OUTPUT_ENABLED */
/**
* xmlCatalogAdd:
* @type: the type of record to add to the catalog
* @orig: the system, public or prefix to match
* @replace: the replacement value for the match
*
* Add an entry in the catalog, it may overwrite existing but
* different entries.
* If called before any other catalog routine, allows to override the
* default shared catalog put in place by xmlInitializeCatalog();
*
* Returns 0 if successful, -1 otherwise
*/
int
xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
int res = -1;
if (!xmlCatalogInitialized)
xmlInitializeCatalogData();
xmlRMutexLock(xmlCatalogMutex);
/*
* Specific case where one want to override the default catalog
* put in place by xmlInitializeCatalog();
*/
if ((xmlDefaultCatalog == NULL) &&
(xmlStrEqual(type, BAD_CAST "catalog"))) {
xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
xmlCatalogDefaultPrefer);
xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
orig, NULL, xmlCatalogDefaultPrefer, NULL);
xmlRMutexUnlock(xmlCatalogMutex);
return(0);
}
res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
xmlRMutexUnlock(xmlCatalogMutex);
return(res);
}
/**
* xmlCatalogRemove:
* @value: the value to remove
*
* Remove an entry from the catalog
*
* Returns the number of entries removed if successful, -1 otherwise
*/
int
xmlCatalogRemove(const xmlChar *value) {
int res;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
xmlRMutexLock(xmlCatalogMutex);
res = xmlACatalogRemove(xmlDefaultCatalog, value);
xmlRMutexUnlock(xmlCatalogMutex);
return(res);
}
/**
* xmlCatalogConvert:
*
* Convert all the SGML catalog entries as XML ones
*
* Returns the number of entries converted if successful, -1 otherwise
*/
int
xmlCatalogConvert(void) {
int res = -1;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
xmlRMutexLock(xmlCatalogMutex);
res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
xmlRMutexUnlock(xmlCatalogMutex);
return(res);
}
/************************************************************************
* *
* Public interface manipulating the common preferences *
* *
************************************************************************/
/**
* xmlCatalogGetDefaults:
*
* Used to get the user preference w.r.t. to what catalogs should
* be accepted
*
* Returns the current xmlCatalogAllow value
*/
xmlCatalogAllow
xmlCatalogGetDefaults(void) {
return(xmlCatalogDefaultAllow);
}
/**
* xmlCatalogSetDefaults:
* @allow: what catalogs should be accepted
*
* Used to set the user preference w.r.t. to what catalogs should
* be accepted
*/
void
xmlCatalogSetDefaults(xmlCatalogAllow allow) {
if (xmlDebugCatalogs) {
switch (allow) {
case XML_CATA_ALLOW_NONE:
xmlGenericError(xmlGenericErrorContext,
"Disabling catalog usage\n");
break;
case XML_CATA_ALLOW_GLOBAL:
xmlGenericError(xmlGenericErrorContext,
"Allowing only global catalogs\n");
break;
case XML_CATA_ALLOW_DOCUMENT:
xmlGenericError(xmlGenericErrorContext,
"Allowing only catalogs from the document\n");
break;
case XML_CATA_ALLOW_ALL:
xmlGenericError(xmlGenericErrorContext,
"Allowing all catalogs\n");
break;
}
}
xmlCatalogDefaultAllow = allow;
}
/**
* xmlCatalogSetDefaultPrefer:
* @prefer: the default preference for delegation
*
* Allows to set the preference between public and system for deletion
* in XML Catalog resolution. C.f. section 4.1.1 of the spec
* Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
*
* Returns the previous value of the default preference for delegation
*/
xmlCatalogPrefer
xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
if (prefer == XML_CATA_PREFER_NONE)
return(ret);
if (xmlDebugCatalogs) {
switch (prefer) {
case XML_CATA_PREFER_PUBLIC:
xmlGenericError(xmlGenericErrorContext,
"Setting catalog preference to PUBLIC\n");
break;
case XML_CATA_PREFER_SYSTEM:
xmlGenericError(xmlGenericErrorContext,
"Setting catalog preference to SYSTEM\n");
break;
default:
return(ret);
}
}
xmlCatalogDefaultPrefer = prefer;
return(ret);
}
/**
* xmlCatalogSetDebug:
* @level: the debug level of catalogs required
*
* Used to set the debug level for catalog operation, 0 disable
* debugging, 1 enable it
*
* Returns the previous value of the catalog debugging level
*/
int
xmlCatalogSetDebug(int level) {
int ret = xmlDebugCatalogs;
if (level <= 0)
xmlDebugCatalogs = 0;
else
xmlDebugCatalogs = level;
return(ret);
}
/************************************************************************
* *
* Minimal interfaces used for per-document catalogs by the parser *
* *
************************************************************************/
/**
* xmlCatalogFreeLocal:
* @catalogs: a document's list of catalogs
*
* Free up the memory associated to the catalog list
*/
void
xmlCatalogFreeLocal(void *catalogs) {
xmlCatalogEntryPtr catal;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
catal = (xmlCatalogEntryPtr) catalogs;
if (catal != NULL)
xmlFreeCatalogEntryList(catal);
}
/**
* xmlCatalogAddLocal:
* @catalogs: a document's list of catalogs
* @URL: the URL to a new local catalog
*
* Add the new entry to the catalog list
*
* Returns the updated list
*/
void *
xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
xmlCatalogEntryPtr catal, add;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
if (URL == NULL)
return(catalogs);
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Adding document catalog %s\n", URL);
add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
xmlCatalogDefaultPrefer, NULL);
if (add == NULL)
return(catalogs);
catal = (xmlCatalogEntryPtr) catalogs;
if (catal == NULL)
return((void *) add);
while (catal->next != NULL)
catal = catal->next;
catal->next = add;
return(catalogs);
}
/**
* xmlCatalogLocalResolve:
* @catalogs: a document's list of catalogs
* @pubID: the public ID string
* @sysID: the system ID string
*
* Do a complete resolution lookup of an External Identifier using a
* document's private catalog list
*
* Returns the URI of the resource or NULL if not found, it must be freed
* by the caller.
*/
xmlChar *
xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
const xmlChar *sysID) {
xmlCatalogEntryPtr catal;
xmlChar *ret;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
if ((pubID == NULL) && (sysID == NULL))
return(NULL);
if (xmlDebugCatalogs) {
if ((pubID != NULL) && (sysID != NULL)) {
xmlGenericError(xmlGenericErrorContext,
"Local Resolve: pubID %s sysID %s\n", pubID, sysID);
} else if (pubID != NULL) {
xmlGenericError(xmlGenericErrorContext,
"Local Resolve: pubID %s\n", pubID);
} else {
xmlGenericError(xmlGenericErrorContext,
"Local Resolve: sysID %s\n", sysID);
}
}
catal = (xmlCatalogEntryPtr) catalogs;
if (catal == NULL)
return(NULL);
ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
if ((ret != NULL) && (ret != XML_CATAL_BREAK))
return(ret);
return(NULL);
}
/**
* xmlCatalogLocalResolveURI:
* @catalogs: a document's list of catalogs
* @URI: the URI
*
* Do a complete resolution lookup of an URI using a
* document's private catalog list
*
* Returns the URI of the resource or NULL if not found, it must be freed
* by the caller.
*/
xmlChar *
xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
xmlCatalogEntryPtr catal;
xmlChar *ret;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
if (URI == NULL)
return(NULL);
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Resolve URI %s\n", URI);
catal = (xmlCatalogEntryPtr) catalogs;
if (catal == NULL)
return(NULL);
ret = xmlCatalogListXMLResolveURI(catal, URI);
if ((ret != NULL) && (ret != XML_CATAL_BREAK))
return(ret);
return(NULL);
}
/************************************************************************
* *
* Deprecated interfaces *
* *
************************************************************************/
/**
* xmlCatalogGetSystem:
* @sysID: the system ID string
*
* Try to lookup the catalog reference associated to a system ID
* DEPRECATED, use xmlCatalogResolveSystem()
*
* Returns the resource if found or NULL otherwise.
*/
const xmlChar *
xmlCatalogGetSystem(const xmlChar *sysID) {
xmlChar *ret;
static xmlChar result[1000];
static int msg = 0;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
if (msg == 0) {
xmlGenericError(xmlGenericErrorContext,
"Use of deprecated xmlCatalogGetSystem() call\n");
msg++;
}
if (sysID == NULL)
return(NULL);
/*
* Check first the XML catalogs
*/
if (xmlDefaultCatalog != NULL) {
ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
result[sizeof(result) - 1] = 0;
return(result);
}
}
if (xmlDefaultCatalog != NULL)
return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
return(NULL);
}
/**
* xmlCatalogGetPublic:
* @pubID: the public ID string
*
* Try to lookup the catalog reference associated to a public ID
* DEPRECATED, use xmlCatalogResolvePublic()
*
* Returns the resource if found or NULL otherwise.
*/
const xmlChar *
xmlCatalogGetPublic(const xmlChar *pubID) {
xmlChar *ret;
static xmlChar result[1000];
static int msg = 0;
if (!xmlCatalogInitialized)
xmlInitializeCatalog();
if (msg == 0) {
xmlGenericError(xmlGenericErrorContext,
"Use of deprecated xmlCatalogGetPublic() call\n");
msg++;
}
if (pubID == NULL)
return(NULL);
/*
* Check first the XML catalogs
*/
if (xmlDefaultCatalog != NULL) {
ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
result[sizeof(result) - 1] = 0;
return(result);
}
}
if (xmlDefaultCatalog != NULL)
return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
return(NULL);
}
#define bottom_catalog
#include "elfgcchack.h"
#endif /* LIBXML_CATALOG_ENABLED */
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/kimjuncotton_y/libxml2_0213.git
git@gitee.com:kimjuncotton_y/libxml2_0213.git
kimjuncotton_y
libxml2_0213
libxml2_backup
openkylin/yangtze

搜索帮助