- some pieces of code for the unified lookup/search interface
[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[*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       keys[i].name = id = idmap[read_id(fp, numid)];
753       keys[i].type = read_id(fp, 0);
754       keys[i].size = read_id(fp, 0);
755       keys[i].storage = KEY_STORAGE_DROPPED;
756       switch (keys[i].type)
757         {
758         case TYPE_ID:
759           switch(id)
760             {
761             case SOLVABLE_NAME:
762             case SOLVABLE_ARCH:
763             case SOLVABLE_EVR:
764             case SOLVABLE_VENDOR:
765               keys[i].storage = KEY_STORAGE_SOLVABLE;
766               break;
767             default:
768               keys[i].storage = KEY_STORAGE_INCORE;
769               break;
770             }
771           break;
772         case TYPE_IDARRAY:
773         case TYPE_REL_IDARRAY:
774           if (id >= INTERESTED_START && id <= INTERESTED_END)
775             keys[i].storage = KEY_STORAGE_SOLVABLE;
776           else
777             keys[i].storage = KEY_STORAGE_INCORE;
778           break;
779         case TYPE_STR:
780           keys[i].storage = KEY_STORAGE_INCORE;
781           break;
782         case TYPE_U32:
783           if (id == RPM_RPMDBID)
784             keys[i].storage = KEY_STORAGE_SOLVABLE;
785           else
786             keys[i].storage = KEY_STORAGE_INCORE;
787           break;
788         default:
789           break;
790         }
791     }
792
793   data.keys = keys;
794   data.nkeys = numkeys;
795
796   /*******  Part 4: Schemata ********************************************/
797   
798   id = read_id(fp, 0);
799   schemadata = xcalloc(id, sizeof(Id));
800   schemadatap = schemadata;
801   schemadataend = schemadata + id;
802   schemata = xcalloc(numschemata, sizeof(Id));
803   for (i = 0; i < numschemata; i++)
804     {
805       schemata[i] = schemadatap - schemadata;
806       schemadatap = read_idarray(fp, numid, 0, schemadatap, schemadataend, 0);
807     }
808   data.schemata = schemata;
809   data.nschemata = numschemata;
810   data.schemadata = schemadata;
811
812   /*******  Part 5: Info  ***********************************************/
813   for (i = 0; i < numinfo; i++)
814     {
815       /* for now we're just interested in data that starts with
816        * the repodata_external id
817        */
818       Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
819       key = *keyp;
820       if (keys[key].name == REPODATA_EXTERNAL && keys[key].type == TYPE_VOID)
821         {
822           /* external data for some ids */
823           parse_repodata(fp, keyp, keys, idmap, numid, numrel, repo);
824         }
825       else
826         skip_schema(fp, keyp, keys, numid, numrel);
827     }
828
829   /*******  Part 6: packed sizes (optional)  ****************************/
830   char *exists = 0;
831   if ((solvflags & SOLV_FLAG_PACKEDSIZES) != 0)
832     {
833       exists = xmalloc (numsolv);
834       for (i = 0; i < numsolv; i++)
835         exists[i] = read_id(fp, 0) != 0;
836     }
837
838   /*******  Part 7: item data *******************************************/
839
840   /* calculate idarray size */
841   size_idarray = 0;
842   for (i = 1; i < numkeys; i++)
843     {
844       id = keys[i].name;
845       if ((keys[i].type == TYPE_IDARRAY || keys[i].type == TYPE_REL_IDARRAY)
846           && id >= INTERESTED_START && id <= INTERESTED_END)
847         size_idarray += keys[i].size;
848     }
849
850   /* allocate needed space in repo */
851   if (size_idarray)
852     {
853       repo_reserve_ids(repo, 0, size_idarray);
854       idarraydatap = repo->idarraydata + repo->idarraysize;
855       repo->idarraysize += size_idarray;
856       idarraydataend = repo->idarraydata + repo->idarraysize;
857       repo->lastoff = 0;
858     }
859   else
860     {
861       idarraydatap = 0;
862       idarraydataend = 0;
863     }
864
865   /* read solvables */
866   s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
867
868   if ((solvflags & SOLV_FLAG_VERTICAL) != 0)
869     {
870       Id *solvschema = xcalloc(numsolv, sizeof(Id));
871       unsigned char *used = xmalloc(numschemata);
872       Solvable *sstart = s;
873       Id type;
874
875 /* XXX BROKEN CODE */
876
877       for (i = 0; i < numsolv; i++)
878         solvschema[i] = read_id(fp, numschemata);
879       for (key = 1; key < numkeys; key++)
880         {
881           id = keys[key].name;
882           type = keys[key].type;
883           memset(used, 0, numschemata);
884           for (i = 0; i < numschemata; i++)
885             {
886               Id *keyp = schemadata + schemata[i];
887               while (*keyp)
888                 if (*keyp++ == key)
889                   {
890                     used[i] = 1;
891                     break;
892                   }
893             }
894           for (i = 0, s = sstart; i < numsolv; i++, s++)
895              {
896               if (!used[solvschema[i]])
897                 continue;
898               switch (type)
899                 {
900                 case TYPE_ID:
901                   did = idmap[read_id(fp, numid + numrel)];
902                   if (id == SOLVABLE_NAME)
903                     s->name = did;
904                   else if (id == SOLVABLE_ARCH)
905                     s->arch = did;
906                   else if (id == SOLVABLE_EVR)
907                     s->evr = did;
908                   else if (id == SOLVABLE_VENDOR)
909                     s->vendor = did;
910                   else
911                     incore_add_id(&data, did);
912                   break;
913                 case TYPE_U32:
914                   h = read_u32(fp);
915                   if (id == RPM_RPMDBID)
916                     {
917                       if (!repo->rpmdbid)
918                         repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
919                       repo->rpmdbid[i] = h;
920                     }
921                   else
922                     {
923                       incore_add_u32(&data, h);
924                     }
925                   break;
926                 case TYPE_STR:
927                   while(read_u8(fp) != 0)
928                     ;
929                   break;
930                 case TYPE_IDARRAY:
931                 case TYPE_REL_IDARRAY:
932                   if (id < INTERESTED_START || id > INTERESTED_END)
933                     {
934                       /* not interested in array */
935                       while ((read_u8(fp) & 0xc0) != 0)
936                         ;
937                       break;
938                     }
939                   ido = idarraydatap - repo->idarraydata;
940                   idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, type == TYPE_REL_IDARRAY);
941                   if (id == SOLVABLE_PROVIDES)
942                     s->provides = ido;
943                   else if (id == SOLVABLE_OBSOLETES)
944                     s->obsoletes = ido;
945                   else if (id == SOLVABLE_CONFLICTS)
946                     s->conflicts = ido;
947                   else if (id == SOLVABLE_REQUIRES)
948                     s->requires = ido;
949                   else if (id == SOLVABLE_RECOMMENDS)
950                     s->recommends= ido;
951                   else if (id == SOLVABLE_SUPPLEMENTS)
952                     s->supplements = ido;
953                   else if (id == SOLVABLE_SUGGESTS)
954                     s->suggests = ido;
955                   else if (id == SOLVABLE_ENHANCES)
956                     s->enhances = ido;
957                   else if (id == SOLVABLE_FRESHENS)
958                     s->freshens = ido;
959                   break;
960                 case TYPE_VOID:
961                   break;
962 #if 0
963                 case TYPE_ATTR_INT:
964                 case TYPE_ATTR_CHUNK:
965                 case TYPE_ATTR_STRING:
966                 case TYPE_ATTR_INTLIST:
967                 case TYPE_ATTR_LOCALIDS:
968                   if (!embedded_store)
969                     embedded_store = new_store (pool);
970                   add_attr_from_file (embedded_store, i, id, type, idmap, numid, fp);
971                   break;
972 #endif
973                 default:
974                   abort();
975                 }
976             }
977         }
978       xfree(used);
979       xfree(solvschema);
980       xfree(idmap);
981       xfree(schemata);
982       xfree(schemadata);
983       xfree(keys);
984       mypool = 0;
985       return;
986     }
987
988   for (i = 0; i < numsolv; i++, s++)
989     {
990       if (exists && !exists[i])
991         continue;
992       Id *keyp = schemadata + schemata[read_id(fp, numschemata)];
993       while ((key = *keyp++) != 0)
994         {
995           id = keys[key].name;
996           switch (keys[key].type)
997             {
998             case TYPE_ID:
999               did = idmap[read_id(fp, numid + numrel)];
1000               if (id == SOLVABLE_NAME)
1001                 s->name = did;
1002               else if (id == SOLVABLE_ARCH)
1003                 s->arch = did;
1004               else if (id == SOLVABLE_EVR)
1005                 s->evr = did;
1006               else if (id == SOLVABLE_VENDOR)
1007                 s->vendor = did;
1008               else if (keys[key].storage == KEY_STORAGE_INCORE)
1009                 incore_add_id(&data, did);
1010 #if 0
1011               POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %s\n", id2str(pool, id), id2str(pool, did));
1012 #endif
1013               break;
1014             case TYPE_U32:
1015               h = read_u32(fp);
1016 #if 0
1017               POOL_DEBUG(SAT_DEBUG_STATS, "%s -> %u\n", id2str(pool, id), h);
1018 #endif
1019               if (id == RPM_RPMDBID)
1020                 {
1021                   if (!repo->rpmdbid)
1022                     repo->rpmdbid = (Id *)xcalloc(numsolv, sizeof(Id));
1023                   repo->rpmdbid[i] = h;
1024                 }
1025               else if (keys[key].storage == KEY_STORAGE_INCORE)
1026                 incore_add_u32(&data, h);
1027               break;
1028             case TYPE_STR:
1029               if (keys[key].storage == KEY_STORAGE_INCORE)
1030                 {
1031                   while ((h = read_u8(fp)) != 0)
1032                     incore_add_u8(&data, h);
1033                   incore_add_u8(&data, 0);
1034                 }
1035               else
1036                 {
1037                   while (read_u8(fp) != 0)
1038                     ;
1039                 }
1040               break;
1041             case TYPE_IDARRAY:
1042             case TYPE_REL_IDARRAY:
1043               if (id < INTERESTED_START || id > INTERESTED_END)
1044                 {
1045                   if (keys[key].storage == KEY_STORAGE_INCORE)
1046                     {
1047                       Id old = 0, rel = keys[key].type == TYPE_REL_IDARRAY ? SOLVABLE_PREREQMARKER : 0;
1048                       do
1049                         {
1050                           did = read_id(fp, 0);
1051                           h = did & 0x40;
1052                           did = (did & 0x3f) | ((did >> 1) & ~0x3f);
1053                           if (rel)
1054                             {
1055                               if (did == 0)
1056                                 {
1057                                   did = rel;
1058                                   old = 0;
1059                                 }
1060                               else
1061                                 {
1062                                   did += old;
1063                                   old = did;
1064                                 }
1065                             }
1066                           if (did >= numid + numrel)
1067                             abort();
1068                           did = idmap[did];
1069                           did = ((did & ~0x3f) << 1) | h;
1070                           incore_add_id(&data, did);
1071                         }
1072                       while (h);
1073                     }
1074                   else
1075                     {
1076                       while ((read_u8(fp) & 0xc0) != 0)
1077                         ;
1078                       break;
1079                     }
1080                 }
1081               ido = idarraydatap - repo->idarraydata;
1082               idarraydatap = read_idarray(fp, numid + numrel, idmap, idarraydatap, idarraydataend, keys[key].type == TYPE_REL_IDARRAY);
1083               if (id == SOLVABLE_PROVIDES)
1084                 s->provides = ido;
1085               else if (id == SOLVABLE_OBSOLETES)
1086                 s->obsoletes = ido;
1087               else if (id == SOLVABLE_CONFLICTS)
1088                 s->conflicts = ido;
1089               else if (id == SOLVABLE_REQUIRES)
1090                 s->requires = ido;
1091               else if (id == SOLVABLE_RECOMMENDS)
1092                 s->recommends= ido;
1093               else if (id == SOLVABLE_SUPPLEMENTS)
1094                 s->supplements = ido;
1095               else if (id == SOLVABLE_SUGGESTS)
1096                 s->suggests = ido;
1097               else if (id == SOLVABLE_ENHANCES)
1098                 s->enhances = ido;
1099               else if (id == SOLVABLE_FRESHENS)
1100                 s->freshens = ido;
1101 #if 0
1102               POOL_DEBUG(SAT_DEBUG_STATS, "%s ->\n", id2str(pool, id));
1103               for (; repo->idarraydata[ido]; ido++)
1104                 POOL_DEBUG(SAT_DEBUG_STATS,"  %s\n", dep2str(pool, repo->idarraydata[ido]));
1105 #endif
1106               break;
1107 #if 0
1108             case TYPE_VOID:
1109
1110             case TYPE_ATTR_INT:
1111             case TYPE_ATTR_CHUNK:
1112             case TYPE_ATTR_STRING:
1113             case TYPE_ATTR_INTLIST:
1114             case TYPE_ATTR_LOCALIDS:
1115               if (!embedded_store)
1116                 embedded_store = new_store (pool);
1117               add_attr_from_file (embedded_store, i, id, keys[key].type, idmap, numid, fp);
1118               break;
1119 #endif
1120             default:
1121               skip_item(fp, keys[key].type, numid, numrel);
1122             }
1123         }
1124     }
1125
1126   if (data.incoredatafree)
1127     {
1128       /* shrink excess size */
1129       data.incoredata = xrealloc(data.incoredata, data.incoredatalen);
1130       data.incoredatafree = 0;
1131     }
1132
1133   for (i = 1; i < numkeys; i++)
1134     if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
1135       break;
1136   if (i < numkeys)
1137     {
1138       /* we have vertical data, make it available */
1139       data.fp = fp;
1140       data.verticaloffset = ftell(fp);
1141     }
1142
1143   if (data.incoredatalen || data.fp)
1144     {
1145       /* we got some data, make it available */
1146       repo->repodata = xrealloc(repo->repodata, (repo->nrepodata + 1) * sizeof(data));
1147       repo->repodata[repo->nrepodata++] = data;
1148     }
1149   else
1150     {
1151       xfree(schemata);
1152       xfree(schemadata);
1153       xfree(keys);
1154     }
1155
1156   xfree(exists);
1157 #if 0
1158   if (embedded_store)
1159     {
1160       attr_store_pack (embedded_store);
1161       /* If we have any attributes we also have pages.  */
1162       read_or_setup_pages (fp, embedded_store);
1163       /* The NULL name here means embedded attributes.  */
1164       repo_add_attrstore (repo, embedded_store, NULL);
1165     }
1166 #endif
1167   xfree(idmap);
1168   mypool = 0;
1169 }
1170
1171 // EOF