4 * XML parser abstraction
6 * Copyright (c) 2017, Novell Inc.
8 * This program is licensed under the BSD license, read LICENSE.BSD
9 * for further information
12 #include <sys/types.h>
18 #include <libxml/parser.h>
25 #include "solv_xmlparser.h"
28 add_contentspace(struct solv_xmlparser *xmlp, int l)
30 l += xmlp->lcontent + 1; /* plus room for trailing zero */
31 if (l > xmlp->acontent)
33 xmlp->acontent = l + 256;
34 xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
41 character_data(void *userData, const xmlChar *s, int len)
44 character_data(void *userData, const XML_Char *s, int len)
47 struct solv_xmlparser *xmlp = userData;
49 if (!xmlp->docontent || !len)
51 add_contentspace(xmlp, len);
52 memcpy(xmlp->content + xmlp->lcontent, s, len);
53 xmlp->lcontent += len;
58 start_element(void *userData, const xmlChar *name, const xmlChar **atts)
61 start_element(void *userData, const char *name, const char **atts)
64 struct solv_xmlparser *xmlp = userData;
65 struct solv_xmlparser_element *elements;
67 struct solv_xmlparser_element *el;
75 elementhelper = xmlp->elementhelper;
76 elements = xmlp->elements;
77 oldstate = xmlp->state;
78 for (i = elementhelper[xmlp->nelements + oldstate]; i; i = elementhelper[i - 1])
79 if (!strcmp(elements[i - 1].element, (char *)name))
84 fprintf(stderr, "into unknown: %s\n", name);
89 el = xmlp->elements + i - 1;
90 queue_push(&xmlp->elementq, xmlp->state);
91 xmlp->state = el->tostate;
92 xmlp->docontent = el->docontent;
97 static const char *nullattr;
98 atts = (const xmlChar **)&nullattr;
101 if (xmlp->state != oldstate)
102 xmlp->startelement(xmlp, xmlp->state, el->element, (const char **)atts);
107 end_element(void *userData, const xmlChar *name)
110 end_element(void *userData, const char *name)
113 struct solv_xmlparser *xmlp = userData;
115 if (xmlp->unknowncnt)
122 xmlp->content[xmlp->lcontent] = 0;
123 if (xmlp->elementq.count && xmlp->state != xmlp->elementq.elements[xmlp->elementq.count - 1])
124 xmlp->endelement(xmlp, xmlp->state, xmlp->content);
125 xmlp->state = queue_pop(&xmlp->elementq);
131 solv_xmlparser_init(struct solv_xmlparser *xmlp,
132 struct solv_xmlparser_element *elements,
134 void (*startelement)(struct solv_xmlparser *, int state, const char *name, const char **atts),
135 void (*endelement)(struct solv_xmlparser *, int state, char *content),
136 void (*errorhandler)(struct solv_xmlparser *, const char *errstr, unsigned int line, unsigned int column))
138 int i, nstates, nelements;
139 struct solv_xmlparser_element *el;
142 memset(xmlp, 0, sizeof(*xmlp));
145 for (el = elements; el->element; el++)
148 if (el->fromstate > nstates)
149 nstates = el->fromstate;
150 if (el->tostate > nstates)
151 nstates = el->tostate;
155 xmlp->elements = elements;
156 xmlp->nelements = nelements;
157 elementhelper = solv_calloc(nelements + nstates, sizeof(Id));
158 for (i = nelements - 1; i >= 0; i--)
160 int fromstate = elements[i].fromstate;
161 elementhelper[i] = elementhelper[nelements + fromstate];
162 elementhelper[nelements + fromstate] = i + 1;
164 xmlp->elementhelper = elementhelper;
165 queue_init(&xmlp->elementq);
166 xmlp->acontent = 256;
167 xmlp->content = solv_malloc(xmlp->acontent);
169 xmlp->userdata = userdata;
170 xmlp->startelement = startelement;
171 xmlp->endelement = endelement;
172 xmlp->errorhandler = errorhandler;
176 solv_xmlparser_free(struct solv_xmlparser *xmlp)
178 xmlp->elementhelper = solv_free(xmlp->elementhelper);
179 queue_free(&xmlp->elementq);
180 xmlp->content = solv_free(xmlp->content);
186 create_parser(struct solv_xmlparser *xmlp)
188 /* delayed to parse_block so that we have the first bytes */
193 free_parser(struct solv_xmlparser *xmlp)
196 xmlFreeParserCtxt(xmlp->parser);
200 static xmlParserCtxtPtr create_parser_ctx(struct solv_xmlparser *xmlp, char *buf, int l)
203 memset(&sax, 0, sizeof(sax));
204 sax.startElement = start_element;
205 sax.endElement = end_element;
206 sax.characters = character_data;
207 return xmlCreatePushParserCtxt(&sax, xmlp, buf, l, NULL);
211 parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
215 int l2 = l > 4 ? 4 : 0;
216 xmlp->parser = create_parser_ctx(xmlp, buf, l2);
219 xmlp->errorhandler(xmlp, "could not create parser", 0, 0);
227 if (xmlParseChunk(xmlp->parser, buf, l, l == 0 ? 1 : 0))
229 xmlErrorPtr err = xmlCtxtGetLastError(xmlp->parser);
230 xmlp->errorhandler(xmlp, err->message, err->line, err->int2);
237 solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
239 return (unsigned int)xmlSAX2GetLineNumber(xmlp->parser);
245 create_parser(struct solv_xmlparser *xmlp)
247 xmlp->parser = XML_ParserCreate(NULL);
250 XML_SetUserData(xmlp->parser, xmlp);
251 XML_SetElementHandler(xmlp->parser, start_element, end_element);
252 XML_SetCharacterDataHandler(xmlp->parser, character_data);
257 free_parser(struct solv_xmlparser *xmlp)
259 XML_ParserFree(xmlp->parser);
264 parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
266 if (XML_Parse(xmlp->parser, buf, l, l == 0) == XML_STATUS_ERROR)
268 unsigned int line = XML_GetCurrentLineNumber(xmlp->parser);
269 unsigned int column = XML_GetCurrentColumnNumber(xmlp->parser);
270 xmlp->errorhandler(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), line, column);
277 solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
279 return (unsigned int)XML_GetCurrentLineNumber(xmlp->parser);
285 solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp)
291 xmlp->unknowncnt = 0;
294 queue_empty(&xmlp->elementq);
296 if (!create_parser(xmlp))
298 xmlp->errorhandler(xmlp, "could not create xml parser", 0, 0);
303 l = fread(buf, 1, sizeof(buf), fp);
304 if (!parse_block(xmlp, buf, l) || !l)
311 solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l)
314 if (l > xmlp->acontent)
316 xmlp->acontent = l + 256;
317 xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
319 return xmlp->content;