Coverage Report

Created: 2022-11-15 06:34

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