2008-05-13 16:02:45 +08:00
|
|
|
#include "system.h"
|
|
|
|
|
|
|
|
#include <rpm/rpmtd.h>
|
|
|
|
#include <rpm/rpmstring.h>
|
2008-05-20 14:40:24 +08:00
|
|
|
#include <rpm/rpmpgp.h>
|
2008-05-13 16:02:45 +08:00
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
|
2008-05-20 16:57:30 +08:00
|
|
|
typedef char * (*headerTagFormatFunction) (rpmtd td, char *formatPrefix);
|
2008-05-20 14:40:24 +08:00
|
|
|
|
|
|
|
extern void *rpmHeaderFormatFuncByValue(rpmtdFormats fmt);
|
|
|
|
|
2008-05-13 16:02:45 +08:00
|
|
|
rpmtd rpmtdNew(void)
|
|
|
|
{
|
|
|
|
rpmtd td = xmalloc(sizeof(*td));
|
|
|
|
rpmtdReset(td);
|
|
|
|
return td;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpmtd rpmtdFree(rpmtd td)
|
|
|
|
{
|
|
|
|
/* permit free on NULL td */
|
|
|
|
if (td != NULL) {
|
|
|
|
/* XXX should we free data too - a flag maybe? */
|
|
|
|
free(td);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpmtdReset(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
memset(td, 0, sizeof(*td));
|
|
|
|
td->ix = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpmtdFreeData(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
|
2008-05-21 14:02:10 +08:00
|
|
|
if (td->flags & RPMTD_ALLOCED) {
|
|
|
|
if (td->flags & RPMTD_PTR_ALLOCED) {
|
2008-05-21 17:41:31 +08:00
|
|
|
assert(td->data != NULL);
|
2008-05-21 14:02:10 +08:00
|
|
|
char **data = td->data;
|
|
|
|
for (int i = 0; i < td->count; i++) {
|
|
|
|
free(data[i]);
|
|
|
|
}
|
|
|
|
}
|
2008-05-13 16:02:45 +08:00
|
|
|
free(td->data);
|
|
|
|
}
|
|
|
|
rpmtdReset(td);
|
|
|
|
}
|
|
|
|
|
|
|
|
rpm_count_t rpmtdCount(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
2008-05-20 17:18:14 +08:00
|
|
|
/* fix up for binary type abusing count as data length */
|
|
|
|
return (td->type == RPM_BIN_TYPE) ? 1 : td->count;
|
2008-05-13 16:02:45 +08:00
|
|
|
}
|
2008-05-13 19:02:40 +08:00
|
|
|
|
|
|
|
rpmTag rpmtdTag(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
return td->tag;
|
|
|
|
}
|
|
|
|
|
2008-05-13 21:11:28 +08:00
|
|
|
rpmTagType rpmtdType(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
return td->type;
|
|
|
|
}
|
|
|
|
|
2008-11-17 17:31:00 +08:00
|
|
|
rpmTagClass rpmtdClass(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
2009-01-28 19:21:39 +08:00
|
|
|
return rpmTagTypeGetClass(td->type);
|
2008-11-17 17:31:00 +08:00
|
|
|
}
|
|
|
|
|
2008-05-23 16:49:56 +08:00
|
|
|
int rpmtdGetIndex(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
return td->ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpmtdSetIndex(rpmtd td, int index)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
if (index < 0 || index >= rpmtdCount(td)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
td->ix = index;
|
|
|
|
return td->ix;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:55 +08:00
|
|
|
int rpmtdInit(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
/* XXX check that this is an array type? */
|
|
|
|
td->ix = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpmtdNext(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
2008-05-20 14:40:24 +08:00
|
|
|
|
|
|
|
int i = -1;
|
|
|
|
|
2008-05-13 19:40:55 +08:00
|
|
|
if (++td->ix >= 0) {
|
2008-05-20 17:18:14 +08:00
|
|
|
if (td->ix < rpmtdCount(td)) {
|
2008-05-13 19:40:55 +08:00
|
|
|
i = td->ix;
|
|
|
|
} else {
|
|
|
|
td->ix = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2008-05-21 19:49:12 +08:00
|
|
|
uint32_t *rpmtdNextUint32(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
uint32_t *res = NULL;
|
|
|
|
if (rpmtdNext(td) >= 0) {
|
|
|
|
res = rpmtdGetUint32(td);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2008-06-07 04:47:37 +08:00
|
|
|
uint64_t *rpmtdNextUint64(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
uint64_t *res = NULL;
|
|
|
|
if (rpmtdNext(td) >= 0) {
|
|
|
|
res = rpmtdGetUint64(td);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2008-05-21 19:49:12 +08:00
|
|
|
const char *rpmtdNextString(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
const char *res = NULL;
|
|
|
|
if (rpmtdNext(td) >= 0) {
|
|
|
|
res = rpmtdGetString(td);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2008-05-20 13:53:05 +08:00
|
|
|
char * rpmtdGetChar(rpmtd td)
|
|
|
|
{
|
|
|
|
char *res = NULL;
|
|
|
|
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
if (td->type == RPM_CHAR_TYPE) {
|
|
|
|
int ix = (td->ix >= 0 ? td->ix : 0);
|
|
|
|
res = (char *) td->data + ix;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2008-05-13 23:09:35 +08:00
|
|
|
uint16_t * rpmtdGetUint16(rpmtd td)
|
|
|
|
{
|
|
|
|
uint16_t *res = NULL;
|
|
|
|
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
if (td->type == RPM_INT16_TYPE) {
|
|
|
|
int ix = (td->ix >= 0 ? td->ix : 0);
|
|
|
|
res = (uint16_t *) td->data + ix;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t * rpmtdGetUint32(rpmtd td)
|
|
|
|
{
|
|
|
|
uint32_t *res = NULL;
|
|
|
|
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
if (td->type == RPM_INT32_TYPE) {
|
|
|
|
int ix = (td->ix >= 0 ? td->ix : 0);
|
|
|
|
res = (uint32_t *) td->data + ix;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2008-06-07 04:47:37 +08:00
|
|
|
|
|
|
|
uint64_t * rpmtdGetUint64(rpmtd td)
|
|
|
|
{
|
|
|
|
uint64_t *res = NULL;
|
|
|
|
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
if (td->type == RPM_INT64_TYPE) {
|
|
|
|
int ix = (td->ix >= 0 ? td->ix : 0);
|
|
|
|
res = (uint64_t *) td->data + ix;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2008-05-13 19:40:55 +08:00
|
|
|
const char * rpmtdGetString(rpmtd td)
|
|
|
|
{
|
|
|
|
const char *str = NULL;
|
|
|
|
|
|
|
|
assert(td != NULL);
|
|
|
|
|
|
|
|
if (td->type == RPM_STRING_TYPE) {
|
|
|
|
str = (const char *) td->data;
|
2008-05-19 13:27:10 +08:00
|
|
|
} else if (td->type == RPM_STRING_ARRAY_TYPE ||
|
|
|
|
td->type == RPM_I18NSTRING_TYPE) {
|
2008-05-13 19:40:55 +08:00
|
|
|
/* XXX TODO: check for array bounds */
|
|
|
|
int ix = (td->ix >= 0 ? td->ix : 0);
|
|
|
|
str = *((const char**) td->data + ix);
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
2008-05-13 21:11:28 +08:00
|
|
|
|
2008-11-17 18:04:08 +08:00
|
|
|
uint64_t rpmtdGetNumber(rpmtd td)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
uint64_t val = 0;
|
|
|
|
int ix = (td->ix >= 0 ? td->ix : 0);
|
|
|
|
|
|
|
|
switch (td->type) {
|
|
|
|
case RPM_INT64_TYPE:
|
|
|
|
val = *((uint64_t *) td->data + ix);
|
|
|
|
break;
|
|
|
|
case RPM_INT32_TYPE:
|
|
|
|
val = *((uint32_t *) td->data + ix);
|
|
|
|
break;
|
|
|
|
case RPM_INT16_TYPE:
|
|
|
|
val = *((uint16_t *) td->data + ix);
|
|
|
|
break;
|
|
|
|
case RPM_INT8_TYPE:
|
|
|
|
case RPM_CHAR_TYPE:
|
|
|
|
val = *((uint8_t *) td->data + ix);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2008-05-20 14:40:24 +08:00
|
|
|
char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
|
|
|
|
{
|
|
|
|
headerTagFormatFunction func = rpmHeaderFormatFuncByValue(fmt);
|
|
|
|
const char *err = NULL;
|
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
if (func) {
|
|
|
|
char fmtbuf[50]; /* yuck, get rid of this */
|
|
|
|
strcpy(fmtbuf, "%");
|
2008-05-20 16:57:30 +08:00
|
|
|
str = func(td, fmtbuf);
|
2008-05-20 14:40:24 +08:00
|
|
|
} else {
|
|
|
|
err = _("Unknown format");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err && errmsg) {
|
|
|
|
errmsg = err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-05-23 15:31:45 +08:00
|
|
|
int rpmtdSetTag(rpmtd td, rpmTag tag)
|
|
|
|
{
|
|
|
|
assert(td != NULL);
|
|
|
|
rpmTagType newtype = rpmTagGetType(tag);
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sanity checks:
|
|
|
|
* - is the new tag valid at all
|
|
|
|
* - if changing tag of non-empty container, require matching type
|
|
|
|
*/
|
|
|
|
if (newtype == RPM_NULL_TYPE)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (td->data || td->count > 0) {
|
|
|
|
if (rpmTagGetType(td->tag) != rpmTagGetType(tag)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
td->tag = tag;
|
|
|
|
td->type = newtype & RPM_MASK_TYPE;
|
|
|
|
rc = 1;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-06-17 17:07:19 +08:00
|
|
|
static inline int rpmtdSet(rpmtd td, rpmTag tag, rpmTagType type,
|
|
|
|
rpm_constdata_t data, rpm_count_t count)
|
|
|
|
{
|
|
|
|
rpmtdReset(td);
|
|
|
|
td->tag = tag;
|
|
|
|
td->type = type;
|
|
|
|
td->count = count;
|
|
|
|
/*
|
|
|
|
* Discards const, but we won't touch the data (even rpmtdFreeData()
|
|
|
|
* wont free it as allocation flags aren't set) so it's "ok".
|
|
|
|
* XXX: Should there be a separate RPMTD_FOO flag for "user data"?
|
|
|
|
*/
|
|
|
|
td->data = (void *) data;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-06-18 17:36:20 +08:00
|
|
|
int rpmtdFromUint8(rpmtd td, rpmTag tag, uint8_t *data, rpm_count_t count)
|
|
|
|
{
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
|
|
|
|
|
|
|
|
if (count < 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BIN type is really just an uint8_t array internally, it's just
|
|
|
|
* treated specially otherwise.
|
|
|
|
*/
|
|
|
|
switch (type) {
|
|
|
|
case RPM_CHAR_TYPE:
|
|
|
|
case RPM_INT8_TYPE:
|
|
|
|
if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
|
|
|
|
return 0;
|
|
|
|
/* fallthrough */
|
|
|
|
case RPM_BIN_TYPE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rpmtdSet(td, tag, type, data, count);
|
|
|
|
}
|
|
|
|
|
2008-06-17 19:24:16 +08:00
|
|
|
int rpmtdFromUint16(rpmtd td, rpmTag tag, uint16_t *data, rpm_count_t count)
|
|
|
|
{
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
|
|
|
|
if (type != RPM_INT16_TYPE || count < 1)
|
|
|
|
return 0;
|
|
|
|
if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return rpmtdSet(td, tag, type, data, count);
|
|
|
|
}
|
|
|
|
|
2008-06-17 17:07:19 +08:00
|
|
|
int rpmtdFromUint32(rpmtd td, rpmTag tag, uint32_t *data, rpm_count_t count)
|
|
|
|
{
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
|
|
|
|
if (type != RPM_INT32_TYPE || count < 1)
|
|
|
|
return 0;
|
2008-06-17 19:24:16 +08:00
|
|
|
if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return rpmtdSet(td, tag, type, data, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpmtdFromUint64(rpmtd td, rpmTag tag, uint64_t *data, rpm_count_t count)
|
|
|
|
{
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
|
|
|
|
if (type != RPM_INT64_TYPE || count < 1)
|
|
|
|
return 0;
|
2008-06-17 17:07:19 +08:00
|
|
|
if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return rpmtdSet(td, tag, type, data, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpmtdFromString(rpmtd td, rpmTag tag, const char *data)
|
|
|
|
{
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (type == RPM_STRING_TYPE) {
|
|
|
|
rc = rpmtdSet(td, tag, type, data, 1);
|
|
|
|
} else if (type == RPM_STRING_ARRAY_TYPE) {
|
|
|
|
rc = rpmtdSet(td, tag, type, &data, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-06-17 21:04:12 +08:00
|
|
|
int rpmtdFromStringArray(rpmtd td, rpmTag tag, const char **data, rpm_count_t count)
|
2008-06-17 17:07:19 +08:00
|
|
|
{
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
if (type != RPM_STRING_ARRAY_TYPE || count < 1)
|
|
|
|
return 0;
|
|
|
|
if (type == RPM_STRING_TYPE && count != 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return rpmtdSet(td, tag, type, data, count);
|
|
|
|
}
|
|
|
|
|
2008-05-13 21:11:28 +08:00
|
|
|
int rpmtdFromArgv(rpmtd td, rpmTag tag, ARGV_t argv)
|
|
|
|
{
|
|
|
|
int count = argvCount(argv);
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
|
|
|
|
if (type != RPM_STRING_ARRAY_TYPE || count < 1)
|
|
|
|
return 0;
|
|
|
|
|
2008-06-17 17:07:19 +08:00
|
|
|
return rpmtdSet(td, tag, type, argv, count);
|
2008-05-13 21:11:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int rpmtdFromArgi(rpmtd td, rpmTag tag, ARGI_t argi)
|
|
|
|
{
|
|
|
|
int count = argiCount(argi);
|
|
|
|
rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
|
|
|
|
rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
|
|
|
|
|
|
|
|
if (type != RPM_INT32_TYPE || retype != RPM_ARRAY_RETURN_TYPE || count < 1)
|
|
|
|
return 0;
|
|
|
|
|
2008-06-17 17:07:19 +08:00
|
|
|
return rpmtdSet(td, tag, type, argiData(argi), count);
|
2008-05-13 21:11:28 +08:00
|
|
|
}
|
2008-05-21 14:22:38 +08:00
|
|
|
|
|
|
|
rpmtd rpmtdDup(rpmtd td)
|
|
|
|
{
|
|
|
|
rpmtd newtd = NULL;
|
|
|
|
char **data = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(td != NULL);
|
|
|
|
/* TODO: permit other types too */
|
|
|
|
if (td->type != RPM_STRING_ARRAY_TYPE && td->type != RPM_I18NSTRING_TYPE) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* deep-copy container and data, drop immutable flag */
|
|
|
|
newtd = rpmtdNew();
|
|
|
|
memcpy(newtd, td, sizeof(*td));
|
|
|
|
newtd->flags &= ~(RPMTD_IMMUTABLE);
|
|
|
|
|
|
|
|
newtd->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
|
|
|
|
newtd->data = data = xmalloc(td->count * sizeof(*data));
|
|
|
|
while ((i = rpmtdNext(td)) >= 0) {
|
|
|
|
data[i] = xstrdup(rpmtdGetString(td));
|
|
|
|
}
|
|
|
|
|
|
|
|
return newtd;
|
|
|
|
}
|