~ubuntu-branches/ubuntu/utopic/libxml2/utopic

« back to all changes in this revision

Viewing changes to .pc/0025-Fix-an-fd-leak-in-an-error-case.patch/catalog.c

  • Committer: Package Import Robot
  • Author(s): Aron Xu, Christian Svensson, Daniel Schepler, Helmut Grohne, Adam Conrad, Matthias Klose, Aron Xu
  • Date: 2014-07-09 05:40:15 UTC
  • mfrom: (43.2.6 sid)
  • Revision ID: package-import@ubuntu.com-20140709054015-1q7dyagza4p2gkm0
Tags: 2.9.1+dfsg1-4
[ Christian Svensson ]
* Do not build-depend on readline (Closes: #742350)

[ Daniel Schepler ]
* Patch to bootstrap without python (Closes: #738080)

[ Helmut Grohne ]
* Drop unneeded B-D on perl and binutils (Closes: #753005)

[ Adam Conrad ]
* Actually run dh_autoreconf, which the old/new mixed rules file misses.

[ Matthias Klose ]
* Add patch to fix python multiarch issue
* Allow the package to cross-build by tweaking B-Ds on python
* Set PYTHON_LIBS for cross builds

[ Aron Xu ]
* Use correct $CC
* Configure udeb without python
* New round of cherry-picking upstream fixes
  - Includes fixes for CVE-2014-0191 (Closes: #747309).
* Call prename with -vf
* Require python-all-dev (>= 2.7.5-5~)
* Bump std-ver: 3.9.4 -> 3.9.5, no change

Show diffs side-by-side

added added

removed removed

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