catalog.c 97 KB

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