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