From: Tomas Mlcoch Date: Mon, 27 May 2013 14:49:46 +0000 (+0200) Subject: xml_parser: Add generic parser. X-Git-Tag: upstream/0.2.1~159 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4e5c686517eef5cc064a5ca048e7f45ad8011b84;p=services%2Fcreaterepo_c.git xml_parser: Add generic parser. --- diff --git a/src/xml_parser.c b/src/xml_parser.c index 67255c3..71e53e8 100644 --- a/src/xml_parser.c +++ b/src/xml_parser.c @@ -8,7 +8,6 @@ cr_ParserData * 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); @@ -37,7 +36,7 @@ cr_char_handler(void *pdata, const XML_Char *s, int len) char *c; cr_ParserData *pd = pdata; - if (pd->ret != CRE_OK) + if (pd->err) return; /* There was an error -> do nothing */ if (!pd->docontent) @@ -76,3 +75,83 @@ cr_newpkgcb(cr_Package **pkg, 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; +} diff --git a/src/xml_parser.h b/src/xml_parser.h index 14be9c0..078dab2 100644 --- a/src/xml_parser.h +++ b/src/xml_parser.h @@ -31,11 +31,15 @@ extern "C" { * @{ */ +#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, @@ -47,13 +51,13 @@ typedef int (*cr_XmlParserPkgCb)(cr_Package *pkg, * 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, diff --git a/src/xml_parser_filelists.c b/src/xml_parser_filelists.c index 037eee6..574773a 100644 --- a/src/xml_parser_filelists.c +++ b/src/xml_parser_filelists.c @@ -60,7 +60,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr) 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) { @@ -103,7 +103,6 @@ cr_start_handler(void *pdata, const char *element, const char **attr) 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; @@ -118,7 +117,6 @@ cr_start_handler(void *pdata, const char *element, const char **attr) pd->newpkgcb_data, &tmp_err)) { - pd->ret = CRE_CBINTERRUPTED; if (tmp_err) g_propagate_prefixed_error(&pd->err, tmp_err, @@ -190,7 +188,7 @@ cr_end_handler(void *pdata, const char *element) CR_UNUSED(element); - if (pd->ret != CRE_OK) + if (pd->err) return; /* There was an error -> do nothing */ if (pd->depth != pd->statedepth) { @@ -215,7 +213,6 @@ cr_end_handler(void *pdata, const char *element) 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, @@ -266,7 +263,6 @@ cr_xml_parse_filelists(const char *path, GError **err) { int ret = CRE_OK; - CR_FILE *f; cr_ParserData *pd; XML_Parser parser; char *msgs; @@ -280,12 +276,7 @@ cr_xml_parse_filelists(const char *path, 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); @@ -306,47 +297,13 @@ cr_xml_parse_filelists(const char *path, 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. @@ -359,18 +316,12 @@ cr_xml_parse_filelists(const char *path, } 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; } diff --git a/src/xml_parser_internal.h b/src/xml_parser_internal.h index ae8caef..e011061 100644 --- a/src/xml_parser_internal.h +++ b/src/xml_parser_internal.h @@ -33,6 +33,15 @@ extern "C" { #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, @@ -49,10 +58,11 @@ typedef struct { } 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 */ @@ -81,8 +91,6 @@ typedef struct _cr_ParserData { The package which is currently loaded. */ GString *msgs; /*!< Messages from xml parser (warnings about unknown elements etc.) */ - GError *err; /*!< - Error message */ /* Filelists related stuff */ @@ -127,6 +135,14 @@ int cr_newpkgcb(cr_Package **pkg, 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