another targeted dup fix, add testcases
[platform/upstream/libsolv.git] / src / repopack.h
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /* pack/unpack functions for key data */
9
10 #ifndef LIBSOLV_REPOPACK_H
11 #define LIBSOLV_REPOPACK_H
12
13 static inline unsigned char *
14 data_read_id(unsigned char *dp, Id *idp)
15 {
16   Id x;
17   unsigned char c;
18   if (!(dp[0] & 0x80))
19     {
20       *idp = dp[0];
21       return dp + 1;
22     }
23   if (!(dp[1] & 0x80))
24     {
25       *idp = dp[0] << 7 ^ dp[1] ^ 0x4000;
26       return dp + 2;
27     }
28   if (!(dp[2] & 0x80))
29     {
30       *idp = dp[0] << 14 ^ dp[1] << 7 ^ dp[2] ^ 0x204000;
31       return dp + 3;
32     }
33   if (!(dp[3] & 0x80))
34     {
35       *idp = dp[0] << 21 ^ dp[1] << 14 ^ dp[2] << 7 ^ dp[3] ^ 0x10204000;
36       return dp + 4;
37     }
38   x = dp[0] << 28 ^ dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204000;
39   if (!(dp[4] & 0x80))
40     {
41       *idp = x;
42       return dp + 5;
43     }
44   x ^= 80;
45   dp += 5;
46   for (;;)
47     {
48       c = *dp++;
49       if (!(c & 0x80))
50         {
51           *idp = (x << 7) ^ c;
52           return dp;
53         }
54       x = (x << 7) ^ (c ^ 128);
55     }
56 }
57
58 static inline unsigned char *
59 data_read_num64(unsigned char *dp, unsigned int *low, unsigned int *high)
60 {
61   unsigned long long int x;
62   unsigned char c;
63
64   *high = 0;
65   if (!(dp[0] & 0x80))
66     {
67       *low = dp[0];
68       return dp + 1;
69     }
70   if (!(dp[1] & 0x80))
71     {
72       *low = dp[0] << 7 ^ dp[1] ^ 0x4000;
73       return dp + 2;
74     }
75   if (!(dp[2] & 0x80))
76     {
77       *low = dp[0] << 14 ^ dp[1] << 7 ^ dp[2] ^ 0x204000;
78       return dp + 3;
79     }
80   if (!(dp[3] & 0x80))
81     {
82       *low = dp[0] << 21 ^ dp[1] << 14 ^ dp[2] << 7 ^ dp[3] ^ 0x10204000;
83       return dp + 4;
84     }
85   if (!(dp[4] & 0x80))
86     {
87       *low = dp[0] << 28 ^ dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204000;
88       *high = (dp[0] ^ 0x80) >> 4;
89       return dp + 5;
90     }
91   x = (unsigned long long)(dp[0] ^ 0x80) << 28 ^ (unsigned int)(dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204080);
92   dp += 5;
93   for (;;)
94     {
95       c = *dp++;
96       if (!(c & 0x80))
97         {
98           x = (x << 7) ^ c;
99           *low = x;
100           *high = x >> 32;
101           return dp;
102         }
103       x = (x << 7) ^ (c ^ 128);
104     }
105 }
106
107 static inline unsigned char *
108 data_read_ideof(unsigned char *dp, Id *idp, int *eof)
109 {
110   Id x = 0;
111   unsigned char c;
112   for (;;)
113     {
114       c = *dp++;
115       if (!(c & 0x80))
116         {
117           if (c & 0x40)
118             {
119               c ^= 0x40;
120               *eof = 0;
121             }
122           else
123             *eof = 1;
124           *idp = (x << 6) ^ c;
125           return dp;
126         }
127       x = (x << 7) ^ c ^ 128;
128     }
129 }
130
131 static inline unsigned char *
132 data_read_u32(unsigned char *dp, unsigned int *nump)
133 {
134   *nump = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3];
135   return dp + 4;
136 }
137
138 static inline unsigned char *
139 data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
140 {
141   kv->eof = 1;
142   if (!dp)
143     return 0;
144   switch (key->type)
145     {
146     case REPOKEY_TYPE_VOID:
147       return dp;
148     case REPOKEY_TYPE_CONSTANT:
149       kv->num2 = 0;
150       kv->num = key->size;
151       return dp;
152     case REPOKEY_TYPE_CONSTANTID:
153       kv->id = key->size;
154       return dp;
155     case REPOKEY_TYPE_STR:
156       kv->str = (const char *)dp;
157       return dp + strlen(kv->str) + 1;
158     case REPOKEY_TYPE_ID:
159     case REPOKEY_TYPE_DIR:
160       return data_read_id(dp, &kv->id);
161     case REPOKEY_TYPE_NUM:
162       return data_read_num64(dp, &kv->num, &kv->num2);
163     case REPOKEY_TYPE_U32:
164       kv->num2 = 0;
165       return data_read_u32(dp, &kv->num);
166     case REPOKEY_TYPE_MD5:
167       kv->str = (const char *)dp;
168       return dp + SIZEOF_MD5;
169     case REPOKEY_TYPE_SHA1:
170       kv->str = (const char *)dp;
171       return dp + SIZEOF_SHA1;
172     case REPOKEY_TYPE_SHA256:
173       kv->str = (const char *)dp;
174       return dp + SIZEOF_SHA256;
175     case REPOKEY_TYPE_BINARY:
176       dp = data_read_id(dp, (Id *)&kv->num);
177       kv->str = (const char *)dp;
178       return dp + kv->num;
179     case REPOKEY_TYPE_IDARRAY:
180       return data_read_ideof(dp, &kv->id, &kv->eof);
181     case REPOKEY_TYPE_DIRSTRARRAY:
182       dp = data_read_ideof(dp, &kv->id, &kv->eof);
183       kv->str = (const char *)dp;
184       return dp + strlen(kv->str) + 1;
185     case REPOKEY_TYPE_DIRNUMNUMARRAY:
186       dp = data_read_id(dp, &kv->id);
187       dp = data_read_id(dp, (Id *)&kv->num);
188       return data_read_ideof(dp, (Id *)&kv->num2, &kv->eof);
189     case REPOKEY_TYPE_FIXARRAY:
190       dp = data_read_id(dp, (Id *)&kv->num);
191       return data_read_id(dp, &kv->id);
192     case REPOKEY_TYPE_FLEXARRAY:
193       return data_read_id(dp, (Id *)&kv->num);
194     default:
195       return 0;
196     }
197 }
198
199 static inline unsigned char *
200 data_skip(unsigned char *dp, int type)
201 {
202   unsigned char x;
203   switch (type)
204     {
205     case REPOKEY_TYPE_VOID:
206     case REPOKEY_TYPE_CONSTANT:
207     case REPOKEY_TYPE_CONSTANTID:
208     case REPOKEY_TYPE_DELETED:
209       return dp;
210     case REPOKEY_TYPE_ID:
211     case REPOKEY_TYPE_NUM:
212     case REPOKEY_TYPE_DIR:
213       while ((*dp & 0x80) != 0)
214         dp++;
215       return dp + 1;
216     case REPOKEY_TYPE_U32:
217       return dp + 4;
218     case REPOKEY_TYPE_MD5:
219       return dp + SIZEOF_MD5;
220     case REPOKEY_TYPE_SHA1:
221       return dp + SIZEOF_SHA1;
222     case REPOKEY_TYPE_SHA256:
223       return dp + SIZEOF_SHA256;
224     case REPOKEY_TYPE_IDARRAY:
225     case REPOKEY_TYPE_REL_IDARRAY:
226       while ((*dp & 0xc0) != 0)
227         dp++;
228       return dp + 1;
229     case REPOKEY_TYPE_STR:
230       while ((*dp) != 0)
231         dp++;
232       return dp + 1;
233     case REPOKEY_TYPE_BINARY:
234       {
235         unsigned int len;
236         dp = data_read_id(dp, (Id *)&len);
237         return dp + len;
238       }
239     case REPOKEY_TYPE_DIRSTRARRAY:
240       for (;;)
241         {
242           while ((*dp & 0x80) != 0)
243             dp++;
244           x = *dp++;
245           while ((*dp) != 0)
246             dp++;
247           dp++;
248           if (!(x & 0x40))
249             return dp;
250         }
251     case REPOKEY_TYPE_DIRNUMNUMARRAY:
252       for (;;)
253         {
254           while ((*dp & 0x80) != 0)
255             dp++;
256           dp++;
257           while ((*dp & 0x80) != 0)
258             dp++;
259           dp++;
260           while ((*dp & 0x80) != 0)
261             dp++;
262           if (!(*dp & 0x40))
263             return dp + 1;
264           dp++;
265         }
266     default:
267       return 0;
268     }
269 }
270
271 static inline unsigned char *
272 data_skip_verify(unsigned char *dp, int type, int maxid, int maxdir)
273 {
274   Id id;
275   int eof;
276
277   switch (type)
278     {
279     case REPOKEY_TYPE_VOID:
280     case REPOKEY_TYPE_CONSTANT:
281     case REPOKEY_TYPE_CONSTANTID:
282     case REPOKEY_TYPE_DELETED:
283       return dp;
284     case REPOKEY_TYPE_NUM:
285       while ((*dp & 0x80) != 0)
286         dp++;
287       return dp + 1;
288     case REPOKEY_TYPE_U32:
289       return dp + 4;
290     case REPOKEY_TYPE_MD5:
291       return dp + SIZEOF_MD5;
292     case REPOKEY_TYPE_SHA1:
293       return dp + SIZEOF_SHA1;
294     case REPOKEY_TYPE_SHA256:
295       return dp + SIZEOF_SHA256;
296     case REPOKEY_TYPE_ID:
297       dp = data_read_id(dp, &id);
298       if (id >= maxid)
299         return 0;
300       return dp;
301     case REPOKEY_TYPE_DIR:
302       dp = data_read_id(dp, &id);
303       if (id >= maxdir)
304         return 0;
305       return dp;
306     case REPOKEY_TYPE_IDARRAY:
307       for (;;)
308         {
309           dp = data_read_ideof(dp, &id, &eof);
310           if (id >= maxid)
311             return 0;
312           if (eof)
313             return dp;
314         }
315     case REPOKEY_TYPE_STR:
316       while ((*dp) != 0)
317         dp++;
318       return dp + 1;
319     case REPOKEY_TYPE_BINARY:
320       {
321         unsigned int len;
322         dp = data_read_id(dp, (Id *)&len);
323         return dp + len;
324       }
325     case REPOKEY_TYPE_DIRSTRARRAY:
326       for (;;)
327         {
328           dp = data_read_ideof(dp, &id, &eof);
329           if (id >= maxdir)
330             return 0;
331           while ((*dp) != 0)
332             dp++;
333           dp++;
334           if (eof)
335             return dp;
336         }
337     case REPOKEY_TYPE_DIRNUMNUMARRAY:
338       for (;;)
339         {
340           dp = data_read_id(dp, &id);
341           if (id >= maxdir)
342             return 0;
343           while ((*dp & 0x80) != 0)
344             dp++;
345           dp++;
346           while ((*dp & 0x80) != 0)
347             dp++;
348           if (!(*dp & 0x40))
349             return dp + 1;
350           dp++;
351         }
352     default:
353       return 0;
354     }
355 }
356
357 #endif  /* LIBSOLV_REPOPACK */