Coverage Report

Created: 2026-05-24 07:45

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