Coverage Report

Created: 2022-06-08 06:16

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