Whoops, description and summary are not supposed to be pool strings.
[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   int numpacks;
230   Solvable *solvable;
231   struct stateswitch *swtab[NUMSTATES];
232   enum state sbtab[NUMSTATES];
233   const char *lang;
234   const char *capkind;
235   // used to store tmp attributes
236   // while the tag ends
237   const char *tmpattr;
238   Repodata *data;
239 };
240
241 static char *flagtabnum[] = {
242   ">",
243   "=",
244   ">=",
245   "<",
246   "!=",
247   "<=",
248 };
249
250 /**
251  * adds plain dependencies, that is strings like "foo > 2.0"
252  * which are used in libzypp xml store, not in rpm-md.
253  */
254 static unsigned int
255 adddepplain(Pool *pool, struct parsedata_common *pd, unsigned int olddeps, char *line, Id marker, const char *kind)
256 {
257   int i, flags;
258   Id id, evrid;
259   char *sp[4];
260
261   i = split(line, sp, 4);
262   if (i != 1 && i != 3)
263     {
264       fprintf(stderr, "Bad dependency line: %s\n", line);
265       exit(1);
266     }
267   if (kind)
268     id = str2id(pool, join2(kind, ":", sp[0]), 1);
269   else
270     id = str2id(pool, sp[0], 1);
271   if (i == 3)
272     {
273       evrid = makeevr(pool, sp[2]);
274       for (flags = 0; flags < 6; flags++)
275         if (!strcmp(sp[1], flagtabnum[flags]))
276           break;
277       if (flags == 6)
278         {
279           if ( !strcmp(sp[1], "=="))
280            {
281             flags = 1;
282            }
283           else
284            {
285             fprintf(stderr, "Unknown relation '%s'\n", sp[1]);
286             exit(1);
287            }
288         }
289       id = rel2id(pool, id, evrid, flags + 1, 1);
290     }
291   return repo_addid_dep(pd->repo, olddeps, id, marker);
292 }
293
294 static Id
295 makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
296 {
297   const char *e, *v, *r, *v2;
298   char *c;
299   int l;
300
301   e = v = r = 0;
302   for (; *atts; atts += 2)
303     {
304       if (!strcmp(*atts, "epoch"))
305         e = atts[1];
306       else if (!strcmp(*atts, "ver"))
307         v = atts[1];
308       else if (!strcmp(*atts, "rel"))
309         r = atts[1];
310     }
311   if (e && !strcmp(e, "0"))
312     e = 0;
313   if (v && !e)
314     {
315       for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
316         ;
317       if (v2 > v && *v2 == ':')
318         e = "0";
319     }
320   l = 1;
321   if (e)
322     l += strlen(e) + 1;
323   if (v)
324     l += strlen(v);
325   if (r)
326     l += strlen(r) + 1;
327   if (l > pd->acontent)
328     {
329       pd->content = sat_realloc(pd->content, l + 256);
330       pd->acontent = l + 256;
331     }
332   c = pd->content;
333   if (e)
334     {
335       strcpy(c, e);
336       c += strlen(c);
337       *c++ = ':';
338     }
339   if (v)
340     {
341       strcpy(c, v);
342       c += strlen(c);
343     }
344   if (r)
345     {
346       *c++ = '-';
347       strcpy(c, r);
348       c += strlen(c);
349     }
350   *c = 0;
351   if (!*pd->content)
352     return 0;
353 #if 0
354   fprintf(stderr, "evr: %s\n", pd->content);
355 #endif
356   return str2id(pool, pd->content, 1);
357 }
358
359 static const char *
360 find_attr(const char *txt, const char **atts)
361 {
362   for (; *atts; atts += 2)
363     {
364       if (!strcmp(*atts, txt))
365         return atts[1];
366     }
367   return 0;
368 }
369
370 static char *flagtab[] = {
371   "GT",
372   "EQ",
373   "GE",
374   "LT",
375   "NE",
376   "LE"
377 };
378
379 static unsigned int
380 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq)
381 {
382   Id id, name, marker;
383   const char *n, *f, *k;
384   const char **a;
385
386   n = f = k = 0;
387   marker = isreq ? -SOLVABLE_PREREQMARKER : 0;
388   for (a = atts; *a; a += 2)
389     {
390       if (!strcmp(*a, "name"))
391         n = a[1];
392       else if (!strcmp(*a, "flags"))
393         f = a[1];
394       else if (!strcmp(*a, "kind"))
395         k = a[1];
396       else if (isreq && !strcmp(*a, "pre") && a[1][0] == '1')
397         marker = SOLVABLE_PREREQMARKER;
398     }
399   if (!n)
400     return olddeps;
401   if (k && !strcmp(k, "package"))
402     k = 0;
403   if (k)
404     {
405       int l = strlen(k) + 1 + strlen(n) + 1;
406       if (l > pd->acontent)
407         {
408           pd->content = sat_realloc(pd->content, l + 256);
409           pd->acontent = l + 256;
410         }
411       sprintf(pd->content, "%s:%s", k, n); 
412       name = str2id(pool, pd->content, 1); 
413     }
414   else
415     name = str2id(pool, (char *)n, 1);
416   if (f)
417     {
418       Id evr = makeevr_atts(pool, pd, atts);
419       int flags;
420       for (flags = 0; flags < 6; flags++)
421         if (!strcmp(f, flagtab[flags]))
422           break;
423       flags = flags < 6 ? flags + 1 : 0;
424       id = rel2id(pool, name, evr, flags, 1);
425     }
426   else
427     id = name;
428 #if 0
429   fprintf(stderr, "new dep %s%s%s\n", id2str(pool, d), id2rel(pool, d), id2evr(pool, d));
430 #endif
431   return repo_addid_dep(pd->common.repo, olddeps, id, marker);
432 }
433
434
435 static void XMLCALL
436 startElement(void *userData, const char *name, const char **atts)
437 {
438   //fprintf(stderr,"+tag: %s\n", name);
439   struct parsedata *pd = userData;
440   Pool *pool = pd->common.pool;
441   Repo *repo = pd->common.repo;
442   Solvable *s = pd->solvable;
443   struct stateswitch *sw;
444   const char *str;
445   Id solvid = s - pool->solvables;
446
447   if (pd->depth != pd->statedepth)
448     {
449       pd->depth++;
450       return;
451     }
452   pd->depth++;
453   for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
454     if (!strcmp(sw->ename, name))
455       break;
456   if (sw->from != pd->state)
457     {
458 #if 0
459       fprintf(stderr, "into unknown: %s\n", name);
460 #endif
461       return;
462     }
463   pd->state = sw->to;
464   pd->docontent = sw->docontent;
465   pd->statedepth = pd->depth;
466   pd->lcontent = 0;
467   *pd->content = 0;
468   switch(pd->state)
469     {
470     case STATE_METADATA:
471       for (; *atts; atts += 2)
472         {
473           if (!strcmp(*atts, "packages"))
474             {
475               pd->numpacks = atoi(atts[1]);
476               if (pd->numpacks < 0)
477                 pd->numpacks = 0;
478 #if 0
479               fprintf(stderr, "numpacks: %d\n", pd->numpacks);
480 #endif
481               pd->solvable = pool_id2solvable(pool, repo_add_solvable_block(pd->common.repo, pd->numpacks));
482             }
483         }
484       break;
485     case STATE_SOLVABLE:
486       pd->kind = 0;
487       if (name[2] == 't' && name[3] == 't')
488         pd->kind = "pattern";
489       else if (name[1] == 'r')
490         pd->kind = "product";
491       else if (name[2] == 't' && name[3] == 'c')
492         pd->kind = "patch";
493       
494       if (pd->numpacks == 0)
495         pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->common.repo));
496 #if 0
497       fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables);
498 #endif
499       break;
500     case STATE_VERSION:
501       s->evr = makeevr_atts(pool, pd, atts);
502       break;
503     case STATE_CAPS_PROVIDES:
504     case STATE_PROVIDES:
505       s->provides = 0;
506       break;
507     case STATE_PROVIDESENTRY:
508       s->provides = adddep(pool, pd, s->provides, atts, 0);
509       break;
510     case STATE_CAPS_REQUIRES:
511     case STATE_REQUIRES:
512       s->requires = 0;
513       break;
514     case STATE_REQUIRESENTRY:
515       s->requires = adddep(pool, pd, s->requires, atts, 1);
516       break;
517     case STATE_CAPS_OBSOLETES:
518     case STATE_OBSOLETES:
519       s->obsoletes = 0;
520       break;
521     case STATE_OBSOLETESENTRY:
522       s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
523       break;
524     case STATE_CAPS_CONFLICTS:
525     case STATE_CONFLICTS:
526       s->conflicts = 0;
527       break;
528     case STATE_CONFLICTSENTRY:
529       s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
530       break;
531     case STATE_CAPS_RECOMMENDS:
532     case STATE_RECOMMENDS:
533       s->recommends = 0;
534       break;
535     case STATE_RECOMMENDSENTRY:
536       s->recommends = adddep(pool, pd, s->recommends, atts, 0);
537       break;
538     case STATE_CAPS_SUPPLEMENTS:
539     case STATE_SUPPLEMENTS:
540       s->supplements= 0;
541       break;
542     case STATE_SUPPLEMENTSENTRY:
543       s->supplements = adddep(pool, pd, s->supplements, atts, 0);
544       break;
545     case STATE_CAPS_SUGGESTS:
546     case STATE_SUGGESTS:
547       s->suggests = 0;
548       break;
549     case STATE_SUGGESTSENTRY:
550       s->suggests = adddep(pool, pd, s->suggests, atts, 0);
551       break;
552     case STATE_CAPS_ENHANCES:
553     case STATE_ENHANCES:
554       s->enhances = 0;
555       break;
556     case STATE_ENHANCESENTRY:
557       s->enhances = adddep(pool, pd, s->enhances, atts, 0);
558       break;
559     case STATE_CAPS_FRESHENS:
560     case STATE_FRESHENS:
561       s->freshens = 0;
562       break;
563     case STATE_FRESHENSENTRY:
564       s->freshens = adddep(pool, pd, s->freshens, atts, 0);
565       break;
566     case STATE_CAP_PROVIDES:
567     case STATE_CAP_REQUIRES:
568     case STATE_CAP_OBSOLETES:
569     case STATE_CAP_CONFLICTS:
570     case STATE_CAP_RECOMMENDS:
571     case STATE_CAP_SUPPLEMENTS:
572     case STATE_CAP_SUGGESTS:
573     case STATE_CAP_ENHANCES:
574     case STATE_CAP_FRESHENS:
575       pd->capkind = find_attr("kind", atts);
576       //fprintf(stderr,"capkind es: %s\n", pd->capkind);
577       break;
578     case STATE_SUMMARY:
579     case STATE_DESCRIPTION:
580       pd->lang = find_attr("lang", atts);
581       break;
582     case STATE_LOCATION:
583       str = find_attr("href", atts);
584       if (str)
585         repo_set_str(repo, solvid, id_mediafile, str);
586       break;
587     case STATE_CHECKSUM:
588       pd->tmpattr = find_attr("type", atts);
589       break;
590     case STATE_TIME:
591       {
592         unsigned t;
593         str = find_attr("build", atts);
594         if (str && (t = atoi(str)) != 0)
595           repo_set_num(repo, solvid, id_time, t);
596         break;
597       }
598     case STATE_SIZE:
599       {
600         unsigned k;
601         str = find_attr("installed", atts);
602         if (str && (k = atoi(str)) != 0)
603           repo_set_num(repo, solvid, id_installsize, (k + 1023) / 1024);
604         /* XXX the "package" attribute gives the size of the rpm file,
605            i.e. the download size.  Except on packman, there it seems to be
606            something else entirely, it has a value near to the other two
607            values, as if the rpm is uncompressed.  */
608         str = find_attr("package", atts);
609         if (str && (k = atoi(str)) != 0)
610           repo_set_num(repo, solvid, id_downloadsize, (k + 1023) / 1024);
611         break;
612       }
613     default:
614       break;
615     }
616 }
617
618 static void XMLCALL
619 endElement(void *userData, const char *name)
620 {
621   //fprintf(stderr,"-tag: %s\n", name);
622   struct parsedata *pd = userData;
623   Pool *pool = pd->common.pool;
624   Solvable *s = pd->solvable;
625   Repo *repo = pd->common.repo;
626   Id id;
627
628   if (pd->depth != pd->statedepth)
629     {
630       pd->depth--;
631       // printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
632       return;
633     }
634   pd->depth--;
635   pd->statedepth--;
636   switch (pd->state)
637     {
638     case STATE_PATTERN:
639     case STATE_PRODUCT:
640     case STATE_SOLVABLE:
641       if (!s->arch)
642         s->arch = ARCH_NOARCH;
643       if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
644         s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
645       s->supplements = repo_fix_legacy(repo, s->provides, s->supplements);
646       if (pd->numpacks > 0)
647         {
648           pd->numpacks--;
649           pd->solvable++;
650         }
651       pd->kind = 0;
652       break;
653     case STATE_NAME:
654       if ( pd->kind )
655           s->name = str2id(pool, join2( pd->kind, ":", pd->content), 1);
656       else
657           s->name = str2id(pool, pd->content, 1);
658       break;
659     case STATE_ARCH:
660       s->arch = str2id(pool, pd->content, 1);
661       break;
662     case STATE_VENDOR:
663       s->vendor = str2id(pool, pd->content, 1);
664       break;
665     case STATE_RPM_GROUP:
666       repo_set_poolstr(repo, s - pool->solvables, id_group, pd->content);
667       break;
668     case STATE_RPM_LICENSE:
669       repo_set_poolstr(repo, s - pool->solvables, id_license, pd->content);
670       break;
671     case STATE_FILE:
672       id = str2id(pool, pd->content, 1);
673       s->provides = repo_addid(repo, s->provides, id);
674       break;
675     // xml store capabilities
676     case STATE_CAP_PROVIDES:
677       s->provides = adddepplain(pool, &pd->common, s->provides, pd->content, 0, pd->capkind);
678       break;
679     case STATE_CAP_REQUIRES:
680       s->requires = adddepplain(pool, &pd->common, s->requires, pd->content, 0, pd->capkind);
681       break;
682     case STATE_CAP_OBSOLETES:
683       s->obsoletes = adddepplain(pool, &pd->common, s->obsoletes, pd->content, 0, pd->capkind);
684       break;
685     case STATE_CAP_CONFLICTS:
686       s->conflicts = adddepplain(pool, &pd->common, s->conflicts, pd->content, 0, pd->capkind);
687       break;
688     case STATE_CAP_RECOMMENDS:
689       s->recommends = adddepplain(pool, &pd->common, s->recommends, pd->content, 0, pd->capkind);
690       break;
691     case STATE_CAP_SUPPLEMENTS:
692       s->supplements = adddepplain(pool, &pd->common, s->supplements, pd->content, 0, pd->capkind);
693       break;
694     case STATE_CAP_SUGGESTS:
695       s->suggests = adddepplain(pool, &pd->common, s->suggests, pd->content, 0, pd->capkind);
696       break;
697     case STATE_CAP_ENHANCES:
698       s->enhances = adddepplain(pool, &pd->common, s->enhances, pd->content, 0, pd->capkind);
699       break;
700     case STATE_CAP_FRESHENS:
701       s->freshens = adddepplain(pool, &pd->common, s->freshens, pd->content, 0, pd->capkind);
702       break;
703     case STATE_SUMMARY:
704       pd->lang = 0;
705       repo_set_str(repo, s - pool->solvables, id_summary, pd->content);
706       break;
707     case STATE_DESCRIPTION:
708       pd->lang = 0;
709       repo_set_str(repo, s - pool->solvables, id_description, pd->content);
710       break;
711     default:
712       break;
713     }
714   pd->state = pd->sbtab[pd->state];
715   pd->docontent = 0;
716   //fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth);
717 }
718
719 static void XMLCALL
720 characterData(void *userData, const XML_Char *s, int len)
721 {
722   struct parsedata *pd = userData;
723   int l;
724   char *c;
725
726   if (!pd->docontent)
727     return;
728   l = pd->lcontent + len + 1;
729   if (l > pd->acontent)
730     {
731       pd->content = sat_realloc(pd->content, l + 256);
732       pd->acontent = l + 256;
733     }
734   c = pd->content + pd->lcontent;
735   pd->lcontent += len;
736   while (len-- > 0)
737     *c++ = *s++;
738   *c = 0;
739 }
740
741
742 #define BUFF_SIZE 8192
743
744 void
745 repo_add_rpmmd(Repo *repo, FILE *fp)
746 {
747   Pool *pool = repo->pool;
748   struct parsedata pd;
749   char buf[BUFF_SIZE];
750   int i, l;
751   struct stateswitch *sw;
752
753   memset(&pd, 0, sizeof(pd));
754   for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
755     {
756       if (!pd.swtab[sw->from])
757         pd.swtab[sw->from] = sw;
758       pd.sbtab[sw->to] = sw->from;
759     }
760   pd.common.pool = pool;
761   pd.common.repo = repo;
762
763   pd.data = repo_add_repodata(repo);
764   init_attr_ids(pool);
765
766   pd.content = sat_malloc(256);
767   pd.acontent = 256;
768   pd.lcontent = 0;
769   pd.common.tmp = 0;
770   pd.common.tmpl = 0;
771   pd.kind = 0;
772   XML_Parser parser = XML_ParserCreate(NULL);
773   XML_SetUserData(parser, &pd);
774   XML_SetElementHandler(parser, startElement, endElement);
775   XML_SetCharacterDataHandler(parser, characterData);
776   for (;;)
777     {
778       l = fread(buf, 1, sizeof(buf), fp);
779       if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
780         {
781           fprintf(stderr, "%s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
782           exit(1);
783         }
784       if (l == 0)
785         break;
786     }
787   XML_ParserFree(parser);
788
789   if (pd.data)
790     repodata_internalize(pd.data);
791
792   if (pd.numpacks)
793     repo_free_solvable_block(repo, pd.solvable - pool->solvables, pd.numpacks, 1);
794   sat_free(pd.content);
795 }