Coverage Report

Created: 2024-02-04 06:18

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