Coverage Report

Created: 2025-07-23 08:13

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