Coverage Report

Created: 2025-08-04 07:15

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