base
This commit is contained in:
+66
@@ -0,0 +1,66 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
DEFS = @DEFS@
|
||||
INCLUDES = -I. -I../.. $(INCLTDL) -I../../lib
|
||||
|
||||
EXTRA_DIST = twofish.h saferplus.h rijndael.h \
|
||||
rc2.h serpent.h cast-256.h blowfish.h \
|
||||
cast-128.h cast-128_sboxes.h des.h tripledes.h \
|
||||
3-way.h enigma.h arcfour.h wake.h \
|
||||
safer.h xtea.h panama.h
|
||||
|
||||
pkglib_LTLIBRARIES = @INSTALL_ALGORITHM_MODULES@
|
||||
|
||||
EXTRA_LTLIBRARIES = twofish.la rijndael-128.la \
|
||||
rijndael-192.la rijndael-256.la saferplus.la rc2.la xtea.la \
|
||||
serpent.la safer-sk64.la safer-sk128.la cast-256.la loki97.la \
|
||||
gost.la threeway.la cast-128.la blowfish.la des.la blowfish-compat.la \
|
||||
tripledes.la enigma.la arcfour.la panama.la wake.la
|
||||
|
||||
noinst_LTLIBRARIES = @NOINSTALL_ALGORITHM_MODULES@
|
||||
|
||||
twofish_la_SOURCES = twofish.c
|
||||
twofish_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
wake_la_SOURCES = wake.c
|
||||
wake_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
panama_la_SOURCES = panama.c
|
||||
panama_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
rijndael_128_la_SOURCES = rijndael-128.c
|
||||
rijndael_128_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
rijndael_192_la_SOURCES = rijndael-192.c
|
||||
rijndael_192_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
rijndael_256_la_SOURCES = rijndael-256.c
|
||||
rijndael_256_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
saferplus_la_SOURCES = saferplus.c
|
||||
saferplus_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
serpent_la_SOURCES = serpent.c
|
||||
serpent_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
xtea_la_SOURCES = xtea.c
|
||||
xtea_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
rc2_la_SOURCES = rc2.c
|
||||
rc2_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
safer_sk64_la_SOURCES = safer64.c
|
||||
safer_sk64_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
safer_sk128_la_SOURCES = safer128.c
|
||||
safer_sk128_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
cast_256_la_SOURCES = cast-256.c
|
||||
cast_256_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
loki97_la_SOURCES = loki97.c
|
||||
loki97_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
gost_la_SOURCES = gost.c
|
||||
gost_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
threeway_la_SOURCES = 3-way.c
|
||||
threeway_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
blowfish_la_SOURCES = blowfish.c
|
||||
blowfish_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
blowfish_compat_la_SOURCES = blowfish-compat.c
|
||||
blowfish_compat_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
cast_128_la_SOURCES = cast-128.c
|
||||
cast_128_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
des_la_SOURCES = des.c
|
||||
des_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
tripledes_la_SOURCES = tripledes.c
|
||||
tripledes_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
enigma_la_SOURCES = enigma.c
|
||||
enigma_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
arcfour_la_SOURCES = arcfour.c
|
||||
arcfour_la_LDFLAGS = -module -avoid-version -rpath $(pkglibdir)
|
||||
+658
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
Wrapper interface to XML parser
|
||||
Copyright (C) 1999-2005, Joe Orton <joe@manyfish.co.uk>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "ne_i18n.h"
|
||||
|
||||
#include "ne_alloc.h"
|
||||
#include "ne_xml.h"
|
||||
#include "ne_utils.h"
|
||||
#include "ne_string.h"
|
||||
|
||||
#if defined(HAVE_EXPAT)
|
||||
/* expat support: */
|
||||
#ifdef HAVE_XMLPARSE_H
|
||||
#include "xmlparse.h"
|
||||
#else
|
||||
#include <expat.h>
|
||||
#endif
|
||||
typedef XML_Char ne_xml_char;
|
||||
|
||||
#if !defined(XML_MAJOR_VERSION) || (XML_MAJOR_VERSION < 2 \
|
||||
&& XML_MINOR_VERSION == 95 \
|
||||
&& XML_MICRO_VERSION < 2)
|
||||
#define NEED_BOM_HANDLING
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_LIBXML)
|
||||
/* libxml2 support: */
|
||||
#include <libxml/xmlversion.h>
|
||||
#include <libxml/parser.h>
|
||||
typedef xmlChar ne_xml_char;
|
||||
|
||||
#if LIBXML_VERSION < 20619
|
||||
/* 2.6.19 and earlier have broken BOM handling */
|
||||
#define NEED_BOM_HANDLING
|
||||
#endif
|
||||
#else /* not HAVE_LIBXML */
|
||||
# error need an XML parser
|
||||
#endif /* not HAVE_EXPAT */
|
||||
|
||||
/* Approx. one screen of text: */
|
||||
#define ERR_SIZE (2048)
|
||||
|
||||
struct handler {
|
||||
ne_xml_startelm_cb *startelm_cb; /* start-element callback */
|
||||
ne_xml_endelm_cb *endelm_cb; /* end-element callback */
|
||||
ne_xml_cdata_cb *cdata_cb; /* character-data callback. */
|
||||
void *userdata; /* userdata for the above. */
|
||||
struct handler *next; /* next handler in stack. */
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBXML
|
||||
static void sax_error(void *ctx, const char *msg, ...);
|
||||
#endif
|
||||
|
||||
struct element {
|
||||
const ne_xml_char *nspace;
|
||||
ne_xml_char *name;
|
||||
|
||||
int state; /* opaque state integer */
|
||||
|
||||
/* Namespaces declared in this element */
|
||||
ne_xml_char *default_ns; /* A default namespace */
|
||||
struct namespace *nspaces; /* List of other namespace scopes */
|
||||
|
||||
struct handler *handler; /* Handler for this element */
|
||||
|
||||
struct element *parent; /* parent element, or NULL */
|
||||
};
|
||||
|
||||
/* We pass around a ne_xml_parser as the userdata in the parsing
|
||||
* library. This maintains the current state of the parse and various
|
||||
* other bits and bobs. Within the parse, we store the current branch
|
||||
* of the tree, i.e., the current element and all its parents, up to
|
||||
* the root, but nothing other than that. */
|
||||
struct ne_xml_parser_s {
|
||||
struct element *root; /* the root of the document */
|
||||
struct element *current; /* current element in the branch */
|
||||
struct handler *top_handlers; /* always points at the
|
||||
* handler on top of the stack. */
|
||||
int failure; /* zero whilst parse should continue */
|
||||
int prune; /* if non-zero, depth within a dead branch */
|
||||
|
||||
#ifdef NEED_BOM_HANDLING
|
||||
int bom_pos;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EXPAT
|
||||
XML_Parser parser;
|
||||
char *encoding;
|
||||
#else
|
||||
xmlParserCtxtPtr parser;
|
||||
#endif
|
||||
char error[ERR_SIZE];
|
||||
};
|
||||
|
||||
/* The callback handlers */
|
||||
static void start_element(void *userdata, const ne_xml_char *name, const ne_xml_char **atts);
|
||||
static void end_element(void *userdata, const ne_xml_char *name);
|
||||
static void char_data(void *userdata, const ne_xml_char *cdata, int len);
|
||||
static const char *resolve_nspace(const struct element *elm,
|
||||
const char *prefix, size_t pfxlen);
|
||||
|
||||
/* Linked list of namespace scopes */
|
||||
struct namespace {
|
||||
ne_xml_char *name;
|
||||
ne_xml_char *uri;
|
||||
struct namespace *next;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBXML
|
||||
|
||||
/* Could be const as far as we care, but libxml doesn't want that */
|
||||
static xmlSAXHandler sax_handler = {
|
||||
NULL, /* internalSubset */
|
||||
NULL, /* isStandalone */
|
||||
NULL, /* hasInternalSubset */
|
||||
NULL, /* hasExternalSubset */
|
||||
NULL, /* resolveEntity */
|
||||
NULL, /* getEntity */
|
||||
NULL, /* entityDecl */
|
||||
NULL, /* notationDecl */
|
||||
NULL, /* attributeDecl */
|
||||
NULL, /* elementDecl */
|
||||
NULL, /* unparsedEntityDecl */
|
||||
NULL, /* setDocumentLocator */
|
||||
NULL, /* startDocument */
|
||||
NULL, /* endDocument */
|
||||
start_element, /* startElement */
|
||||
end_element, /* endElement */
|
||||
NULL, /* reference */
|
||||
char_data, /* characters */
|
||||
NULL, /* ignorableWhitespace */
|
||||
NULL, /* processingInstruction */
|
||||
NULL, /* comment */
|
||||
NULL, /* xmlParserWarning */
|
||||
sax_error, /* xmlParserError */
|
||||
sax_error, /* fatal error (never called by libxml2?) */
|
||||
NULL, /* getParameterEntity */
|
||||
char_data /* cdataBlock */
|
||||
};
|
||||
|
||||
/* empty attributes array to mimic expat behaviour */
|
||||
static const char *empty_atts[] = {NULL, NULL};
|
||||
|
||||
/* macro for determining the attributes array to pass */
|
||||
#define PASS_ATTS(atts) (atts ? (const char **)(atts) : empty_atts)
|
||||
|
||||
#else
|
||||
|
||||
#define PASS_ATTS(atts) ((const char **)(atts))
|
||||
|
||||
/* XML declaration callback for expat. */
|
||||
static void decl_handler(void *userdata,
|
||||
const XML_Char *version, const XML_Char *encoding,
|
||||
int standalone)
|
||||
{
|
||||
ne_xml_parser *p = userdata;
|
||||
if (encoding) p->encoding = ne_strdup(encoding);
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBXML */
|
||||
|
||||
int ne_xml_currentline(ne_xml_parser *p)
|
||||
{
|
||||
#ifdef HAVE_EXPAT
|
||||
return XML_GetCurrentLineNumber(p->parser);
|
||||
#else
|
||||
return p->parser->input->line;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *ne_xml_doc_encoding(const ne_xml_parser *p)
|
||||
{
|
||||
#ifdef HAVE_LIBXML
|
||||
return p->parser->encoding;
|
||||
#else
|
||||
return p->encoding;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The first character of the REC-xml-names "NCName" rule excludes
|
||||
* "Digit | '.' | '-' | '_' | CombiningChar | Extender"; the XML
|
||||
* parser will not enforce this rule in a namespace declaration since
|
||||
* it treats the entire attribute name as a REC-xml "Name" rule. It's
|
||||
* too hard to check for all of CombiningChar | Digit | Extender here,
|
||||
* but the valid_ncname_ch1 macro catches some of the rest. */
|
||||
|
||||
/* Return non-zero if 'ch' is an invalid start character for an NCName: */
|
||||
#define invalid_ncname_ch1(ch) ((ch) == '\0' || strchr("-.0123456789", (ch)) != NULL)
|
||||
|
||||
/* Subversion repositories have been deployed which use property names
|
||||
* marshalled as NCNames including a colon character; these should
|
||||
* also be rejected but will be allowed for the time being. */
|
||||
#define invalid_ncname(xn) (invalid_ncname_ch1((xn)[0]))
|
||||
|
||||
/* Extract the namespace prefix declarations from 'atts'. */
|
||||
static int declare_nspaces(ne_xml_parser *p, struct element *elm,
|
||||
const ne_xml_char **atts)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; atts && atts[n]; n += 2) {
|
||||
if (strcmp(atts[n], "xmlns") == 0) {
|
||||
/* New default namespace */
|
||||
elm->default_ns = ne_strdup(atts[n+1]);
|
||||
} else if (strncmp(atts[n], "xmlns:", 6) == 0) {
|
||||
struct namespace *ns;
|
||||
|
||||
/* Reject some invalid NCNames as namespace prefix, and an
|
||||
* empty URI as the namespace URI */
|
||||
if (invalid_ncname(atts[n] + 6) || atts[n+1][0] == '\0') {
|
||||
ne_snprintf(p->error, ERR_SIZE,
|
||||
("XML parse error at line %d: invalid namespace "
|
||||
"declaration"), ne_xml_currentline(p));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* New namespace scope */
|
||||
ns = ne_calloc(sizeof(*ns));
|
||||
ns->next = elm->nspaces;
|
||||
elm->nspaces = ns;
|
||||
ns->name = ne_strdup(atts[n]+6); /* skip the xmlns= */
|
||||
ns->uri = ne_strdup(atts[n+1]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expand an XML qualified name, which may include a namespace prefix
|
||||
* as well as the local part. */
|
||||
static int expand_qname(ne_xml_parser *p, struct element *elm,
|
||||
const ne_xml_char *qname)
|
||||
{
|
||||
const ne_xml_char *pfx;
|
||||
|
||||
pfx = strchr(qname, ':');
|
||||
if (pfx == NULL) {
|
||||
struct element *e = elm;
|
||||
|
||||
/* Find default namespace; guaranteed to terminate as the root
|
||||
* element always has default_ns="". */
|
||||
while (e->default_ns == NULL)
|
||||
e = e->parent;
|
||||
|
||||
elm->name = ne_strdup(qname);
|
||||
elm->nspace = e->default_ns;
|
||||
} else if (invalid_ncname(pfx + 1) || qname == pfx) {
|
||||
ne_snprintf(p->error, ERR_SIZE,
|
||||
_("XML parse error at line %d: invalid element name"),
|
||||
ne_xml_currentline(p));
|
||||
return -1;
|
||||
} else {
|
||||
const char *uri = resolve_nspace(elm, qname, pfx-qname);
|
||||
|
||||
if (uri) {
|
||||
elm->name = ne_strdup(pfx+1);
|
||||
elm->nspace = uri;
|
||||
} else {
|
||||
ne_snprintf(p->error, ERR_SIZE,
|
||||
("XML parse error at line %d: undeclared namespace prefix"),
|
||||
ne_xml_currentline(p));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called with the start of a new element. */
|
||||
static void start_element(void *userdata, const ne_xml_char *name,
|
||||
const ne_xml_char **atts)
|
||||
{
|
||||
ne_xml_parser *p = userdata;
|
||||
struct element *elm;
|
||||
struct handler *hand;
|
||||
int state = NE_XML_DECLINE;
|
||||
|
||||
if (p->failure) return;
|
||||
|
||||
if (p->prune) {
|
||||
p->prune++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new element */
|
||||
elm = ne_calloc(sizeof *elm);
|
||||
elm->parent = p->current;
|
||||
p->current = elm;
|
||||
|
||||
if (declare_nspaces(p, elm, atts) || expand_qname(p, elm, name)) {
|
||||
p->failure = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find a handler which will accept this element (or abort the parse) */
|
||||
for (hand = elm->parent->handler; hand && state == NE_XML_DECLINE;
|
||||
hand = hand->next) {
|
||||
elm->handler = hand;
|
||||
state = hand->startelm_cb(hand->userdata, elm->parent->state,
|
||||
elm->nspace, elm->name, PASS_ATTS(atts));
|
||||
}
|
||||
|
||||
NE_DEBUG(NE_DBG_XML, "XML: start-element (%d, {%s, %s}) => %d\n",
|
||||
elm->parent->state, elm->nspace, elm->name, state);
|
||||
|
||||
if (state > 0)
|
||||
elm->state = state;
|
||||
else if (state == NE_XML_DECLINE)
|
||||
/* prune this branch. */
|
||||
p->prune++;
|
||||
else /* state < 0 => abort parse */
|
||||
p->failure = state;
|
||||
}
|
||||
|
||||
/* Destroys an element structure. */
|
||||
static void destroy_element(struct element *elm)
|
||||
{
|
||||
struct namespace *this_ns, *next_ns;
|
||||
ne_free(elm->name);
|
||||
/* Free the namespaces */
|
||||
this_ns = elm->nspaces;
|
||||
while (this_ns != NULL) {
|
||||
next_ns = this_ns->next;
|
||||
ne_free(this_ns->name);
|
||||
ne_free(this_ns->uri);
|
||||
ne_free(this_ns);
|
||||
this_ns = next_ns;
|
||||
}
|
||||
if (elm->default_ns)
|
||||
ne_free(elm->default_ns);
|
||||
ne_free(elm);
|
||||
}
|
||||
|
||||
/* cdata SAX callback */
|
||||
static void char_data(void *userdata, const ne_xml_char *data, int len)
|
||||
{
|
||||
ne_xml_parser *p = userdata;
|
||||
struct element *elm = p->current;
|
||||
|
||||
if (p->failure || p->prune) return;
|
||||
|
||||
if (elm->handler->cdata_cb) {
|
||||
p->failure = elm->handler->cdata_cb(elm->handler->userdata, elm->state, data, len);
|
||||
NE_DEBUG(NE_DBG_XML, "XML: char-data (%d) returns %d\n",
|
||||
elm->state, p->failure);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called with the end of an element */
|
||||
static void end_element(void *userdata, const ne_xml_char *name)
|
||||
{
|
||||
ne_xml_parser *p = userdata;
|
||||
struct element *elm = p->current;
|
||||
|
||||
if (p->failure) return;
|
||||
|
||||
if (p->prune) {
|
||||
if (p->prune-- > 1) return;
|
||||
} else if (elm->handler->endelm_cb) {
|
||||
p->failure = elm->handler->endelm_cb(elm->handler->userdata, elm->state,
|
||||
elm->nspace, elm->name);
|
||||
if (p->failure) {
|
||||
NE_DEBUG(NE_DBG_XML, "XML: end-element for %d failed with %d.\n",
|
||||
elm->state, p->failure);
|
||||
}
|
||||
}
|
||||
|
||||
NE_DEBUG(NE_DBG_XML, "XML: end-element (%d, {%s, %s})\n",
|
||||
elm->state, elm->nspace, elm->name);
|
||||
|
||||
/* move back up the tree */
|
||||
p->current = elm->parent;
|
||||
p->prune = 0;
|
||||
|
||||
destroy_element(elm);
|
||||
}
|
||||
|
||||
/* Find a namespace definition for 'prefix' in given element, where
|
||||
* length of prefix is 'pfxlen'. Returns the URI or NULL. */
|
||||
static const char *resolve_nspace(const struct element *elm,
|
||||
const char *prefix, size_t pfxlen)
|
||||
{
|
||||
const struct element *s;
|
||||
|
||||
/* Search up the tree. */
|
||||
for (s = elm; s != NULL; s = s->parent) {
|
||||
const struct namespace *ns;
|
||||
/* Iterate over defined spaces on this node. */
|
||||
for (ns = s->nspaces; ns != NULL; ns = ns->next) {
|
||||
if (strlen(ns->name) == pfxlen &&
|
||||
memcmp(ns->name, prefix, pfxlen) == 0)
|
||||
return ns->uri;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ne_xml_parser *ne_xml_create(void)
|
||||
{
|
||||
ne_xml_parser *p = ne_calloc(sizeof *p);
|
||||
/* Placeholder for the root element */
|
||||
p->current = p->root = ne_calloc(sizeof *p->root);
|
||||
p->root->default_ns = "";
|
||||
p->root->state = 0;
|
||||
strcpy(p->error, _("Unknown error"));
|
||||
#ifdef HAVE_EXPAT
|
||||
p->parser = XML_ParserCreate(NULL);
|
||||
if (p->parser == NULL) {
|
||||
abort();
|
||||
}
|
||||
XML_SetElementHandler(p->parser, start_element, end_element);
|
||||
XML_SetCharacterDataHandler(p->parser, char_data);
|
||||
XML_SetUserData(p->parser, (void *) p);
|
||||
XML_SetXmlDeclHandler(p->parser, decl_handler);
|
||||
#else
|
||||
p->parser = xmlCreatePushParserCtxt(&sax_handler,
|
||||
(void *)p, NULL, 0, NULL);
|
||||
if (p->parser == NULL) {
|
||||
abort();
|
||||
}
|
||||
p->parser->replaceEntities = 1;
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
void ne_xml_push_handler(ne_xml_parser *p,
|
||||
ne_xml_startelm_cb *startelm_cb,
|
||||
ne_xml_cdata_cb *cdata_cb,
|
||||
ne_xml_endelm_cb *endelm_cb,
|
||||
void *userdata)
|
||||
{
|
||||
struct handler *hand = ne_calloc(sizeof(struct handler));
|
||||
|
||||
hand->startelm_cb = startelm_cb;
|
||||
hand->cdata_cb = cdata_cb;
|
||||
hand->endelm_cb = endelm_cb;
|
||||
hand->userdata = userdata;
|
||||
|
||||
/* If this is the first handler registered, update the
|
||||
* base pointer too. */
|
||||
if (p->top_handlers == NULL) {
|
||||
p->root->handler = hand;
|
||||
p->top_handlers = hand;
|
||||
} else {
|
||||
p->top_handlers->next = hand;
|
||||
p->top_handlers = hand;
|
||||
}
|
||||
}
|
||||
|
||||
int ne_xml_parse_v(void *userdata, const char *block, size_t len)
|
||||
{
|
||||
ne_xml_parser *p = userdata;
|
||||
return ne_xml_parse(p, (const ne_xml_char *)block, len);
|
||||
}
|
||||
|
||||
#define BOM_UTF8 "\xEF\xBB\xBF" /* UTF-8 BOM */
|
||||
|
||||
int ne_xml_parse(ne_xml_parser *p, const char *block, size_t len)
|
||||
{
|
||||
int ret, flag;
|
||||
/* duck out if it's broken */
|
||||
if (p->failure) {
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: Failed; ignoring %" NE_FMT_SIZE_T
|
||||
" bytes.\n", len);
|
||||
return p->failure;
|
||||
}
|
||||
if (len == 0) {
|
||||
flag = -1;
|
||||
block = "";
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: End of document.\n");
|
||||
} else {
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: Parsing %" NE_FMT_SIZE_T " bytes.\n", len);
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
#ifdef NEED_BOM_HANDLING
|
||||
if (p->bom_pos < 3) {
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "Checking for UTF-8 BOM.\n");
|
||||
while (len > 0 && p->bom_pos < 3 &&
|
||||
block[0] == BOM_UTF8[p->bom_pos]) {
|
||||
block++;
|
||||
len--;
|
||||
p->bom_pos++;
|
||||
}
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (p->bom_pos == 0) {
|
||||
p->bom_pos = 3; /* no BOM */
|
||||
} else if (p->bom_pos > 0 && p->bom_pos < 3) {
|
||||
strcpy(p->error, _("Invalid Byte Order Mark"));
|
||||
return p->failure = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Note, don't write a parser error if p->failure, since an error
|
||||
* will already have been written in that case. */
|
||||
#ifdef HAVE_EXPAT
|
||||
ret = XML_Parse(p->parser, block, len, flag);
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: XML_Parse returned %d\n", ret);
|
||||
if (ret == 0 && p->failure == 0) {
|
||||
ne_snprintf(p->error, ERR_SIZE,
|
||||
"XML parse error at line %d: %s",
|
||||
XML_GetCurrentLineNumber(p->parser),
|
||||
XML_ErrorString(XML_GetErrorCode(p->parser)));
|
||||
p->failure = 1;
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: Parse error: %s\n", p->error);
|
||||
}
|
||||
#else
|
||||
ret = xmlParseChunk(p->parser, block, len, flag);
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: xmlParseChunk returned %d\n", ret);
|
||||
/* Parse errors are normally caught by the sax_error() callback,
|
||||
* which clears p->valid. */
|
||||
if (p->parser->errNo && p->failure == 0) {
|
||||
ne_snprintf(p->error, ERR_SIZE, "XML parse error at line %d.",
|
||||
ne_xml_currentline(p));
|
||||
p->failure = 1;
|
||||
NE_DEBUG(NE_DBG_XMLPARSE, "XML: Parse error: %s\n", p->error);
|
||||
}
|
||||
#endif
|
||||
return p->failure;
|
||||
}
|
||||
|
||||
int ne_xml_failed(ne_xml_parser *p)
|
||||
{
|
||||
return p->failure;
|
||||
}
|
||||
|
||||
void ne_xml_destroy(ne_xml_parser *p)
|
||||
{
|
||||
struct element *elm, *parent;
|
||||
struct handler *hand, *next;
|
||||
|
||||
/* Free up the handlers on the stack: the root element has the
|
||||
* pointer to the base of the handler stack. */
|
||||
for (hand = p->root->handler; hand!=NULL; hand=next) {
|
||||
next = hand->next;
|
||||
ne_free(hand);
|
||||
}
|
||||
|
||||
/* Clean up remaining elements */
|
||||
for (elm = p->current; elm != p->root; elm = parent) {
|
||||
parent = elm->parent;
|
||||
destroy_element(elm);
|
||||
}
|
||||
|
||||
/* free root element */
|
||||
ne_free(p->root);
|
||||
|
||||
#ifdef HAVE_EXPAT
|
||||
XML_ParserFree(p->parser);
|
||||
if (p->encoding) ne_free(p->encoding);
|
||||
#else
|
||||
xmlFreeParserCtxt(p->parser);
|
||||
#endif
|
||||
|
||||
ne_free(p);
|
||||
}
|
||||
|
||||
void ne_xml_set_error(ne_xml_parser *p, const char *msg)
|
||||
{
|
||||
ne_snprintf(p->error, ERR_SIZE, "%s", msg);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBXML
|
||||
static void sax_error(void *ctx, const char *msg, ...)
|
||||
{
|
||||
ne_xml_parser *p = ctx;
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
|
||||
va_start(ap, msg);
|
||||
ne_vsnprintf(buf, 1024, msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (p->failure == 0) {
|
||||
ne_snprintf(p->error, ERR_SIZE,
|
||||
_("XML parse error at line %d: %s."),
|
||||
p->parser->input->line, buf);
|
||||
p->failure = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *ne_xml_get_error(ne_xml_parser *p)
|
||||
{
|
||||
return p->error;
|
||||
}
|
||||
|
||||
const char *
|
||||
ne_xml_get_attr(ne_xml_parser *p, const char **attrs,
|
||||
const char *nspace, const char *name)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; attrs[n] != NULL; n += 2) {
|
||||
char *pnt = strchr(attrs[n], ':');
|
||||
|
||||
if (!nspace && !pnt && strcmp(attrs[n], name) == 0) {
|
||||
return attrs[n+1];
|
||||
} else if (nspace && pnt) {
|
||||
/* If a namespace is given, and the local part matches,
|
||||
* then resolve the namespace and compare that too. */
|
||||
if (strcmp(pnt + 1, name) == 0) {
|
||||
const char *uri = resolve_nspace(p->current,
|
||||
attrs[n], pnt - attrs[n]);
|
||||
if (uri && strcmp(uri, nspace) == 0)
|
||||
return attrs[n+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ne_xml_mapid(const struct ne_xml_idmap map[], size_t maplen,
|
||||
const char *nspace, const char *name)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
for (n = 0; n < maplen; n++)
|
||||
if (strcmp(name, map[n].name) == 0 &&
|
||||
strcmp(nspace, map[n].nspace) == 0)
|
||||
return map[n].id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user