cr_xml_parser_data(unsigned int numstates)
{
cr_ParserData *pd = g_new0(cr_ParserData, 1);
- pd->ret = CRE_OK;
pd->content = g_malloc(CONTENT_REALLOC_STEP);
pd->acontent = CONTENT_REALLOC_STEP;
pd->msgs = g_string_new(0);
char *c;
cr_ParserData *pd = pdata;
- if (pd->ret != CRE_OK)
+ if (pd->err)
return; /* There was an error -> do nothing */
if (!pd->docontent)
return CRE_OK;
}
+
+int
+cr_xml_parser_generic(XML_Parser parser,
+ cr_ParserData *pd,
+ const char *path,
+ GError **err)
+{
+ /* Note: This function uses .err members of cr_ParserData! */
+
+ int ret = CRE_OK;
+ CR_FILE *f;
+ GError *tmp_err = NULL;
+
+ assert(parser);
+ assert(pd);
+ assert(path);
+ assert(!err || *err == NULL);
+
+ f = cr_open(path, CR_CW_MODE_READ, CR_CW_AUTO_DETECT_COMPRESSION, &tmp_err);
+ if (tmp_err) {
+ int code = tmp_err->code;
+ g_propagate_prefixed_error(err, tmp_err, "Cannot open %s: ", path);
+ return code;
+ }
+
+ while (1) {
+ int len;
+ void *buf = XML_GetBuffer(parser, XML_BUFFER_SIZE);
+ if (!buf) {
+ ret = CRE_MEMORY;
+ g_set_error(err, CR_XML_PARSER_FIL_ERROR, CRE_MEMORY,
+ "Out of memory: Cannot allocate buffer for xml parser");
+ break;
+ }
+
+ len = cr_read(f, buf, XML_BUFFER_SIZE, &tmp_err);
+ if (tmp_err) {
+ ret = tmp_err->code;
+ g_critical("%s: Error while reading xml : %s\n",
+ __func__, tmp_err->message);
+ g_propagate_prefixed_error(err, tmp_err, "Read error: ");
+ break;
+ }
+
+ if (!XML_ParseBuffer(parser, len, len == 0)) {
+ ret = CRE_XMLPARSER;
+ g_critical("%s: parsing error: %s\n",
+ __func__, XML_ErrorString(XML_GetErrorCode(parser)));
+ g_set_error(err, CR_XML_PARSER_FIL_ERROR, CRE_XMLPARSER,
+ "Parse error at line: %d (%s)",
+ (int) XML_GetCurrentLineNumber(parser),
+ (char *) XML_ErrorString(XML_GetErrorCode(parser)));
+ break;
+ }
+
+ if (pd->err) {
+ ret = pd->err->code;
+ g_propagate_error(err, pd->err);
+ break;
+ }
+
+ if (len == 0)
+ break;
+ }
+
+ if (ret != CRE_OK) {
+ // An error already encoutentered
+ // just close the file without error checking
+ cr_close(f, NULL);
+ } else {
+ // No error encountered yet
+ cr_close(f, &tmp_err);
+ if (tmp_err) {
+ ret = tmp_err->code;
+ g_propagate_prefixed_error(err, tmp_err, "Error while closing: ");
+ }
+ }
+
+ return ret;
+}
* @{
*/
+#define CR_CB_RET_OK 0
+#define CR_CB_RET_ERR 1
+
+
/** Callback for XML parser wich is called when a package element is parsed.
* @param pkg Currently parsed package.
* @param cbdata User data.
* @err GError **
- * @return 0 - OK, 1 - ERROR (stops the parsing)
+ * @return CR_CB_RET_OK (0) or CR_CB_RET_ERR (1) - stops the parsing
*/
typedef int (*cr_XmlParserPkgCb)(cr_Package *pkg,
void *cbdata,
* filled (by other XML parsers) package object.
* If the pointer is set to NULL, current package will be skiped.
* Note: For the primary.xml file pkgId, name and arch are NULL!
- * @param pkg Package that will be populated.
- * @param pkgId pkgId (hash) of the new package.
- * @param name Name of the new package.
- * @param arch Arch of the new package.
- * @param cbdata User data.
- * @param err GError **
- * @return 0 - OK, 1 - ERR (stops the parsing)
+ * @param pkg Package that will be populated.
+ * @param pkgId pkgId (hash) of the new package.
+ * @param name Name of the new package.
+ * @param arch Arch of the new package.
+ * @param cbdata User data.
+ * @param err GError **
+ * @return CR_CB_RET_OK (0) or CR_CB_RET_ERR (1) - stops the parsing
*/
typedef int (*cr_XmlParserNewPkgCb)(cr_Package **pkg,
const char *pkgId,
cr_ParserData *pd = pdata;
cr_StatesSwitch *sw;
- if (pd->ret != CRE_OK)
+ if (pd->err)
return; // There was an error -> do nothing
if (pd->depth != pd->statedepth) {
if (!pkgId) {
// Package without a pkgid attr is error
- pd->ret = CRE_BADXMLFILELISTS;
g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_BADXMLFILELISTS,
"Package pkgid attributte is missing!");
break;
pd->newpkgcb_data,
&tmp_err))
{
- pd->ret = CRE_CBINTERRUPTED;
if (tmp_err)
g_propagate_prefixed_error(&pd->err,
tmp_err,
CR_UNUSED(element);
- if (pd->ret != CRE_OK)
+ if (pd->err)
return; /* There was an error -> do nothing */
if (pd->depth != pd->statedepth) {
return;
if (pd->pkgcb && pd->pkgcb(pd->pkg, pd->pkgcb_data, &tmp_err)) {
- pd->ret = CRE_CBINTERRUPTED;
if (tmp_err)
g_propagate_prefixed_error(&pd->err,
tmp_err,
GError **err)
{
int ret = CRE_OK;
- CR_FILE *f;
cr_ParserData *pd;
XML_Parser parser;
char *msgs;
if (!newpkgcb) // Use default newpkgcb
newpkgcb = cr_newpkgcb;
- f = cr_open(path, CR_CW_MODE_READ, CR_CW_AUTO_DETECT_COMPRESSION, &tmp_err);
- if (tmp_err) {
- int code = tmp_err->code;
- g_propagate_prefixed_error(err, tmp_err, "Cannot open %s: ", path);
- return code;
- }
+ // Init
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, cr_start_handler, cr_end_handler);
XML_SetUserData(parser, pd);
- while (1) {
- int len;
- void *buf = XML_GetBuffer(parser, XML_BUFFER_SIZE);
- if (!buf) {
- ret = CRE_MEMORY;
- g_set_error(err, CR_XML_PARSER_FIL_ERROR, CRE_MEMORY,
- "Out of memory: Cannot allocate buffer for xml parser");
- break;
- }
-
- len = cr_read(f, buf, XML_BUFFER_SIZE, &tmp_err);
- if (tmp_err) {
- ret = tmp_err->code;
- g_critical("%s: Error while reading xml : %s\n",
- __func__, tmp_err->message);
- g_propagate_prefixed_error(err, tmp_err, "Read error: ");
- break;
- }
-
- if (!XML_ParseBuffer(parser, len, len == 0)) {
- ret = CRE_XMLPARSER;
- g_critical("%s: parsing error: %s\n",
- __func__, XML_ErrorString(XML_GetErrorCode(parser)));
- g_set_error(err, CR_XML_PARSER_FIL_ERROR, CRE_XMLPARSER,
- "Parse error at line: %d (%s)",
- (int) XML_GetCurrentLineNumber(parser),
- (char *) XML_ErrorString(XML_GetErrorCode(parser)));
- break;
- }
-
- if (pd->ret != CRE_OK) {
- ret = pd->ret;
- break;
- }
+ // Parsing
- if (len == 0)
- break;
- }
+ ret = cr_xml_parser_generic(parser, pd, path, &tmp_err);
+ if (tmp_err)
+ g_propagate_error(err, tmp_err);
- if (pd->err)
- g_propagate_error(err, pd->err);
+ // Clean up
if (ret != CRE_OK && newpkgcb == cr_newpkgcb) {
// Prevent memory leak when the parsing is interrupted by an error.
}
msgs = cr_xml_parser_data_free(pd);
- XML_ParserFree(parser);
- cr_close(f, &tmp_err);
- if (tmp_err) {
- int code = tmp_err->code;
- g_propagate_prefixed_error(err, tmp_err, "Error while closing: ");
- return code;
- }
-
if (messages)
*messages = msgs;
else
g_free(msgs);
+ XML_ParserFree(parser);
+
return ret;
}
#define XML_BUFFER_SIZE 8192
#define CONTENT_REALLOC_STEP 256
+/* Some notes about XML parsing (primary, filelists, other)
+ * ========================================================
+ * - Error during parsing is indicated via cr_ParserData->err member.
+ * - User specified callback have to be sanitized! User callbacks
+ * are allowed return CR_CB_RET_ERR and do not set the GError.
+ * So if the CR_CB_RET_ERR is returned and GError not setted, caller
+ * of the callback has to set the GError by himself.
+ */
+
/* File types in filelists.xml */
typedef enum {
FILE_FILE,
} cr_StatesSwitch;
typedef struct _cr_ParserData {
- int ret; /*!< status of parsing (return code) */
int depth;
int statedepth;
unsigned int state; /*!< current state */
+ GError *err; /*!< Error message */
+
/* Tag content related values */
The package which is currently loaded. */
GString *msgs; /*!<
Messages from xml parser (warnings about unknown elements etc.) */
- GError *err; /*!<
- Error message */
/* Filelists related stuff */
void *cbdata,
GError **err);
+/** Generic parser.
+ */
+int
+cr_xml_parser_generic(XML_Parser parser,
+ cr_ParserData *pd,
+ const char *path,
+ GError **err);
+
#ifdef __cplusplus
}
#endif