Coverage Report

Created: 2026-02-14 07:05

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