Add rpmtdDup() method for deep copying of tag containers
[platform/upstream/rpm.git] / lib / rpmtd.c
1 #include "system.h"
2
3 #include <rpm/rpmtd.h>
4 #include <rpm/rpmstring.h>
5 #include <rpm/rpmpgp.h>
6
7 #include "debug.h"
8
9 typedef char * (*headerTagFormatFunction) (rpmtd td, char *formatPrefix);
10
11 extern void *rpmHeaderFormatFuncByValue(rpmtdFormats fmt);
12
13 rpmtd rpmtdNew(void)
14 {
15     rpmtd td = xmalloc(sizeof(*td));
16     rpmtdReset(td);
17     return td;
18 }
19
20 rpmtd rpmtdFree(rpmtd td)
21 {
22     /* permit free on NULL td */
23     if (td != NULL) {
24         /* XXX should we free data too - a flag maybe? */
25         free(td);
26     }
27     return NULL;
28 }
29
30 void rpmtdReset(rpmtd td)
31 {
32     assert(td != NULL);
33
34     memset(td, 0, sizeof(*td));
35     td->ix = -1;
36 }
37
38 void rpmtdFreeData(rpmtd td)
39 {
40     assert(td != NULL);
41
42     if (td->flags & RPMTD_ALLOCED) {
43         assert(td->data != NULL);
44         if (td->flags & RPMTD_PTR_ALLOCED) {
45             char **data = td->data;
46             for (int i = 0; i < td->count; i++) {
47                 free(data[i]);
48             }
49         }
50         free(td->data);
51     }
52     rpmtdReset(td);
53 }
54
55 rpm_count_t rpmtdCount(rpmtd td)
56 {
57     assert(td != NULL);
58     /* fix up for binary type abusing count as data length */
59     return (td->type == RPM_BIN_TYPE) ? 1 : td->count;
60 }
61
62 rpmTag rpmtdTag(rpmtd td)
63 {
64     assert(td != NULL);
65     return td->tag;
66 }
67
68 rpmTagType rpmtdType(rpmtd td)
69 {
70     assert(td != NULL);
71     return td->type;
72 }
73
74 int rpmtdInit(rpmtd td)
75 {
76     assert(td != NULL);
77
78     /* XXX check that this is an array type? */
79     td->ix = -1;
80     return 0;
81 }
82
83 int rpmtdNext(rpmtd td)
84 {
85     assert(td != NULL);
86
87     int i = -1;
88     
89     if (++td->ix >= 0) {
90         if (td->ix < rpmtdCount(td)) {
91             i = td->ix;
92         } else {
93             td->ix = i;
94         }
95     }
96     return i;
97 }
98
99 char * rpmtdGetChar(rpmtd td)
100 {
101     char *res = NULL;
102
103     assert(td != NULL);
104
105     if (td->type == RPM_CHAR_TYPE) {
106         int ix = (td->ix >= 0 ? td->ix : 0);
107         res = (char *) td->data + ix;
108     } 
109     return res;
110 }
111 uint16_t * rpmtdGetUint16(rpmtd td)
112 {
113     uint16_t *res = NULL;
114
115     assert(td != NULL);
116
117     if (td->type == RPM_INT16_TYPE) {
118         int ix = (td->ix >= 0 ? td->ix : 0);
119         res = (uint16_t *) td->data + ix;
120     } 
121     return res;
122 }
123
124 uint32_t * rpmtdGetUint32(rpmtd td)
125 {
126     uint32_t *res = NULL;
127
128     assert(td != NULL);
129
130     if (td->type == RPM_INT32_TYPE) {
131         int ix = (td->ix >= 0 ? td->ix : 0);
132         res = (uint32_t *) td->data + ix;
133     } 
134     return res;
135 }
136 const char * rpmtdGetString(rpmtd td)
137 {
138     const char *str = NULL;
139
140     assert(td != NULL);
141
142     if (td->type == RPM_STRING_TYPE) {
143         str = (const char *) td->data;
144     } else if (td->type == RPM_STRING_ARRAY_TYPE ||
145                td->type == RPM_I18NSTRING_TYPE) {
146         /* XXX TODO: check for array bounds */
147         int ix = (td->ix >= 0 ? td->ix : 0);
148         str = *((const char**) td->data + ix);
149     } 
150     return str;
151 }
152
153 char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
154 {
155     headerTagFormatFunction func = rpmHeaderFormatFuncByValue(fmt);
156     const char *err = NULL;
157     char *str = NULL;
158
159     if (func) {
160         char fmtbuf[50]; /* yuck, get rid of this */
161         strcpy(fmtbuf, "%");
162         str = func(td, fmtbuf);
163     } else {
164         err = _("Unknown format");
165     }
166     
167     if (err && errmsg) {
168         errmsg = err;
169     }
170
171     return str;
172 }
173
174 int rpmtdFromArgv(rpmtd td, rpmTag tag, ARGV_t argv)
175 {
176     int count = argvCount(argv);
177     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
178
179     if (type != RPM_STRING_ARRAY_TYPE || count < 1)
180         return 0;
181
182     assert(td != NULL);
183     rpmtdReset(td);
184     td->type = type;
185     td->tag = tag;
186     td->count = count;
187     td->data = argv;
188     return 1;
189 }
190
191 int rpmtdFromArgi(rpmtd td, rpmTag tag, ARGI_t argi)
192 {
193     int count = argiCount(argi);
194     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
195     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
196
197     if (type != RPM_INT32_TYPE || retype != RPM_ARRAY_RETURN_TYPE || count < 1)
198         return 0;
199
200     assert(td != NULL);
201     rpmtdReset(td);
202     td->type = type;
203     td->tag = tag;
204     td->count = count;
205     td->data = argiData(argi);
206     return 1;
207 }
208
209 rpmtd rpmtdDup(rpmtd td)
210 {
211     rpmtd newtd = NULL;
212     char **data = NULL;
213     int i;
214     
215     assert(td != NULL);
216     /* TODO: permit other types too */
217     if (td->type != RPM_STRING_ARRAY_TYPE && td->type != RPM_I18NSTRING_TYPE) {
218         return NULL;
219     }
220
221     /* deep-copy container and data, drop immutable flag */
222     newtd = rpmtdNew();
223     memcpy(newtd, td, sizeof(*td));
224     newtd->flags &= ~(RPMTD_IMMUTABLE);
225
226     newtd->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
227     newtd->data = data = xmalloc(td->count * sizeof(*data));
228     while ((i = rpmtdNext(td)) >= 0) {
229         data[i] = xstrdup(rpmtdGetString(td));
230     }
231
232     return newtd;
233 }