- removed verticals for now to make work easier
[platform/upstream/libsolv.git] / src / repo_solv.c
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 /*
9  * repo_solv.c
10  * 
11  * Read the binary dump of a Repo and create a Repo * from it
12  * 
13  *  See
14  *   Repo *pool_addrepo_solv(Pool *pool, FILE *fp)
15  * below
16  * 
17  */
18
19
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25
26 #include "repo_solv.h"
27 #include "util.h"
28 #include "attr_store_p.h"
29
30 #define INTERESTED_START        SOLVABLE_NAME
31 #define INTERESTED_END          SOLVABLE_FRESHENS
32
33 static Pool *mypool;            /* for pool_debug... */
34
35 /*-----------------------------------------------------------------*/
36 /* .solv read functions */
37
38 /*
39  * read u32
40  */
41
42 static unsigned int
43 read_u32(FILE *fp)
44 {
45   int c, i;
46   unsigned int x = 0;
47
48   for (i = 0; i < 4; i++)
49     {
50       c = getc(fp);
51       if (c == EOF)
52         {
53           pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
54           exit(1);
55         }
56       x = (x << 8) | c;
57     }
58   return x;
59 }
60
61
62 /*
63  * read u8
64  */
65
66 static unsigned int
67 read_u8(FILE *fp)
68 {
69   int c;
70   c = getc(fp);
71   if (c == EOF)
72     {
73       pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
74       exit(1);
75     }
76   return c;
77 }
78
79
80 /*
81  * read Id
82  */
83
84 static Id
85 read_id(FILE *fp, Id max)
86 {
87   unsigned int x = 0;
88   int c, i;
89
90   for (i = 0; i < 5; i++)
91     {
92       c = getc(fp);
93       if (c == EOF)
94         {
95           pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
96           exit(1);
97         }
98       if (!(c & 128))
99         {
100           x = (x << 7) | c;
101           if (max && x >= max)
102             {
103               pool_debug(mypool, SAT_FATAL, "read_id: id too large (%u/%u)\n", x, max);
104               exit(1);
105             }
106           return x;
107         }
108       x = (x << 7) ^ c ^ 128;
109     }
110   pool_debug(mypool, SAT_FATAL, "read_id: id too long\n");
111   exit(1);
112 }
113
114
115 /*
116  * read array of Ids
117  */
118
119 static Id *
120 read_idarray(FILE *fp, Id max, Id *map, Id *store, Id *end, int relative)
121 {
122   unsigned int x = 0;
123   int c;
124   Id old = 0;
125   for (;;)
126     {
127       c = getc(fp);
128       if (c == EOF)
129         {
130           pool_debug(mypool, SAT_FATAL, "unexpected EOF\n");
131           exit(1);
132         }
133       if ((c & 128) == 0)
134         {
135           x = (x << 6) | (c & 63);
136           if (relative)
137             {
138               if (x == 0 && c == 0x40)
139                 {
140                   /* prereq hack */
141                   if (store == end)
142                     {
143                       pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
144                       exit(1);
145                     }
146                   *store++ = SOLVABLE_PREREQMARKER;
147                   old = 0;
148                   x = 0;
149                   continue;
150                 }
151               x = (x - 1) + old;
152               old = x;
153             }
154           if (max && x >= max)
155             {
156               pool_debug(mypool, SAT_FATAL, "read_idarray: id too large (%u/%u)\n", x, max);
157               exit(1);
158             }
159           if (map)
160             x = map[x];
161           if (store == end)
162             {
163               pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
164               exit(1);
165             }
166           *store++ = x;
167           if ((c & 64) == 0)
168             {
169               if (x == 0)       /* already have trailing zero? */
170                 return store;
171               if (store == end)
172                 {
173                   pool_debug(mypool, SAT_FATAL, "read_idarray: array overflow\n");
174                   exit(1);
175                 }
176               *store++ = 0;
177               return store;
178             }
179           x = 0;
180           continue;
181         }
182       x = (x << 7) ^ c ^ 128;
183     }
184 }
185
186 static void
187 read_str(FILE *fp, char **inbuf, unsigned *len)
188 {
189   unsigned char *buf = (unsigned char*)*inbuf;
190   if (!buf)
191     {
192       buf = xmalloc (1024);
193       *len = 1024;
194     }
195   int c;
196   unsigned ofs = 0;
197   while((c = getc (fp)) != 0)
198     {
199       if (c == EOF)
200         {
201           pool_debug (mypool, SAT_FATAL, "unexpected EOF\n");
202           exit (1);
203         }
204       /* Plus 1 as we also want to add the 0.  */
205       if (ofs + 1 >= *len)
206         {
207           *len += 256;
208           /* Don't realloc on the inbuf, it might be on the stack.  */
209           if (buf == (unsigned char*)*inbuf)
210             {
211               buf = xmalloc (*len);
212               memcpy (buf, *inbuf, *len - 256);
213             }
214           else
215             buf = xrealloc (buf, *len);
216         }
217       buf[ofs++] = c;
218     }
219   buf[ofs++] = 0;
220   *inbuf = (char*)buf;
221 }
222
223 static void
224 skip_item (FILE *fp, unsigned type, unsigned numid, unsigned numrel)
225 {
226   switch (type)
227     {
228       case TYPE_VOID:
229         break;
230       case TYPE_ID:
231         read_id(fp, numid + numrel);   /* just check Id */
232         break;
233       case TYPE_U32:
234         read_u32(fp);
235         break;
236       case TYPE_ATTR_STRING:
237       case TYPE_STR:
238         while(read_u8(fp) != 0)
239           ;
240         break;
241       case TYPE_IDARRAY:
242       case TYPE_IDVALUEARRAY:
243       case TYPE_IDVALUEVALUEARRAY:
244       case TYPE_REL_IDARRAY:
245         while ((read_u8(fp) & 0xc0) != 0)
246           ;
247         break;
248       case TYPE_COUNT_NAMED:
249         {
250           unsigned count = read_id (fp, 0);
251           while (count--)
252             {
253               read_id (fp, numid);    /* Name */
254               unsigned t = read_id (fp, TYPE_ATTR_TYPE_MAX + 1);
255               skip_item (fp, t, numid, numrel);
256             }
257         }
258         break;
259       case TYPE_COUNTED:
260         {
261           unsigned count = read_id (fp, 0);
262           unsigned t = read_id (fp, TYPE_ATTR_TYPE_MAX + 1);
263           while (count--)
264             skip_item (fp, t, numid, numrel);
265         }
266         break;
267       case TYPE_ATTR_CHUNK:
268         read_id(fp, 0);
269         /* Fallthrough.  */
270       case TYPE_ATTR_INT:
271         read_id(fp, 0);
272         break;
273       case TYPE_ATTR_INTLIST:
274       case TYPE_ATTR_LOCALIDS:
275         while (read_id(fp, 0) != 0)
276           ;
277         break;
278       default:
279         pool_debug(mypool, SAT_FATAL, "unknown type %d\n", type);
280         exit(1);
281     }
282 }
283
284 static int
285 key_cmp (const void *pa, const void *pb)
286 {
287   Repokey *a = (Repokey *)pa;
288   Repokey *b = (Repokey *)pb;
289   return a->name - b->name;
290 }
291
292 static void
293 parse_repodata (FILE *fp, Id *keyp, Repokey *keys, Id *idmap, unsigned numid, unsigned numrel, Repo *repo)
294 {
295   Id key, id;
296   Id *ida, *ide;
297   Repodata *data;
298   int i, n;
299
300   repo->repodata = xrealloc(repo->repodata, (repo->nrepodata + 1) * sizeof (*data));
301   data = repo->repodata + repo->nrepodata++;
302   data->repo = repo;
303   memset(data, 0, sizeof(*data));
304
305   while ((key = *keyp++) != 0)
306     {
307       id = keys[key].name;
308       switch (keys[key].type)
309         {
310         case TYPE_IDVALUEARRAY:
311           if (id != REPODATA_KEYS)
312             {
313               skip_item(fp, TYPE_IDVALUEARRAY, numid, numrel);
314               break;
315             }
316           ida = xcalloc(keys[key].size, sizeof(Id));
317           ide = read_idarray(fp, 0, 0, ida, ida + keys[key].size, 0);
318           n = ide - ida - 1;
319           if (n & 1)
320             {
321               pool_debug (mypool, SAT_FATAL, "invalid attribute data\n");
322               exit (1);
323             }
324           data->nkeys = 1 + (n >> 1);
325           data->keys = xmalloc2(data->nkeys, sizeof(data->keys[0]));
326           memset(data->keys, 0, sizeof(Repokey));
327           for (i = 1, ide = ida; i < data->nkeys; i++)
328             {
329               if (*ide >= numid)
330                 {
331                   pool_debug (mypool, SAT_FATAL, "invalid attribute data\n");
332                   exit (1);
333                 }
334               data->keys[i].name = idmap ? idmap[*ide++] : *ide++;
335               data->keys[i].type = *ide++;
336               data->keys[i].size = 0;
337               data->keys[i].storage = 0;
338             }
339           xfree(ida);
340           if (data->nkeys > 2)
341             qsort(data->keys + 1, data->nkeys - 1, sizeof(data->keys[0]), key_cmp);
342           break;
343         case TYPE_STR:
344           if (id != REPODATA_LOCATION)
345             skip_item(fp, TYPE_STR, numid, numrel);
346           else
347             {
348               char buf[1024];
349               unsigned len = sizeof (buf);
350               char *filename = buf;
351               read_str(fp, &filename, &len);
352               data->location = strdup(filename);
353               if (filename != buf)
354                 free(filename);
355             }
356           break;
357         default:
358           skip_item(fp, keys[key].type, numid, numrel);
359           break;
360         }
361     }
362 }
363
364 /*-----------------------------------------------------------------*/
365
366
367 static void
368 skip_schema(FILE *fp, Id *keyp, Repokey *keys, unsigned int numid, unsigned int numrel)
369 {
370   Id key;
371   while ((key = *keyp++) != 0)
372     skip_item(fp, keys[key].type, numid, numrel);
373 }
374
375 /*-----------------------------------------------------------------*/
376
377 static void
378 incore_add_id(Repodata *data, Id x)
379 {
380   unsigned char *dp;
381   /* make sure we have at least 5 bytes free */
382   if (data->incoredatafree < 5)
383     {
384       data->incoredata = xrealloc(data->incoredata, data->incoredatalen + 1024);
385       data->incoredatafree = 1024;
386     }
387   dp = data->incoredata + data->incoredatalen;
388   if (x < 0)
389     abort();
390   if (x >= (1 << 14))
391     {
392       if (x >= (1 << 28))
393         *dp++ = (x >> 28) | 128;
394       if (x >= (1 << 21))
395         *dp++ = (x >> 21) | 128;
396       *dp++ = (x >> 14) | 128;
397     }
398   if (x >= (1 << 7))
399     *dp++ = (x >> 7) | 128;
400   *dp++ = x & 127;
401   data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
402   data->incoredatalen = dp - data->incoredata;
403 }
404
405 static void
406 incore_add_u32(Repodata *data, unsigned int x)
407 {
408   unsigned char *dp;
409   /* make sure we have at least 4 bytes free */
410   if (data->incoredatafree < 4)
411     {
412       data->incoredata = xrealloc(data->incoredata, data->incoredatalen + 1024);
413       data->incoredatafree = 1024;
414     }
415   dp = data->incoredata + data->incoredatalen;
416   *dp++ = x >> 24;
417   *dp++ = x >> 16;
418   *dp++ = x >> 8;
419   *dp++ = x;
420   data->incoredatafree -= 4;
421   data->incoredatalen += 4;
422 }
423
424 static void
425 incore_add_u8(Repodata *data, unsigned int x)
426 {
427   unsigned char *dp;
428   /* make sure we have at least 1 byte free */
429   if (data->incoredatafree < 1)
430     {
431       data->incoredata = xrealloc(data->incoredata, data->incoredatalen + 1024);
432       data->incoredatafree = 1024;
433     }
434   dp = data->incoredata + data->incoredatalen;
435   *dp++ = x;
436   data->incoredatafree--;
437   data->incoredatalen++;
438 }
439
440 // ----------------------------------------------
441
442 /*
443  * read repo from .solv file
444  *  and add it to pool
445  */
446
447 void
448 repo_add_solv(Repo *repo, FILE *fp)
449 {
450   Pool *pool = repo->pool;
451   int i, l;
452   unsigned int numid, numrel, numsolv;
453   unsigned int numkeys, numschemata, numinfo;
454 #if 0
455   Attrstore *embedded_store = 0;
456 #endif
457
458   Offset sizeid;
459   Offset *str;                         /* map Id -> Offset into string space */
460   char *strsp;                         /* repo string space */
461   char *sp;                            /* pointer into string space */
462   Id *idmap;                           /* map of repo Ids to pool Ids */
463   Id id;
464   unsigned int hashmask, h;
465   int hh;
466   Id *hashtbl;
467   Id name, evr, did;
468   int flags;
469   Reldep *ran;
470   unsigned int size_idarray;
471   Id *idarraydatap, *idarraydataend;
472   Offset ido;
473   Solvable *s;
474   unsigned int solvflags;
475   unsigned int solvversion;
476   Repokey *keys;
477   Id *schemadata, *schemadatap, *schemadataend;
478   Id *schemata, key;
479
480   Repodata data;
481
482   mypool = pool;
483
484   if (read_u32(fp) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
485     {
486       pool_debug(pool, SAT_FATAL, "not a SOLV file\n");
487       exit(1);
488     }
489   solvversion = read_u32(fp);
490   switch (solvversion)
491     {
492       case SOLV_VERSION_1:
493       case SOLV_VERSION_2:
494       case SOLV_VERSION_3:
495         break;
496       default:
497         pool_debug(pool, SAT_FATAL, "unsupported SOLV version\n");
498         exit(1);
499     }
500
501   pool_freeidhashes(pool);
502
503   numid = read_u32(fp);
504   numrel = read_u32(fp);
505   numsolv = read_u32(fp);
506   numkeys = read_u32(fp);
507   numschemata = read_u32(fp);
508   numinfo = read_u32(fp);
509   solvflags = read_u32(fp);
510
511   memset(&data, 0, sizeof(data));
512   data.repo = repo;
513
514   if (solvversion < SOLV_VERSION_3
515       && numinfo)
516     {
517       pool_debug(pool, SAT_FATAL, "unsupported SOLV format (has info)\n");
518       exit(1);
519     }
520
521   /*******  Part 1: string IDs  *****************************************/
522
523   sizeid = read_u32(fp);               /* size of string+Id space */
524
525   /*
526    * read strings and Ids
527    * 
528    */
529
530   
531   /*
532    * alloc buffers
533    */
534
535   /* alloc string buffer */
536   strsp = (char *)xrealloc(pool->ss.stringspace, pool->ss.sstrings + sizeid + 1);
537   /* alloc string offsets (Id -> Offset into string space) */
538   str = (Offset *)xrealloc(pool->ss.strings, (pool->ss.nstrings + numid) * sizeof(Offset));
539
540   pool->ss.stringspace = strsp;
541   pool->ss.strings = str;                      /* array of offsets into strsp, indexed by Id */
542
543   /* point to _BEHIND_ already allocated string/Id space */
544   strsp += pool->ss.sstrings;
545
546   /* alloc id map for name and rel Ids. this maps ids in the solv files
547    * to the ids in our pool */
548   idmap = (Id *)xcalloc(numid + numrel, sizeof(Id));
549
550   /*
551    * read new repo at end of pool
552    */
553   
554   if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
555     {
556       if (fread(strsp, sizeid, 1, fp) != 1)
557         {
558           pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
559           exit(1);
560         }
561     }
562   else
563     {
564       unsigned int pfsize = read_u32 (fp);
565       char *prefix = xmalloc (pfsize);
566       char *pp = prefix;
567       char *old_str = "";
568       char *dest = strsp;
569       if (fread (prefix, pfsize, 1, fp) != 1)
570         {
571           pool_debug(pool, SAT_FATAL, "read error while reading strings\n");
572           exit(1);
573         }
574       for (i = 1; i < numid; i++)
575         {
576           int same = (unsigned char)*pp++;
577           size_t len = strlen (pp) + 1;
578           if (same)
579             memcpy (dest, old_str, same);
580           memcpy (dest + same, pp, len);
581           pp += len;
582           old_str = dest;
583           dest += same + len;
584         }
585       xfree (prefix);
586     }
587   strsp[sizeid] = 0;                   /* make string space \0 terminated */
588   sp = strsp;
589
590   /*
591    * build hashes for all read strings
592    * 
593    */
594   
595   hashmask = mkmask(pool->ss.nstrings + numid);
596
597 #if 0
598   POOL_DEBUG(SAT_DEBUG_STATS, "read %d strings\n", numid);
599   POOL_DEBUG(SAT_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
600 #endif
601
602   /*
603    * ensure sufficient hash size
604    */
605   
606   hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
607
608   /*
609    * fill hashtable with strings already in pool
610    */
611   
612   for (i = 1; i < pool->ss.nstrings; i++)  /* leave out our dummy zero id */
613     {
614       h = strhash(pool->ss.stringspace + pool->ss.strings[i]) & hashmask;
615       hh = HASHCHAIN_START;
616       while (hashtbl[h])
617         h = HASHCHAIN_NEXT(h, hh, hashmask);
618       hashtbl[h] = i;
619     }
620
621   /*
622    * run over string space, calculate offsets
623    * 
624    * build id map (maps solv Id -> pool Id)
625    */
626   
627   for (i = 1; i < numid; i++)
628     {
629       if (sp >= strsp + sizeid)
630         {
631           pool_debug(pool, SAT_FATAL, "not enough strings\n");
632           exit(1);
633         }
634       if (!*sp)                        /* empty string */
635         {
636           idmap[i] = ID_EMPTY;
637           sp++;
638           continue;
639         }
640
641       /* find hash slot */
642       h = strhash(sp) & hashmask;
643       hh = HASHCHAIN_START;
644       for (;;)
645         {
646           id = hashtbl[h];
647           if (id == 0)
648             break;
649           if (!strcmp(pool->ss.stringspace + pool->ss.strings[id], sp))
650             break;                     /* existing string */
651           h = HASHCHAIN_NEXT(h, hh, hashmask);
652         }
653
654       /* length == offset to next string */
655       l = strlen(sp) + 1;
656       if (id == ID_NULL)               /* end of hash chain -> new string */
657         {
658           id = pool->ss.nstrings++;
659           hashtbl[h] = id;
660           str[id] = pool->ss.sstrings;    /* save Offset */
661           if (sp != pool->ss.stringspace + pool->ss.sstrings)   /* not at end-of-buffer */
662             memmove(pool->ss.stringspace + pool->ss.sstrings, sp, l);   /* append to pool buffer */
663           pool->ss.sstrings += l;
664         }
665       idmap[i] = id;                   /* repo relative -> pool relative */
666       sp += l;                         /* next string */
667     }
668   xfree(hashtbl);
669   pool_shrink_strings(pool);           /* vacuum */
670
671   
672   /*******  Part 2: Relation IDs  ***************************************/
673
674   /*
675    * read RelDeps
676    * 
677    */
678   
679   if (numrel)
680     {
681       /* extend rels */
682       ran = (Reldep *)xrealloc(pool->rels, (pool->nrels + numrel) * sizeof(Reldep));
683       if (!ran)
684         {
685           pool_debug(pool, SAT_FATAL, "no mem for rel space\n");
686           exit(1);
687         }
688       pool->rels = ran;        /* extended rel space */
689
690       hashmask = mkmask(pool->nrels + numrel);
691 #if 0
692       POOL_DEBUG(SAT_DEBUG_STATS, "read %d rels\n", numrel);
693       POOL_DEBUG(SAT_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
694 #endif
695       /*
696        * prep hash table with already existing RelDeps
697        */
698       
699       hashtbl = (Id *)xcalloc(hashmask + 1, sizeof(Id));
700       for (i = 1; i < pool->nrels; i++)
701         {
702           h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
703           hh = HASHCHAIN_START;
704           while (hashtbl[h])
705             h = HASHCHAIN_NEXT(h, hh, hashmask);
706           hashtbl[h] = i;
707         }
708
709       /*
710        * read RelDeps from repo
711        */
712       
713       for (i = 0; i < numrel; i++)
714         {
715           name = read_id(fp, i + numid);        /* read (repo relative) Ids */
716           evr = read_id(fp, i + numid);
717           flags = read_u8(fp);
718           name = idmap[name];           /* map to (pool relative) Ids */
719           evr = idmap[evr];
720           h = relhash(name, evr, flags) & hashmask;
721           hh = HASHCHAIN_START;
722           for (;;)
723             {
724               id = hashtbl[h];
725               if (id == ID_NULL)        /* end of hash chain */
726                 break;
727               if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
728                 break;
729               h = HASHCHAIN_NEXT(h, hh, hashmask);
730             }
731           if (id == ID_NULL)            /* new RelDep */
732             {
733               id = pool->nrels++;
734               hashtbl[h] = id;
735               ran[id].name = name;
736               ran[id].evr = evr;
737               ran[id].flags = flags;
738             }
739           idmap[i + numid] = MAKERELDEP(id);   /* fill Id map */
740         }
741       xfree(hashtbl);
742       pool_shrink_rels(pool);           /* vacuum */
743     }
744
745
746   /*******  Part 3: Keys  ***********************************************/
747
748   keys = xcalloc(numkeys, sizeof(*keys));
749   /* keys start at 1 */
750   for (i = 1; i < numkeys; i++)
751     {
752       id = read_id(fp, numid);
753       if (idmap)
754         id = idmap[id];
755       keys[i].name = id;
756       keys[i].type = read_id(fp, 0);
757       keys[i].size = read_id(fp, 0);
758       keys[i].storage = KEY_STORAGE_DROPPED;
759       switch (keys[i].type)
760         {
761         case TYPE_ID:
762           switch(id)
763             {
764             case SOLVABLE_NAME:
765             case SOLVABLE_ARCH:
766             case SOLVABLE_EVR:
767             case SOLVABLE_VENDOR:
768               keys[i].storage = KEY_STORAGE_SOLVABLE;
769               break;
770             default:
771               keys[i].storage = KEY_STORAGE_INCORE;
772               break;
773             }
774           break;
775         case TYPE_IDARRAY:
776         case TYPE_REL_IDARRAY:
777           if (id >= INTERESTED_START && id <= INTERESTED_END)
778             keys[i].storage = KEY_STORAGE_SOLVABLE;
779           else
780             keys[i].storage = KEY_STORAGE_INCORE;
781           break;
782         case TYPE_STR:
783           keys[i].storage = KEY_STORAGE_INCORE;
784           break;
785         case TYPE_U32:
786           if (id == RPM_RPMDBID)
787             keys[i].storage = KEY_STORAGE_SOLVABLE;
788           else
789             keys[i].storage = KEY_STORAGE_INCORE;
790           break;
791         default:
792           break;
793         }
794     }
795
796   data.keys = keys;
797   data.nkeys = numkeys;
798
799   /*******  Part 4: Schemata ********************************************/
800   
801   id = read_id(fp, 0);
802   schemadata = xcalloc(id, sizeof(Id));
803   schemadatap = schemadata;
804   schemadataend = schemadata + id;
805   schemata = xcalloc(numschemata, sizeof(Id));
806   for (i = 0; i < numschemata; i++)
807     {
808       schemata[i] = schemadatap - schemadata;
809       schemadatap = read_idarray(fp, numid, 0, schemadatap, schemadataend, 0);
810     }
811   data.schemata = schemata;
812   data.nschemata = numschemata;
813   data.schemadata = schemadata;
814
815   /*******  Part 5: Info  ***********************************************/
816   for (i = 0; i < numinfo; i++)
817     {
818       /* for now we're just interested in data that starts with
819        * the repodata_external id
820        */
821       Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
822       key = *keyp;
823       if (keys[key].name == REPODATA_EXTERNAL && keys[key].type == TYPE_VOID)
824         {
825           /* external data for some ids */
826           parse_repodata(fp, keyp, keys, idmap, numid, numrel, repo);
827         }
828       else
829         skip_schema(fp, keyp, keys, numid, numrel);
830     }
831
832   /*******  Part 6: packed sizes (optional)  ****************************/
833   char *exists = 0;
834   if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0)
835     {
836       exists = xmalloc (numsolv);
837       for (i = 0; i < numsolv; i++)
838         exists[i] = read_id(fp, 0) != 0;
839     }
840
841   /*******  Part 7: item data *******************************************/
842
843   /* calculate idarray size */
844   size_idarray = 0;
845   for (i = 1; i < numkeys; i++)
846     {
847       id = keys[i].name;
848       if ((keys[i].type == TYPE_IDARRAY || keys[i].type == TYPE_REL_IDARRAY)
849           && id >= INTERESTED_START && id <= INTERESTED_END)
850         size_idarray += keys[i].size;
851     }
852
853   /* allocate needed space in repo */
854   if (size_idarray)
855     {
856       repo_reserve_ids(repo, 0, size_idarray);
857       idarraydatap = repo->idarraydata + repo->idarraysize;
858       repo->idarraysize += size_idarray;
859       idarraydataend = repo->idarraydata + repo->idarraysize;
860       repo->lastoff = 0;
861     }
862   else
863     {
864       idarraydatap = 0;
865       idarraydataend = 0;
866     }
867
868   /* read solvables */
869   s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
870
871   /* store start and end of our id block */
872   data.start = s - pool->solvables;
873   data.end = data.start + numsolv;
874
875   for (i = 0; i < numsolv; i++, s++)
876     {
877       if (exists && !exists[i])
878         continue;
879       Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
880       while ((key = *keyp++) != 0)
881         {
882           id = keys[key].name;
883           switch (keys[key].type)
884             {
885             case TYPE_ID:
886               did = read_id(fp, numid + numrel);
887               if (idmap)
888                 did = idmap[did];
889               if (id == SOLVABLE_NAME)
890                 s->name = did;
891               else if (id == SOLVABLE_ARCH)
892                 s->arch = did;
893               else if (id == SOLVABLE_EVR)
894                 s->evr = did;
895               else if (id == SOLVABLE_VENDOR)
896                 s->vendor = did;
897               else if (keys[key].storage == KEY_STORAGE_INCORE)
898                 incore_add_id(&data, did);
899 #if 0
900               POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
901 #endif
902               break;
903             case TYPE_U32:
904               h = read_u32(fp);
905 #if 0
906               POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
907 #endif
908               if (id == RPM_RPMDBID)
909                 {
910                   if (!repo->rpmdbid)
911                     repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
912                   repo->rpmdbid[i] = h;
913                 }
914               else if (keys[key].storage == KEY_STORAGE_INCORE)
915                 incore_add_u32(&data, h);
916               break;
917             case TYPE_STR:
918               if (keys[key].storage == KEY_STORAGE_INCORE)
919                 {
920                   while ((h = read_u8(fp)) != 0)
921                     incore_add_u8(&data, h);
922                   incore_add_u8(&data, 0);
923                 }
924               else
925                 {
926                   while (read_u8(fp) != 0)
927                     ;
928                 }
929               break;
930             case TYPE_IDARRAY:
931             case TYPE_REL_IDARRAY:
932               if (id < INTERESTED_START || id > INTERESTED_END)
933                 {
934                   if (keys[key].storage == KEY_STORAGE_INCORE)
935                     {
936                       if (idmap)
937                         {
938                           Id old = 0, rel = keys[key].type == TYPE_REL_IDARRAY ? SOLVABLE_PREREQMARKER : 0;
939                           do
940                             {
941                               did = read_id(fp, 0);
942                               h = did & 0x40;
943                               did = (did & 0x3f) | ((did >> 1) & ~0x3f);
944                               if (rel)
945                                 {
946                                   if (did == 0)
947                                     {
948                                       did = rel;
949                                       old = 0;
950                                     }
951                                   else
952                                     {
953                                       did += old;
954                                       old = did;
955                                     }
956                                 }
957                               if (did >= numid + numrel)
958                                 abort();
959                               did = idmap[did];
960                               did = ((did & ~0x3f) << 1) | h;
961                               incore_add_id(&data, did);
962                             }
963                           while (h);
964                         }
965                       else
966                         {
967                           while (((h = read_u8(fp)) & 0xc0) != 0)
968                             incore_add_u8(&data, h);
969                           break;
970                         }
971                     }
972                   else
973                     {
974                       while ((read_u8(fp) & 0xc0) != 0)
975                         ;
976                       break;
977                     }
978                   break;
979                 }
980               ido = idarraydatap - repo->idarraydata;
981               idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, keys[key].type == TYPE_REL_IDARRAY);
982               if (id == SOLVABLE_PROVIDES)
983                 s->provides = ido;
984               else if (id == SOLVABLE_OBSOLETES)
985                 s->obsoletes = ido;
986               else if (id == SOLVABLE_CONFLICTS)
987                 s->conflicts = ido;
988               else if (id == SOLVABLE_REQUIRES)
989                 s->requires = ido;
990               else if (id == SOLVABLE_RECOMMENDS)
991                 s->recommends= ido;
992               else if (id == SOLVABLE_SUPPLEMENTS)
993                 s->supplements = ido;
994               else if (id == SOLVABLE_SUGGESTS)
995                 s->suggests = ido;
996               else if (id == SOLVABLE_ENHANCES)
997                 s->enhances = ido;
998               else if (id == SOLVABLE_FRESHENS)
999                 s->freshens = ido;
1000 #if 0
1001               POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
1002               for (; repo->idarraydata[ido]; ido++)
1003                 POOL_DEBUG(SAT_DEBUG_STATS,"  %s\n", dep2str(pool, repo->idarraydata[ido]));
1004 #endif
1005               break;
1006 #if 0
1007             case TYPE_VOID:
1008
1009             case TYPE_ATTR_INT:
1010             case TYPE_ATTR_CHUNK:
1011             case TYPE_ATTR_STRING:
1012             case TYPE_ATTR_INTLIST:
1013             case TYPE_ATTR_LOCALIDS:
1014               if (!embedded_store)
1015                 embedded_store = new_store (pool);
1016               add_attr_from_file (embedded_store, i, id, keys[key].type, idmap, numid, fp);
1017               break;
1018 #endif
1019             default:
1020               skip_item(fp, keys[key].type, numid, numrel);
1021             }
1022         }
1023     }
1024
1025   if (data.incoredatafree)
1026     {
1027       /* shrink excess size */
1028       data.incoredata = xrealloc(data.incoredata, data.incoredatalen);
1029       data.incoredatafree = 0;
1030     }
1031
1032   for (i = 1; i < numkeys; i++)
1033     if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
1034       break;
1035   if (i < numkeys)
1036     {
1037       /* we have vertical data, make it available */
1038       data.fp = fp;
1039       data.verticaloffset = ftell(fp);
1040     }
1041
1042   if (data.incoredatalen || data.fp)
1043     {
1044       /* we got some data, make it available */
1045       repo->repodata = xrealloc(repo->repodata, (repo->nrepodata + 1) * sizeof(data));
1046       repo->repodata[repo->nrepodata++] = data;
1047     }
1048   else
1049     {
1050       xfree(schemata);
1051       xfree(schemadata);
1052       xfree(keys);
1053     }
1054
1055   xfree(exists);
1056 #if 0
1057   if (embedded_store)
1058     {
1059       attr_store_pack (embedded_store);
1060       /* If we have any attributes we also have pages.  */
1061       read_or_setup_pages (fp, embedded_store);
1062       /* The NULL name here means embedded attributes.  */
1063       repo_add_attrstore (repo, embedded_store, NULL);
1064     }
1065 #endif
1066   xfree(idmap);
1067   mypool = 0;
1068 }
1069
1070 // EOF