Coverage Report

Created: 2026-10-22 06:29

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