1 #include "system.h"
2
3 #include <rpm/rpmtd.h>
4 #include <rpm/rpmstring.h>
5 #include <rpm/rpmpgp.h>
6 #include <rpm/rpmstrpool.h>
7 #include "lib/misc.h" /* format function prototypes */
8
9 #include "debug.h"
10
rpmtdNew(void)11 rpmtd rpmtdNew(void)
12 {
13 rpmtd td = xmalloc(sizeof(*td));
14 rpmtdReset(td);
15 return td;
16 }
17
rpmtdFree(rpmtd td)18 rpmtd rpmtdFree(rpmtd td)
19 {
20 /* permit free on NULL td */
21 if (td != NULL) {
22 rpmtdFreeData(td);
23 free(td);
24 }
25 return NULL;
26 }
27
rpmtdReset(rpmtd td)28 void rpmtdReset(rpmtd td)
29 {
30 if (td) {
31 memset(td, 0, sizeof(*td));
32 td->ix = -1;
33 }
34 }
35
rpmtdFreeData(rpmtd td)36 void rpmtdFreeData(rpmtd td)
37 {
38 if (td && td->data && td->flags & RPMTD_ALLOCED) {
39 if (td->flags & RPMTD_PTR_ALLOCED) {
40 char **data = td->data;
41 for (int i = 0; i < td->count; i++) {
42 free(data[i]);
43 }
44 }
45 free(td->data);
46 }
47 rpmtdReset(td);
48 }
49
rpmtdCount(rpmtd td)50 rpm_count_t rpmtdCount(rpmtd td)
51 {
52 rpm_count_t count = 0;
53 if (td != NULL) {
54 /* fix up for binary type abusing count as data length */
55 count = (td->type == RPM_BIN_TYPE) ? 1 : td->count;
56 }
57 return count;
58 }
59
rpmtdSize(rpmtd td)60 rpm_count_t rpmtdSize(rpmtd td)
61 {
62 return (td != NULL) ? td->size : 0;
63 }
64
rpmtdTag(rpmtd td)65 rpmTagVal rpmtdTag(rpmtd td)
66 {
67 return (td != NULL) ? td->tag : 0;
68 }
69
rpmtdType(rpmtd td)70 rpmTagType rpmtdType(rpmtd td)
71 {
72 return (td != NULL) ? td->type : 0;
73 }
74
rpmtdClass(rpmtd td)75 rpmTagClass rpmtdClass(rpmtd td)
76 {
77 return (td != NULL) ? rpmTagTypeGetClass(td->type) : 0;
78 }
79
rpmtdGetFlags(rpmtd td)80 rpmtdFlags rpmtdGetFlags(rpmtd td)
81 {
82 return (td != NULL) ? td->flags : 0;
83 }
84
rpmtdGetIndex(rpmtd td)85 int rpmtdGetIndex(rpmtd td)
86 {
87 return (td != NULL) ? td->ix : -1;
88 }
89
rpmtdSetIndex(rpmtd td,int index)90 int rpmtdSetIndex(rpmtd td, int index)
91 {
92 if (td == NULL || index < 0 || index >= rpmtdCount(td)) {
93 return -1;
94 }
95 td->ix = index;
96 return td->ix;
97 }
98
rpmtdInit(rpmtd td)99 int rpmtdInit(rpmtd td)
100 {
101 if (td == NULL)
102 return -1;
103
104 /* XXX check that this is an array type? */
105 td->ix = -1;
106 return 0;
107 }
108
rpmtdNext(rpmtd td)109 int rpmtdNext(rpmtd td)
110 {
111 int i = -1;
112
113 if (td != NULL && ++td->ix >= 0) {
114 if (td->ix < rpmtdCount(td)) {
115 i = td->ix;
116 } else {
117 td->ix = i;
118 }
119 }
120 return i;
121 }
122
rpmtdNextUint32(rpmtd td)123 uint32_t *rpmtdNextUint32(rpmtd td)
124 {
125 uint32_t *res = NULL;
126 if (rpmtdNext(td) >= 0) {
127 res = rpmtdGetUint32(td);
128 }
129 return res;
130 }
131
rpmtdNextUint64(rpmtd td)132 uint64_t *rpmtdNextUint64(rpmtd td)
133 {
134 uint64_t *res = NULL;
135 if (rpmtdNext(td) >= 0) {
136 res = rpmtdGetUint64(td);
137 }
138 return res;
139 }
140
rpmtdNextString(rpmtd td)141 const char *rpmtdNextString(rpmtd td)
142 {
143 const char *res = NULL;
144 if (rpmtdNext(td) >= 0) {
145 res = rpmtdGetString(td);
146 }
147 return res;
148 }
149
rpmtdGetChar(rpmtd td)150 char * rpmtdGetChar(rpmtd td)
151 {
152 char *res = NULL;
153
154 if (td != NULL && td->type == RPM_CHAR_TYPE) {
155 int ix = (td->ix >= 0 ? td->ix : 0);
156 res = (char *) td->data + ix;
157 }
158 return res;
159 }
rpmtdGetUint16(rpmtd td)160 uint16_t * rpmtdGetUint16(rpmtd td)
161 {
162 uint16_t *res = NULL;
163
164 if (td != NULL && 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
rpmtdGetUint32(rpmtd td)171 uint32_t * rpmtdGetUint32(rpmtd td)
172 {
173 uint32_t *res = NULL;
174
175 if (td != NULL && td->type == RPM_INT32_TYPE) {
176 int ix = (td->ix >= 0 ? td->ix : 0);
177 res = (uint32_t *) td->data + ix;
178 }
179 return res;
180 }
181
rpmtdGetUint64(rpmtd td)182 uint64_t * rpmtdGetUint64(rpmtd td)
183 {
184 uint64_t *res = NULL;
185
186 if (td != NULL && td->type == RPM_INT64_TYPE) {
187 int ix = (td->ix >= 0 ? td->ix : 0);
188 res = (uint64_t *) td->data + ix;
189 }
190 return res;
191 }
192
rpmtdGetString(rpmtd td)193 const char * rpmtdGetString(rpmtd td)
194 {
195 const char *str = NULL;
196
197 if (td == NULL)
198 return NULL;
199
200 if (td->type == RPM_STRING_TYPE) {
201 str = (const char *) td->data;
202 } else if (td->type == RPM_STRING_ARRAY_TYPE ||
203 td->type == RPM_I18NSTRING_TYPE) {
204 /* XXX TODO: check for array bounds */
205 int ix = (td->ix >= 0 ? td->ix : 0);
206 str = *((const char**) td->data + ix);
207 }
208 return str;
209 }
210
rpmtdGetNumber(rpmtd td)211 uint64_t rpmtdGetNumber(rpmtd td)
212 {
213 if (td == NULL)
214 return 0;
215
216 uint64_t val = 0;
217 int ix = (td->ix >= 0 ? td->ix : 0);
218
219 switch (td->type) {
220 case RPM_INT64_TYPE:
221 val = *((uint64_t *) td->data + ix);
222 break;
223 case RPM_INT32_TYPE:
224 val = *((uint32_t *) td->data + ix);
225 break;
226 case RPM_INT16_TYPE:
227 val = *((uint16_t *) td->data + ix);
228 break;
229 case RPM_INT8_TYPE:
230 case RPM_CHAR_TYPE:
231 val = *((uint8_t *) td->data + ix);
232 break;
233 default:
234 break;
235 }
236 return val;
237 }
238
rpmtdFormat(rpmtd td,rpmtdFormats fmt,const char * errmsg)239 char *rpmtdFormat(rpmtd td, rpmtdFormats fmt, const char *errmsg)
240 {
241 headerFmt ext = rpmHeaderFormatByValue(fmt);
242 const char *err = NULL;
243 char *str = NULL;
244
245 if (ext) {
246 str = rpmHeaderFormatCall(ext, td);
247 } else {
248 err = _("Unknown format");
249 }
250
251 if (err && errmsg) {
252 errmsg = err;
253 }
254
255 return str;
256 }
257
rpmtdSetTag(rpmtd td,rpmTagVal tag)258 int rpmtdSetTag(rpmtd td, rpmTagVal tag)
259 {
260 rpmTagType newtype = rpmTagGetTagType(tag);
261 int rc = 0;
262
263 if (td == NULL)
264 goto exit;
265
266 /*
267 * Sanity checks:
268 * - is the new tag valid at all
269 * - if changing tag of non-empty container, require matching type
270 */
271 if (newtype == RPM_NULL_TYPE)
272 goto exit;
273
274 if (td->data || td->count > 0) {
275 if (rpmTagGetTagType(td->tag) != rpmTagGetTagType(tag)) {
276 goto exit;
277 }
278 }
279
280 td->tag = tag;
281 td->type = newtype;
282 rc = 1;
283
284 exit:
285 return rc;
286 }
287
rpmtdSet(rpmtd td,rpmTagVal tag,rpmTagType type,rpm_constdata_t data,rpm_count_t count)288 static inline int rpmtdSet(rpmtd td, rpmTagVal tag, rpmTagType type,
289 rpm_constdata_t data, rpm_count_t count)
290 {
291 rpmtdReset(td);
292 td->tag = tag;
293 td->type = type;
294 td->count = count;
295 /*
296 * Discards const, but we won't touch the data (even rpmtdFreeData()
297 * wont free it as allocation flags aren't set) so it's "ok".
298 * XXX: Should there be a separate RPMTD_FOO flag for "user data"?
299 */
300 td->data = (void *) data;
301 return 1;
302 }
303
rpmtdFromUint8(rpmtd td,rpmTagVal tag,uint8_t * data,rpm_count_t count)304 int rpmtdFromUint8(rpmtd td, rpmTagVal tag, uint8_t *data, rpm_count_t count)
305 {
306 rpmTagType type = rpmTagGetTagType(tag);
307 rpmTagReturnType retype = rpmTagGetReturnType(tag);
308
309 if (count < 1)
310 return 0;
311
312 /*
313 * BIN type is really just an uint8_t array internally, it's just
314 * treated specially otherwise.
315 */
316 switch (type) {
317 case RPM_CHAR_TYPE:
318 case RPM_INT8_TYPE:
319 if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
320 return 0;
321 /* fallthrough */
322 case RPM_BIN_TYPE:
323 break;
324 default:
325 return 0;
326 }
327
328 return rpmtdSet(td, tag, type, data, count);
329 }
330
rpmtdFromUint16(rpmtd td,rpmTagVal tag,uint16_t * data,rpm_count_t count)331 int rpmtdFromUint16(rpmtd td, rpmTagVal tag, uint16_t *data, rpm_count_t count)
332 {
333 rpmTagType type = rpmTagGetTagType(tag);
334 rpmTagReturnType retype = rpmTagGetReturnType(tag);
335 if (type != RPM_INT16_TYPE || count < 1)
336 return 0;
337 if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
338 return 0;
339
340 return rpmtdSet(td, tag, type, data, count);
341 }
342
rpmtdFromUint32(rpmtd td,rpmTagVal tag,uint32_t * data,rpm_count_t count)343 int rpmtdFromUint32(rpmtd td, rpmTagVal tag, uint32_t *data, rpm_count_t count)
344 {
345 rpmTagType type = rpmTagGetTagType(tag);
346 rpmTagReturnType retype = rpmTagGetReturnType(tag);
347 if (type != RPM_INT32_TYPE || count < 1)
348 return 0;
349 if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
350 return 0;
351
352 return rpmtdSet(td, tag, type, data, count);
353 }
354
rpmtdFromUint64(rpmtd td,rpmTagVal tag,uint64_t * data,rpm_count_t count)355 int rpmtdFromUint64(rpmtd td, rpmTagVal tag, uint64_t *data, rpm_count_t count)
356 {
357 rpmTagType type = rpmTagGetTagType(tag);
358 rpmTagReturnType retype = rpmTagGetReturnType(tag);
359 if (type != RPM_INT64_TYPE || count < 1)
360 return 0;
361 if (retype != RPM_ARRAY_RETURN_TYPE && count > 1)
362 return 0;
363
364 return rpmtdSet(td, tag, type, data, count);
365 }
366
rpmtdFromString(rpmtd td,rpmTagVal tag,const char * data)367 int rpmtdFromString(rpmtd td, rpmTagVal tag, const char *data)
368 {
369 rpmTagType type = rpmTagGetTagType(tag);
370 int rc = 0;
371
372 if (type == RPM_STRING_TYPE) {
373 rc = rpmtdSet(td, tag, type, data, 1);
374 } else if (type == RPM_STRING_ARRAY_TYPE) {
375 rc = rpmtdSet(td, tag, type, &data, 1);
376 }
377
378 return rc;
379 }
380
rpmtdFromStringArray(rpmtd td,rpmTagVal tag,const char ** data,rpm_count_t count)381 int rpmtdFromStringArray(rpmtd td, rpmTagVal tag, const char **data, rpm_count_t count)
382 {
383 rpmTagType type = rpmTagGetTagType(tag);
384 if (type != RPM_STRING_ARRAY_TYPE || count < 1)
385 return 0;
386 if (type == RPM_STRING_TYPE && count != 1)
387 return 0;
388
389 return rpmtdSet(td, tag, type, data, count);
390 }
391
rpmtdFromArgv(rpmtd td,rpmTagVal tag,ARGV_t argv)392 int rpmtdFromArgv(rpmtd td, rpmTagVal tag, ARGV_t argv)
393 {
394 int count = argvCount(argv);
395 rpmTagType type = rpmTagGetTagType(tag);
396
397 if (type != RPM_STRING_ARRAY_TYPE || count < 1)
398 return 0;
399
400 return rpmtdSet(td, tag, type, argv, count);
401 }
402
rpmtdFromArgi(rpmtd td,rpmTagVal tag,ARGI_t argi)403 int rpmtdFromArgi(rpmtd td, rpmTagVal tag, ARGI_t argi)
404 {
405 int count = argiCount(argi);
406 rpmTagType type = rpmTagGetTagType(tag);
407 rpmTagReturnType retype = rpmTagGetReturnType(tag);
408
409 if (type != RPM_INT32_TYPE || retype != RPM_ARRAY_RETURN_TYPE || count < 1)
410 return 0;
411
412 return rpmtdSet(td, tag, type, argiData(argi), count);
413 }
414
rpmtdDup(rpmtd td)415 rpmtd rpmtdDup(rpmtd td)
416 {
417 rpmtd newtd = NULL;
418 char **data = NULL;
419 int i;
420
421 if (td == NULL)
422 return NULL;
423
424 /* TODO: permit other types too */
425 if (td->type != RPM_STRING_ARRAY_TYPE && td->type != RPM_I18NSTRING_TYPE) {
426 return NULL;
427 }
428
429 /* deep-copy container and data, drop immutable flag */
430 newtd = rpmtdNew();
431 memcpy(newtd, td, sizeof(*td));
432 newtd->flags &= ~(RPMTD_IMMUTABLE);
433
434 newtd->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
435 newtd->data = data = xmalloc(td->count * sizeof(*data));
436 while ((i = rpmtdNext(td)) >= 0) {
437 data[i] = xstrdup(rpmtdGetString(td));
438 }
439
440 return newtd;
441 }
442
rpmtdToPool(rpmtd td,rpmstrPool pool)443 rpmsid * rpmtdToPool(rpmtd td, rpmstrPool pool)
444 {
445 rpmsid *sids = NULL;
446
447 if (pool && td) {
448 const char **strings = td->data;
449 switch (td->type) {
450 case RPM_STRING_ARRAY_TYPE:
451 case RPM_I18NSTRING_TYPE:
452 sids = xmalloc(td->count * sizeof(*sids));
453 for (rpm_count_t i = 0; i < td->count; i++)
454 sids[i] = rpmstrPoolId(pool, strings[i], 1);
455 break;
456 }
457 }
458 return sids;
459 }
460