Project

General

Profile

Statistics
| Branch: | Revision:

root / src / nedxml / saxparser_libxml.cc @ c87b95b0

History | View | Annotate | Download (10.9 KB)

1
//==========================================================================
2
//  SAXPARSERLIBXML.CC - part of
3
//
4
//                     OMNeT++/OMNEST
5
//            Discrete System Simulation in C++
6
//
7
//==========================================================================
8

    
9
/*--------------------------------------------------------------*
10
  Copyright (C) 2002-2008 Andras Varga
11
  Copyright (C) 2006-2008 OpenSim Ltd.
12

13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16

    
17

    
18
#include <string.h>
19
#include <stdio.h>
20
#include <assert.h>
21
#include <stdio.h>
22
#include <stdarg.h>
23
#include <libxml/parser.h>
24
#include <libxml/SAX.h>
25
#include "saxparser.h"
26

    
27
USING_NAMESPACE
28

    
29

    
30
//
31
// Validating only if LibXML is at least 2.6.0
32
//
33
#if LIBXML_VERSION>20600
34

    
35
SAXParser::SAXParser()
36
{
37
    saxhandler = NULL;
38
}
39

    
40
void SAXParser::setHandler(SAXHandler *sh)
41
{
42
    saxhandler = sh;
43
    sh->setParser(this);
44
}
45

    
46
static int nodeLine;  // line number of current node
47
static xmlParserCtxtPtr ctxt; // parser context
48

    
49
static void dontPrintError(void *, xmlErrorPtr) {} // an xmlStructuredErrorFunc
50

    
51
static void generateSAXEvents(xmlNode *node, SAXHandler *sh)
52
{
53
    nodeLine = node->line;
54
    switch (node->type)
55
    {
56
        case XML_ELEMENT_NODE: {
57
            // collect attributes for startElement()
58
            int numAttrs = 0;
59
            xmlAttr *attr;
60
            for (attr = node->properties; attr; attr = (xmlAttr *)attr->next)
61
                numAttrs++;
62
            const char **attrs = new const char *[2*(numAttrs+1)];
63
            int k;
64
            for (attr = node->properties, k=0; attr; attr = (xmlAttr *)attr->next, k+=2)
65
            {
66
                // ignore namespaces: pass "prefix:name" to SAX handler
67
                if (attr->ns) {
68
                    attrs[k] = new char [strlen((const char *)attr->name)+strlen((const char *)attr->ns->prefix)+2];
69
                    sprintf((char *)attrs[k], "%s:%s", attr->ns->prefix, attr->name);
70
                } else {
71
                    attrs[k] = (const char *) attr->name;
72
                }
73
                attrs[k+1] = (const char *) attr->children->content; // first text node within attr
74
            }
75
            attrs[k] = NULL;
76
            attrs[k+1] = NULL;
77

    
78
            // element name. ignore namespaces: pass "prefix:name" to SAX handler
79
            char *nodename;
80
            if (node->ns) {
81
                nodename = new char [strlen((const char *)node->name)+strlen((const char *)node->ns->prefix)+2];
82
                sprintf(nodename, "%s:%s", node->ns->prefix, node->name);
83
            } else {
84
                nodename = (char *) node->name;
85
            }
86

    
87
            // invoke startElement()
88
            sh->startElement(nodename, attrs);
89

    
90
            // dealloc prefixed attr names and element name
91
            for (attr = node->properties, k=0; attr; attr = (xmlAttr *)attr->next, k+=2)
92
                if (attr->ns)
93
                    delete [] (char *)attrs[k];
94
            delete [] attrs;
95
            if (node->ns)
96
                delete [] nodename;
97

    
98
            // recursive processing of children
99
            xmlNode *child;
100
            for (child = node->children; child; child = child->next)
101
                generateSAXEvents(child, sh);
102

    
103
            // invoke endElement()
104
            sh->endElement((const char *)node->name);
105
            break;
106
        }
107
        case XML_TEXT_NODE:
108
            sh->characterData((const char *)node->content,strlen((const char *)node->content));
109
            break;
110
        case XML_PI_NODE:
111
            // FIXME sh->processingInstruction((const char *)target,(const char *)data);
112
            break;
113
        case XML_COMMENT_NODE:
114
            sh->comment((const char *)node->content);
115
            break;
116
        case XML_CDATA_SECTION_NODE:
117
        case XML_ENTITY_REF_NODE:
118
        case XML_ENTITY_NODE:
119
        case XML_XINCLUDE_START:
120
        case XML_XINCLUDE_END:
121
        case XML_ATTRIBUTE_NODE:
122
            // should not occur (see XML_PARSE_xxx options)
123
            fprintf(stderr,"ERROR: libxml wrapper: generateSAXEvents(): node type %d unexpected\n",node->type);
124
            assert(0);
125
            break;
126
        default:
127
            // DTD stuff: ignore
128
            break;
129

    
130
    }
131
}
132

    
133

    
134
bool SAXParser::parse(const char *filename)
135
{
136
    //
137
    // When there's a DTD given, we *must* use it, and complete default attrs from it.
138
    //
139
    // Strategy: build DOM tree with validation enabled, then generate SAX events
140
    // from it. LibXML's SAX2-based validation code isn't robust enough yet
141
    // (as of 09/2004)
142
    //
143
    ctxt = xmlNewParserCtxt();
144
    if (!ctxt)
145
    {
146
        strcpy(errortext, "Failed to allocate parser context");
147
        return false;
148
    }
149

    
150
    // parse the file
151
    unsigned options = XML_PARSE_DTDVALID | // validate with the DTD
152
                       XML_PARSE_DTDATTR |  // complete default attributes from DTD
153
                       XML_PARSE_NOENT |    // substitute entities
154
                       XML_PARSE_NONET |    // forbid network access
155
                       XML_PARSE_NOBLANKS | // discard ignorable white space
156
                       XML_PARSE_NOCDATA |  // merge CDATA as text nodes
157
                       XML_PARSE_NOERROR |  // suppress error reports
158
                       XML_PARSE_NOWARNING; // suppress warning reports
159
    //ctxt->vctxt.warning = NULL;
160
    //ctxt->vctxt.error = NULL;
161
    xmlStructuredError = dontPrintError; // hack to prevent errors being written to stdout
162
    xmlDocPtr doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
163

    
164
    // check if parsing succeeded
165
    if (!doc)
166
    {
167
        sprintf(errortext, "Parse error: %s at line %s:%d",
168
                ctxt->lastError.message, ctxt->lastError.file, ctxt->lastError.line);
169
        xmlFreeParserCtxt(ctxt);
170
        return false;
171
    }
172

    
173
    // handle validation errors.
174
    // note: errNo==XML_ERR_NO_DTD is unusable, because it occurs both when there's
175
    // no DOCTYPE in document and when DTD cannot be opened (wrong URI)
176
    bool hasDTD = false;
177
    for (xmlNode *child = doc->children; child; child = child->next)
178
        if (child->type == XML_DTD_NODE)
179
            hasDTD = true;
180
    if (!ctxt->valid && hasDTD) // ctxt->errNo!=XML_ERR_NO_DTD
181
    {
182
        sprintf(errortext, "Validation error: %s at line %s:%d",
183
                ctxt->lastError.message, ctxt->lastError.file, ctxt->lastError.line);
184
        xmlFreeParserCtxt(ctxt);
185
        xmlFreeDoc(doc);
186
        return false;
187
    }
188

    
189
    // traverse tree and generate SAX events
190
    xmlNode *root = xmlDocGetRootElement(doc);
191
    generateSAXEvents(root, saxhandler);
192

    
193
    // free parser context and document tree
194
    xmlFreeParserCtxt(ctxt);
195
    xmlFreeDoc(doc);
196
    return true;
197
}
198

    
199
int SAXParser::getCurrentLineNumber()
200
{
201
    return nodeLine;
202
}
203

    
204

    
205
#else
206

    
207
//
208
// Old, SAX1-based code, left here as fallback. Doesn't perform DTD validation
209
// and attr completion.
210
//
211

    
212
static void libxmlStartElementHandler(void *userData, const xmlChar *name, const xmlChar **atts)
213
{
214
    SAXHandler *sh = (SAXHandler *)userData;
215
    sh->startElement((const char *)name, (const char **)atts);
216
}
217

    
218
static void libxmlEndElementHandler(void *userData, const xmlChar *name)
219
{
220
    SAXHandler *sh = (SAXHandler *)userData;
221
    sh->endElement((const char *)name);
222
}
223

    
224
static void libxmlCharacterDataHandler(void *userData, const xmlChar *s, int len)
225
{
226
    SAXHandler *sh = (SAXHandler *)userData;
227
    sh->characterData((const char *)s,len);
228
}
229

    
230
/*
231
static void libxmlProcessingInstructionHandler(void *userData, const xmlChar *target, const xmlChar *data)
232
{
233
    SAXHandler *sh = (SAXHandler *)userData;
234
    sh->processingInstruction((const char *)target,(const char *)data);
235
}
236
*/
237

    
238
static void libxmlCommentHandler(void *userData, const xmlChar *data)
239
{
240
    SAXHandler *sh = (SAXHandler *)userData;
241
    sh->comment((const char *)data);
242
}
243

    
244

    
245
/*
246
static void libxmlStartCdataSectionHandler(void *userData)
247
{
248
    SAXHandler *sh = (SAXHandler *)userData;
249
    sh->startCdataSection();
250
}
251

252
static void libxmlEndCdataSectionHandler(void *userData)
253
{
254
    SAXHandler *sh = (SAXHandler *)userData;
255
    sh->endCdataSection();
256
}
257
*/
258

    
259
static void libxmlWarningHandler(void *userData, const char *msg, ...) {
260
  va_list args;
261
  va_start(args, msg);
262
  // g_logv("XML", G_LOG_LEVEL_WARNING, msg, args);
263
  // printf(msg, args);
264
  va_end(args);
265
}
266

    
267
static void libxmlErrorHandler(void *userData, const char *msg, ...) {
268
  va_list args;
269
  va_start(args, msg);
270
  // g_logv("XML", G_LOG_LEVEL_CRITICAL, msg, args);
271
  // printf(msg, args);
272
  va_end(args);
273
}
274

    
275
static void libxmlFatalErrorHandler(void *userData, const char *msg, ...) {
276
  va_list args;
277
  va_start(args, msg);
278
  // g_logv("XML", G_LOG_LEVEL_ERROR, msg, args);
279
  // printf(msg, args);
280
  va_end(args);
281
}
282

    
283
SAXParser::SAXParser()
284
{
285
    saxhandler = NULL;
286
}
287

    
288
void SAXParser::setHandler(SAXHandler *sh)
289
{
290
    saxhandler = sh;
291
    sh->setParser(this);
292
}
293

    
294
static xmlSAXHandler libxmlSAXParser = {
295
    0, // internalSubset
296
    0, // isStandalone
297
    0, // hasInternalSubset
298
    0, // hasExternalSubset
299
    0, // resolveEntity
300
    0, // getEntity
301
    0, // entityDecl
302
    0, // notationDecl
303
    0, // attributeDecl
304
    0, // elementDecl
305
    0, // unparsedEntityDecl
306
    0, // setDocumentLocator
307
    0, // startDocument
308
    0, // endDocument
309
    (startElementSAXFunc)libxmlStartElementHandler, // startElement
310
    (endElementSAXFunc)libxmlEndElementHandler, // endElement
311
    0, // reference
312
    (charactersSAXFunc)libxmlCharacterDataHandler, // characters
313
    0, // ignorableWhitespace
314
    0, // processingInstruction
315
    (commentSAXFunc)libxmlCommentHandler, // comment
316
    (warningSAXFunc)libxmlWarningHandler, // warning
317
    (errorSAXFunc)libxmlErrorHandler, // error
318
    (fatalErrorSAXFunc)libxmlFatalErrorHandler, // fatalError
319
};
320

    
321
static xmlParserCtxtPtr ctxt;
322

    
323
bool SAXParser::parse(const char *filename)
324
{
325
    LIBXML_TEST_VERSION
326

    
327
    printf("\n*** WARNING: Your LibXML version is too old: " LIBXML_DOTTED_VERSION
328
           ". DTD validation and attribute completion is currently OFF. "
329
           "Please upgrade to at least version 2.6.0!\n\n");
330

    
331
    FILE *f = fopen(filename,"r");
332
    if (!f)
333
    {
334
        sprintf(errortext, "Cannot open file");
335
        return false;
336
    }
337

    
338
    ctxt = xmlCreatePushParserCtxt(&libxmlSAXParser, saxhandler, NULL, 0, NULL);
339

    
340
    int n;
341
    char Buffer[512];
342
    while (0 != (n=fread(Buffer,  sizeof(char), 512, f)))
343
    {
344
        xmlParseChunk(ctxt, Buffer, n, 0);
345
    }
346

    
347
    xmlParseChunk(ctxt, Buffer, 0, 1);
348

    
349
    bool ok = true;
350
    if (!ctxt->wellFormed)
351
    {
352
        ok = false;
353
        sprintf(errortext, "parser error %d at line %d",
354
                ctxt->errNo, // TODO something better
355
                ctxt->input->line);
356
    }
357

    
358
    if (!ctxt->valid)
359
    {
360
        ok = false;
361
        sprintf(errortext, "validation error %d at line %d",
362
                ctxt->errNo, // TODO something better
363
                ctxt->input->line);
364
    }
365

    
366
    ctxt->sax = NULL;
367

    
368
    xmlFreeParserCtxt(ctxt);
369
    fclose(f);
370

    
371
    return ok;
372
}
373

    
374
int SAXParser::getCurrentLineNumber()
375
{
376
    return ctxt->input->line;
377
}
378

    
379
#endif
380