- change solv format in an incompatible way, breaking compatibility
[platform/upstream/libsolv.git] / tools / repo_rpmmd.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 #include <sys/types.h>
9 #include <limits.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <expat.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "tools_util.h"
19 #include "repo_rpmmd.h"
20
21
22 enum state {
23   STATE_START,
24   STATE_METADATA,
25   STATE_SOLVABLE,
26   STATE_PRODUCT,
27   STATE_PATTERN,
28   STATE_PATCH,
29   STATE_NAME,
30   STATE_ARCH,
31   STATE_VERSION,
32
33   // package rpm-md
34   STATE_LOCATION,
35   STATE_CHECKSUM,
36   STATE_RPM_GROUP,
37   STATE_RPM_LICENSE,
38
39   /* resobject attributes */
40   STATE_SUMMARY,
41   STATE_DESCRIPTION,
42   STATE_INSNOTIFY,
43   STATE_DELNOTIFY,
44   STATE_VENDOR,
45   STATE_SIZE,
46   STATE_TIME,
47   STATE_DOWNLOADSIZE,
48   STATE_INSTALLTIME,
49   STATE_INSTALLONLY,
50   
51   /* patch */
52   STATE_ID,
53   STATE_TIMESTAMP,
54   STATE_AFFECTSPKG,
55   STATE_REBOOTNEEDED,
56
57    // xml store pattern attributes
58   STATE_CATEGORY, /* pattern and patches */
59   STATE_SCRIPT,
60   STATE_ICON,
61   STATE_USERVISIBLE,
62   STATE_DEFAULT,
63   STATE_INSTALL_TIME,
64
65   /* product */
66   STATE_SHORTNAME,
67   STATE_DISTNAME,
68   STATE_DISTEDITION,
69   STATE_SOURCE,
70   STATE_RELNOTESURL,
71
72   STATE_FORMAT,
73   
74   /* rpm-md dependencies inside the
75      format tag */
76   STATE_PROVIDES,
77   STATE_REQUIRES,
78   STATE_OBSOLETES,
79   STATE_CONFLICTS,
80   STATE_RECOMMENDS,
81   STATE_SUPPLEMENTS,
82   STATE_SUGGESTS,
83   STATE_ENHANCES,
84   STATE_FRESHENS,
85
86   STATE_CAPS_FORMAT,
87   STATE_CAPS_VENDOR,
88   STATE_CAPS_PROVIDES,
89   STATE_CAPS_REQUIRES,
90   STATE_CAPS_OBSOLETES,
91   STATE_CAPS_CONFLICTS,
92   STATE_CAPS_RECOMMENDS,
93   STATE_CAPS_SUPPLEMENTS,
94   STATE_CAPS_SUGGESTS,
95   STATE_CAPS_ENHANCES,
96   STATE_CAPS_FRESHENS,
97
98   STATE_PROVIDESENTRY,
99   STATE_REQUIRESENTRY,
100   STATE_OBSOLETESENTRY,
101   STATE_CONFLICTSENTRY,
102   STATE_RECOMMENDSENTRY,
103   STATE_SUPPLEMENTSENTRY,
104   STATE_SUGGESTSENTRY,
105   STATE_ENHANCESENTRY,
106   STATE_FRESHENSENTRY,
107
108   STATE_CAP_FRESHENS,
109   STATE_CAP_PROVIDES,
110   STATE_CAP_REQUIRES,
111   STATE_CAP_OBSOLETES,
112   STATE_CAP_CONFLICTS,
113   STATE_CAP_SUGGESTS,
114   STATE_CAP_RECOMMENDS,
115   STATE_CAP_SUPPLEMENTS,
116   STATE_CAP_ENHANCES,
117
118   STATE_FILE,
119
120   // general
121   NUMSTATES
122 };
123
124 struct stateswitch {
125   enum state from;
126   char *ename;
127   enum state to;
128   int docontent;
129 };
130
131 static struct stateswitch stateswitches[] = {
132
133   { STATE_START,       "product",         STATE_SOLVABLE, 0 },
134   { STATE_START,       "pattern",         STATE_SOLVABLE, 0 },
135   { STATE_START,       "patch",           STATE_SOLVABLE, 0 },
136
137   { STATE_START,       "metadata",        STATE_METADATA, 0 },
138   { STATE_METADATA,    "package",         STATE_SOLVABLE, 0 },
139   
140   { STATE_SOLVABLE,    "name",            STATE_NAME, 1 },
141   { STATE_SOLVABLE,    "arch",            STATE_ARCH, 1 },
142   { STATE_SOLVABLE,    "version",         STATE_VERSION, 0 },
143
144   // package attributes rpm-md
145   { STATE_SOLVABLE,    "location",        STATE_LOCATION, 0 },
146   { STATE_SOLVABLE,    "checksum",        STATE_CHECKSUM, 1 },
147   
148   /* resobject attributes */
149
150   { STATE_SOLVABLE,    "summary",         STATE_SUMMARY, 1 },
151   { STATE_SOLVABLE,    "description",     STATE_DESCRIPTION, 1 },
152   //{ STATE_SOLVABLE,    "???",         STATE_INSNOTIFY, 1 },
153   //{ STATE_SOLVABLE,    "??",     STATE_DELNOTIFY, 1 },
154   { STATE_SOLVABLE,    "vendor",          STATE_VENDOR, 1 },
155   { STATE_SOLVABLE,    "size",            STATE_SIZE, 0 },
156   { STATE_SOLVABLE,    "archive-size",    STATE_DOWNLOADSIZE, 1 },
157   { STATE_SOLVABLE,    "install-time",    STATE_INSTALLTIME, 1 },
158   { STATE_SOLVABLE,    "install-only",    STATE_INSTALLONLY, 1 },
159   { STATE_SOLVABLE,    "time",            STATE_TIME, 0 },
160
161   // xml store pattern attributes
162   { STATE_SOLVABLE,    "script",          STATE_SCRIPT, 1 },
163   { STATE_SOLVABLE,    "icon",            STATE_ICON, 1 },
164   { STATE_SOLVABLE,    "uservisible",     STATE_USERVISIBLE, 1 },
165   { STATE_SOLVABLE,    "category",        STATE_CATEGORY, 1 },
166   { STATE_SOLVABLE,    "default",         STATE_DEFAULT, 1 },
167   { STATE_SOLVABLE,    "install-time",    STATE_INSTALL_TIME, 1 },
168
169   { STATE_SOLVABLE,    "format",          STATE_FORMAT, 0 },
170
171   /* those are used in libzypp xml store */
172   { STATE_SOLVABLE,    "obsoletes",       STATE_CAPS_OBSOLETES , 0 },
173   { STATE_SOLVABLE,    "conflicts",       STATE_CAPS_CONFLICTS , 0 },
174   { STATE_SOLVABLE,    "recommends",      STATE_CAPS_RECOMMENDS , 0 },
175   { STATE_SOLVABLE,    "supplements",     STATE_CAPS_SUPPLEMENTS, 0 },
176   { STATE_SOLVABLE,    "suggests",        STATE_CAPS_SUGGESTS, 0 },
177   { STATE_SOLVABLE,    "enhances",        STATE_CAPS_ENHANCES, 0 },
178   { STATE_SOLVABLE,    "freshens",        STATE_CAPS_FRESHENS, 0 },
179   { STATE_SOLVABLE,    "provides",        STATE_CAPS_PROVIDES, 0 },
180   { STATE_SOLVABLE,    "requires",        STATE_CAPS_REQUIRES, 0 },
181
182   { STATE_CAPS_PROVIDES,    "capability",      STATE_CAP_PROVIDES, 1 },
183   { STATE_CAPS_REQUIRES,    "capability",      STATE_CAP_REQUIRES, 1 },
184   { STATE_CAPS_OBSOLETES,   "capability",      STATE_CAP_OBSOLETES, 1 },
185   { STATE_CAPS_CONFLICTS,   "capability",      STATE_CAP_CONFLICTS, 1 },
186   { STATE_CAPS_RECOMMENDS,  "capability",      STATE_CAP_RECOMMENDS, 1 },
187   { STATE_CAPS_SUPPLEMENTS, "capability",      STATE_CAP_SUPPLEMENTS, 1 },
188   { STATE_CAPS_SUGGESTS,    "capability",      STATE_CAP_SUGGESTS, 1 },
189   { STATE_CAPS_ENHANCES,    "capability",      STATE_CAP_ENHANCES, 1 },
190   { STATE_CAPS_FRESHENS,    "capability",      STATE_CAP_FRESHENS, 1 },
191   
192   { STATE_FORMAT,      "rpm:vendor",      STATE_VENDOR, 1 },
193   { STATE_FORMAT,      "rpm:group",       STATE_RPM_GROUP, 1 },
194   { STATE_FORMAT,      "rpm:license",     STATE_RPM_LICENSE, 1 },
195
196   /* rpm-md dependencies */ 
197   { STATE_FORMAT,      "rpm:provides",    STATE_PROVIDES, 0 },
198   { STATE_FORMAT,      "rpm:requires",    STATE_REQUIRES, 0 },
199   { STATE_FORMAT,      "rpm:obsoletes",   STATE_OBSOLETES , 0 },
200   { STATE_FORMAT,      "rpm:conflicts",   STATE_CONFLICTS , 0 },
201   { STATE_FORMAT,      "rpm:recommends",  STATE_RECOMMENDS , 0 },
202   { STATE_FORMAT,      "rpm:supplements", STATE_SUPPLEMENTS, 0 },
203   { STATE_FORMAT,      "rpm:suggests",    STATE_SUGGESTS, 0 },
204   { STATE_FORMAT,      "rpm:enhances",    STATE_ENHANCES, 0 },
205   { STATE_FORMAT,      "rpm:freshens",    STATE_FRESHENS, 0 },
206   { STATE_FORMAT,      "file",            STATE_FILE, 1 },
207   { STATE_PROVIDES,    "rpm:entry",       STATE_PROVIDESENTRY, 0 },
208   { STATE_REQUIRES,    "rpm:entry",       STATE_REQUIRESENTRY, 0 },
209   { STATE_OBSOLETES,   "rpm:entry",       STATE_OBSOLETESENTRY, 0 },
210   { STATE_CONFLICTS,   "rpm:entry",       STATE_CONFLICTSENTRY, 0 },
211   { STATE_RECOMMENDS,  "rpm:entry",       STATE_RECOMMENDSENTRY, 0 },
212   { STATE_SUPPLEMENTS, "rpm:entry",       STATE_SUPPLEMENTSENTRY, 0 },
213   { STATE_SUGGESTS,    "rpm:entry",       STATE_SUGGESTSENTRY, 0 },
214   { STATE_ENHANCES,    "rpm:entry",       STATE_ENHANCESENTRY, 0 },
215   { STATE_FRESHENS,    "rpm:entry",       STATE_FRESHENSENTRY, 0 },
216   { NUMSTATES}
217 };
218
219 struct parsedata {
220   struct parsedata_common common;
221   char *kind;
222   int depth;
223   enum state state;
224   int statedepth;
225   char *content;
226   int lcontent;
227   int acontent;
228   int docontent;
229   Solvable *solvable;
230   struct stateswitch *swtab[NUMSTATES];
231   enum state sbtab[NUMSTATES];
232   const char *lang;
233   const char *capkind;
234   // used to store tmp attributes
235   // while the tag ends
236   const char *tmpattr;
237   Repodata *data;
238 };
239
240 static char *flagtabnum[] = {
241   ">",
242   "=",
243   ">=",
244   "<",
245   "!=",
246   "<=",
247 };
248
249 /**
250  * adds plain dependencies, that is strings like "foo > 2.0"
251  * which are used in libzypp xml store, not in rpm-md.
252  */
253 static unsigned int
254 adddepplain(Pool *pool, struct parsedata_common *pd, unsigned int olddeps, char *line, Id marker, const char *kind)
255 {
256   int i, flags;
257   Id id, evrid;
258   char *sp[4];
259
260   i = split(line, sp, 4);
261   if (i != 1 && i != 3)
262     {
263       fprintf(stderr, "Bad dependency line: %s\n", line);
264       exit(1);
265     }
266   if (kind)
267     id = str2id(pool, join2(kind, ":", sp[0]), 1);
268   else
269     id = str2id(pool, sp[0], 1);
270   if (i == 3)
271     {
272       evrid = makeevr(pool, sp[2]);
273       for (flags = 0; flags < 6; flags++)
274         if (!strcmp(sp[1], flagtabnum[flags]))
275           break;
276       if (flags == 6)
277         {
278           if ( !strcmp(sp[1], "=="))
279            {
280             flags = 1;
281            }
282           else
283            {
284             fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
285             exit(1);
286            }
287         }
288       id = rel2id(pool, id, evrid, flags + 1, 1);
289     }
290   return repo_addid_dep(pd->repo, olddeps, id, marker);
291 }
292
293 static Id
294 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
295 {
296   const char *e, *v, *r, *v2;
297   char *c;
298   int l;
299
300   e = v = r = 0;
301   for (; *atts; atts += 2)
302     {
303       if (!strcmp(*atts, "epoch"))
304         e = atts[1];
305       else if (!strcmp(*atts, "ver"))
306         v = atts[1];
307       else if (!strcmp(*atts, "rel"))
308         r = atts[1];
309     }
310   if (e && !strcmp(e, "0"))
311     e = 0;
312   if (v && !e)
313     {
314       for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
315         ;
316       if (v2 > v && *v2 == ':')
317         e = "0";
318     }
319   l = 1;
320   if (e)
321     l += strlen(e) + 1;
322   if (v)
323     l += strlen(v);
324   if (r)
325     l += strlen(r) + 1;
326   if (l > pd->acontent)
327     {
328       pd->content = sat_realloc(pd->content, l + 256);
329       pd->acontent = l + 256;
330     }
331   c = pd->content;
332   if (e)
333     {
334       strcpy(c, e);
335       c += strlen(c);
336       *c++ = ':';
337     }
338   if (v)
339     {
340       strcpy(c, v);
341       c += strlen(c);
342     }
343   if (r)
344     {
345       *c++ = '-';
346       strcpy(c, r);
347       c += strlen(c);
348     }
349   *c = 0;
350   if (!*pd->content)
351     return 0;
352 #if 0
353   fprintf(stderr, "evr: %s\n", pd->content);
354 #endif
355   return str2id(pool, pd->content, 1);
356 }
357
358 static const char *
359 find_attr(const char *txt, const char **atts)
360 {
361   for (; *atts; atts += 2)
362     {
363       if (!strcmp(*atts, txt))
364         return atts[1];
365     }
366   return 0;
367 }
368
369 static char *flagtab[] = {
370   "GT",
371   "EQ",
372   "GE",
373   "LT",
374   "NE",
375   "LE"
376 };
377
378 static unsigned int
379 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq)
380 {
381   Id id, name, marker;
382   const char *n, *f, *k;
383   const char **a;
384
385   n = f = k = 0;
386   marker = isreq ? -SOLVABLE_PREREQMARKER : 0;
387   for (a = atts; *a; a += 2)
388     {
389       if (!strcmp(*a, "name"))
390         n = a[1];
391       else if (!strcmp(*a, "flags"))
392         f = a[1];
393       else if (!strcmp(*a, "kind"))
394         k = a[1];
395       else if (isreq && !strcmp(*a, "pre") && a[1][0] == '1')
396         marker = SOLVABLE_PREREQMARKER;
397     }
398   if (!n)
399     return olddeps;
400   if (k && !strcmp(k, "package"))
401     k = 0;
402   if (k)
403     {
404       int l = strlen(k) + 1 + strlen(n) + 1;
405       if (l > pd->acontent)
406         {
407           pd->content = sat_realloc(pd->content, l + 256);
408           pd->acontent = l + 256;
409         }
410       sprintf(pd->content, "%s:%s", k, n); 
411       name = str2id(pool, pd->content, 1); 
412     }
413   else
414     name = str2id(pool, (char *)n, 1);
415   if (f)
416     {
417       Id evr = makeevr_atts(pool, pd, atts);
418       int flags;
419       for (flags = 0; flags < 6; flags++)
420         if (!strcmp(f, flagtab[flags]))
421           break;
422       flags = flags < 6 ? flags + 1 : 0;
423       id = rel2id(pool, name, evr, flags, 1);
424     }
425   else
426     id = name;
427 #if 0
428   fprintf(stderr, "new dep %s%s%s\n", id2str(pool, d), id2rel(pool, d), id2evr(pool, d));
429 #endif
430   return repo_addid_dep(pd->common.repo, olddeps, id, marker);
431 }
432
433 static void
434 set_desciption_author(Repodata *data, Id entry, char *str)
435 {
436   char *aut, *p;
437
438   if (!str || !*str)
439     return;
440   for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
441     if (!strncmp(aut, "\nAuthors:\n--------\n", 19)) 
442       break;
443   if (aut)
444     {
445       /* oh my, found SUSE special author section */
446       int l = aut - str; 
447       str[l] = 0; 
448       while (l > 0 && str[l - 1] == '\n')
449         str[--l] = 0; 
450       if (l)
451         repodata_set_str(data, entry, SOLVABLE_DESCRIPTION, str);
452       p = aut + 19;
453       aut = str;        /* copy over */
454       while (*p == ' ' || *p == '\n')
455         p++;
456       while (*p) 
457         {
458           if (*p == '\n')
459             {
460               *aut++ = *p++;
461               while (*p == ' ') 
462                 p++;
463               continue;
464             }
465           *aut++ = *p++;
466         }
467       while (aut != str && aut[-1] == '\n')
468         aut--;
469       *aut = 0; 
470       if (*str)
471         repodata_set_str(data, entry, SOLVABLE_AUTHORS, str);
472     }
473   else if (*str)
474     repodata_set_str(data, entry, SOLVABLE_DESCRIPTION, str);
475 }
476
477 static void XMLCALL
478 startElement(void *userData, const char *name, const char **atts)
479 {
480   //fprintf(stderr,"+tag: %s\n", name);
481   struct parsedata *pd = userData;
482   Pool *pool = pd->common.pool;
483   Solvable *s = pd->solvable;
484   struct stateswitch *sw;
485   const char *str;
486   Id entry = s ? (s - pool->solvables) - pd->data->start : 0;
487
488   if (pd->depth != pd->statedepth)
489     {
490       pd->depth++;
491       return;
492     }
493   pd->depth++;
494   for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
495     if (!strcmp(sw->ename, name))
496       break;
497   if (sw->from != pd->state)
498     {
499 #if 0
500       fprintf(stderr, "into unknown: %s\n", name);
501 #endif
502       return;
503     }
504   pd->state = sw->to;
505   pd->docontent = sw->docontent;
506   pd->statedepth = pd->depth;
507   pd->lcontent = 0;
508   *pd->content = 0;
509   switch(pd->state)
510     {
511     case STATE_SOLVABLE:
512       pd->kind = 0;
513       if (name[2] == 't' && name[3] == 't')
514         pd->kind = "pattern";
515       else if (name[1] == 'r')
516         pd->kind = "product";
517       else if (name[2] == 't' && name[3] == 'c')
518         pd->kind = "patch";
519       
520       pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->common.repo));
521       repodata_extend(pd->data, pd->solvable - pool->solvables);
522 #if 0
523       fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables);
524 #endif
525       break;
526     case STATE_VERSION:
527       s->evr = makeevr_atts(pool, pd, atts);
528       break;
529     case STATE_CAPS_PROVIDES:
530     case STATE_PROVIDES:
531       s->provides = 0;
532       break;
533     case STATE_PROVIDESENTRY:
534       s->provides = adddep(pool, pd, s->provides, atts, 0);
535       break;
536     case STATE_CAPS_REQUIRES:
537     case STATE_REQUIRES:
538       s->requires = 0;
539       break;
540     case STATE_REQUIRESENTRY:
541       s->requires = adddep(pool, pd, s->requires, atts, 1);
542       break;
543     case STATE_CAPS_OBSOLETES:
544     case STATE_OBSOLETES:
545       s->obsoletes = 0;
546       break;
547     case STATE_OBSOLETESENTRY:
548       s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
549       break;
550     case STATE_CAPS_CONFLICTS:
551     case STATE_CONFLICTS:
552       s->conflicts = 0;
553       break;
554     case STATE_CONFLICTSENTRY:
555       s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
556       break;
557     case STATE_CAPS_RECOMMENDS:
558     case STATE_RECOMMENDS:
559       s->recommends = 0;
560       break;
561     case STATE_RECOMMENDSENTRY:
562       s->recommends = adddep(pool, pd, s->recommends, atts, 0);
563       break;
564     case STATE_CAPS_SUPPLEMENTS:
565     case STATE_SUPPLEMENTS:
566       s->supplements= 0;
567       break;
568     case STATE_SUPPLEMENTSENTRY:
569       s->supplements = adddep(pool, pd, s->supplements, atts, 0);
570       break;
571     case STATE_CAPS_SUGGESTS:
572     case STATE_SUGGESTS:
573       s->suggests = 0;
574       break;
575     case STATE_SUGGESTSENTRY:
576       s->suggests = adddep(pool, pd, s->suggests, atts, 0);
577       break;
578     case STATE_CAPS_ENHANCES:
579     case STATE_ENHANCES:
580       s->enhances = 0;
581       break;
582     case STATE_ENHANCESENTRY:
583       s->enhances = adddep(pool, pd, s->enhances, atts, 0);
584       break;
585     case STATE_CAPS_FRESHENS:
586     case STATE_FRESHENS:
587       s->freshens = 0;
588       break;
589     case STATE_FRESHENSENTRY:
590       s->freshens = adddep(pool, pd, s->freshens, atts, 0);
591       break;
592     case STATE_CAP_PROVIDES:
593     case STATE_CAP_REQUIRES:
594     case STATE_CAP_OBSOLETES:
595     case STATE_CAP_CONFLICTS:
596     case STATE_CAP_RECOMMENDS:
597     case STATE_CAP_SUPPLEMENTS:
598     case STATE_CAP_SUGGESTS:
599     case STATE_CAP_ENHANCES:
600     case STATE_CAP_FRESHENS:
601       pd->capkind = find_attr("kind", atts);
602       //fprintf(stderr,"capkind es: %s\n", pd->capkind);
603       break;
604     case STATE_SUMMARY:
605     case STATE_DESCRIPTION:
606       pd->lang = find_attr("lang", atts);
607       break;
608     case STATE_LOCATION:
609       str = find_attr("href", atts);
610       if (str)
611         {
612           const char *str2 = strrchr(str, '/');
613           if (str2)
614             {
615               char *str3 = strdup(str);
616               str3[str2 - str] = 0;
617               repodata_set_poolstr(pd->data, entry, SOLVABLE_MEDIADIR, str3);
618               free(str3);
619               repodata_set_str(pd->data, entry, SOLVABLE_MEDIAFILE, str2 + 1);
620             }
621           else
622             repodata_set_str(pd->data, entry, SOLVABLE_MEDIAFILE, str);
623         }
624       break;
625     case STATE_CHECKSUM:
626       pd->tmpattr = find_attr("type", atts);
627       break;
628     case STATE_TIME:
629       {
630         unsigned t;
631         str = find_attr("build", atts);
632         if (str && (t = atoi(str)) != 0)
633           repodata_set_num(pd->data, entry, SOLVABLE_BUILDTIME, t);
634         break;
635       }
636     case STATE_SIZE:
637       {
638         unsigned k;
639         str = find_attr("installed", atts);
640         if (str && (k = atoi(str)) != 0)
641           repodata_set_num(pd->data, entry, SOLVABLE_INSTALLSIZE, (k + 1023) / 1024);
642         /* XXX the "package" attribute gives the size of the rpm file,
643            i.e. the download size.  Except on packman, there it seems to be
644            something else entirely, it has a value near to the other two
645            values, as if the rpm is uncompressed.  */
646         str = find_attr("package", atts);
647         if (str && (k = atoi(str)) != 0)
648           repodata_set_num(pd->data, entry, SOLVABLE_DOWNLOADSIZE, (k + 1023) / 1024);
649         break;
650       }
651     default:
652       break;
653     }
654 }
655
656 static void XMLCALL
657 endElement(void *userData, const char *name)
658 {
659   //fprintf(stderr,"-tag: %s\n", name);
660   struct parsedata *pd = userData;
661   Pool *pool = pd->common.pool;
662   Solvable *s = pd->solvable;
663   Repo *repo = pd->common.repo;
664   Id entry = s ? (s - pool->solvables) - pd->data->start : 0;
665   Id id;
666   char *p;
667
668   if (pd->depth != pd->statedepth)
669     {
670       pd->depth--;
671       // printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
672       return;
673     }
674   pd->depth--;
675   pd->statedepth--;
676   switch (pd->state)
677     {
678     case STATE_PATTERN:
679     case STATE_PRODUCT:
680     case STATE_SOLVABLE:
681       if (!s->arch)
682         s->arch = ARCH_NOARCH;
683       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
684         s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
685       s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
686       pd->kind = 0;
687       break;
688     case STATE_NAME:
689       if ( pd->kind )
690           s->name = str2id(pool, join2( pd->kind, ":", pd->content), 1);
691       else
692           s->name = str2id(pool, pd->content, 1);
693       break;
694     case STATE_ARCH:
695       s->arch = str2id(pool, pd->content, 1);
696       break;
697     case STATE_VENDOR:
698       s->vendor = str2id(pool, pd->content, 1);
699       break;
700     case STATE_RPM_GROUP:
701       repodata_set_poolstr(pd->data, entry, SOLVABLE_GROUP, pd->content);
702       break;
703     case STATE_RPM_LICENSE:
704       repodata_set_poolstr(pd->data, entry, SOLVABLE_LICENSE, pd->content);
705       break;
706     case STATE_FILE:
707 #if 0
708       id = str2id(pool, pd->content, 1);
709       s->provides = repo_addid_dep(repo, s->provides, id, SOLVABLE_FILEMARKER);
710 #endif
711       if ((p = strrchr(pd->content, '/')) != 0) {
712         *p++ = 0;
713         id = repodata_str2dir(pd->data, pd->content, 1);
714       } else {
715         id = 1;
716         p = pd->content;
717       }
718       repodata_add_dirstr(pd->data, entry, SOLVABLE_FILELIST, id, p);
719       break;
720     // xml store capabilities
721     case STATE_CAP_PROVIDES:
722       s->provides = adddepplain(pool, &pd->common, s->provides, pd->content, 0, pd->capkind);
723       break;
724     case STATE_CAP_REQUIRES:
725       s->requires = adddepplain(pool, &pd->common, s->requires, pd->content, 0, pd->capkind);
726       break;
727     case STATE_CAP_OBSOLETES:
728       s->obsoletes = adddepplain(pool, &pd->common, s->obsoletes, pd->content, 0, pd->capkind);
729       break;
730     case STATE_CAP_CONFLICTS:
731       s->conflicts = adddepplain(pool, &pd->common, s->conflicts, pd->content, 0, pd->capkind);
732       break;
733     case STATE_CAP_RECOMMENDS:
734       s->recommends = adddepplain(pool, &pd->common, s->recommends, pd->content, 0, pd->capkind);
735       break;
736     case STATE_CAP_SUPPLEMENTS:
737       s->supplements = adddepplain(pool, &pd->common, s->supplements, pd->content, 0, pd->capkind);
738       break;
739     case STATE_CAP_SUGGESTS:
740       s->suggests = adddepplain(pool, &pd->common, s->suggests, pd->content, 0, pd->capkind);
741       break;
742     case STATE_CAP_ENHANCES:
743       s->enhances = adddepplain(pool, &pd->common, s->enhances, pd->content, 0, pd->capkind);
744       break;
745     case STATE_CAP_FRESHENS:
746       s->freshens = adddepplain(pool, &pd->common, s->freshens, pd->content, 0, pd->capkind);
747       break;
748     case STATE_SUMMARY:
749       pd->lang = 0;
750       repodata_set_str(pd->data, entry, SOLVABLE_SUMMARY, pd->content);
751       break;
752     case STATE_DESCRIPTION:
753       pd->lang = 0;
754       set_desciption_author(pd->data, entry, pd->content);
755       break;
756     default:
757       break;
758     }
759   pd->state = pd->sbtab[pd->state];
760   pd->docontent = 0;
761   //fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth);
762 }
763
764 static void XMLCALL
765 characterData(void *userData, const XML_Char *s, int len)
766 {
767   struct parsedata *pd = userData;
768   int l;
769   char *c;
770
771   if (!pd->docontent)
772     return;
773   l = pd->lcontent + len + 1;
774   if (l > pd->acontent)
775     {
776       pd->content = sat_realloc(pd->content, l + 256);
777       pd->acontent = l + 256;
778     }
779   c = pd->content + pd->lcontent;
780   pd->lcontent += len;
781   while (len-- > 0)
782     *c++ = *s++;
783   *c = 0;
784 }
785
786
787 #define BUFF_SIZE 8192
788
789 void
790 repo_add_rpmmd(Repo *repo, FILE *fp, int flags)
791 {
792   Pool *pool = repo->pool;
793   struct parsedata pd;
794   char buf[BUFF_SIZE];
795   int i, l;
796   struct stateswitch *sw;
797
798   memset(&pd, 0, sizeof(pd));
799   for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
800     {
801       if (!pd.swtab[sw->from])
802         pd.swtab[sw->from] = sw;
803       pd.sbtab[sw->to] = sw->from;
804     }
805   pd.common.pool = pool;
806   pd.common.repo = repo;
807
808   pd.data = repo_add_repodata(repo);
809
810   pd.content = sat_malloc(256);
811   pd.acontent = 256;
812   pd.lcontent = 0;
813   pd.common.tmp = 0;
814   pd.common.tmpl = 0;
815   pd.kind = 0;
816   XML_Parser parser = XML_ParserCreate(NULL);
817   XML_SetUserData(parser, &pd);
818   XML_SetElementHandler(parser, startElement, endElement);
819   XML_SetCharacterDataHandler(parser, characterData);
820   for (;;)
821     {
822       l = fread(buf, 1, sizeof(buf), fp);
823       if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
824         {
825           fprintf(stderr, "repo_rpmmd: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
826           exit(1);
827         }
828       if (l == 0)
829         break;
830     }
831   XML_ParserFree(parser);
832
833   if (pd.data)
834     repodata_internalize(pd.data);
835   sat_free(pd.content);
836 }