Sanitize python object -> tag number exception handling
[platform/upstream/rpm.git] / lib / tagname.c
1 /**
2  * \file lib/tagname.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/header.h>
8 #include <rpm/rpmstring.h>
9 #include "debug.h"
10
11 /** \ingroup header
12  * Associate tag names with numeric values.
13  */
14 typedef const struct headerTagTableEntry_s * headerTagTableEntry;
15 struct headerTagTableEntry_s {
16     const char * name;          /*!< Tag name. */
17     const char * shortname;     /*!< "Human readable" short name. */
18     rpmTag val;                 /*!< Tag numeric value. */
19     rpmTagType type;            /*!< Tag type. */
20     int extension;              /*!< Extension or "real" tag */
21 };
22
23 #include "lib/tagtbl.c"
24
25 static const int rpmTagTableSize = sizeof(rpmTagTable) / sizeof(rpmTagTable[0]) - 1;
26
27 /**
28  */
29 typedef struct headerTagIndices_s * headerTagIndices;
30
31 struct headerTagIndices_s {
32     int (*loadIndex) (headerTagTableEntry ** ipp, int * np,
33                 int (*cmp) (const void * avp, const void * bvp));
34                                         /*!< load sorted tag index. */
35     headerTagTableEntry * byName;       /*!< header tags sorted by name. */
36     int byNameSize;                     /*!< no. of entries. */
37     int (*byNameCmp) (const void * avp, const void * bvp);                              /*!< compare entries by name. */
38     rpmTag (*tagValue) (const char * name);     /* return value from name. */
39     headerTagTableEntry * byValue;      /*!< header tags sorted by value. */
40     int byValueSize;                    /*!< no. of entries. */
41     int (*byValueCmp) (const void * avp, const void * bvp);                             /*!< compare entries by value. */
42     const char * (*tagName) (rpmTag value);     /* Return name from value. */
43     rpmTagType (*tagType) (rpmTag value);       /* Return type from value. */
44 };
45
46 /**
47  * Compare tag table entries by name.
48  * @param *avp          tag table entry a
49  * @param *bvp          tag table entry b
50  * @return              comparison
51  */
52 static int tagCmpName(const void * avp, const void * bvp)
53 {
54     headerTagTableEntry a = *(const headerTagTableEntry *) avp;
55     headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
56     return strcmp(a->name, b->name);
57 }
58
59 /**
60  * Compare tag table entries by value.
61  * @param *avp          tag table entry a
62  * @param *bvp          tag table entry b
63  * @return              comparison
64  */
65 static int tagCmpValue(const void * avp, const void * bvp)
66 {
67     headerTagTableEntry a = *(const headerTagTableEntry *) avp;
68     headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
69     int ret = (a->val - b->val);
70     /* Make sure that sort is stable, longest name first. */
71     if (ret == 0)
72         ret = (strlen(b->name) - strlen(a->name));
73     return ret;
74 }
75
76 /**
77  * Load/sort a tag index.
78  * @retval *ipp         tag index
79  * @retval *np          no. of tags
80  * @param cmp           sort compare routine
81  * @return              0 always
82  */
83 static int tagLoadIndex(headerTagTableEntry ** ipp, int * np,
84                 int (*cmp) (const void * avp, const void * bvp))
85 {
86     headerTagTableEntry tte, *ip;
87     int n = 0;
88
89     ip = xcalloc(rpmTagTableSize, sizeof(*ip));
90     n = 0;
91     for (tte = (headerTagTableEntry)rpmTagTable; tte->name != NULL; tte++) {
92         ip[n] = tte;
93         n++;
94     }
95 assert(n == rpmTagTableSize);
96
97     if (n > 1)
98         qsort(ip, n, sizeof(*ip), cmp);
99     *ipp = ip;
100     *np = n;
101     return 0;
102 }
103
104
105 /* forward refs */
106 static const char * _tagName(rpmTag tag);
107 static rpmTagType _tagType(rpmTag tag);
108 static rpmTag _tagValue(const char * tagstr);
109
110 static struct headerTagIndices_s _rpmTags = {
111     tagLoadIndex,
112     NULL, 0, tagCmpName, _tagValue,
113     NULL, 0, tagCmpValue, _tagName, _tagType,
114 };
115
116 static headerTagIndices const rpmTags = &_rpmTags;
117
118 static const char * _tagName(rpmTag tag)
119 {
120     const char *name = "(unknown)";
121     const struct headerTagTableEntry_s *t;
122     int comparison, i, l, u;
123     int xx;
124
125     if (_rpmTags.byValue == NULL)
126         xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
127
128     switch (tag) {
129     case RPMDBI_PACKAGES:
130         name = "Packages";
131         break;
132     case RPMDBI_DEPENDS:
133         name = "Depends";
134         break;
135     case RPMDBI_ADDED:
136         name = "Added";
137         break;
138     case RPMDBI_REMOVED:
139         name = "Removed";
140         break;
141     case RPMDBI_AVAILABLE:
142         name = "Available";
143         break;
144     case RPMDBI_HDLIST:
145         name = "Hdlist";
146         break;
147     case RPMDBI_ARGLIST:
148         name = "Arglist";
149         break;
150     case RPMDBI_FTSWALK:
151         name = "Ftswalk";
152         break;
153
154     /* XXX make sure rpmdb indices are identically named. */
155     case RPMTAG_CONFLICTS:
156         name = "Conflictname";
157         break;
158     case RPMTAG_HDRID:
159         name = "Sha1header";
160         break;
161
162     default:
163         if (_rpmTags.byValue == NULL)
164             break;
165         l = 0;
166         u = _rpmTags.byValueSize;
167         while (l < u) {
168             i = (l + u) / 2;
169             t = _rpmTags.byValue[i];
170         
171             comparison = (tag - t->val);
172
173             if (comparison < 0)
174                 u = i;
175             else if (comparison > 0)
176                 l = i + 1;
177             else {
178                 /* Make sure that the bsearch retrieve is stable. */
179                 while (i > 0 && tag == _rpmTags.byValue[i-1]->val) {
180                     i--;
181                 }
182                 t = _rpmTags.byValue[i];
183                 if (t->shortname != NULL)
184                     name = t->shortname;
185                 break;
186             }
187         }
188         break;
189     }
190     return name;
191 }
192
193 static rpmTagType _tagType(rpmTag tag)
194 {
195     const struct headerTagTableEntry_s *t;
196     int comparison, i, l, u;
197     int xx;
198
199     if (_rpmTags.byValue == NULL)
200         xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
201
202     switch (tag) {
203     case RPMDBI_PACKAGES:
204     case RPMDBI_DEPENDS:
205     case RPMDBI_ADDED:
206     case RPMDBI_REMOVED:
207     case RPMDBI_AVAILABLE:
208     case RPMDBI_HDLIST:
209     case RPMDBI_ARGLIST:
210     case RPMDBI_FTSWALK:
211         break;
212     default:
213         if (_rpmTags.byValue == NULL)
214             break;
215         l = 0;
216         u = _rpmTags.byValueSize;
217         while (l < u) {
218             i = (l + u) / 2;
219             t = _rpmTags.byValue[i];
220         
221             comparison = (tag - t->val);
222
223             if (comparison < 0)
224                 u = i;
225             else if (comparison > 0)
226                 l = i + 1;
227             else {
228                 /* Make sure that the bsearch retrieve is stable. */
229                 while (i > 0 && t->val == _rpmTags.byValue[i-1]->val) {
230                     i--;
231                 }
232                 t = _rpmTags.byValue[i];
233                 return t->type;
234             }
235         }
236         break;
237     }
238     return RPM_NULL_TYPE;
239 }
240
241 static rpmTag _tagValue(const char * tagstr)
242 {
243     const struct headerTagTableEntry_s *t;
244     int comparison, i, l, u;
245     int xx;
246
247     if (!rstrcasecmp(tagstr, "Packages"))
248         return RPMDBI_PACKAGES;
249     if (!rstrcasecmp(tagstr, "Depends"))
250         return RPMDBI_DEPENDS;
251     if (!rstrcasecmp(tagstr, "Added"))
252         return RPMDBI_ADDED;
253     if (!rstrcasecmp(tagstr, "Removed"))
254         return RPMDBI_REMOVED;
255     if (!rstrcasecmp(tagstr, "Available"))
256         return RPMDBI_AVAILABLE;
257     if (!rstrcasecmp(tagstr, "Hdlist"))
258         return RPMDBI_HDLIST;
259     if (!rstrcasecmp(tagstr, "Arglist"))
260         return RPMDBI_ARGLIST;
261     if (!rstrcasecmp(tagstr, "Ftswalk"))
262         return RPMDBI_FTSWALK;
263
264     if (_rpmTags.byName == NULL)
265         xx = tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
266     if (_rpmTags.byName == NULL)
267         return RPMTAG_NOT_FOUND;
268
269     l = 0;
270     u = _rpmTags.byNameSize;
271     while (l < u) {
272         i = (l + u) / 2;
273         t = _rpmTags.byName[i];
274         
275         comparison = rstrcasecmp(tagstr, t->shortname);
276
277         if (comparison < 0)
278             u = i;
279         else if (comparison > 0)
280             l = i + 1;
281         else
282             return t->val;
283     }
284     return RPMTAG_NOT_FOUND;
285 }
286
287 const char * rpmTagGetName(rpmTag tag)
288 {
289     return ((*rpmTags->tagName)(tag));
290 }
291
292 rpmTagType rpmTagGetType(rpmTag tag)
293 {
294     return ((*rpmTags->tagType)(tag));
295 }
296
297 rpmTagClass rpmTagTypeGetClass(rpmTagType type)
298 {
299     rpmTagClass class;
300     switch (type & RPM_MASK_TYPE) {
301     case RPM_CHAR_TYPE:
302     case RPM_INT8_TYPE:
303     case RPM_INT16_TYPE:
304     case RPM_INT32_TYPE:
305     case RPM_INT64_TYPE:
306         class = RPM_NUMERIC_CLASS;
307         break;
308     case RPM_STRING_TYPE:
309     case RPM_STRING_ARRAY_TYPE:
310     case RPM_I18NSTRING_TYPE:
311         class = RPM_STRING_CLASS;
312         break;
313     case RPM_BIN_TYPE:
314         class = RPM_BINARY_CLASS;
315         break;
316     case RPM_NULL_TYPE:
317     default:
318         class = RPM_NULL_CLASS;
319         break;
320     }
321     return class;
322 }
323
324 rpmTagClass rpmTagGetClass(rpmTag tag)
325 {
326     return rpmTagTypeGetClass(rpmTagGetType(tag));
327 }
328
329 rpmTag rpmTagGetValue(const char * tagstr)
330 {
331     return ((*rpmTags->tagValue)(tagstr));
332 }
333
334 int rpmTagGetNames(rpmtd tagnames, int fullname)
335 {
336     const char **names;
337     const char *name;
338
339     if (_rpmTags.byName == NULL)
340         tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
341     if (tagnames == NULL ||_rpmTags.byName == NULL)
342         return 0;
343
344     rpmtdReset(tagnames);
345     tagnames->count = _rpmTags.byNameSize;
346     tagnames->data = names = xmalloc(tagnames->count * sizeof(*names));
347     tagnames->type = RPM_STRING_ARRAY_TYPE;
348     tagnames->flags = RPMTD_ALLOCED | RPMTD_IMMUTABLE;
349
350     for (int i = 0; i < tagnames->count; i++) {
351         name = fullname ? _rpmTags.byName[i]->name : 
352                           _rpmTags.byName[i]->shortname;
353         names[i] = name;
354     }
355     return tagnames->count;
356 }