Coverage Report

Created: 2025-07-18 06:31

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