Add access methods for 64bit integer types to rpmtd
[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         if (td->flags & RPMTD_PTR_ALLOCED) {
44             assert(td->data != NULL);
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 rpmtdGetIndex(rpmtd td)
75 {
76     assert(td != NULL);
77     return td->ix;
78 }
79
80 int rpmtdSetIndex(rpmtd td, int index)
81 {
82     assert(td != NULL);
83
84     if (index < 0 || index >= rpmtdCount(td)) {
85         return -1;
86     }
87     td->ix = index;
88     return td->ix;
89 }
90
91 int rpmtdInit(rpmtd td)
92 {
93     assert(td != NULL);
94
95     /* XXX check that this is an array type? */
96     td->ix = -1;
97     return 0;
98 }
99
100 int rpmtdNext(rpmtd td)
101 {
102     assert(td != NULL);
103
104     int i = -1;
105     
106     if (++td->ix >= 0) {
107         if (td->ix < rpmtdCount(td)) {
108             i = td->ix;
109         } else {
110             td->ix = i;
111         }
112     }
113     return i;
114 }
115
116 uint32_t *rpmtdNextUint32(rpmtd td)
117 {
118     assert(td != NULL);
119     uint32_t *res = NULL;
120     if (rpmtdNext(td) >= 0) {
121         res = rpmtdGetUint32(td);
122     }
123     return res;
124 }
125
126 uint64_t *rpmtdNextUint64(rpmtd td)
127 {
128     assert(td != NULL);
129     uint64_t *res = NULL;
130     if (rpmtdNext(td) >= 0) {
131         res = rpmtdGetUint64(td);
132     }
133     return res;
134 }
135
136 const char *rpmtdNextString(rpmtd td)
137 {
138     assert(td != NULL);
139     const char *res = NULL;
140     if (rpmtdNext(td) >= 0) {
141         res = rpmtdGetString(td);
142     }
143     return res;
144 }
145
146 char * rpmtdGetChar(rpmtd td)
147 {
148     char *res = NULL;
149
150     assert(td != NULL);
151
152     if (td->type == RPM_CHAR_TYPE) {
153         int ix = (td->ix >= 0 ? td->ix : 0);
154         res = (char *) td->data + ix;
155     } 
156     return res;
157 }
158 uint16_t * rpmtdGetUint16(rpmtd td)
159 {
160     uint16_t *res = NULL;
161
162     assert(td != NULL);
163
164     if (td->type == RPM_INT16_TYPE) {
165         int ix = (td->ix >= 0 ? td->ix : 0);
166         res = (uint16_t *) td->data + ix;
167     } 
168     return res;
169 }
170
171 uint32_t * rpmtdGetUint32(rpmtd td)
172 {
173     uint32_t *res = NULL;
174
175     assert(td != NULL);
176
177     if (td->type == RPM_INT32_TYPE) {
178         int ix = (td->ix >= 0 ? td->ix : 0);
179         res = (uint32_t *) td->data + ix;
180     } 
181     return res;
182 }
183
184 uint64_t * rpmtdGetUint64(rpmtd td)
185 {
186     uint64_t *res = NULL;
187
188     assert(td != NULL);
189
190     if (td->type == RPM_INT64_TYPE) {
191         int ix = (td->ix >= 0 ? td->ix : 0);
192         res = (uint64_t *) td->data + ix;
193     } 
194     return res;
195 }
196
197 const char * rpmtdGetString(rpmtd td)
198 {
199     const char *str = NULL;
200
201     assert(td != NULL);
202
203     if (td->type == RPM_STRING_TYPE) {
204         str = (const char *) td->data;
205     } else if (td->type == RPM_STRING_ARRAY_TYPE ||
206                td->type == RPM_I18NSTRING_TYPE) {
207         /* XXX TODO: check for array bounds */
208         int ix = (td->ix >= 0 ? td->ix : 0);
209         str = *((const char**) td->data + ix);
210     } 
211     return str;
212 }
213
214 char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
215 {
216     headerTagFormatFunction func = rpmHeaderFormatFuncByValue(fmt);
217     const char *err = NULL;
218     char *str = NULL;
219
220     if (func) {
221         char fmtbuf[50]; /* yuck, get rid of this */
222         strcpy(fmtbuf, "%");
223         str = func(td, fmtbuf);
224     } else {
225         err = _("Unknown format");
226     }
227     
228     if (err && errmsg) {
229         errmsg = err;
230     }
231
232     return str;
233 }
234
235 int rpmtdSetTag(rpmtd td, rpmTag tag)
236 {
237     assert(td != NULL);
238     rpmTagType newtype = rpmTagGetType(tag);
239     int rc = 0;
240
241     /* 
242      * Sanity checks: 
243      * - is the new tag valid at all
244      * - if changing tag of non-empty container, require matching type 
245      */
246     if (newtype == RPM_NULL_TYPE)
247         goto exit;
248
249     if (td->data || td->count > 0) {
250         if (rpmTagGetType(td->tag) != rpmTagGetType(tag)) {
251             goto exit;
252         }
253     } 
254
255     td->tag = tag;
256     td->type = newtype & RPM_MASK_TYPE;
257     rc = 1;
258     
259 exit:
260     return rc;
261 }
262
263 int rpmtdFromArgv(rpmtd td, rpmTag tag, ARGV_t argv)
264 {
265     int count = argvCount(argv);
266     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
267
268     if (type != RPM_STRING_ARRAY_TYPE || count < 1)
269         return 0;
270
271     assert(td != NULL);
272     rpmtdReset(td);
273     td->type = type;
274     td->tag = tag;
275     td->count = count;
276     td->data = argv;
277     return 1;
278 }
279
280 int rpmtdFromArgi(rpmtd td, rpmTag tag, ARGI_t argi)
281 {
282     int count = argiCount(argi);
283     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
284     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
285
286     if (type != RPM_INT32_TYPE || retype != RPM_ARRAY_RETURN_TYPE || count < 1)
287         return 0;
288
289     assert(td != NULL);
290     rpmtdReset(td);
291     td->type = type;
292     td->tag = tag;
293     td->count = count;
294     td->data = argiData(argi);
295     return 1;
296 }
297
298 rpmtd rpmtdDup(rpmtd td)
299 {
300     rpmtd newtd = NULL;
301     char **data = NULL;
302     int i;
303     
304     assert(td != NULL);
305     /* TODO: permit other types too */
306     if (td->type != RPM_STRING_ARRAY_TYPE && td->type != RPM_I18NSTRING_TYPE) {
307         return NULL;
308     }
309
310     /* deep-copy container and data, drop immutable flag */
311     newtd = rpmtdNew();
312     memcpy(newtd, td, sizeof(*td));
313     newtd->flags &= ~(RPMTD_IMMUTABLE);
314
315     newtd->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
316     newtd->data = data = xmalloc(td->count * sizeof(*data));
317     while ((i = rpmtdNext(td)) >= 0) {
318         data[i] = xstrdup(rpmtdGetString(td));
319     }
320
321     return newtd;
322 }