📄 xml-parser.c
字号:
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, * version 2, as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA. */#include <string.h>#include <glib.h>#include <sqlite3.h>#include <libxml/parser.h>#include <libxml/tree.h>#include "xml-parser.h"#define PACKAGE_FIELD_SIZE 1024GQuarkyum_parser_error_quark (void){ static GQuark quark; if (!quark) quark = g_quark_from_static_string ("yum_parser_error"); return quark;}static guint32string_to_guint32_with_default (const char *n, guint32 def){ char *ret; guint32 z; z = strtoul (n, &ret, 10); if (*ret != '\0') return def; else return z;}typedef struct { const char *md_type; xmlParserCtxt *xml_context; GError **error; CountFn count_fn; PackageFn package_fn; gpointer user_data; Package *current_package; gboolean want_text; GString *text_buffer;} SAXContext;typedef enum { PRIMARY_PARSER_TOPLEVEL = 0, PRIMARY_PARSER_PACKAGE, PRIMARY_PARSER_FORMAT, PRIMARY_PARSER_DEP,} PrimarySAXContextState;typedef struct { SAXContext sctx; PrimarySAXContextState state; GSList **current_dep_list; PackageFile *current_file;} PrimarySAXContext;static voidprimary_parser_toplevel_start (PrimarySAXContext *ctx, const char *name, const char **attrs){ SAXContext *sctx = &ctx->sctx; if (!strcmp (name, "package")) { g_assert (sctx->current_package == NULL); ctx->state = PRIMARY_PARSER_PACKAGE; sctx->current_package = package_new (); } else if (sctx->count_fn && !strcmp (name, "metadata")) { int i; const char *attr; const char *value; for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "packages")) { sctx->count_fn (string_to_guint32_with_default (value, 0), sctx->user_data); break; } } }}static voidparse_version_info(const char **attrs, Package *p){ int i; const char *attr; const char *value; for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "epoch")) p->epoch = g_string_chunk_insert (p->chunk, value); else if (!strcmp (attr, "ver")) p->version = g_string_chunk_insert (p->chunk, value); else if (!strcmp (attr, "rel")) p->release = g_string_chunk_insert (p->chunk, value); }}static voidprimary_parser_package_start (PrimarySAXContext *ctx, const char *name, const char **attrs){ SAXContext *sctx = &ctx->sctx; Package *p = sctx->current_package; int i; const char *attr; const char *value; g_assert (p != NULL); sctx->want_text = TRUE; if (!strcmp (name, "format")) { ctx->state = PRIMARY_PARSER_FORMAT; } else if (!strcmp (name, "version")) { parse_version_info(attrs, p); } else if (!strcmp (name, "checksum")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "type")) p->checksum_type = g_string_chunk_insert (p->chunk, value); } } else if (!strcmp (name, "time")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "file")) p->time_file = strtol(value, NULL, 10); else if (!strcmp (attr, "build")) p->time_build = strtol(value, NULL, 10); } } else if (!strcmp (name, "size")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "package")) p->size_package = strtol(value, NULL, 10); else if (!strcmp (attr, "installed")) p->size_installed = strtol(value, NULL, 10); else if (!strcmp (attr, "archive")) p->size_archive = strtol(value, NULL, 10); } } else if (!strcmp (name, "location")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "href")) p->location_href = g_string_chunk_insert (p->chunk, value); else if (!strcmp (attr, "xml:base")) p->location_base = g_string_chunk_insert (p->chunk, value); } }}static voidprimary_parser_format_start (PrimarySAXContext *ctx, const char *name, const char **attrs){ SAXContext *sctx = &ctx->sctx; Package *p = sctx->current_package; int i; const char *attr; const char *value; g_assert (p != NULL); if (!strcmp (name, "rpm:header-range")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "start")) p->rpm_header_start = strtol(value, NULL, 10); else if (!strcmp (attr, "end")) p->rpm_header_end = strtol(value, NULL, 10); } } else if (!strcmp (name, "rpm:provides")) { ctx->state = PRIMARY_PARSER_DEP; ctx->current_dep_list = &sctx->current_package->provides; } else if (!strcmp (name, "rpm:requires")) { ctx->state = PRIMARY_PARSER_DEP; ctx->current_dep_list = &sctx->current_package->requires; } else if (!strcmp (name, "rpm:obsoletes")) { ctx->state = PRIMARY_PARSER_DEP; ctx->current_dep_list = &sctx->current_package->obsoletes; } else if (!strcmp (name, "rpm:conflicts")) { ctx->state = PRIMARY_PARSER_DEP; ctx->current_dep_list = &sctx->current_package->conflicts; } else if (!strcmp (name, "file")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "type")) { ctx->current_file = package_file_new (); ctx->current_file->type = g_string_chunk_insert_const (p->chunk, value); } } }}static voidprimary_parser_dep_start (PrimarySAXContext *ctx, const char *name, const char **attrs){ SAXContext *sctx = &ctx->sctx; const char *tmp_name = NULL; const char *tmp_version = NULL; const char *tmp_release = NULL; const char *tmp_epoch = NULL; const char *tmp_flags = NULL; gboolean tmp_pre = FALSE; Dependency *dep; int i; gboolean ignore = FALSE; const char *attr; const char *value; if (!strcmp (name, "rpm:entry")) { for (i = 0; attrs && attrs[i]; i++) { attr = attrs[i]; value = attrs[++i]; if (!strcmp (attr, "name")) { if (!strncmp (value, "rpmlib(", strlen ("rpmlib("))) { ignore = TRUE; break; } tmp_name = value; } else if (!strcmp (attr, "flags")) tmp_flags = value; else if (!strcmp (attr, "epoch")) tmp_epoch = value; else if (!strcmp (attr, "ver")) tmp_version = value; else if (!strcmp (attr, "rel")) tmp_release = value; else if (!strcmp (attr, "pre")) tmp_pre = TRUE; } if (!ignore) { GStringChunk *chunk = sctx->current_package->chunk; dep = dependency_new (); dep->name = g_string_chunk_insert (chunk, tmp_name); if (tmp_flags) dep->flags = g_string_chunk_insert (chunk, tmp_flags); if (tmp_epoch) dep->epoch = g_string_chunk_insert (chunk, tmp_epoch); if (tmp_version) dep->version = g_string_chunk_insert (chunk, tmp_version); if (tmp_release) dep->release = g_string_chunk_insert (chunk, tmp_release); dep->pre = tmp_pre; *ctx->current_dep_list = g_slist_prepend (*ctx->current_dep_list, dep); } }}static voidprimary_sax_start_element (void *data, const char *name, const char **attrs){ PrimarySAXContext *ctx = (PrimarySAXContext *) data; SAXContext *sctx = &ctx->sctx; if (sctx->text_buffer->len) g_string_truncate (sctx->text_buffer, 0); switch (ctx->state) { case PRIMARY_PARSER_TOPLEVEL: primary_parser_toplevel_start (ctx, name, attrs); break; case PRIMARY_PARSER_PACKAGE: primary_parser_package_start (ctx, name, attrs); break; case PRIMARY_PARSER_FORMAT: primary_parser_format_start (ctx, name, attrs); break; case PRIMARY_PARSER_DEP: primary_parser_dep_start (ctx, name, attrs); break; default: break; }}static voidprimary_parser_package_end (PrimarySAXContext *ctx, const char *name){ SAXContext *sctx = &ctx->sctx; Package *p = sctx->current_package; g_assert (p != NULL); if (!strcmp (name, "package")) { if (sctx->package_fn && !*sctx->error) sctx->package_fn (p, sctx->user_data); package_free (p); sctx->current_package = NULL; sctx->want_text = FALSE; ctx->state = PRIMARY_PARSER_TOPLEVEL; } else if (sctx->text_buffer->len == 0) /* Nothing interesting to do here */ return; else if (!strcmp (name, "name")) p->name = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "arch")) p->arch = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "checksum")) p->pkgId = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "summary")) p->summary = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "description")) p->description = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "packager")) p->rpm_packager = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "url")) p->url = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len);}static voidprimary_parser_format_end (PrimarySAXContext *ctx, const char *name){ SAXContext *sctx = &ctx->sctx; Package *p = sctx->current_package; g_assert (p != NULL); if (!strcmp (name, "rpm:license")) p->rpm_license = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); if (!strcmp (name, "rpm:vendor")) p->rpm_vendor = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); if (!strcmp (name, "rpm:group")) p->rpm_group = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); if (!strcmp (name, "rpm:buildhost")) p->rpm_buildhost = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); if (!strcmp (name, "rpm:sourcerpm")) p->rpm_sourcerpm = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); else if (!strcmp (name, "file")) { PackageFile *file = ctx->current_file != NULL ? ctx->current_file : package_file_new (); file->name = g_string_chunk_insert_len (p->chunk, sctx->text_buffer->str, sctx->text_buffer->len); if (!file->type) file->type = g_string_chunk_insert_const (p->chunk, "file"); p->files = g_slist_prepend (p->files, file); ctx->current_file = NULL; } else if (!strcmp (name, "format")) ctx->state = PRIMARY_PARSER_PACKAGE;}static voidprimary_parser_dep_end (PrimarySAXContext *ctx, const char *name){ SAXContext *sctx = &ctx->sctx; g_assert (sctx->current_package != NULL); if (strcmp (name, "rpm:entry")) ctx->state = PRIMARY_PARSER_FORMAT;}static voidprimary_sax_end_element (void *data, const char *name){ PrimarySAXContext *ctx = (PrimarySAXContext *) data; SAXContext *sctx = &ctx->sctx; switch (ctx->state) { case PRIMARY_PARSER_PACKAGE: primary_parser_package_end (ctx, name); break; case PRIMARY_PARSER_FORMAT: primary_parser_format_end (ctx, name); break; case PRIMARY_PARSER_DEP: primary_parser_dep_end (ctx, name); break; default: break; } g_string_truncate (sctx->text_buffer, 0);}static voidsax_characters (void *data, const char *ch, int len){ SAXContext *sctx = (SAXContext *) data; if (sctx->want_text) g_string_append_len (sctx->text_buffer, ch, len);}static voidsax_warning (void *data, const char *msg, ...){ va_list args; char *tmp; va_start (args, msg); tmp = g_strdup_vprintf (msg, args); g_warning ("* SAX Warning: %s", tmp); g_free (tmp); va_end (args);}static voidsax_error (void *data, const char *msg, ...){ SAXContext *sctx = (SAXContext *) data; va_list args; char *tmp; va_start (args, msg); tmp = g_strdup_vprintf (msg, args); g_set_error (sctx->error, YUM_PARSER_ERROR, YUM_PARSER_ERROR, "Parsing %s error: %s", sctx->md_type, tmp); g_free (tmp); va_end (args);}static xmlSAXHandler primary_sax_handler = { NULL, /* internalSubset */ NULL, /* isStandalone */ NULL, /* hasInternalSubset */ NULL, /* hasExternalSubset */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -