Sanitize python object -> tag number exception handling
[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 rpmTagClass rpmtdClass(rpmtd td)
75 {
76     assert(td != NULL);
77     return rpmTagTypeGetClass(td->type);
78 }
79
80 int rpmtdGetIndex(rpmtd td)
81 {
82     assert(td != NULL);
83     return td->ix;
84 }
85
86 int rpmtdSetIndex(rpmtd td, int index)
87 {
88     assert(td != NULL);
89
90     if (index < 0 || index >= rpmtdCount(td)) {
91         return -1;
92     }
93     td->ix = index;
94     return td->ix;
95 }
96
97 int rpmtdInit(rpmtd td)
98 {
99     assert(td != NULL);
100
101     /* XXX check that this is an array type? */
102     td->ix = -1;
103     return 0;
104 }
105
106 int rpmtdNext(rpmtd td)
107 {
108     assert(td != NULL);
109
110     int i = -1;
111     
112     if (++td->ix >= 0) {
113         if (td->ix < rpmtdCount(td)) {
114             i = td->ix;
115         } else {
116             td->ix = i;
117         }
118     }
119     return i;
120 }
121
122 uint32_t *rpmtdNextUint32(rpmtd td)
123 {
124     assert(td != NULL);
125     uint32_t *res = NULL;
126     if (rpmtdNext(td) >= 0) {
127         res = rpmtdGetUint32(td);
128     }
129     return res;
130 }
131
132 uint64_t *rpmtdNextUint64(rpmtd td)
133 {
134     assert(td != NULL);
135     uint64_t *res = NULL;
136     if (rpmtdNext(td) >= 0) {
137         res = rpmtdGetUint64(td);
138     }
139     return res;
140 }
141
142 const char *rpmtdNextString(rpmtd td)
143 {
144     assert(td != NULL);
145     const char *res = NULL;
146     if (rpmtdNext(td) >= 0) {
147         res = rpmtdGetString(td);
148     }
149     return res;
150 }
151
152 char * rpmtdGetChar(rpmtd td)
153 {
154     char *res = NULL;
155
156     assert(td != NULL);
157
158     if (td->type == RPM_CHAR_TYPE) {
159         int ix = (td->ix >= 0 ? td->ix : 0);
160         res = (char *) td->data + ix;
161     } 
162     return res;
163 }
164 uint16_t * rpmtdGetUint16(rpmtd td)
165 {
166     uint16_t *res = NULL;
167
168     assert(td != NULL);
169
170     if (td->type == RPM_INT16_TYPE) {
171         int ix = (td->ix >= 0 ? td->ix : 0);
172         res = (uint16_t *) td->data + ix;
173     } 
174     return res;
175 }
176
177 uint32_t * rpmtdGetUint32(rpmtd td)
178 {
179     uint32_t *res = NULL;
180
181     assert(td != NULL);
182
183     if (td->type == RPM_INT32_TYPE) {
184         int ix = (td->ix >= 0 ? td->ix : 0);
185         res = (uint32_t *) td->data + ix;
186     } 
187     return res;
188 }
189
190 uint64_t * rpmtdGetUint64(rpmtd td)
191 {
192     uint64_t *res = NULL;
193
194     assert(td != NULL);
195
196     if (td->type == RPM_INT64_TYPE) {
197         int ix = (td->ix >= 0 ? td->ix : 0);
198         res = (uint64_t *) td->data + ix;
199     } 
200     return res;
201 }
202
203 const char * rpmtdGetString(rpmtd td)
204 {
205     const char *str = NULL;
206
207     assert(td != NULL);
208
209     if (td->type == RPM_STRING_TYPE) {
210         str = (const char *) td->data;
211     } else if (td->type == RPM_STRING_ARRAY_TYPE ||
212                td->type == RPM_I18NSTRING_TYPE) {
213         /* XXX TODO: check for array bounds */
214         int ix = (td->ix >= 0 ? td->ix : 0);
215         str = *((const char**) td->data + ix);
216     } 
217     return str;
218 }
219
220 uint64_t rpmtdGetNumber(rpmtd td)
221 {
222     assert(td != NULL);
223     uint64_t val = 0;
224     int ix = (td->ix >= 0 ? td->ix : 0);
225
226     switch (td->type) {
227     case RPM_INT64_TYPE:
228         val = *((uint64_t *) td->data + ix);
229         break;
230     case RPM_INT32_TYPE:
231         val = *((uint32_t *) td->data + ix);
232         break;
233     case RPM_INT16_TYPE:
234         val = *((uint16_t *) td->data + ix);
235         break;
236     case RPM_INT8_TYPE:
237     case RPM_CHAR_TYPE:
238         val = *((uint8_t *) td->data + ix);
239         break;
240     default:
241         break;
242     }
243     return val;
244 }
245
246 char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
247 {
248     headerTagFormatFunction func = rpmHeaderFormatFuncByValue(fmt);
249     const char *err = NULL;
250     char *str = NULL;
251
252     if (func) {
253         char fmtbuf[50]; /* yuck, get rid of this */
254         strcpy(fmtbuf, "%");
255         str = func(td, fmtbuf);
256     } else {
257         err = _("Unknown format");
258     }
259     
260     if (err && errmsg) {
261         errmsg = err;
262     }
263
264     return str;
265 }
266
267 int rpmtdSetTag(rpmtd td, rpmTag tag)
268 {
269     assert(td != NULL);
270     rpmTagType newtype = rpmTagGetType(tag);
271     int rc = 0;
272
273     /* 
274      * Sanity checks: 
275      * - is the new tag valid at all
276      * - if changing tag of non-empty container, require matching type 
277      */
278     if (newtype == RPM_NULL_TYPE)
279         goto exit;
280
281     if (td->data || td->count > 0) {
282         if (rpmTagGetType(td->tag) != rpmTagGetType(tag)) {
283             goto exit;
284         }
285     } 
286
287     td->tag = tag;
288     td->type = newtype & RPM_MASK_TYPE;
289     rc = 1;
290     
291 exit:
292     return rc;
293 }
294
295 static inline int rpmtdSet(rpmtd td, rpmTag tag, rpmTagType type, 
296                             rpm_constdata_t data, rpm_count_t count)
297 {
298     rpmtdReset(td);
299     td->tag = tag;
300     td->type = type;
301     td->count = count;
302     /* 
303      * Discards const, but we won't touch the data (even rpmtdFreeData()
304      * wont free it as allocation flags aren't set) so it's "ok". 
305      * XXX: Should there be a separate RPMTD_FOO flag for "user data"?
306      */
307     td->data = (void *) data;
308     return 1;
309 }
310
311 int rpmtdFromUint8(rpmtd td, rpmTag tag, uint8_t *data, rpm_count_t count)
312 {
313     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
314     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
315     
316     if (count < 1)
317         return 0;
318
319     /*
320      * BIN type is really just an uint8_t array internally, it's just
321      * treated specially otherwise.
322      */
323     switch (type) {
324     case RPM_CHAR_TYPE:
325     case RPM_INT8_TYPE:
326         if (retype != RPM_ARRAY_RETURN_TYPE && count > 1) 
327             return 0;
328         /* fallthrough */
329     case RPM_BIN_TYPE:
330         break;
331     default:
332         return 0;
333     }
334     
335     return rpmtdSet(td, tag, type, data, count);
336 }
337
338 int rpmtdFromUint16(rpmtd td, rpmTag tag, uint16_t *data, rpm_count_t count)
339 {
340     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
341     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
342     if (type != RPM_INT16_TYPE || count < 1) 
343         return 0;
344     if (retype != RPM_ARRAY_RETURN_TYPE && count > 1) 
345         return 0;
346     
347     return rpmtdSet(td, tag, type, data, count);
348 }
349
350 int rpmtdFromUint32(rpmtd td, rpmTag tag, uint32_t *data, rpm_count_t count)
351 {
352     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
353     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
354     if (type != RPM_INT32_TYPE || count < 1) 
355         return 0;
356     if (retype != RPM_ARRAY_RETURN_TYPE && count > 1) 
357         return 0;
358     
359     return rpmtdSet(td, tag, type, data, count);
360 }
361
362 int rpmtdFromUint64(rpmtd td, rpmTag tag, uint64_t *data, rpm_count_t count)
363 {
364     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
365     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
366     if (type != RPM_INT64_TYPE || count < 1) 
367         return 0;
368     if (retype != RPM_ARRAY_RETURN_TYPE && count > 1) 
369         return 0;
370     
371     return rpmtdSet(td, tag, type, data, count);
372 }
373
374 int rpmtdFromString(rpmtd td, rpmTag tag, const char *data)
375 {
376     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
377     int rc = 0;
378
379     if (type == RPM_STRING_TYPE) {
380         rc = rpmtdSet(td, tag, type, data, 1);
381     } else if (type == RPM_STRING_ARRAY_TYPE) {
382         rc = rpmtdSet(td, tag, type, &data, 1);
383     }
384
385     return rc;
386 }
387
388 int rpmtdFromStringArray(rpmtd td, rpmTag tag, const char **data, rpm_count_t count)
389 {
390     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
391     if (type != RPM_STRING_ARRAY_TYPE || count < 1)
392         return 0;
393     if (type == RPM_STRING_TYPE && count != 1)
394         return 0;
395
396     return rpmtdSet(td, tag, type, data, count);
397 }
398
399 int rpmtdFromArgv(rpmtd td, rpmTag tag, ARGV_t argv)
400 {
401     int count = argvCount(argv);
402     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
403
404     if (type != RPM_STRING_ARRAY_TYPE || count < 1)
405         return 0;
406
407     return rpmtdSet(td, tag, type, argv, count);
408 }
409
410 int rpmtdFromArgi(rpmtd td, rpmTag tag, ARGI_t argi)
411 {
412     int count = argiCount(argi);
413     rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
414     rpmTagReturnType retype = rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE;
415
416     if (type != RPM_INT32_TYPE || retype != RPM_ARRAY_RETURN_TYPE || count < 1)
417         return 0;
418
419     return rpmtdSet(td, tag, type, argiData(argi), count);
420 }
421
422 rpmtd rpmtdDup(rpmtd td)
423 {
424     rpmtd newtd = NULL;
425     char **data = NULL;
426     int i;
427     
428     assert(td != NULL);
429     /* TODO: permit other types too */
430     if (td->type != RPM_STRING_ARRAY_TYPE && td->type != RPM_I18NSTRING_TYPE) {
431         return NULL;
432     }
433
434     /* deep-copy container and data, drop immutable flag */
435     newtd = rpmtdNew();
436     memcpy(newtd, td, sizeof(*td));
437     newtd->flags &= ~(RPMTD_IMMUTABLE);
438
439     newtd->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
440     newtd->data = data = xmalloc(td->count * sizeof(*data));
441     while ((i = rpmtdNext(td)) >= 0) {
442         data[i] = xstrdup(rpmtdGetString(td));
443     }
444
445     return newtd;
446 }