repodata_diskusage.c)
ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+ SET (libsolvext_SRCS ${libsolvext_SRCS}
+ solv_xmlparser.c)
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
IF (HAVE_LINKER_VERSION_SCRIPT)
SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
#include <string.h>
#include <assert.h>
#include <dirent.h>
-#include <expat.h>
#include <errno.h>
#include "pool.h"
#include "repo.h"
#include "util.h"
+#include "solv_xmlparser.h"
#include "repo_appdata.h"
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "applications", STATE_START, 0 },
{ STATE_START, "components", STATE_START, 0 },
{ STATE_START, "application", STATE_APPLICATION, 0 },
};
struct parsedata {
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Pool *pool;
Repo *repo;
Repodata *data;
-
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
+ int ret;
Solvable *solvable;
Id handle;
+ int skiplang;
char *description;
int licnt;
int skip_depth;
int havesummary;
const char *filename;
Queue *owners;
-};
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- if (!strcmp(*atts, txt))
- return atts[1];
- return 0;
-}
+ struct solv_xmlparser xmlp;
+};
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
- struct stateswitch *sw;
const char *type;
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- pd->depth++;
- if (!pd->swtab[pd->state]) /* no statetable -> no substates */
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
-
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
-
- if (!pd->skip_depth && find_attr("xml:lang", atts))
- pd->skip_depth = pd->depth;
- if (pd->skip_depth)
+ /* ignore all language tags */
+ if (pd->skiplang || solv_xmlparser_find_attr("xml:lang", atts))
{
- pd->docontent = 0;
+ pd->skiplang++;
return;
}
- switch(pd->state)
+ switch(state)
{
case STATE_APPLICATION:
- type = find_attr("type", atts);
+ type = solv_xmlparser_find_attr("type", atts);
if (!type || !*type)
type = "desktop";
if (strcmp(type, "desktop") != 0)
/* replace whitespace with one space/newline */
/* also strip starting/ending whitespace */
-static void
+static char *
wsstrip(struct parsedata *pd)
{
+ struct solv_xmlparser *xmlp = &pd->xmlp;
int i, j;
int ws = 0;
- for (i = j = 0; pd->content[i]; i++)
+ for (i = j = 0; xmlp->content[i]; i++)
{
- if (pd->content[i] == ' ' || pd->content[i] == '\t' || pd->content[i] == '\n')
+ if (xmlp->content[i] == ' ' || xmlp->content[i] == '\t' || xmlp->content[i] == '\n')
{
- ws |= pd->content[i] == '\n' ? 2 : 1;
+ ws |= xmlp->content[i] == '\n' ? 2 : 1;
continue;
}
if (ws && j)
- pd->content[j++] = (ws & 2) ? '\n' : ' ';
+ xmlp->content[j++] = (ws & 2) ? '\n' : ' ';
ws = 0;
- pd->content[j++] = pd->content[i];
+ xmlp->content[j++] = xmlp->content[i];
}
- pd->content[j] = 0;
- pd->lcontent = j;
+ xmlp->content[j] = 0;
+ xmlp->lcontent = j;
+ return xmlp->content;
}
/* indent all lines */
-static void
+static char *
indent(struct parsedata *pd, int il)
{
+ struct solv_xmlparser *xmlp = &pd->xmlp;
int i, l;
- for (l = 0; pd->content[l]; )
+ for (l = 0; xmlp->content[l]; )
{
- if (pd->content[l] == '\n')
+ if (xmlp->content[l] == '\n')
{
l++;
continue;
}
- if (pd->lcontent + il + 1 > pd->acontent)
+ if (xmlp->lcontent + il + 1 > xmlp->acontent)
{
- pd->acontent = pd->lcontent + il + 256;
- pd->content = realloc(pd->content, pd->acontent);
+ xmlp->acontent = xmlp->lcontent + il + 256;
+ xmlp->content = realloc(xmlp->content, xmlp->acontent);
}
- memmove(pd->content + l + il, pd->content + l, pd->lcontent - l + 1);
+ memmove(xmlp->content + l + il, xmlp->content + l, xmlp->lcontent - l + 1);
for (i = 0; i < il; i++)
- pd->content[l + i] = ' ';
- pd->lcontent += il;
- while (pd->content[l] && pd->content[l] != '\n')
+ xmlp->content[l + i] = ' ';
+ xmlp->lcontent += il;
+ while (xmlp->content[l] && xmlp->content[l] != '\n')
l++;
}
+ return xmlp->content;
}
static void
return r;
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
Id id;
-#if 0
- fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
-
- if (pd->skip_depth && pd->depth + 1 >= pd->skip_depth)
+ if (pd->skiplang)
{
- if (pd->depth + 1 == pd->skip_depth)
- pd->skip_depth = 0;
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
+ pd->skiplang--;
return;
}
- pd->skip_depth = 0;
-
if (!s)
- {
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
- return;
- }
+ return;
- switch (pd->state)
+ switch (state)
{
case STATE_APPLICATION:
if (!s->arch)
pd->desktop_file = solv_free(pd->desktop_file);
break;
case STATE_ID:
- pd->desktop_file = solv_strdup(pd->content);
+ pd->desktop_file = solv_strdup(content);
break;
case STATE_NAME:
- s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", pd->content, 0), 1);
+ s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", content, 0), 1);
break;
case STATE_LICENCE:
- repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, pd->content);
+ repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, content);
break;
case STATE_SUMMARY:
pd->havesummary = 1;
- repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content);
break;
case STATE_URL:
- repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, pd->content);
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, content);
break;
case STATE_GROUP:
- repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, pd->content);
+ repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, content);
break;
case STATE_EXTENDS:
- repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, pd->content);
+ repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, content);
break;
case STATE_DESCRIPTION:
if (pd->description)
}
break;
case STATE_P:
- wsstrip(pd);
- pd->description = solv_dupappend(pd->description, pd->content, "\n\n");
+ content = wsstrip(pd);
+ pd->description = solv_dupappend(pd->description, content, "\n\n");
break;
case STATE_UL_LI:
wsstrip(pd);
- indent(pd, 4);
- pd->content[2] = '-';
- pd->description = solv_dupappend(pd->description, pd->content, "\n");
+ content = indent(pd, 4);
+ content[2] = '-';
+ pd->description = solv_dupappend(pd->description, content, "\n");
break;
case STATE_OL_LI:
wsstrip(pd);
- indent(pd, 4);
+ content = indent(pd, 4);
if (++pd->licnt >= 10)
- pd->content[0] = '0' + (pd->licnt / 10) % 10;
- pd->content[1] = '0' + pd->licnt % 10;
- pd->content[2] = '.';
- pd->description = solv_dupappend(pd->description, pd->content, "\n");
+ content[0] = '0' + (pd->licnt / 10) % 10;
+ content[1] = '0' + pd->licnt % 10;
+ content[2] = '.';
+ pd->description = solv_dupappend(pd->description, content, "\n");
break;
case STATE_UL:
case STATE_OL:
pd->description = solv_dupappend(pd->description, "\n", 0);
break;
case STATE_PKGNAME:
- id = pool_str2id(pd->pool, pd->content, 1);
+ id = pool_str2id(pd->pool, content, 1);
s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
- id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", pd->content, ")"), 1);
+ id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", content, ")"), 1);
s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
break;
case STATE_KEYWORD:
- repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, pd->content);
+ repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, content);
break;
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
-
-#if 0
- fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->acontent = l + 256;
- pd->content = realloc(pd->content, pd->acontent);
+ struct parsedata *pd = xmlp->userdata;
+ pool_debug(pd->pool, SOLV_ERROR, "repo_appdata: %s at line %u:%u\n", errstr, line, column);
+ pd->ret = -1;
+ if (pd->solvable)
+ {
+ repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
+ pd->solvable = 0;
}
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
}
-#define BUFF_SIZE 8192
-
static int
repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue *owners)
{
- Pool *pool = repo->pool;
- struct parsedata pd;
- struct stateswitch *sw;
Repodata *data;
- char buf[BUFF_SIZE];
- int i, l;
- int ret = 0;
+ struct parsedata pd;
data = repo_add_repodata(repo, flags);
memset(&pd, 0, sizeof(pd));
pd.filename = filename;
pd.owners = owners;
- pd.content = malloc(256);
- pd.acontent = 256;
-
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
-
- XML_Parser parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pool_error(pool, -1, "repo_appdata: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- if (pd.solvable)
- {
- repo_free_solvable(repo, pd.solvable - pd.pool->solvables, 1);
- pd.solvable = 0;
- }
- ret = -1;
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
+ solv_free(pd.desktop_file);
+ solv_free(pd.description);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
- solv_free(pd.content);
- solv_free(pd.desktop_file);
- solv_free(pd.description);
- return ret;
+ return pd.ret;
}
int
#include <string.h>
#include <assert.h>
#include <dirent.h>
-#include <expat.h>
#include "pool.h"
#include "repo.h"
#include "util.h"
+#include "solv_xmlparser.h"
#define DISABLE_SPLIT
#include "tools_util.h"
#include "repo_comps.h"
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-/* must be sorted by first column */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "comps", STATE_COMPS, 0 },
{ STATE_COMPS, "group", STATE_GROUP, 0 },
{ STATE_COMPS, "category", STATE_CATEGORY, 0 },
{ STATE_GROUP, "lang_only", STATE_LANG_ONLY, 1 },
{ STATE_GROUP, "packagelist", STATE_PACKAGELIST, 0 },
{ STATE_PACKAGELIST, "packagereq", STATE_PACKAGEREQ, 1 },
- { STATE_CATEGORY, "id", STATE_CID, 1 },
- { STATE_CATEGORY, "name", STATE_CNAME, 1 },
- { STATE_CATEGORY, "description", STATE_CDESCRIPTION, 1 },
+ { STATE_CATEGORY, "id", STATE_ID, 1 },
+ { STATE_CATEGORY, "name", STATE_NAME, 1 },
+ { STATE_CATEGORY, "description", STATE_DESCRIPTION, 1 },
{ STATE_CATEGORY , "grouplist", STATE_GROUPLIST, 0 },
- { STATE_CATEGORY , "display_order", STATE_CDISPLAY_ORDER, 1 },
+ { STATE_CATEGORY , "display_order", STATE_DISPLAY_ORDER, 1 },
{ STATE_GROUPLIST, "groupid", STATE_GROUPID, 1 },
{ NUMSTATES }
};
Repodata *data;
const char *filename;
const char *basename;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
-
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
+
+ struct solv_xmlparser xmlp;
struct joindata jd;
const char *tmplang;
Id condreq;
Solvable *solvable;
+ const char *kind;
Id handle;
};
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
-}
-
-
-/*
- * XML callback: startElement
- */
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
- struct stateswitch *sw;
-
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- pd->depth++;
- if (!pd->swtab[pd->state]) /* no statetable -> no substates */
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
-
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
- switch(pd->state)
+ switch(state)
{
case STATE_GROUP:
case STATE_CATEGORY:
s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
pd->handle = s - pool->solvables;
+ pd->kind = state == STATE_GROUP ? "group" : "category";
break;
case STATE_NAME:
case STATE_CNAME:
case STATE_DESCRIPTION:
case STATE_CDESCRIPTION:
- pd->tmplang = join_dup(&pd->jd, find_attr("xml:lang", atts));
+ pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("xml:lang", atts));
break;
case STATE_PACKAGEREQ:
{
- const char *type = find_attr("type", atts);
+ const char *type = solv_xmlparser_find_attr("type", atts);
pd->condreq = 0;
pd->reqtype = SOLVABLE_RECOMMENDS;
if (type && !strcmp(type, "conditional"))
{
- const char *requires = find_attr("requires", atts);
+ const char *requires = solv_xmlparser_find_attr("requires", atts);
if (requires && *requires)
pd->condreq = pool_str2id(pool, requires, 1);
}
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Solvable *s = pd->solvable;
Id id;
-#if 0
- fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
-
- switch (pd->state)
+ switch (state)
{
case STATE_GROUP:
case STATE_CATEGORY:
break;
case STATE_ID:
- case STATE_CID:
- s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->state == STATE_ID ? "group" : "category", ":", pd->content), 1);
+ s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->kind, ":", content), 1);
break;
case STATE_NAME:
- case STATE_CNAME:
- repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
+ repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
break;
case STATE_DESCRIPTION:
- case STATE_CDESCRIPTION:
- repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content);
+ repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
break;
case STATE_PACKAGEREQ:
- id = pool_str2id(pd->pool, pd->content, 1);
+ id = pool_str2id(pd->pool, content, 1);
if (pd->condreq)
id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1);
repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id);
break;
case STATE_GROUPID:
- id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", pd->content), 1);
+ id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", content), 1);
s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
break;
break;
case STATE_DISPLAY_ORDER:
- case STATE_CDISPLAY_ORDER:
- repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, pd->content);
- break;
-
- case STATE_DEFAULT:
- break;
-
- case STATE_LANGONLY:
- case STATE_LANG_ONLY:
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, content);
break;
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
-
-#if 0
- fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pool_debug(pd->pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", errstr, line, column);
}
-#define BUFF_SIZE 8192
-
int
repo_add_comps(Repo *repo, FILE *fp, int flags)
{
Repodata *data;
struct parsedata pd;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
- XML_Parser parser;
data = repo_add_repodata(repo, flags);
pd.repo = repo;
pd.pool = repo->pool;
pd.data = data;
-
- pd.content = solv_malloc(256);
- pd.acontent = 256;
-
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
-
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
-
- solv_free(pd.content);
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
join_freemem(&pd.jd);
if (!(flags & REPO_NO_INTERNALIZE))
* for further information
*/
-#define DO_ARRAY 1
-
#define _GNU_SOURCE
#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <expat.h>
#include "pool.h"
#include "repo.h"
#include "chksum.h"
+#include "solv_xmlparser.h"
#include "repo_deltainfoxml.h"
/*
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
/* compatibility with old yum-presto */
{ STATE_START, "prestodelta", STATE_START, 0 },
{ STATE_START, "deltainfo", STATE_START, 0 },
struct parsedata {
int ret;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Pool *pool;
Repo *repo;
Repodata *data;
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
struct deltarpm delta;
Id newpkgevr;
Id newpkgname;
Id *handles;
int nhandles;
-};
-/*
- * find attribute
- */
-
-static const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
-}
+ struct solv_xmlparser xmlp;
+};
/*
makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
{
const char *e, *v, *r, *v2;
- char *c;
+ char *c, *space;
int l;
e = v = r = 0;
l += strlen(v);
if (r)
l += strlen(r) + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content;
+ c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
if (e)
{
strcpy(c, e);
c += strlen(c);
}
*c = 0;
- if (!*pd->content)
+ if (!*space)
return 0;
#if 0
- fprintf(stderr, "evr: %s\n", pd->content);
+ fprintf(stderr, "evr: %s\n", space);
#endif
- return pool_str2id(pool, pd->content, 1);
+ return pool_str2id(pool, space, 1);
}
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
- struct stateswitch *sw;
const char *str;
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- pd->depth++;
- if (!pd->swtab[pd->state])
- return;
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
- if (sw->from != pd->state)
+ switch(state)
{
-#if 0
- fprintf(stderr, "into unknown: [%d]%s (from: %d)\n", sw->to, name, sw->from);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
-
- switch(pd->state)
- {
- case STATE_START:
- break;
case STATE_NEWPACKAGE:
- if ((str = find_attr("name", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("name", atts)) != 0)
pd->newpkgname = pool_str2id(pool, str, 1);
pd->newpkgevr = makeevr_atts(pool, pd, atts);
- if ((str = find_attr("arch", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("arch", atts)) != 0)
pd->newpkgarch = pool_str2id(pool, str, 1);
break;
pd->delta.bevr = solv_extend(pd->delta.bevr, pd->delta.nbevr, 1, sizeof(Id), 7);
pd->delta.bevr[pd->delta.nbevr++] = makeevr_atts(pool, pd, atts);
break;
+
case STATE_FILENAME:
- if ((str = find_attr("xml:base", atts)))
+ if ((str = solv_xmlparser_find_attr("xml:base", atts)))
pd->delta.locbase = solv_strdup(str);
break;
+
case STATE_LOCATION:
- pd->delta.location = solv_strdup(find_attr("href", atts));
- if ((str = find_attr("xml:base", atts)))
+ pd->delta.location = solv_strdup(solv_xmlparser_find_attr("href", atts));
+ if ((str = solv_xmlparser_find_attr("xml:base", atts)))
pd->delta.locbase = solv_strdup(str);
break;
- case STATE_SIZE:
- break;
+
case STATE_CHECKSUM:
pd->delta.filechecksum = 0;
pd->delta.filechecksumtype = REPOKEY_TYPE_SHA1;
- if ((str = find_attr("type", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("type", atts)) != 0)
{
pd->delta.filechecksumtype = solv_chksum_str2type(str);
if (!pd->delta.filechecksumtype)
pool_debug(pool, SOLV_ERROR, "unknown checksum type: '%s'\n", str);
}
break;
- case STATE_SEQUENCE:
- break;
+
default:
break;
}
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
const char *str;
-#if 0
- fprintf(stderr, "end: %s\n", name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
- switch (pd->state)
+ switch (state)
{
- case STATE_START:
- break;
- case STATE_NEWPACKAGE:
- break;
case STATE_DELTA:
{
/* read all data for a deltarpm. commit into attributes */
pd->delta.locbase = solv_free(pd->delta.locbase);
break;
case STATE_FILENAME:
- pd->delta.location = solv_strdup(pd->content);
+ pd->delta.location = solv_strdup(content);
break;
case STATE_CHECKSUM:
- pd->delta.filechecksum = solv_strdup(pd->content);
+ pd->delta.filechecksum = solv_strdup(content);
break;
case STATE_SIZE:
- pd->delta.downloadsize = strtoull(pd->content, 0, 10);
+ pd->delta.downloadsize = strtoull(content, 0, 10);
break;
case STATE_SEQUENCE:
- if ((str = pd->content))
+ if ((str = content) != 0)
{
const char *s1, *s2;
s1 = strrchr(str, '-');
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pd->ret = pool_error(pd->pool, -1, "repo_deltainfoxml: %s at line %u:%u", errstr, line, column);
}
-#define BUFF_SIZE 8192
-
int
repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
{
Pool *pool = repo->pool;
- struct parsedata pd;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
Repodata *data;
- XML_Parser parser;
+ struct parsedata pd;
+ int i;
data = repo_add_repodata(repo, flags);
memset(&pd, 0, sizeof(pd));
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
pd.pool = pool;
pd.repo = repo;
pd.data = data;
-
- pd.content = solv_malloc(256);
- pd.acontent = 256;
- pd.lcontent = 0;
-
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
- solv_free(pd.content);
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
/* now commit all handles */
if (!pd.ret)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <expat.h>
+#include "queue.h"
+#include "solv_xmlparser.h"
#include "repo_helix.h"
#include "evr.h"
STATE_PATCH,
STATE_PRODUCT,
- STATE_PEPOCH,
- STATE_PVERSION,
- STATE_PRELEASE,
- STATE_PARCH,
-
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "channel", STATE_CHANNEL, 0 },
{ STATE_CHANNEL, "subchannel", STATE_SUBCHANNEL, 0 },
{ STATE_SUBCHANNEL, "package", STATE_PACKAGE, 0 },
{ STATE_PACKAGE, "name", STATE_NAME, 1 },
{ STATE_PACKAGE, "vendor", STATE_VENDOR, 1 },
{ STATE_PACKAGE, "buildtime", STATE_BUILDTIME, 1 },
- { STATE_PACKAGE, "epoch", STATE_PEPOCH, 1 },
- { STATE_PACKAGE, "version", STATE_PVERSION, 1 },
- { STATE_PACKAGE, "release", STATE_PRELEASE, 1 },
- { STATE_PACKAGE, "arch", STATE_PARCH, 1 },
+ { STATE_PACKAGE, "epoch", STATE_EPOCH, 1 },
+ { STATE_PACKAGE, "version", STATE_VERSION, 1 },
+ { STATE_PACKAGE, "release", STATE_RELEASE, 1 },
+ { STATE_PACKAGE, "arch", STATE_ARCH, 1 },
{ STATE_PACKAGE, "history", STATE_HISTORY, 0 },
{ STATE_PACKAGE, "provides", STATE_PROVIDES, 0 },
{ STATE_PACKAGE, "requires", STATE_REQUIRES, 0 },
{ STATE_PACKAGE, "suggests", STATE_SUGGESTS, 0 },
{ STATE_PACKAGE, "enhances", STATE_ENHANCES, 0 },
{ STATE_PACKAGE, "freshens", STATE_FRESHENS, 0 },
+ { STATE_PACKAGE, "deps", STATE_PACKAGE, 0 }, /* ignore deps element */
{ STATE_HISTORY, "update", STATE_UPDATE, 0 },
{ STATE_UPDATE, "epoch", STATE_EPOCH, 1 },
* parser data
*/
-typedef struct _parsedata {
+struct parsedata {
int ret;
- /* XML parser data */
- int depth;
- enum state state; /* current state */
- int statedepth;
- char *content; /* buffer for content of node */
- int lcontent; /* actual length of current content */
- int acontent; /* actual buffer size */
- int docontent; /* handle content */
-
/* repo data */
Pool *pool; /* current pool */
Repo *repo; /* current repo */
Offset freshens; /* current freshens vector */
/* package data */
+ int srcpackage; /* is srcpackage element */
int epoch; /* epoch (as offset into evrspace) */
int version; /* version (as offset into evrspace) */
int release; /* release (as offset into evrspace) */
int levrspace; /* actual evr length */
char *kind;
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
-} Parsedata;
+ struct solv_xmlparser xmlp;
+};
/*------------------------------------------------------------------*/
/* create Id from epoch:version-release */
static Id
-evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
+evr2id(Pool *pool, struct parsedata *pd, const char *e, const char *v, const char *r)
{
- char *c;
+ char *c, *space;
int l;
/* treat explitcit 0 as NULL */
if (r)
l += strlen(r) + 1; /* -r */
- /* extend content if not sufficient */
- if (l > pd->acontent)
- {
- pd->content = (char *)realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
+ /* get content space */
+ c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
- /* copy e-v-r to content */
- c = pd->content;
+ /* copy e-v-r */
if (e)
{
strcpy(c, e);
}
*c = 0;
/* if nothing inserted, return Id 0 */
- if (!*pd->content)
- return ID_NULL;
+ if (!*space)
+ return 0;
#if 0
- fprintf(stderr, "evr: %s\n", pd->content);
+ fprintf(stderr, "evr: %s\n", space);
#endif
/* intern and create */
- return pool_str2id(pool, pd->content, 1);
+ return pool_str2id(pool, space, 1);
}
* odd index is value
*/
static Id
-evr_atts2id(Pool *pool, Parsedata *pd, const char **atts)
+evr_atts2id(Pool *pool, struct parsedata *pd, const char **atts)
{
const char *e, *v, *r;
e = v = r = 0;
*/
static unsigned int
-adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
+adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
{
Id id, name;
const char *n, *f, *k;
if (k) /* if kind!=package, intern <kind>:<name> */
{
int l = strlen(k) + 1 + strlen(n) + 1;
- if (l > pd->acontent) /* extend buffer if needed */
- {
- pd->content = (char *)realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- sprintf(pd->content, "%s:%s", k, n);
- name = pool_str2id(pool, pd->content, 1);
+ char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
+ sprintf(space, "%s:%s", k, n);
+ name = pool_str2id(pool, space, 1);
}
else
{
/*----------------------------------------------------------------*/
-/*
- * XML callback
- * <name>
- *
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- Parsedata *pd = (Parsedata *)userData;
- struct stateswitch *sw;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- /* ignore deps element */
- if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
- return;
-
- pd->depth++;
-
- /* find node name in stateswitch */
- if (!pd->swtab[pd->state])
- return;
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
- {
- if (!strcmp(sw->ename, name))
- break;
- }
-
- /* check if we're at the right level */
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s\n", name);
-#endif
- return;
- }
-
- /* set new state */
- pd->state = sw->to;
-
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
-
- /* start with empty content */
- /* (will collect data until end element) */
- pd->lcontent = 0;
- *pd->content = 0;
-
- switch (pd->state)
+ switch (state)
{
case STATE_NAME:
if (pd->kind) /* if kind is set (non package) */
{
- strcpy(pd->content, pd->kind);
- pd->lcontent = strlen(pd->content);
- pd->content[pd->lcontent++] = ':'; /* prefix name with '<kind>:' */
- pd->content[pd->lcontent] = 0;
+ strcpy(xmlp->content, pd->kind);
+ xmlp->lcontent = strlen(xmlp->content);
+ xmlp->content[xmlp->lcontent++] = ':'; /* prefix name with '<kind>:' */
+ xmlp->content[xmlp->lcontent] = 0;
}
break;
case STATE_PACKAGE: /* solvable name */
pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+ pd->srcpackage = 0;
+ pd->kind = NULL; /* default is (src)package */
if (!strcmp(name, "selection"))
pd->kind = "selection";
else if (!strcmp(name, "pattern"))
pd->kind = "patch";
else if (!strcmp(name, "application"))
pd->kind = "application";
- else
- pd->kind = NULL; /* default is package */
+ else if (!strcmp(name, "srcpackage"))
+ pd->srcpackage = 1;
pd->levrspace = 1;
pd->epoch = 0;
pd->version = 0;
}
}
-static const char *findKernelFlavor(Parsedata *pd, Solvable *s)
+static const char *
+findKernelFlavor(struct parsedata *pd, Solvable *s)
{
Pool *pool = pd->pool;
Id pid, *pidp;
}
-/*
- * XML callback
- * </name>
- *
- * create Solvable from collected data
- */
-
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- Parsedata *pd = (Parsedata *)userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
Id evr;
unsigned int t = 0;
const char *flavor;
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
- /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
- return;
- }
-
- /* ignore deps element */
- if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
- return;
-
- pd->depth--;
- pd->statedepth--;
- switch (pd->state)
+ switch (state)
{
case STATE_PACKAGE: /* package complete */
- if (name[0] == 's' && name[1] == 'r' && name[2] == 'c' && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+ if (pd->srcpackage && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
s->arch = ARCH_SRC;
if (!s->arch) /* default to "noarch" */
s->arch = ARCH_NOARCH;
}
break;
case STATE_NAME:
- s->name = pool_str2id(pool, pd->content, 1);
+ s->name = pool_str2id(pool, content, 1);
break;
case STATE_VENDOR:
- s->vendor = pool_str2id(pool, pd->content, 1);
+ s->vendor = pool_str2id(pool, content, 1);
break;
case STATE_BUILDTIME:
- t = atoi (pd->content);
+ t = atoi(content);
if (t)
repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
break;
case STATE_EPOCH:
case STATE_VERSION:
case STATE_RELEASE:
- case STATE_PEPOCH:
- case STATE_PVERSION:
- case STATE_PRELEASE:
/* ensure buffer space */
- if (pd->lcontent + 1 + pd->levrspace > pd->aevrspace)
+ if (xmlp->lcontent + 1 + pd->levrspace > pd->aevrspace)
{
- pd->evrspace = (char *)realloc(pd->evrspace, pd->lcontent + 1 + pd->levrspace + 256);
- pd->aevrspace = pd->lcontent + 1 + pd->levrspace + 256;
+ pd->aevrspace = xmlp->lcontent + 1 + pd->levrspace + 256;
+ pd->evrspace = (char *)realloc(pd->evrspace, pd->aevrspace);
}
- memcpy(pd->evrspace + pd->levrspace, pd->content, pd->lcontent + 1);
- if (pd->state == STATE_EPOCH || pd->state == STATE_PEPOCH)
+ memcpy(pd->evrspace + pd->levrspace, xmlp->content, xmlp->lcontent + 1);
+ if (state == STATE_EPOCH)
pd->epoch = pd->levrspace;
- else if (pd->state == STATE_VERSION || pd->state == STATE_PVERSION)
+ else if (state == STATE_VERSION)
pd->version = pd->levrspace;
else
pd->release = pd->levrspace;
- pd->levrspace += pd->lcontent + 1;
+ pd->levrspace += xmlp->lcontent + 1;
break;
case STATE_ARCH:
- case STATE_PARCH:
- s->arch = pool_str2id(pool, pd->content, 1);
+ s->arch = pool_str2id(pool, content, 1);
break;
default:
break;
}
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
- /* printf("back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
}
-
-/*
- * XML callback
- * character data
- *
- */
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- Parsedata *pd = (Parsedata *)userData;
- int l;
- char *c;
-
- /* check if current nodes content is interesting */
- if (!pd->docontent)
- return;
-
- /* adapt content buffer */
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = (char *)realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- /* append new content to buffer */
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pd->ret = pool_error(pd->pool, -1, "%s at line %u", errstr, line);
}
-/*-------------------------------------------------------------------*/
-#define BUFF_SIZE 8192
+/*-------------------------------------------------------------------*/
/*
* read 'helix' type xml from fp
repo_add_helix(Repo *repo, FILE *fp, int flags)
{
Pool *pool = repo->pool;
- Parsedata pd;
+ struct parsedata pd;
Repodata *data;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
unsigned int now;
- XML_Parser parser;
now = solv_timems(0);
data = repo_add_repodata(repo, flags);
/* prepare parsedata */
memset(&pd, 0, sizeof(pd));
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
-
pd.pool = pool;
pd.repo = repo;
-
- pd.content = (char *)malloc(256); /* must hold all solvable kinds! */
- pd.acontent = 256;
- pd.lcontent = 0;
-
- pd.evrspace = (char *)malloc(256);
- pd.aevrspace= 256;
- pd.levrspace = 1;
pd.data = data;
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
- /* set up XML parser */
+ pd.evrspace = (char *)solv_malloc(256);
+ pd.aevrspace = 256;
+ pd.levrspace = 1;
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd); /* make parserdata available to XML callbacks */
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
- /* read/parse XML file */
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pd.ret = pool_error(pool, -1, "%s at line %u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
- free(pd.content);
- free(pd.evrspace);
+ solv_free(pd.evrspace);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <expat.h>
#include "pool.h"
#include "repo.h"
#include "util.h"
#include "chksum.h"
+#include "solv_xmlparser.h"
#include "repo_mdk.h"
static Offset
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-/* must be sorted by first column */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "media_info", STATE_MEDIA_INFO, 0 },
{ STATE_MEDIA_INFO, "info", STATE_INFO, 1 },
{ STATE_MEDIA_INFO, "files", STATE_FILES, 1 },
Pool *pool;
Repo *repo;
Repodata *data;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
Solvable *solvable;
Hashtable joinhash;
Hashval joinhashmask;
+ struct solv_xmlparser xmlp;
};
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
-}
-
static Hashtable
joinhash_init(Repo *repo, Hashval *hmp)
{
return 0;
}
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
- struct stateswitch *sw;
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
- pd->depth++;
- if (!pd->swtab[pd->state])
- return;
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
- if (!strcmp(sw->ename, name))
- break;
- if (sw->from != pd->state)
- return;
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
- switch (pd->state)
+ switch (state)
{
case STATE_INFO:
{
- const char *fn = find_attr("fn", atts);
- const char *distepoch = find_attr("distepoch", atts);
+ const char *fn = solv_xmlparser_find_attr("fn", atts);
+ const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
const char *str;
pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
if (!pd->solvable)
break;
- str = find_attr("url", atts);
+ str = solv_xmlparser_find_attr("url", atts);
if (str && *str)
repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str);
- str = find_attr("license", atts);
+ str = solv_xmlparser_find_attr("license", atts);
if (str && *str)
repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str);
- str = find_attr("sourcerpm", atts);
+ str = solv_xmlparser_find_attr("sourcerpm", atts);
if (str && *str)
repodata_set_sourcepkg(pd->data, pd->solvable - pool->solvables, str);
break;
}
case STATE_FILES:
{
- const char *fn = find_attr("fn", atts);
- const char *distepoch = find_attr("distepoch", atts);
+ const char *fn = solv_xmlparser_find_attr("fn", atts);
+ const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
break;
}
}
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Solvable *s = pd->solvable;
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
- return;
- }
- pd->depth--;
- pd->statedepth--;
- switch (pd->state)
+ switch (state)
{
case STATE_INFO:
- if (s && *pd->content)
- repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, pd->content);
+ if (s && *content)
+ repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, content);
break;
case STATE_FILES:
- if (s && *pd->content)
+ if (s && *content)
{
char *np, *p, *sl;
- for (p = pd->content; p && *p; p = np)
+ for (p = content; p && *p; p = np)
{
Id id;
np = strchr(p, '\n');
default:
break;
}
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
}
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pool_debug(pd->pool, SOLV_ERROR, "%s at line %u:%u\n", errstr, line, column);
}
-#define BUFF_SIZE 8192
int
repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
{
Repodata *data;
struct parsedata pd;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
- XML_Parser parser;
if (!(flags & REPO_EXTEND_SOLVABLES))
{
pd.repo = repo;
pd.pool = repo->pool;
pd.data = data;
-
- pd.content = solv_malloc(256);
- pd.acontent = 256;
-
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
-
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
-
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
- solv_free(pd.content);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
solv_free(pd.joinhash);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
#include <string.h>
#include <assert.h>
#include <dirent.h>
-#include <expat.h>
#include "pool.h"
#include "repo.h"
#include "util.h"
+#include "solv_xmlparser.h"
#define DISABLE_SPLIT
#include "tools_util.h"
#include "repo_content.h"
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "product", STATE_PRODUCT, 0 },
{ STATE_PRODUCT, "vendor", STATE_VENDOR, 1 },
{ STATE_PRODUCT, "name", STATE_NAME, 1 },
struct parsedata {
const char *filename;
const char *basename;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Pool *pool;
Repo *repo;
Repodata *data;
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
+ struct solv_xmlparser xmlp;
struct joindata jd;
const char *tmplang;
};
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
-}
-
static time_t
datestr2timestamp(const char *date)
{
return timegm(&tm);
}
-/*
- * XML callback: startElement
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
- struct stateswitch *sw;
-
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- pd->depth++;
- if (!pd->swtab[pd->state]) /* no statetable -> no substates */
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
-
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
- switch(pd->state)
+ switch(state)
{
case STATE_PRODUCT:
/* parse 'schemeversion' and store in global variable */
{
- const char * scheme = find_attr("schemeversion", atts);
+ const char * scheme = solv_xmlparser_find_attr("schemeversion", atts);
pd->productscheme = (scheme && *scheme) ? atoi(scheme) : -1;
}
if (!s)
/* <summary lang="xy">... */
case STATE_SUMMARY:
case STATE_DESCRIPTION:
- pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
+ pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
break;
case STATE_URL:
- pd->urltype = pool_str2id(pd->pool, find_attr("name", atts), 1);
+ pd->urltype = pool_str2id(pd->pool, solv_xmlparser_find_attr("name", atts), 1);
break;
case STATE_REGUPDREPO:
{
- const char *repoid = find_attr("repoid", atts);
+ const char *repoid = solv_xmlparser_find_attr("repoid", atts);
if (repoid && *repoid)
{
Id h = repodata_new_handle(pd->data);
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Solvable *s = pd->solvable;
-#if 0
- fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
-
- switch (pd->state)
+ switch (state)
{
case STATE_PRODUCT:
/* product done, finish solvable */
pd->solvable = 0;
break;
case STATE_VENDOR:
- s->vendor = pool_str2id(pd->pool, pd->content, 1);
+ s->vendor = pool_str2id(pd->pool, content, 1);
break;
case STATE_NAME:
- s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1);
+ s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1);
break;
case STATE_VERSION:
- pd->tmpvers = solv_strdup(pd->content);
+ pd->tmpvers = solv_strdup(content);
break;
case STATE_RELEASE:
- pd->tmprel = solv_strdup(pd->content);
+ pd->tmprel = solv_strdup(content);
break;
case STATE_ARCH:
- s->arch = pool_str2id(pd->pool, pd->content, 1);
+ s->arch = pool_str2id(pd->pool, content, 1);
break;
case STATE_PRODUCTLINE:
- repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, pd->content);
+ repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, content);
break;
case STATE_UPDATEREPOKEY:
/** obsolete **/
break;
case STATE_SUMMARY:
- repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
+ repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
break;
case STATE_SHORTSUMMARY:
- repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, pd->content);
+ repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, content);
break;
case STATE_DESCRIPTION:
- repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content);
+ repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
break;
case STATE_URL:
if (pd->urltype)
{
- repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content);
+ repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, content);
repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, pd->urltype);
}
break;
case STATE_TARGET:
- repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, pd->content);
+ repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, content);
break;
case STATE_REGRELEASE:
- repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, pd->content);
+ repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, content);
break;
case STATE_REGFLAVOR:
- repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, pd->content);
+ repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, content);
break;
case STATE_CPEID:
- if (*pd->content)
- repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, pd->content);
+ if (*content)
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, content);
break;
case STATE_ENDOFLIFE:
/* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */
- repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (*pd->content ? datestr2timestamp(pd->content) : 0));
+ repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (*content ? datestr2timestamp(content) : 0));
break;
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
-
-#if 0
- fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-
-/*
- * add single product to repo
- *
- */
-
static void
-add_code11_product(struct parsedata *pd, FILE *fp)
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- char buf[BUFF_SIZE];
- int l;
- struct stat st;
- XML_Parser parser;
-
- if (!fstat(fileno(fp), &st))
- {
- pd->currentproduct = st.st_ino;
- pd->ctime = (unsigned int)st.st_ctime;
- }
- else
- {
- pd->currentproduct = pd->baseproduct + 1; /* make it != baseproduct if stat fails */
- pool_error(pd->pool, 0, "fstat: %s", strerror(errno));
- pd->ctime = 0;
- }
-
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
-
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- XML_ParserFree(parser);
- if (pd->solvable)
- {
- repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
- pd->solvable = 0;
- }
- return;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
+ struct parsedata *pd = xmlp->userdata;
+ pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, errstr, line, column);
+ if (pd->solvable)
+ {
+ repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
+ pd->solvable = 0;
+ }
}
{
Repodata *data;
struct parsedata pd;
- struct stateswitch *sw;
DIR *dir;
- int i;
data = repo_add_repodata(repo, flags);
pd.pool = repo->pool;
pd.data = data;
- pd.content = solv_malloc(256);
- pd.acontent = 256;
-
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
if (flags & REPO_USE_ROOTDIR)
dirpath = pool_prepend_rootdir(repo->pool, dirpath);
pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
continue;
}
+ if (fstat(fileno(fp), &st))
+ {
+ pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
+ fclose(fp);
+ continue;
+ }
+ pd.currentproduct = st.st_ino;
+ pd.ctime = (unsigned int)st.st_ctime;
pd.filename = fullpath;
pd.basename = entry->d_name;
- add_code11_product(&pd, fp);
+ solv_xmlparser_parse(&pd.xmlp, fp);
fclose(fp);
}
closedir(dir);
}
- solv_free(pd.content);
+ solv_xmlparser_free(&pd.xmlp);
join_freemem(&pd.jd);
if (flags & REPO_USE_ROOTDIR)
solv_free((char *)dirpath);
* for further information
*/
-#define DO_ARRAY 1
-
#define _GNU_SOURCE
#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <expat.h>
#include "pool.h"
#include "repo.h"
#include "chksum.h"
+#include "solv_xmlparser.h"
#include "repo_repomdxml.h"
/*
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
/* suseinfo tags */
{ STATE_START, "repomd", STATE_REPOMD, 0 },
{ STATE_START, "suseinfo", STATE_SUSEINFO, 0 },
struct parsedata {
int ret;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Pool *pool;
Repo *repo;
Repodata *data;
- XML_Parser *parser;
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
+ struct solv_xmlparser xmlp;
+
int timestamp;
/* handles for collection
structures */
Id chksumtype;
};
-/*
- * find attribute
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
-}
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
- /*Pool *pool = pd->pool;*/
- struct stateswitch *sw;
-
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
+ struct parsedata *pd = xmlp->userdata;
- pd->depth++;
- if (!pd->swtab[pd->state])
- return;
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
-
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
-
- switch(pd->state)
+ switch(state)
{
case STATE_REPOMD:
{
const char *updstr;
/* this should be OBSOLETE soon */
- updstr = find_attr("updates", atts);
+ updstr = solv_xmlparser_find_attr("updates", atts);
if (updstr)
{
char *value = solv_strdup(updstr);
repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value);
value = p;
}
- free(fvalue);
+ solv_free(fvalue);
}
break;
}
{
/* this is extra metadata about the product this repository
was designed for */
- const char *cpeid = find_attr("cpeid", atts);
+ const char *cpeid = solv_xmlparser_find_attr("cpeid", atts);
pd->rphandle = repodata_new_handle(pd->data);
/* set the cpeid for the product
the label is set in the content of the tag */
{
/* this is extra metadata about the product this repository
was designed for */
- const char *cpeid = find_attr("cpeid", atts);
+ const char *cpeid = solv_xmlparser_find_attr("cpeid", atts);
pd->ruhandle = repodata_new_handle(pd->data);
/* set the cpeid for the product
the label is set in the content of the tag */
}
case STATE_DATA:
{
- const char *type= find_attr("type", atts);
+ const char *type= solv_xmlparser_find_attr("type", atts);
pd->rdhandle = repodata_new_handle(pd->data);
if (type)
repodata_set_poolstr(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TYPE, type);
}
case STATE_LOCATION:
{
- const char *href = find_attr("href", atts);
+ const char *href = solv_xmlparser_find_attr("href", atts);
if (href)
repodata_set_str(pd->data, pd->rdhandle, REPOSITORY_REPOMD_LOCATION, href);
break;
case STATE_CHECKSUM:
case STATE_OPENCHECKSUM:
{
- const char *type= find_attr("type", atts);
+ const char *type= solv_xmlparser_find_attr("type", atts);
pd->chksumtype = type && *type ? solv_chksum_str2type(type) : 0;
if (!pd->chksumtype)
- pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), type ? type : "NULL");
+ pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), type ? type : "NULL");
break;
}
default:
return;
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
- /* Pool *pool = pd->pool; */
-
-#if 0
- fprintf(stderr, "endElement: %s\n", name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
- switch (pd->state)
+ struct parsedata *pd = xmlp->userdata;
+ switch (state)
{
case STATE_REPOMD:
if (pd->timestamp > 0)
case STATE_OPENCHECKSUM:
if (!pd->chksumtype)
break;
- if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype))
- pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype));
+ if (strlen(content) != 2 * solv_chksum_len(pd->chksumtype))
+ pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype));
else
- repodata_set_checksum(pd->data, pd->rdhandle, pd->state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, pd->content);
+ repodata_set_checksum(pd->data, pd->rdhandle, state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, content);
break;
case STATE_TIMESTAMP:
* of all resources to save it as the time
* the metadata was generated
*/
- int timestamp = atoi(pd->content);
+ int timestamp = atoi(content);
if (timestamp)
repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TIMESTAMP, timestamp);
if (timestamp > pd->timestamp)
}
case STATE_EXPIRE:
{
- int expire = atoi(pd->content);
+ int expire = atoi(content);
if (expire > 0)
repodata_set_num(pd->data, SOLVID_META, REPOSITORY_EXPIRE, expire);
break;
/* repomd.xml content and suseinfo.xml keywords are equivalent */
case STATE_CONTENT:
case STATE_KEYWORD:
- if (*pd->content)
- repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, pd->content);
+ if (*content)
+ repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, content);
break;
case STATE_REVISION:
- if (*pd->content)
- repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, pd->content);
+ if (*content)
+ repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, content);
break;
case STATE_DISTRO:
/* distro tag is used in repomd.xml to say the product this repo is
made for */
- if (*pd->content)
- repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, pd->content);
+ if (*content)
+ repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, content);
repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_DISTROS, pd->rphandle);
break;
case STATE_UPDATES:
/* updates tag is used in suseinfo.xml to say the repo updates a product
however it s not yet a tag standarized for repomd.xml */
- if (*pd->content)
- repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, pd->content);
+ if (*content)
+ repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, content);
repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_UPDATES, pd->ruhandle);
break;
case STATE_REPO:
- if (*pd->content)
- repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, pd->content);
+ if (*content)
+ repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, content);
break;
case STATE_SIZE:
- if (*pd->content)
- repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(pd->content, 0, 10));
+ if (*content)
+ repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(content, 0, 10));
break;
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
-
- return;
}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pd->ret = pool_error(pd->pool, -1, "repo_repomdxml: %s at line %u:%u", errstr, line, column);
}
-#define BUFF_SIZE 8192
-
int
repo_add_repomdxml(Repo *repo, FILE *fp, int flags)
{
Pool *pool = repo->pool;
struct parsedata pd;
Repodata *data;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
- XML_Parser parser;
data = repo_add_repodata(repo, flags);
memset(&pd, 0, sizeof(pd));
pd.timestamp = 0;
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
pd.pool = pool;
pd.repo = repo;
pd.data = data;
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
- pd.content = malloc(256);
- pd.acontent = 256;
- pd.lcontent = 0;
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- pd.parser = &parser;
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pd.ret = pool_error(pool, -1, "repo_repomdxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
- free(pd.content);
return pd.ret;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <expat.h>
#include "pool.h"
#include "repo.h"
#include "tools_util.h"
#include "repo_rpmmd.h"
#include "chksum.h"
+#include "solv_xmlparser.h"
#ifdef ENABLE_COMPLEX_DEPS
#include "pool_parserpmrichdep.h"
#endif
STATE_OPTIONALURL,
STATE_FLAG,
- /* rpm-md dependencies inside the
- format tag */
+ /* rpm-md dependencies inside the format tag */
STATE_PROVIDES,
STATE_REQUIRES,
STATE_OBSOLETES,
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-static struct stateswitch stateswitches[] = {
- /** fake tag used to enclose 2 different xml files in one **/
+static struct solv_xmlparser_element stateswitches[] = {
+ /** fake tag used to enclose multiple xml files in one **/
{ STATE_START, "rpmmd", STATE_START, 0 },
- /** tags for different package data, we just ignore the tag **/
+ /** tags for different package data, just ignore them **/
+ { STATE_START, "patterns", STATE_START, 0 },
+ { STATE_START, "products", STATE_START, 0 },
{ STATE_START, "metadata", STATE_START, 0 },
{ STATE_START, "otherdata", STATE_START, 0 },
{ STATE_START, "filelists", STATE_START, 0 },
{ STATE_START, "patch", STATE_SOLVABLE, 0 },
{ STATE_START, "package", STATE_SOLVABLE, 0 },
+ { STATE_SOLVABLE, "format", STATE_SOLVABLE, 0 },
+
{ STATE_SOLVABLE, "name", STATE_NAME, 1 },
{ STATE_SOLVABLE, "arch", STATE_ARCH, 1 },
{ STATE_SOLVABLE, "version", STATE_VERSION, 0 },
Repo *repo;
Repodata *data;
char *kind;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Solvable *solvable;
Offset freshens;
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
+
+ struct solv_xmlparser xmlp;
struct joindata jd;
/* temporal to store attribute tag language */
const char *tmplang;
Id chksumtype;
Id handle;
- XML_Parser *parser;
Queue diskusageq;
const char *language; /* default language */
Id langcache[ID_NUM_INTERNAL]; /* cache for the default language */
makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
{
const char *e, *v, *r, *v2;
- char *c;
+ char *c, *space;
int l;
e = v = r = 0;
l += strlen(v);
if (r)
l += strlen(r) + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content;
+ c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
if (e)
{
strcpy(c, e);
c += strlen(c);
}
*c = 0;
- if (!*pd->content)
+ if (!*space)
return 0;
#if 0
- fprintf(stderr, "evr: %s\n", pd->content);
+ fprintf(stderr, "evr: %s\n", space);
#endif
- return pool_str2id(pool, pd->content, 1);
-}
-
-
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
+ return pool_str2id(pool, space, 1);
}
if (k)
{
int l = strlen(k) + 1 + strlen(n) + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- sprintf(pd->content, "%s:%s", k, n);
- id = pool_str2id(pool, pd->content, 1);
+ char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
+ sprintf(space, "%s:%s", k, n);
+ id = pool_str2id(pool, space, 1);
}
#ifdef ENABLE_COMPLEX_DEPS
else if (!f && n[0] == '(')
/*
* startElement
- * XML callback
- *
*/
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
- struct stateswitch *sw;
- const char *str;
Id handle = pd->handle;
+ const char *str;
const char *pkgid;
- /* fprintf(stderr, "into %s, from %d, depth %d, statedepth %d\n", name, pd->state, pd->depth, pd->statedepth); */
-
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- if (pd->state == STATE_START && !strcmp(name, "patterns"))
- return;
- if (pd->state == STATE_START && !strcmp(name, "products"))
- return;
-#if 0
- if (pd->state == STATE_START && !strcmp(name, "metadata"))
- return;
-#endif
- if (pd->state == STATE_SOLVABLE && !strcmp(name, "format"))
+ if (!s && state != STATE_SOLVABLE)
return;
- pd->depth++;
- if (!pd->swtab[pd->state])
- return;
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
- if (!strcmp(sw->ename, name))
- break;
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s\n", name);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
-
- if (!s && pd->state != STATE_SOLVABLE)
- return;
-
- switch(pd->state)
+ switch(state)
{
case STATE_SOLVABLE:
pd->kind = 0;
one.
*/
pd->extending = 0;
- if ((pkgid = find_attr("pkgid", atts)) != NULL)
+ if ((pkgid = solv_xmlparser_find_attr("pkgid", atts)) != NULL)
{
unsigned char chk[256];
int l;
if (pd->kind && pd->kind[1] == 'r')
{
/* products can have a type */
- const char *type = find_attr("type", atts);
+ const char *type = solv_xmlparser_find_attr("type", atts);
if (type && *type)
repodata_set_str(pd->data, handle, PRODUCT_TYPE, type);
}
case STATE_SUMMARY:
case STATE_CATEGORY:
case STATE_DESCRIPTION:
- pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
+ pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
break;
case STATE_USERVISIBLE:
repodata_set_void(pd->data, handle, SOLVABLE_ISVISIBLE);
break;
case STATE_INCLUDESENTRY:
- str = find_attr("pattern", atts);
+ str = solv_xmlparser_find_attr("pattern", atts);
if (str)
repodata_add_poolstr_array(pd->data, handle, SOLVABLE_INCLUDES, join2(&pd->jd, "pattern", ":", str));
break;
case STATE_EXTENDSENTRY:
- str = find_attr("pattern", atts);
+ str = solv_xmlparser_find_attr("pattern", atts);
if (str)
repodata_add_poolstr_array(pd->data, handle, SOLVABLE_EXTENDS, join2(&pd->jd, "pattern", ":", str));
break;
case STATE_LOCATION:
- str = find_attr("href", atts);
+ str = solv_xmlparser_find_attr("href", atts);
if (str)
{
int medianr = 0;
- const char *base = find_attr("xml:base", atts);
+ const char *base = solv_xmlparser_find_attr("xml:base", atts);
if (base && !strncmp(base, "media:", 6))
{
/* check for the media number in the fragment */
}
break;
case STATE_CHECKSUM:
- str = find_attr("type", atts);
+ str = solv_xmlparser_find_attr("type", atts);
pd->chksumtype = str && *str ? solv_chksum_str2type(str) : 0;
if (!pd->chksumtype)
- pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), str ? str : "NULL");
+ pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), str ? str : "NULL");
break;
case STATE_TIME:
{
unsigned int t;
- str = find_attr("build", atts);
+ str = solv_xmlparser_find_attr("build", atts);
if (str && (t = atoi(str)) != 0)
repodata_set_num(pd->data, handle, SOLVABLE_BUILDTIME, t);
break;
}
case STATE_SIZE:
- if ((str = find_attr("installed", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("installed", atts)) != 0)
repodata_set_num(pd->data, handle, SOLVABLE_INSTALLSIZE, strtoull(str, 0, 10));
- if ((str = find_attr("package", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("package", atts)) != 0)
repodata_set_num(pd->data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(str, 0, 10));
break;
case STATE_HEADERRANGE:
{
unsigned int end;
- str = find_attr("end", atts);
+ str = solv_xmlparser_find_attr("end", atts);
if (str && (end = atoi(str)) != 0)
repodata_set_num(pd->data, handle, SOLVABLE_HEADEREND, end);
break;
long filesz = 0, filenum = 0;
Id did;
- if ((str = find_attr("name", atts)) == 0)
+ if ((str = solv_xmlparser_find_attr("name", atts)) == 0)
{
pd->ret = pool_error(pool, -1, "<dir .../> tag without 'name' attribute");
break;
else
{
int l = strlen(str) + 2;
- if (l > pd->acontent)
- {
- pd->acontent = l + 256;
- pd->content = solv_realloc(pd->content, pd->acontent);
- }
- pd->content[0] = '/';
- memcpy(pd->content + 1, str, l - 1);
- str = pd->content;
+ char *space = solv_xmlparser_contentspace(xmlp, l);
+ space[0] = '/';
+ memcpy(space + 1, str, l - 1);
+ str = space;
}
}
did = repodata_str2dir(pd->data, str, 1);
- if ((str = find_attr("size", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("size", atts)) != 0)
filesz = strtol(str, 0, 0);
- if ((str = find_attr("count", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("count", atts)) != 0)
filenum = strtol(str, 0, 0);
if (filesz || filenum)
{
}
case STATE_CHANGELOG:
pd->changelog_handle = repodata_new_handle(pd->data);
- if ((str = find_attr("date", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("date", atts)) != 0)
repodata_set_num(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TIME, strtoull(str, 0, 10));
- if ((str = find_attr("author", atts)) != 0)
+ if ((str = solv_xmlparser_find_attr("author", atts)) != 0)
repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_AUTHOR, str);
break;
default:
/*
* endElement
- * XML callback
- *
*/
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
Repo *repo = pd->repo;
Id id;
char *p;
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
- /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
- return;
- }
-
- /* ignore patterns & metadata */
- if (pd->state == STATE_START && !strcmp(name, "patterns"))
- return;
- if (pd->state == STATE_START && !strcmp(name, "products"))
- return;
-#if 0
- if (pd->state == STATE_START && !strcmp(name, "metadata"))
- return;
-#endif
- if (pd->state == STATE_SOLVABLE && !strcmp(name, "format"))
- return;
-
- pd->depth--;
- pd->statedepth--;
-
-
if (!s)
- {
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
- return;
- }
+ return;
- switch (pd->state)
+ switch (state)
{
case STATE_SOLVABLE:
if (pd->extending)
break;
case STATE_NAME:
if (pd->kind)
- s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", pd->content), 1);
+ s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", content), 1);
else
- s->name = pool_str2id(pool, pd->content, 1);
+ s->name = pool_str2id(pool, content, 1);
break;
case STATE_ARCH:
- s->arch = pool_str2id(pool, pd->content, 1);
+ s->arch = pool_str2id(pool, content, 1);
break;
case STATE_VENDOR:
- s->vendor = pool_str2id(pool, pd->content, 1);
+ s->vendor = pool_str2id(pool, content, 1);
break;
case STATE_RPM_GROUP:
- repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, pd->content);
+ repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, content);
break;
case STATE_RPM_LICENSE:
- repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, pd->content);
+ repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, content);
break;
case STATE_CHECKSUM:
{
unsigned char chk[256];
int l = solv_chksum_len(pd->chksumtype);
- const char *str = pd->content;
+ const char *str = content;
if (!l || l > sizeof(chk))
break;
- if (solv_hex2bin(&str, chk, l) != l || pd->content[2 * l])
+ if (solv_hex2bin(&str, chk, l) != l || content[2 * l])
{
- pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype));
+ pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype));
break;
}
repodata_set_bin_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, chk);
break;
}
case STATE_FILE:
- if ((p = strrchr(pd->content, '/')) != 0)
+ if ((p = strrchr(content, '/')) != 0)
{
*p++ = 0;
- if (pd->lastdir && !strcmp(pd->lastdirstr, pd->content))
+ if (pd->lastdir && !strcmp(pd->lastdirstr, content))
{
id = pd->lastdir;
}
else
{
- int l = p - pd->content;
+ int l = p - content;
if (l + 1 > pd->lastdirstrl) /* + 1 for the possible leading / we need to insert */
{
pd->lastdirstrl = l + 128;
pd->lastdirstr = solv_realloc(pd->lastdirstr, pd->lastdirstrl);
}
- if (pd->content[0] != '/')
+ if (content[0] != '/')
{
pd->lastdirstr[0] = '/';
- memcpy(pd->lastdirstr + 1, pd->content, l);
+ memcpy(pd->lastdirstr + 1, content, l);
id = repodata_str2dir(pd->data, pd->lastdirstr, 1);
}
else
- id = repodata_str2dir(pd->data, pd->content, 1);
+ id = repodata_str2dir(pd->data, content, 1);
pd->lastdir = id;
- memcpy(pd->lastdirstr, pd->content, l);
+ memcpy(pd->lastdirstr, content, l);
}
}
else
{
- p = pd->content;
+ p = content;
id = repodata_str2dir(pd->data, "/", 1);
}
repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, id, p);
break;
case STATE_SUMMARY:
- repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content);
+ repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), content);
break;
case STATE_DESCRIPTION:
- set_description_author(pd->data, handle, pd->content, pd);
+ set_description_author(pd->data, handle, content, pd);
break;
case STATE_CATEGORY:
- repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), pd->content);
+ repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), content);
break;
case STATE_DISTRIBUTION:
- repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, pd->content);
+ repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, content);
break;
case STATE_URL:
- if (pd->content[0])
- repodata_set_str(pd->data, handle, SOLVABLE_URL, pd->content);
+ if (*content)
+ repodata_set_str(pd->data, handle, SOLVABLE_URL, content);
break;
case STATE_PACKAGER:
- if (pd->content[0])
- repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, pd->content);
+ if (*content)
+ repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, content);
break;
case STATE_SOURCERPM:
- if (pd->content[0])
- repodata_set_sourcepkg(pd->data, handle, pd->content);
+ if (*content)
+ repodata_set_sourcepkg(pd->data, handle, content);
break;
case STATE_RELNOTESURL:
- if (pd->content[0])
+ if (*content)
{
- repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
+ repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "releasenotes", 1));
}
break;
case STATE_UPDATEURL:
- if (pd->content[0])
+ if (*content)
{
- repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
+ repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "update", 1));
}
break;
case STATE_OPTIONALURL:
- if (pd->content[0])
+ if (*content)
{
- repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
+ repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "optional", 1));
}
break;
case STATE_FLAG:
- if (pd->content[0])
- repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, pd->content);
+ if (*content)
+ repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, content);
break;
case STATE_EULA:
- if (pd->content[0])
- repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), pd->content);
+ if (*content)
+ repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), content);
break;
case STATE_KEYWORD:
- if (pd->content[0])
- repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, pd->content);
+ if (*content)
+ repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, content);
break;
case STATE_DISKUSAGE:
if (pd->diskusageq.count)
repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
break;
case STATE_ORDER:
- if (pd->content[0])
- repodata_set_str(pd->data, handle, SOLVABLE_ORDER, pd->content);
+ if (*content)
+ repodata_set_str(pd->data, handle, SOLVABLE_ORDER, content);
break;
case STATE_CHANGELOG:
- repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, pd->content);
+ repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, content);
repodata_add_flexarray(pd->data, handle, SOLVABLE_CHANGELOG, pd->changelog_handle);
pd->changelog_handle = 0;
break;
default:
break;
}
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
- /* fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
}
-
-/*
- * characterData
- * XML callback
- *
- */
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
-
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = solv_realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pd->ret = pool_error(pd->pool, -1, "repo_rpmmd: %s at line %u:%u", errstr, line, column);
}
/*-----------------------------------------------*/
-/* 'main' */
-
-#define BUFF_SIZE 8192
/*
* repo_add_rpmmd
{
Pool *pool = repo->pool;
struct parsedata pd;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
Repodata *data;
unsigned int now;
- XML_Parser parser;
now = solv_timems(0);
data = repo_add_repodata(repo, flags);
memset(&pd, 0, sizeof(pd));
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
pd.pool = pool;
pd.repo = repo;
pd.data = data;
- pd.content = solv_malloc(256);
- pd.acontent = 256;
- pd.lcontent = 0;
pd.kind = 0;
pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0;
queue_init(&pd.diskusageq);
fill_cshash_from_repo(&pd);
}
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- pd.parser = &parser;
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
- solv_free(pd.content);
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
+
solv_free(pd.lastdirstr);
join_freemem(&pd.jd);
free_cshash(&pd);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <expat.h>
#include <time.h>
#include "pool.h"
#include "repo.h"
+#include "solv_xmlparser.h"
#include "repo_updateinfoxml.h"
#define DISABLE_SPLIT
#include "tools_util.h"
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "updates", STATE_UPDATES, 0 },
{ STATE_START, "update", STATE_UPDATE, 0 },
{ STATE_UPDATES, "update", STATE_UPDATE, 0 },
struct parsedata {
int ret;
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Pool *pool;
Repo *repo;
Repodata *data;
Solvable *solvable;
time_t buildtime;
Id collhandle;
+ struct solv_xmlparser xmlp;
struct joindata jd;
-
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
};
/*
makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
{
const char *e, *v, *r, *v2;
- char *c;
+ char *c, *space;
int l;
e = v = r = 0;
l += strlen(v);
if (r)
l += strlen(r) + 1;
- if (l > pd->acontent)
- {
- pd->content = realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content;
+
+ c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
if (e)
{
strcpy(c, e);
c += strlen(c);
}
*c = 0;
- if (!*pd->content)
+ if (!*space)
return 0;
#if 0
- fprintf(stderr, "evr: %s\n", pd->content);
+ fprintf(stderr, "evr: %s\n", space);
#endif
- return pool_str2id(pool, pd->content, 1);
+ return pool_str2id(pool, space, 1);
}
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *solvable = pd->solvable;
- struct stateswitch *sw;
- /*const char *str; */
-
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
- pd->depth++;
- if (!pd->swtab[pd->state])
- return;
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
-
- if (sw->from != pd->state)
+ switch(state)
{
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
-
- switch(pd->state)
- {
- case STATE_START:
- break;
- case STATE_UPDATES:
- break;
/*
* <update from="rel-eng@fedoraproject.org"
* status="stable"
pd->buildtime = (time_t)0;
}
break;
- /* <id>FEDORA-2007-4594</id> */
- case STATE_ID:
- break;
- /* <title>imlib-1.9.15-6.fc8</title> */
- case STATE_TITLE:
- break;
- /* <release>Fedora 8</release> */
- case STATE_RELEASE:
- break;
- /* <issued date="2008-03-21 21:36:55"/>
- */
+
case STATE_ISSUED:
case STATE_UPDATED:
{
- const char *date = 0;
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, "date"))
- date = atts[1];
- }
+ const char *date = solv_xmlparser_find_attr("date", atts);
if (date)
{
time_t t = datestr2timestamp(date);
}
}
break;
- case STATE_REFERENCES:
- break;
- /* <reference href="https://bugzilla.redhat.com/show_bug.cgi?id=330471"
- * id="330471"
- * title="LDAP schema file missing for dhcpd"
- * type="bugzilla"/>
- */
+
case STATE_REFERENCE:
{
const char *href = 0, *id = 0, *title = 0, *type = 0;
repodata_add_flexarray(pd->data, pd->handle, UPDATE_REFERENCE, refhandle);
}
break;
- /* <description>This update ...</description> */
- case STATE_DESCRIPTION:
- break;
- /* <message type="confirm">This update ...</message> */
- case STATE_MESSAGE:
- break;
- case STATE_PKGLIST:
- break;
- /* <collection short="F8" */
- case STATE_COLLECTION:
- break;
- /* <name>Fedora 8</name> */
- case STATE_NAME:
- break;
+
/* <package arch="ppc64" name="imlib-debuginfo" release="6.fc8"
* src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm"
* version="1.9.15">
repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
break;
}
- /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
- /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
- case STATE_FILENAME:
- break;
- /* <reboot_suggested>True</reboot_suggested> */
- case STATE_REBOOT:
- break;
- /* <restart_suggested>True</restart_suggested> */
- case STATE_RESTART:
- break;
- /* <relogin_suggested>True</relogin_suggested> */
- case STATE_RELOGIN:
- break;
+
default:
break;
}
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
Repo *repo = pd->repo;
-#if 0
- fprintf(stderr, "end: %s\n", name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
- switch (pd->state)
+ switch (state)
{
- case STATE_START:
- break;
- case STATE_UPDATES:
- break;
case STATE_UPDATE:
s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
if (pd->buildtime)
pd->buildtime = (time_t)0;
}
break;
+
case STATE_ID:
- s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", pd->content), 1);
+ s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", content), 1);
break;
+
/* <title>imlib-1.9.15-6.fc8</title> */
case STATE_TITLE:
- while (pd->lcontent > 0 && pd->content[pd->lcontent - 1] == '\n')
- pd->content[--pd->lcontent] = 0;
- repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
+ /* strip trailing newlines */
+ while (pd->xmlp.lcontent > 0 && content[pd->xmlp.lcontent - 1] == '\n')
+ content[--pd->xmlp.lcontent] = 0;
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content);
break;
+
case STATE_SEVERITY:
- repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, pd->content);
+ repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, content);
break;
+
case STATE_RIGHTS:
- repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, pd->content);
- break;
- /*
- * <release>Fedora 8</release>
- */
- case STATE_RELEASE:
- break;
- case STATE_ISSUED:
- break;
- case STATE_REFERENCES:
- break;
- case STATE_REFERENCE:
+ repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, content);
break;
+
/*
* <description>This update ...</description>
*/
case STATE_DESCRIPTION:
- repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, pd->content);
+ repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, content);
break;
+
/*
* <message>Warning! ...</message>
*/
case STATE_MESSAGE:
- repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, pd->content);
- break;
- case STATE_PKGLIST:
- break;
- case STATE_COLLECTION:
- break;
- case STATE_NAME:
+ repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, content);
break;
+
case STATE_PACKAGE:
repodata_add_flexarray(pd->data, pd->handle, UPDATE_COLLECTION, pd->collhandle);
pd->collhandle = 0;
break;
+
/* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
/* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
case STATE_FILENAME:
- repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, pd->content);
+ repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, content);
break;
+
/* <reboot_suggested>True</reboot_suggested> */
case STATE_REBOOT:
- if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
+ if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
{
/* FIXME: this is per-package, the global flag should be computed at runtime */
repodata_set_void(pd->data, pd->handle, UPDATE_REBOOT);
repodata_set_void(pd->data, pd->collhandle, UPDATE_REBOOT);
}
break;
+
/* <restart_suggested>True</restart_suggested> */
case STATE_RESTART:
- if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
+ if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
{
/* FIXME: this is per-package, the global flag should be computed at runtime */
repodata_set_void(pd->data, pd->handle, UPDATE_RESTART);
repodata_set_void(pd->data, pd->collhandle, UPDATE_RESTART);
}
break;
+
/* <relogin_suggested>True</relogin_suggested> */
case STATE_RELOGIN:
- if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
+ if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
{
/* FIXME: this is per-package, the global flag should be computed at runtime */
repodata_set_void(pd->data, pd->handle, UPDATE_RELOGIN);
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
+static void
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- struct parsedata *pd = userData;
- int l;
- char *c;
-
- if (!pd->docontent)
- {
-#if 0
- fprintf(stderr, "Content: [%d]'%.*s'\n", pd->state, len, s);
-#endif
- return;
- }
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
+ struct parsedata *pd = xmlp->userdata;
+ pd->ret = pool_error(pd->pool, -1, "repo_updateinfoxml: %s at line %u:%u", errstr, line, column);
}
-
-#define BUFF_SIZE 8192
-
int
repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
{
Pool *pool = repo->pool;
- struct parsedata pd;
- char buf[BUFF_SIZE];
- int i, l;
- struct stateswitch *sw;
Repodata *data;
- XML_Parser parser;
+ struct parsedata pd;
data = repo_add_repodata(repo, flags);
memset(&pd, 0, sizeof(pd));
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
pd.pool = pool;
pd.repo = repo;
pd.data = data;
-
- pd.content = malloc(256);
- pd.acontent = 256;
- pd.lcontent = 0;
- parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, &pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
- for (;;)
- {
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- break;
- }
- if (l == 0)
- break;
- }
- XML_ParserFree(parser);
- free(pd.content);
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+ solv_xmlparser_parse(&pd.xmlp, fp);
+ solv_xmlparser_free(&pd.xmlp);
join_freemem(&pd.jd);
if (!(flags & REPO_NO_INTERNALIZE))
* Parses legacy /var/lib/zypp/db/products/... files.
* They are old (pre Code11) product descriptions. See bnc#429177
*
- *
* Copyright (c) 2008, Novell Inc.
*
* This program is licensed under the BSD license, read LICENSE.BSD
#include <string.h>
#include <assert.h>
#include <dirent.h>
-#include <expat.h>
#include <errno.h>
#include "pool.h"
#include "repo.h"
#include "util.h"
+#include "solv_xmlparser.h"
#define DISABLE_SPLIT
#include "tools_util.h"
#include "repo_zyppdb.h"
NUMSTATES
};
-struct stateswitch {
- enum state from;
- char *ename;
- enum state to;
- int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
+static struct solv_xmlparser_element stateswitches[] = {
{ STATE_START, "product", STATE_PRODUCT, 0 },
{ STATE_PRODUCT, "name", STATE_NAME, 1 },
{ STATE_PRODUCT, "version", STATE_VERSION, 0 },
};
struct parsedata {
- int depth;
- enum state state;
- int statedepth;
- char *content;
- int lcontent;
- int acontent;
- int docontent;
Pool *pool;
Repo *repo;
Repodata *data;
-
- struct stateswitch *swtab[NUMSTATES];
- enum state sbtab[NUMSTATES];
- struct joindata jd;
-
+ const char *filename;
const char *tmplang;
-
Solvable *solvable;
Id handle;
+ struct solv_xmlparser xmlp;
+ struct joindata jd;
};
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
- for (; *atts; atts += 2)
- {
- if (!strcmp(*atts, txt))
- return atts[1];
- }
- return 0;
-}
-
-
-/*
- * XML callback: startElement
- */
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Pool *pool = pd->pool;
Solvable *s = pd->solvable;
- struct stateswitch *sw;
-
-#if 0
- fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth++;
- return;
- }
-
- pd->depth++;
- if (!pd->swtab[pd->state]) /* no statetable -> no substates */
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */
- if (!strcmp(sw->ename, name))
- break;
-
- if (sw->from != pd->state)
- {
-#if 0
- fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
- return;
- }
- pd->state = sw->to;
- pd->docontent = sw->docontent;
- pd->statedepth = pd->depth;
- pd->lcontent = 0;
- *pd->content = 0;
- switch(pd->state)
+ switch(state)
{
case STATE_PRODUCT:
{
/* parse 'type' */
- const char *type = find_attr("type", atts);
+ const char *type = solv_xmlparser_find_attr("type", atts);
s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
pd->handle = s - pool->solvables;
if (type)
break;
case STATE_VERSION:
{
- const char *ver = find_attr("ver", atts);
- const char *rel = find_attr("rel", atts);
- /* const char *epoch = find_attr("epoch", atts); ignored */
+ const char *ver = solv_xmlparser_find_attr("ver", atts);
+ const char *rel = solv_xmlparser_find_attr("rel", atts);
+ /* const char *epoch = solv_xmlparser_find_attr("epoch", atts); ignored */
s->evr = makeevr(pd->pool, join2(&pd->jd, ver, "-", rel));
}
break;
- /* <summary lang="xy">... */
- case STATE_SUMMARY:
- pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
+ case STATE_SUMMARY: /* <summary lang="xy">... */
+ pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
break;
default:
break;
}
-static void XMLCALL
-endElement(void *userData, const char *name)
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
{
- struct parsedata *pd = userData;
+ struct parsedata *pd = xmlp->userdata;
Solvable *s = pd->solvable;
-#if 0
- fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
- if (pd->depth != pd->statedepth)
- {
- pd->depth--;
-#if 0
- fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
- return;
- }
-
- pd->depth--;
- pd->statedepth--;
-
- switch (pd->state)
+ switch (state)
{
case STATE_PRODUCT:
if (!s->arch)
pd->solvable = 0;
break;
case STATE_NAME:
- s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1);
+ s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1);
break;
case STATE_ARCH:
- s->arch = pool_str2id(pd->pool, pd->content, 1);
+ s->arch = pool_str2id(pd->pool, content, 1);
break;
case STATE_SUMMARY:
- repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
+ repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
break;
case STATE_VENDOR:
- s->vendor = pool_str2id(pd->pool, pd->content, 1);
+ s->vendor = pool_str2id(pd->pool, content, 1);
break;
case STATE_INSTALLTIME:
- repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(pd->content));
+ repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(content));
default:
break;
}
-
- pd->state = pd->sbtab[pd->state];
- pd->docontent = 0;
-
-#if 0
- fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
- struct parsedata *pd = userData;
- int l;
- char *c;
- if (!pd->docontent)
- return;
- l = pd->lcontent + len + 1;
- if (l > pd->acontent)
- {
- pd->content = realloc(pd->content, l + 256);
- pd->acontent = l + 256;
- }
- c = pd->content + pd->lcontent;
- pd->lcontent += len;
- while (len-- > 0)
- *c++ = *s++;
- *c = 0;
}
-#define BUFF_SIZE 8192
-
-
-/*
- * add single product to repo
- *
- */
-
static void
-add_zyppdb_product(struct parsedata *pd, FILE *fp)
+errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
{
- char buf[BUFF_SIZE];
- int l;
-
- XML_Parser parser = XML_ParserCreate(NULL);
- XML_SetUserData(parser, pd);
- XML_SetElementHandler(parser, startElement, endElement);
- XML_SetCharacterDataHandler(parser, characterData);
-
- for (;;)
+ struct parsedata *pd = xmlp->userdata;
+ pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s: %s at line %u:%u\n", pd->filename, errstr, line, column);
+ if (pd->solvable)
{
- l = fread(buf, 1, sizeof(buf), fp);
- if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
- {
- pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
- if (pd->solvable)
- {
- repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
- pd->solvable = 0;
- }
- return;
- }
- if (l == 0)
- break;
+ repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
+ pd->solvable = 0;
}
- XML_ParserFree(parser);
}
int
repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
{
- int i;
struct parsedata pd;
- struct stateswitch *sw;
struct dirent *entry;
char *fullpath;
DIR *dir;
pd.repo = repo;
pd.pool = repo->pool;
pd.data = data;
-
- pd.content = malloc(256);
- pd.acontent = 256;
-
- for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
- {
- if (!pd.swtab[sw->from])
- pd.swtab[sw->from] = sw;
- pd.sbtab[sw->to] = sw->from;
- }
+ solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
if (flags & REPO_USE_ROOTDIR)
dirpath = pool_prepend_rootdir(repo->pool, dirpath);
{
while ((entry = readdir(dir)))
{
- if (strlen(entry->d_name) < 3)
- continue; /* skip '.' and '..' */
+ if (entry->d_name[0] == '.')
+ continue; /* skip dot files */
fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
if ((fp = fopen(fullpath, "r")) == 0)
{
pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
continue;
}
- add_zyppdb_product(&pd, fp);
+ pd.filename = entry->d_name;
+ solv_xmlparser_parse(&pd.xmlp, fp);
fclose(fp);
}
}
closedir(dir);
- free(pd.content);
+ solv_xmlparser_free(&pd.xmlp);
join_freemem(&pd.jd);
if (flags & REPO_USE_ROOTDIR)
solv_free((char *)dirpath);
--- /dev/null
+/*
+ * solv_xmlparser.c
+ *
+ * XML parser abstraction
+ *
+ * Copyright (c) 2017, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <expat.h>
+
+#include "util.h"
+#include "queue.h"
+#include "solv_xmlparser.h"
+
+static inline void
+add_contentspace(struct solv_xmlparser *xmlp, int l)
+{
+ l += xmlp->lcontent + 1; /* plus room for trailing zero */
+ if (l > xmlp->acontent)
+ {
+ xmlp->acontent = l + 256;
+ xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
+ }
+}
+
+static void XMLCALL
+characterData(void *userData, const XML_Char *s, int len)
+{
+ struct solv_xmlparser *xmlp = userData;
+ char *c;
+
+ if (!xmlp->docontent)
+ return;
+ add_contentspace(xmlp, len);
+ c = xmlp->content + xmlp->lcontent;
+ xmlp->lcontent += len;
+ while (len-- > 0)
+ *c++ = *s++;
+}
+
+static void XMLCALL
+startElement(void *userData, const char *name, const char **atts)
+{
+ struct solv_xmlparser *xmlp = userData;
+ struct solv_xmlparser_element *elements;
+ Id *elementhelper;
+ struct solv_xmlparser_element *el;
+ int i, oldstate;
+
+ if (xmlp->unknowncnt)
+ {
+ xmlp->unknowncnt++;
+ return;
+ }
+ elementhelper = xmlp->elementhelper;
+ elements = xmlp->elements;
+ oldstate = xmlp->state;
+ for (i = elementhelper[xmlp->nelements + oldstate]; i; i = elementhelper[i - 1])
+ if (!strcmp(elements[i - 1].element, name))
+ break;
+ if (!i)
+ {
+#if 0
+ fprintf(stderr, "into unknown: %s\n", name);
+#endif
+ xmlp->unknowncnt++;
+ return;
+ }
+ el = xmlp->elements + i - 1;
+ queue_push(&xmlp->elementq, xmlp->state);
+ xmlp->state = el->tostate;
+ xmlp->docontent = el->docontent;
+ xmlp->lcontent = 0;
+ if (xmlp->state != oldstate)
+ xmlp->startelement(xmlp, xmlp->state, el->element, atts);
+}
+
+static void XMLCALL
+endElement(void *userData, const char *name)
+{
+ struct solv_xmlparser *xmlp = userData;
+
+ if (xmlp->unknowncnt)
+ {
+ xmlp->unknowncnt--;
+ xmlp->lcontent = 0;
+ xmlp->docontent = 0;
+ return;
+ }
+ xmlp->content[xmlp->lcontent] = 0;
+ if (xmlp->elementq.count && xmlp->state != xmlp->elementq.elements[xmlp->elementq.count - 1])
+ xmlp->endelement(xmlp, xmlp->state, xmlp->content);
+ xmlp->state = queue_pop(&xmlp->elementq);
+ xmlp->docontent = 0;
+ xmlp->lcontent = 0;
+}
+
+void
+solv_xmlparser_init(struct solv_xmlparser *xmlp,
+ struct solv_xmlparser_element *elements,
+ void *userdata,
+ void (*startelement)(struct solv_xmlparser *, int state, const char *name, const char **atts),
+ void (*endelement)(struct solv_xmlparser *, int state, char *content),
+ void (*errorhandler)(struct solv_xmlparser *, const char *errstr, unsigned int line, unsigned int column))
+{
+ int i, nstates, nelements;
+ struct solv_xmlparser_element *el;
+ Id *elementhelper;
+
+ memset(xmlp, 0, sizeof(*xmlp));
+ nstates = 0;
+ nelements = 0;
+ for (el = elements; el->element; el++)
+ {
+ nelements++;
+ if (el->fromstate > nstates)
+ nstates = el->fromstate;
+ if (el->tostate > nstates)
+ nstates = el->tostate;
+ }
+ nstates++;
+
+ xmlp->elements = elements;
+ xmlp->nelements = nelements;
+ elementhelper = solv_calloc(nelements + nstates, sizeof(Id));
+ for (i = nelements - 1; i >= 0; i--)
+ {
+ int fromstate = elements[i].fromstate;
+ elementhelper[i] = elementhelper[nelements + fromstate];
+ elementhelper[nelements + fromstate] = i + 1;
+ }
+ xmlp->elementhelper = elementhelper;
+ queue_init(&xmlp->elementq);
+ xmlp->acontent = 256;
+ xmlp->content = solv_malloc(xmlp->acontent);
+
+ xmlp->userdata = userdata;
+ xmlp->startelement = startelement;
+ xmlp->endelement = endelement;
+ xmlp->errorhandler = errorhandler;
+}
+
+unsigned int
+solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
+{
+ return (unsigned int)XML_GetCurrentLineNumber(xmlp->parser);
+}
+
+void
+solv_xmlparser_free(struct solv_xmlparser *xmlp)
+{
+ xmlp->elementhelper = solv_free(xmlp->elementhelper);
+ queue_free(&xmlp->elementq);
+ xmlp->content = solv_free(xmlp->content);
+}
+
+void
+solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp)
+{
+ char buf[8192];
+ int l;
+
+ xmlp->state = 0;
+ xmlp->unknowncnt = 0;
+ xmlp->docontent = 0;
+ xmlp->lcontent = 0;
+ queue_empty(&xmlp->elementq);
+ xmlp->parser = XML_ParserCreate(NULL);
+ XML_SetUserData(xmlp->parser, xmlp);
+ XML_SetElementHandler(xmlp->parser, startElement, endElement);
+ XML_SetCharacterDataHandler(xmlp->parser, characterData);
+
+ for (;;)
+ {
+ l = fread(buf, 1, sizeof(buf), fp);
+ if (XML_Parse(xmlp->parser, buf, l, l == 0) == XML_STATUS_ERROR)
+ {
+ unsigned int line = XML_GetCurrentLineNumber(xmlp->parser);
+ unsigned int column = XML_GetCurrentColumnNumber(xmlp->parser);
+ xmlp->errorhandler(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), line, column);
+ break;
+ }
+ if (l == 0)
+ break;
+ }
+ XML_ParserFree(xmlp->parser);
+ xmlp->parser = 0;
+}
+
+char *
+solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l)
+{
+ xmlp->lcontent = 0;
+ if (l > xmlp->acontent)
+ {
+ xmlp->acontent = l + 256;
+ xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
+ }
+ return xmlp->content;
+}
+
--- /dev/null
+
+struct solv_xmlparser_element {
+ int fromstate;
+ char *element;
+ int tostate;
+ int docontent;
+};
+
+struct solv_xmlparser {
+ void *userdata;
+
+ int state;
+ int docontent;
+
+ Queue elementq;
+ int unknowncnt;
+
+ char *content;
+ int lcontent; /* current content length */
+ int acontent; /* allocated content length */
+
+ struct solv_xmlparser_element *elements;
+ int nelements;
+
+ void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts);
+ void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content);
+ void (*errorhandler)(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column);
+
+ Id *elementhelper;
+ void *parser;
+};
+
+static inline const char *
+solv_xmlparser_find_attr(const char *txt, const char **atts)
+{
+ for (; *atts; atts += 2)
+ if (!strcmp(*atts, txt))
+ return atts[1];
+ return 0;
+}
+
+extern void solv_xmlparser_init(struct solv_xmlparser *xmlp, struct solv_xmlparser_element *elements, void *userdata,
+ void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts),
+ void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content),
+ void (*errorhandler)(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column));
+
+extern void solv_xmlparser_free(struct solv_xmlparser *xmlp);
+extern void solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp);
+unsigned int solv_xmlparser_lineno(struct solv_xmlparser *xmlp);
+char *solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l);
+
+