catalog.c 97 KB

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