Coverage Report

Created: 2025-10-10 06:43

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