Imported Upstream version 4.14.1
[platform/upstream/rpm.git] / lib / formats.c
index 653f43d..fff53d6 100644 (file)
 
 #include "debug.h"
 
+#define RPM_ANY_CLASS 255
+
+typedef char * (*headerTagFormatFunction) (rpmtd td, char **emsg);
+
 /** \ingroup header
  * Define header tag output formats.
  */
 
-struct headerFormatFunc_s {
+struct headerFmt_s {
     rpmtdFormats fmt;  /*!< Value of extension */
     const char *name;  /*!< Name of extension. */
+    rpmTagClass class; /*!< Class of source data (RPM_ANY_CLASS for any) */
     headerTagFormatFunction func;      /*!< Pointer to formatter function. */  
 };
 
-/**
- * barebones string representation with no extra formatting
- * @param td           tag data container
- * @return             formatted string
- */
-static char * stringFormat(rpmtd td)
+static const char *classEr(rpmTagClass class)
+{
+    switch (class) {
+    case RPM_BINARY_CLASS:      return _("(not a blob)");
+    case RPM_NUMERIC_CLASS:     return _("(not a number)");
+    case RPM_STRING_CLASS:      return _("(not a string)");
+    default:                    break;
+    }
+    return _("(invalid type)");
+}
+
+/* barebones string representation with no extra formatting */
+static char * stringFormat(rpmtd td, char **emsg)
 {
     char *val = NULL;
 
@@ -44,109 +56,80 @@ static char * stringFormat(rpmtd td)
        case RPM_NUMERIC_CLASS:
            rasprintf(&val, "%" PRIu64, rpmtdGetNumber(td));
            break;
-       case RPM_STRING_CLASS:
-           val = xstrdup(rpmtdGetString(td));
+       case RPM_STRING_CLASS: {
+           const char *str = rpmtdGetString(td);
+           if (str)
+               val = xstrdup(str);
            break;
+       }
        case RPM_BINARY_CLASS:
            val = pgpHexStr(td->data, td->count);
            break;
        default:
-           val = xstrdup("(unknown type)");
+           *emsg = xstrdup("(unknown type)");
            break;
     }
     return val;
 }
 
+/* arbitrary number format as per format arg */
 static char * numFormat(rpmtd td, const char *format)
 {
     char * val = NULL;
-
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       rasprintf(&val, format, rpmtdGetNumber(td));
-    }
-
+    rasprintf(&val, format, rpmtdGetNumber(td));
     return val;
 }
-/**
- * octalFormat.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * octalFormat(rpmtd td)
+
+/* octal number formatting */
+static char * octalFormat(rpmtd td, char **emsg)
 {
     return numFormat(td, "%o");
 }
 
-/**
- * hexFormat.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * hexFormat(rpmtd td)
+/* hexadecimal format */
+static char * hexFormat(rpmtd td, char **emsg)
 {
     return numFormat(td, "%x");
 }
 
-/**
- * @param td           tag data container
- * @return             formatted string
- */
-static char * realDateFormat(rpmtd td, const char * strftimeFormat)
+/* arbitrary date formatting as per strftimeFormat arg */
+static char * realDateFormat(rpmtd td, const char * strftimeFormat, char **emsg)
 {
     char * val = NULL;
+    struct tm * tstruct;
+    char buf[1024];
+    time_t dateint = rpmtdGetNumber(td);
+    tstruct = localtime(&dateint);
 
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       struct tm * tstruct;
-       char buf[50];
-       time_t dateint = rpmtdGetNumber(td);
-       tstruct = localtime(&dateint);
-
-       /* XXX TODO: deal with non-fitting date string correctly */
-       buf[0] = '\0';
-       if (tstruct)
-           (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
-       val = xstrdup(buf);
-    }
+    buf[0] = '\0';
+    if (tstruct)
+       if (strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct) == 0)
+           *emsg = xstrdup("date output too long");
+    val = xstrdup(buf);
 
     return val;
 }
 
-/**
- * Format a date.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * dateFormat(rpmtd td)
+/* date formatting */
+static char * dateFormat(rpmtd td, char **emsg)
 {
-    return realDateFormat(td, _("%c"));
+    return realDateFormat(td, _("%c"), emsg);
 }
 
-/**
- * Format a day.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * dayFormat(rpmtd td)
+/* day formatting */
+static char * dayFormat(rpmtd td, char **emsg)
 {
-    return realDateFormat(td, _("%a %b %d %Y"));
+    return realDateFormat(td, _("%a %b %d %Y"), emsg);
 }
 
-/**
- * Return shell escape formatted data.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * shescapeFormat(rpmtd td)
+/* shell escape formatting */
+static char * shescapeFormat(rpmtd td, char **emsg)
 {
     char * result = NULL, * dst, * src;
 
     if (rpmtdClass(td) == RPM_NUMERIC_CLASS) {
        rasprintf(&result, "%" PRIu64, rpmtdGetNumber(td));
-    } else {
+    } else if (rpmtdClass(td) == RPM_STRING_CLASS) {
        char *buf = xstrdup(rpmtdGetString(td));;
 
        result = dst = xmalloc(strlen(buf) * 4 + 3);
@@ -164,139 +147,95 @@ static char * shescapeFormat(rpmtd td)
        *dst++ = '\'';
        *dst = '\0';
        free(buf);
+    } else {
+       *emsg = xstrdup(_("(invalid type)"));
     }
 
     return result;
 }
 
 
-/**
- * Identify type of trigger.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * triggertypeFormat(rpmtd td)
+/* trigger type formatting (from rpmsense flags) */
+static char * triggertypeFormat(rpmtd td, char **emsg)
 {
     char * val;
-
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       uint64_t item = rpmtdGetNumber(td);
-       if (item & RPMSENSE_TRIGGERPREIN)
-           val = xstrdup("prein");
-       else if (item & RPMSENSE_TRIGGERIN)
-           val = xstrdup("in");
-       else if (item & RPMSENSE_TRIGGERUN)
-           val = xstrdup("un");
-       else if (item & RPMSENSE_TRIGGERPOSTUN)
-           val = xstrdup("postun");
-       else
-           val = xstrdup("");
-    }
+    uint64_t item = rpmtdGetNumber(td);
+    if (item & RPMSENSE_TRIGGERPREIN)
+       val = xstrdup("prein");
+    else if (item & RPMSENSE_TRIGGERIN)
+       val = xstrdup("in");
+    else if (item & RPMSENSE_TRIGGERUN)
+       val = xstrdup("un");
+    else if (item & RPMSENSE_TRIGGERPOSTUN)
+       val = xstrdup("postun");
+    else
+       val = xstrdup("");
     return val;
 }
 
-/**
- * Identify type of dependency.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * deptypeFormat(rpmtd td)
+/* dependency type formatting (from rpmsense flags) */
+static char * deptypeFormat(rpmtd td, char **emsg)
 {
     char *val = NULL;
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
+    ARGV_t sdeps = NULL;
+    uint64_t item = rpmtdGetNumber(td);
+
+    if (item & RPMSENSE_SCRIPT_PRE)
+       argvAdd(&sdeps, "pre");
+    if (item & RPMSENSE_SCRIPT_POST)
+       argvAdd(&sdeps, "post");
+    if (item & RPMSENSE_SCRIPT_PREUN)
+       argvAdd(&sdeps, "preun");
+    if (item & RPMSENSE_SCRIPT_POSTUN)
+       argvAdd(&sdeps, "postun");
+    if (item & RPMSENSE_SCRIPT_VERIFY)
+       argvAdd(&sdeps, "verify");
+    if (item & RPMSENSE_INTERP)
+       argvAdd(&sdeps, "interp");
+    if (item & RPMSENSE_RPMLIB)
+       argvAdd(&sdeps, "rpmlib");
+    if ((item & RPMSENSE_FIND_REQUIRES) || (item & RPMSENSE_FIND_PROVIDES))
+       argvAdd(&sdeps, "auto");
+    if (item & RPMSENSE_PREREQ)
+       argvAdd(&sdeps, "prereq");
+    if (item & RPMSENSE_PRETRANS)
+       argvAdd(&sdeps, "pretrans");
+    if (item & RPMSENSE_POSTTRANS)
+       argvAdd(&sdeps, "posttrans");
+    if (item & RPMSENSE_CONFIG)
+       argvAdd(&sdeps, "config");
+    if (item & RPMSENSE_MISSINGOK)
+       argvAdd(&sdeps, "missingok");
+
+    if (sdeps) {
+       val = argvJoin(sdeps, ",");
     } else {
-       ARGV_t sdeps = NULL;
-       uint64_t item = rpmtdGetNumber(td);
-
-       if (item & RPMSENSE_SCRIPT_PRE)
-           argvAdd(&sdeps, "pre");
-       if (item & RPMSENSE_SCRIPT_POST)
-           argvAdd(&sdeps, "post");
-       if (item & RPMSENSE_SCRIPT_PREUN)
-           argvAdd(&sdeps, "preun");
-       if (item & RPMSENSE_SCRIPT_POSTUN)
-           argvAdd(&sdeps, "postun");
-       if (item & RPMSENSE_SCRIPT_VERIFY)
-           argvAdd(&sdeps, "verify");
-       if (item & RPMSENSE_INTERP)
-           argvAdd(&sdeps, "interp");
-       if (item & RPMSENSE_RPMLIB)
-           argvAdd(&sdeps, "rpmlib");
-       if ((item & RPMSENSE_FIND_REQUIRES) || (item & RPMSENSE_FIND_PROVIDES))
-           argvAdd(&sdeps, "auto");
-       if (item & RPMSENSE_PREREQ)
-           argvAdd(&sdeps, "prereq");
-       if (item & RPMSENSE_PRETRANS)
-           argvAdd(&sdeps, "pretrans");
-       if (item & RPMSENSE_POSTTRANS)
-           argvAdd(&sdeps, "posttrans");
-       if (item & RPMSENSE_CONFIG)
-           argvAdd(&sdeps, "config");
-       if (item & RPMSENSE_MISSINGOK)
-           argvAdd(&sdeps, "missingok");
-
-       if (sdeps) {
-           val = argvJoin(sdeps, ",");
-       } else {
-           val = xstrdup("manual");
-       }
-
-       argvFree(sdeps);
+       val = xstrdup("manual");
     }
+
+    argvFree(sdeps);
     return val;
 }
 
-/**
- * Format file permissions for display.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * permsFormat(rpmtd td)
+/* file permissions formatting */
+static char * permsFormat(rpmtd td, char **emsg)
 {
-    char * val = NULL;
-
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       val = rpmPermsString(rpmtdGetNumber(td));
-    }
-
-    return val;
+    return rpmPermsString(rpmtdGetNumber(td));
 }
 
-/**
- * Format file flags for display.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * fflagsFormat(rpmtd td)
+/* file flags formatting */
+static char * fflagsFormat(rpmtd td, char **emsg)
 {
-    char * val = NULL;
-
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       val = rpmFFlagsString(rpmtdGetNumber(td), "");
-    }
-
-    return val;
+    return rpmFFlagsString(rpmtdGetNumber(td), "");
 }
 
-/**
- * Wrap a pubkey in ascii armor for display.
- * @todo Permit selectable display formats (i.e. binary).
- * @param td           tag data container
- * @return             formatted string
- */
-static char * armorFormat(rpmtd td)
+/* pubkey ascii armor formatting */
+static char * armorFormat(rpmtd td, char **emsg)
 {
     const char * enc;
     const unsigned char * s;
     unsigned char * bs = NULL;
-    char *val;
+    char *val = NULL;
     size_t ns;
     int atype;
 
@@ -310,8 +249,10 @@ static char * armorFormat(rpmtd td)
     case RPM_STRING_TYPE:
     case RPM_STRING_ARRAY_TYPE:
        enc = rpmtdGetString(td);
-       if (rpmBase64Decode(enc, (void **)&bs, &ns))
-           return xstrdup(_("(not base64)"));
+       if (rpmBase64Decode(enc, (void **)&bs, &ns)) {
+           *emsg = xstrdup(_("(not base64)"));
+           goto exit;
+       }
        s = bs;
        atype = PGPARMOR_PUBKEY;        /* XXX check pkt for pubkey */
        break;
@@ -323,7 +264,8 @@ static char * armorFormat(rpmtd td)
     case RPM_INT64_TYPE:
     case RPM_I18NSTRING_TYPE:
     default:
-       return xstrdup(_("(invalid type)"));
+       *emsg = xstrdup(_("(invalid type)"));
+       goto exit;
        break;
     }
 
@@ -332,48 +274,35 @@ static char * armorFormat(rpmtd td)
     if (atype == PGPARMOR_PUBKEY) {
        free(bs);
     }
+
+exit:
     return val;
 }
 
-/**
- * Encode binary data in base64 for display.
- * @todo Permit selectable display formats (i.e. binary).
- * @param td           tag data container
- * @return             formatted string
- */
-static char * base64Format(rpmtd td)
+/* base64 encoding formatting */
+static char * base64Format(rpmtd td, char **emsg)
 {
-    char * val = NULL;
-
-    if (rpmtdType(td) != RPM_BIN_TYPE) {
-       val = xstrdup(_("(not a blob)"));
-    } else {
-       val = rpmBase64Encode(td->data, td->count, -1);
-       if (val == NULL)
-           val = xstrdup("");
-    }
+    char * val = rpmBase64Encode(td->data, td->count, -1);
+    if (val == NULL)
+       val = xstrdup("");
 
     return val;
 }
 
-/**
- * Wrap tag data in simple header xml markup.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * xmlFormat(rpmtd td)
+/* xml formatting */
+static char * xmlFormat(rpmtd td, char **emsg)
 {
     const char *xtag = NULL;
     char *val = NULL;
     char *s = NULL;
-    rpmtdFormats fmt = RPMTD_FORMAT_STRING;
+    headerTagFormatFunction fmt = stringFormat;
 
     switch (rpmtdClass(td)) {
     case RPM_STRING_CLASS:
        xtag = "string";
        break;
     case RPM_BINARY_CLASS:
-       fmt = RPMTD_FORMAT_BASE64;
+       fmt = base64Format;
        xtag = "base64";
        break;
     case RPM_NUMERIC_CLASS:
@@ -381,12 +310,14 @@ static char * xmlFormat(rpmtd td)
        break;
     case RPM_NULL_TYPE:
     default:
-       return xstrdup(_("(invalid xml type)"));
+       *emsg = xstrdup(_("(invalid xml type)"));
+       goto exit;
        break;
     }
 
-    /* XXX TODO: handle errors */
-    s = rpmtdFormat(td, fmt, NULL);
+    s = fmt(td, emsg);
+    if (s == NULL)
+       goto exit;
 
     if (s[0] == '\0') {
        val = rstrscat(NULL, "\t<", xtag, "/>", NULL);
@@ -413,212 +344,205 @@ static char * xmlFormat(rpmtd td)
     }
     free(s);
 
+exit:
     return val;
 }
 
-/**
- * Display signature fingerprint and time.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * pgpsigFormat(rpmtd td)
+/* signature fingerprint and time formatting */
+static char * pgpsigFormat(rpmtd td, char **emsg)
 {
     char * val = NULL;
+    pgpDigParams sigp = NULL;
 
-    if (rpmtdType(td) != RPM_BIN_TYPE) {
-       val = xstrdup(_("(not a blob)"));
+    if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) {
+       *emsg = xstrdup(_("(not an OpenPGP signature)"));
     } else {
-       pgpDigParams sigp = NULL;
-
-       if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) {
-           val = xstrdup(_("(not an OpenPGP signature)"));
+       char dbuf[BUFSIZ];
+       char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid));
+       unsigned int dateint = sigp->time;
+       time_t date = dateint;
+       struct tm * tms = localtime(&date);
+       unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
+       unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
+
+       if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) {
+           rasprintf(emsg, _("Invalid date %u"), dateint);
        } else {
-           char dbuf[BUFSIZ];
-           char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid));
-           unsigned int dateint = pgpGrab(sigp->time, sizeof(sigp->time));
-           time_t date = dateint;
-           struct tm * tms = localtime(&date);
-           unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
-           unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
-
-           if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) {
-               snprintf(dbuf, sizeof(dbuf),
-                        _("Invalid date %u"), dateint);
-               dbuf[sizeof(dbuf)-1] = '\0';
-           }
-
            rasprintf(&val, "%s/%s, %s, Key ID %s",
-                       pgpValString(PGPVAL_PUBKEYALGO, key_algo),
-                       pgpValString(PGPVAL_HASHALGO, hash_algo),
-                       dbuf, keyid);
-
-           free(keyid);
-           pgpDigParamsFree(sigp);
+                   pgpValString(PGPVAL_PUBKEYALGO, key_algo),
+                   pgpValString(PGPVAL_HASHALGO, hash_algo),
+                   dbuf, keyid);
        }
+
+       free(keyid);
+       pgpDigParamsFree(sigp);
     }
 
     return val;
 }
 
-/**
- * Format dependency flags for display.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * depflagsFormat(rpmtd td)
+/* dependency flags formatting */
+static char * depflagsFormat(rpmtd td, char **emsg)
 {
     char * val = NULL;
+    uint64_t anint = rpmtdGetNumber(td);
+    val = xcalloc(4, 1);
 
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       uint64_t anint = rpmtdGetNumber(td);
-       val = xcalloc(4, 1);
-
-       if (anint & RPMSENSE_LESS) 
-           strcat(val, "<");
-       if (anint & RPMSENSE_GREATER)
-           strcat(val, ">");
-       if (anint & RPMSENSE_EQUAL)
-           strcat(val, "=");
-    }
+    if (anint & RPMSENSE_LESS)
+       strcat(val, "<");
+    if (anint & RPMSENSE_GREATER)
+       strcat(val, ">");
+    if (anint & RPMSENSE_EQUAL)
+       strcat(val, "=");
 
     return val;
 }
 
-/**
- * Return tag container array size.
- * @param td           tag data container
- * @return             formatted string
- */
-static char * arraysizeFormat(rpmtd td)
+/* tag container array size */
+static char * arraysizeFormat(rpmtd td, char **emsg)
 {
     char *val = NULL;
     rasprintf(&val, "%u", rpmtdCount(td));
     return val;
 }
 
-static char * fstateFormat(rpmtd td)
+/* file state formatting */
+static char * fstateFormat(rpmtd td, char **emsg)
 {
     char * val = NULL;
-
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       const char * str;
-       rpmfileState fstate = rpmtdGetNumber(td);
-       switch (fstate) {
-       case RPMFILE_STATE_NORMAL:
-           str = _("normal");
-           break;
-       case RPMFILE_STATE_REPLACED:
-           str = _("replaced");
-           break;
-       case RPMFILE_STATE_NOTINSTALLED:
-           str = _("not installed");
-           break;
-       case RPMFILE_STATE_NETSHARED:
-           str = _("net shared");
-           break;
-       case RPMFILE_STATE_WRONGCOLOR:
-           str = _("wrong color");
-           break;
-       case RPMFILE_STATE_MISSING:
-           str = _("missing");
-           break;
-       default:
-           str = _("(unknown)");
-           break;
-       }
-       
-       val = xstrdup(str);
+    const char * str;
+    rpmfileState fstate = rpmtdGetNumber(td);
+    switch (fstate) {
+    case RPMFILE_STATE_NORMAL:
+       str = _("normal");
+       break;
+    case RPMFILE_STATE_REPLACED:
+       str = _("replaced");
+       break;
+    case RPMFILE_STATE_NOTINSTALLED:
+       str = _("not installed");
+       break;
+    case RPMFILE_STATE_NETSHARED:
+       str = _("net shared");
+       break;
+    case RPMFILE_STATE_WRONGCOLOR:
+       str = _("wrong color");
+       break;
+    case RPMFILE_STATE_MISSING:
+       str = _("missing");
+       break;
+    default:
+       str = _("(unknown)");
+       break;
     }
+
+    val = xstrdup(str);
     return val;
 }
 
+/* file verification flags formatting with optional padding */
 static char * verifyFlags(rpmtd td, const char *pad)
 {
-    char * val = NULL;
-
-    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
-       val = xstrdup(_("(not a number)"));
-    } else {
-       val = rpmVerifyString(rpmtdGetNumber(td), pad);
-    }
-    return val;
+    return rpmVerifyString(rpmtdGetNumber(td), pad);
 }
 
-static char * vflagsFormat(rpmtd td)
+static char * vflagsFormat(rpmtd td, char **emsg)
 {
     return verifyFlags(td, "");
 }
 
-static char * fstatusFormat(rpmtd td)
+static char * fstatusFormat(rpmtd td, char **emsg)
 {
     return verifyFlags(td, ".");
 }
 
-static char * expandFormat(rpmtd td)
+/* macro expansion formatting */
+static char * expandFormat(rpmtd td, char **emsg)
 {
-    char *val = NULL;
-    if (rpmtdClass(td) != RPM_STRING_CLASS) {
-       val = xstrdup(_("(not a string)"));
-    } else {
-       val = rpmExpand(td->data, NULL);
-    }
-    return val;
+    return rpmExpand(rpmtdGetString(td), NULL);
 }
 
-static const struct headerFormatFunc_s rpmHeaderFormats[] = {
-    { RPMTD_FORMAT_STRING,     "string",       stringFormat },
-    { RPMTD_FORMAT_ARMOR,      "armor",        armorFormat },
-    { RPMTD_FORMAT_BASE64,     "base64",       base64Format },
-    { RPMTD_FORMAT_PGPSIG,     "pgpsig",       pgpsigFormat },
-    { RPMTD_FORMAT_DEPFLAGS,   "depflags",     depflagsFormat },
-    { RPMTD_FORMAT_DEPTYPE,    "deptype",      deptypeFormat },
-    { RPMTD_FORMAT_FFLAGS,     "fflags",       fflagsFormat },
-    { RPMTD_FORMAT_PERMS,      "perms",        permsFormat },
-    { RPMTD_FORMAT_PERMS,      "permissions",  permsFormat },
-    { RPMTD_FORMAT_TRIGGERTYPE,        "triggertype",  triggertypeFormat },
-    { RPMTD_FORMAT_XML,                "xml",          xmlFormat },
-    { RPMTD_FORMAT_OCTAL,      "octal",        octalFormat },
-    { RPMTD_FORMAT_HEX,                "hex",          hexFormat },
-    { RPMTD_FORMAT_DATE,       "date",         dateFormat },
-    { RPMTD_FORMAT_DAY,                "day",          dayFormat },
-    { RPMTD_FORMAT_SHESCAPE,   "shescape",     shescapeFormat },
-    { RPMTD_FORMAT_ARRAYSIZE,  "arraysize",    arraysizeFormat },
-    { RPMTD_FORMAT_FSTATE,     "fstate",       fstateFormat },
-    { RPMTD_FORMAT_VFLAGS,     "vflags",       vflagsFormat },
-    { RPMTD_FORMAT_EXPAND,     "expand",       expandFormat },
-    { RPMTD_FORMAT_FSTATUS,    "fstatus",      fstatusFormat },
-    { -1,                      NULL,           NULL }
+static const struct headerFmt_s rpmHeaderFormats[] = {
+    { RPMTD_FORMAT_STRING,     "string",
+       RPM_ANY_CLASS,          stringFormat },
+    { RPMTD_FORMAT_ARMOR,      "armor",
+       RPM_ANY_CLASS,          armorFormat },
+    { RPMTD_FORMAT_BASE64,     "base64",
+       RPM_BINARY_CLASS,       base64Format },
+    { RPMTD_FORMAT_PGPSIG,     "pgpsig",
+       RPM_BINARY_CLASS,       pgpsigFormat },
+    { RPMTD_FORMAT_DEPFLAGS,   "depflags",
+       RPM_NUMERIC_CLASS, depflagsFormat },
+    { RPMTD_FORMAT_DEPTYPE,    "deptype",
+       RPM_NUMERIC_CLASS,      deptypeFormat },
+    { RPMTD_FORMAT_FFLAGS,     "fflags",
+       RPM_NUMERIC_CLASS,      fflagsFormat },
+    { RPMTD_FORMAT_PERMS,      "perms",
+       RPM_NUMERIC_CLASS,      permsFormat },
+    { RPMTD_FORMAT_PERMS,      "permissions",
+       RPM_NUMERIC_CLASS,      permsFormat },
+    { RPMTD_FORMAT_TRIGGERTYPE,        "triggertype",
+       RPM_NUMERIC_CLASS,      triggertypeFormat },
+    { RPMTD_FORMAT_XML,                "xml",
+       RPM_ANY_CLASS,          xmlFormat },
+    { RPMTD_FORMAT_OCTAL,      "octal",
+       RPM_NUMERIC_CLASS,      octalFormat },
+    { RPMTD_FORMAT_HEX,                "hex",
+       RPM_NUMERIC_CLASS,      hexFormat },
+    { RPMTD_FORMAT_DATE,       "date",
+       RPM_NUMERIC_CLASS,      dateFormat },
+    { RPMTD_FORMAT_DAY,                "day",
+       RPM_NUMERIC_CLASS,      dayFormat },
+    { RPMTD_FORMAT_SHESCAPE,   "shescape",
+       RPM_ANY_CLASS,          shescapeFormat },
+    { RPMTD_FORMAT_ARRAYSIZE,  "arraysize",
+       RPM_ANY_CLASS,          arraysizeFormat },
+    { RPMTD_FORMAT_FSTATE,     "fstate",
+       RPM_NUMERIC_CLASS,      fstateFormat },
+    { RPMTD_FORMAT_VFLAGS,     "vflags",
+       RPM_NUMERIC_CLASS,      vflagsFormat },
+    { RPMTD_FORMAT_EXPAND,     "expand",
+       RPM_STRING_CLASS,       expandFormat },
+    { RPMTD_FORMAT_FSTATUS,    "fstatus",
+       RPM_NUMERIC_CLASS,      fstatusFormat },
+    { -1,                      NULL,           0,      NULL }
 };
 
-headerTagFormatFunction rpmHeaderFormatFuncByName(const char *fmt)
+headerFmt rpmHeaderFormatByName(const char *fmt)
 {
-    const struct headerFormatFunc_s * ext;
-    headerTagFormatFunction func = NULL;
+    const struct headerFmt_s * ext;
 
     for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
-       if (rstreq(ext->name, fmt)) {
-           func = ext->func;
-           break;
-       }
+       if (rstreq(ext->name, fmt))
+           return ext;
     }
-    return func;
+    return NULL;
 }
 
-headerTagFormatFunction rpmHeaderFormatFuncByValue(rpmtdFormats fmt)
+headerFmt rpmHeaderFormatByValue(rpmtdFormats fmt)
 {
-    const struct headerFormatFunc_s * ext;
-    headerTagFormatFunction func = NULL;
+    const struct headerFmt_s * ext;
 
     for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
-       if (fmt == ext->fmt) {
-           func = ext->func;
-           break;
-       }
+       if (fmt == ext->fmt)
+           return ext;
     }
-    return func;
+    return NULL;
 }
 
+char *rpmHeaderFormatCall(headerFmt fmt, rpmtd td)
+{
+    char *ret = NULL;
+    char *err = NULL;
+
+    if (fmt->class != RPM_ANY_CLASS && rpmtdClass(td) != fmt->class)
+       err = xstrdup(classEr(fmt->class));
+    else
+       ret = fmt->func(td, &err);
+
+    if (err) {
+       free(ret);
+       ret = err;
+    }
+    return ret;
+}