Coverage Report

Created: 2024-08-17 06:44

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