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_helix.c
10  *
11  * Parse 'helix' XML representation
12  * and create 'repo'
13  *
14  * A bit of history: "Helix Code" was the name of the company that
15  * wrote Red Carpet. The company was later renamed to Ximian.
16  * The Red Carpet solver was merged into the ZYPP project, the
17  * library used both by ZENworks and YaST for package management.
18  * Red Carpet came with solver testcases in its own repository
19  * format, the 'helix' format.
20  *
21  */
22 
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "queue.h"
29 #include "solv_xmlparser.h"
30 #include "repo_helix.h"
31 #include "evr.h"
32 
33 
34 /* XML parser states */
35 
36 enum state {
37   STATE_START,
38   STATE_CHANNEL,
39   STATE_SUBCHANNEL,
40   STATE_PACKAGE,
41   STATE_NAME,
42   STATE_VENDOR,
43   STATE_BUILDTIME,
44   STATE_HISTORY,
45   STATE_UPDATE,
46   STATE_EPOCH,
47   STATE_VERSION,
48   STATE_RELEASE,
49   STATE_ARCH,
50   STATE_PROVIDES,
51   STATE_PROVIDESENTRY,
52   STATE_REQUIRES,
53   STATE_REQUIRESENTRY,
54   STATE_PREREQUIRES,
55   STATE_PREREQUIRESENTRY,
56   STATE_OBSOLETES,
57   STATE_OBSOLETESENTRY,
58   STATE_CONFLICTS,
59   STATE_CONFLICTSENTRY,
60   STATE_RECOMMENDS,
61   STATE_RECOMMENDSENTRY,
62   STATE_SUPPLEMENTS,
63   STATE_SUPPLEMENTSENTRY,
64   STATE_SUGGESTS,
65   STATE_SUGGESTSENTRY,
66   STATE_ENHANCES,
67   STATE_ENHANCESENTRY,
68   STATE_FRESHENS,
69   STATE_FRESHENSENTRY,
70 
71   STATE_SELECTTION,
72   STATE_PATTERN,
73   STATE_ATOM,
74   STATE_PATCH,
75   STATE_PRODUCT,
76 
77   NUMSTATES
78 };
79 
80 static struct solv_xmlparser_element stateswitches[] = {
81   { STATE_START,       "channel",         STATE_CHANNEL, 0 },
82   { STATE_CHANNEL,     "subchannel",      STATE_SUBCHANNEL, 0 },
83   { STATE_SUBCHANNEL,  "package",         STATE_PACKAGE, 0 },
84   { STATE_SUBCHANNEL,  "srcpackage",      STATE_PACKAGE, 0 },
85   { STATE_SUBCHANNEL,  "selection",       STATE_PACKAGE, 0 },
86   { STATE_SUBCHANNEL,  "pattern",         STATE_PACKAGE, 0 },
87   { STATE_SUBCHANNEL,  "atom",            STATE_PACKAGE, 0 },
88   { STATE_SUBCHANNEL,  "patch",           STATE_PACKAGE, 0 },
89   { STATE_SUBCHANNEL,  "product",         STATE_PACKAGE, 0 },
90   { STATE_SUBCHANNEL,  "application",     STATE_PACKAGE, 0 },
91   { STATE_PACKAGE,     "name",            STATE_NAME, 1 },
92   { STATE_PACKAGE,     "vendor",          STATE_VENDOR, 1 },
93   { STATE_PACKAGE,     "buildtime",       STATE_BUILDTIME, 1 },
94   { STATE_PACKAGE,     "epoch",           STATE_EPOCH, 1 },
95   { STATE_PACKAGE,     "version",         STATE_VERSION, 1 },
96   { STATE_PACKAGE,     "release",         STATE_RELEASE, 1 },
97   { STATE_PACKAGE,     "arch",            STATE_ARCH, 1 },
98   { STATE_PACKAGE,     "history",         STATE_HISTORY, 0 },
99   { STATE_PACKAGE,     "provides",        STATE_PROVIDES, 0 },
100   { STATE_PACKAGE,     "requires",        STATE_REQUIRES, 0 },
101   { STATE_PACKAGE,     "prerequires",     STATE_PREREQUIRES, 0 },
102   { STATE_PACKAGE,     "obsoletes",       STATE_OBSOLETES , 0 },
103   { STATE_PACKAGE,     "conflicts",       STATE_CONFLICTS , 0 },
104   { STATE_PACKAGE,     "recommends" ,     STATE_RECOMMENDS , 0 },
105   { STATE_PACKAGE,     "supplements",     STATE_SUPPLEMENTS, 0 },
106   { STATE_PACKAGE,     "suggests",        STATE_SUGGESTS, 0 },
107   { STATE_PACKAGE,     "enhances",        STATE_ENHANCES, 0 },
108   { STATE_PACKAGE,     "freshens",        STATE_FRESHENS, 0 },
109   { STATE_PACKAGE,     "deps",            STATE_PACKAGE, 0 },	/* ignore deps element */
110 
111   { STATE_HISTORY,     "update",          STATE_UPDATE, 0 },
112   { STATE_UPDATE,      "epoch",           STATE_EPOCH, 1 },
113   { STATE_UPDATE,      "version",         STATE_VERSION, 1 },
114   { STATE_UPDATE,      "release",         STATE_RELEASE, 1 },
115   { STATE_UPDATE,      "arch",            STATE_ARCH, 1 },
116 
117   { STATE_PROVIDES,    "dep",             STATE_PROVIDESENTRY, 0 },
118   { STATE_REQUIRES,    "dep",             STATE_REQUIRESENTRY, 0 },
119   { STATE_PREREQUIRES, "dep",             STATE_PREREQUIRESENTRY, 0 },
120   { STATE_OBSOLETES,   "dep",             STATE_OBSOLETESENTRY, 0 },
121   { STATE_CONFLICTS,   "dep",             STATE_CONFLICTSENTRY, 0 },
122   { STATE_RECOMMENDS,  "dep",             STATE_RECOMMENDSENTRY, 0 },
123   { STATE_SUPPLEMENTS, "dep",             STATE_SUPPLEMENTSENTRY, 0 },
124   { STATE_SUGGESTS,    "dep",             STATE_SUGGESTSENTRY, 0 },
125   { STATE_ENHANCES,    "dep",             STATE_ENHANCESENTRY, 0 },
126   { STATE_FRESHENS,    "dep",             STATE_FRESHENSENTRY, 0 },
127   { NUMSTATES }
128 
129 };
130 
131 /*
132  * parser data
133  */
134 
135 struct parsedata {
136   int ret;
137   /* repo data */
138   Pool *pool;		/* current pool */
139   Repo *repo;		/* current repo */
140   Repodata *data;       /* current repo data */
141   Solvable *solvable;	/* current solvable */
142   Offset freshens;	/* current freshens vector */
143 
144   /* package data */
145   int  srcpackage;	/* is srcpackage element */
146   int  epoch;		/* epoch (as offset into evrspace) */
147   int  version;		/* version (as offset into evrspace) */
148   int  release;		/* release (as offset into evrspace) */
149   char *evrspace;	/* buffer for evr */
150   int  aevrspace;	/* actual buffer space */
151   int  levrspace;	/* actual evr length */
152   char *kind;
153 
154   struct solv_xmlparser xmlp;
155 };
156 
157 
158 /*------------------------------------------------------------------*/
159 /* E:V-R handling */
160 
161 /* create Id from epoch:version-release */
162 
163 static Id
evr2id(Pool * pool,struct parsedata * pd,const char * e,const char * v,const char * r)164 evr2id(Pool *pool, struct parsedata *pd, const char *e, const char *v, const char *r)
165 {
166   char *c, *space;
167   int l;
168 
169   /* treat explitcit 0 as NULL */
170   if (e && (!*e || !strcmp(e, "0")))
171     e = 0;
172 
173   if (v && !e)
174     {
175       const char *v2;
176       /* scan version for ":" */
177       for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)	/* skip leading digits */
178         ;
179       /* if version contains ":", set epoch to "0" */
180       if (v2 > v && *v2 == ':')
181 	e = "0";
182     }
183 
184   /* compute length of Id string */
185   l = 1;  /* for the \0 */
186   if (e)
187     l += strlen(e) + 1;  /* e: */
188   if (v)
189     l += strlen(v);      /* v */
190   if (r)
191     l += strlen(r) + 1;  /* -r */
192 
193   /* get content space */
194   c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
195 
196   /* copy e-v-r */
197   if (e)
198     {
199       strcpy(c, e);
200       c += strlen(c);
201       *c++ = ':';
202     }
203   if (v)
204     {
205       strcpy(c, v);
206       c += strlen(c);
207     }
208   if (r)
209     {
210       *c++ = '-';
211       strcpy(c, r);
212       c += strlen(c);
213     }
214   *c = 0;
215   /* if nothing inserted, return Id 0 */
216   if (!*space)
217     return 0;
218 #if 0
219   fprintf(stderr, "evr: %s\n", space);
220 #endif
221   /* intern and create */
222   return pool_str2id(pool, space, 1);
223 }
224 
225 
226 /* create e:v-r from attributes
227  * atts is array of name,value pairs, NULL at end
228  *   even index into atts is name
229  *   odd index is value
230  */
231 static Id
evr_atts2id(Pool * pool,struct parsedata * pd,const char ** atts)232 evr_atts2id(Pool *pool, struct parsedata *pd, const char **atts)
233 {
234   const char *e, *v, *r;
235   e = v = r = 0;
236   for (; *atts; atts += 2)
237     {
238       if (!strcmp(*atts, "epoch"))
239 	e = atts[1];
240       else if (!strcmp(*atts, "version"))
241 	v = atts[1];
242       else if (!strcmp(*atts, "release"))
243 	r = atts[1];
244     }
245   return evr2id(pool, pd, e, v, r);
246 }
247 
248 /*------------------------------------------------------------------*/
249 /* rel operator handling */
250 
251 struct flagtab {
252   char *from;
253   int to;
254 };
255 
256 static struct flagtab flagtab[] = {
257   { ">",  REL_GT },
258   { "=",  REL_EQ },
259   { ">=", REL_GT|REL_EQ },
260   { "<",  REL_LT },
261   { "!=", REL_GT|REL_LT },
262   { "<=", REL_LT|REL_EQ },
263   { "(any)", REL_LT|REL_EQ|REL_GT },
264   { "==", REL_EQ },
265   { "gt", REL_GT },
266   { "eq", REL_EQ },
267   { "ge", REL_GT|REL_EQ },
268   { "lt", REL_LT },
269   { "ne", REL_GT|REL_LT },
270   { "le", REL_LT|REL_EQ },
271   { "gte", REL_GT|REL_EQ },
272   { "lte", REL_LT|REL_EQ },
273   { "GT", REL_GT },
274   { "EQ", REL_EQ },
275   { "GE", REL_GT|REL_EQ },
276   { "LT", REL_LT },
277   { "NE", REL_GT|REL_LT },
278   { "LE", REL_LT|REL_EQ }
279 };
280 
281 /*
282  * process new dependency from parser
283  *  olddeps = already collected deps, this defines the 'kind' of dep
284  *  atts = array of name,value attributes of dep
285  *  isreq == 1 if its a requires
286  */
287 
288 static unsigned int
adddep(Pool * pool,struct parsedata * pd,unsigned int olddeps,const char ** atts,Id marker)289 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
290 {
291   Id id, name;
292   const char *n, *f, *k;
293   const char **a;
294 
295   n = f = k = NULL;
296 
297   /* loop over name,value pairs */
298   for (a = atts; *a; a += 2)
299     {
300       if (!strcmp(*a, "name"))
301 	n = a[1];
302       if (!strcmp(*a, "kind"))
303 	k = a[1];
304       else if (!strcmp(*a, "op"))
305 	f = a[1];
306       else if (marker && !strcmp(*a, "pre") && a[1][0] == '1')
307         marker = SOLVABLE_PREREQMARKER;
308     }
309   if (!n)			       /* quit if no name found */
310     return olddeps;
311 
312   /* kind, name */
313   if (k && !strcmp(k, "package"))
314     k = NULL;			       /* package is default */
315 
316   if (k)			       /* if kind!=package, intern <kind>:<name> */
317     {
318       int l = strlen(k) + 1 + strlen(n) + 1;
319       char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
320       sprintf(space, "%s:%s", k, n);
321       name = pool_str2id(pool, space, 1);
322     }
323   else
324     {
325       name = pool_str2id(pool, n, 1);       /* package: just intern <name> */
326     }
327 
328   if (f)			       /* operator ? */
329     {
330       /* intern e:v-r */
331       Id evr = evr_atts2id(pool, pd, atts);
332       /* parser operator to flags */
333       int flags;
334       for (flags = 0; flags < sizeof(flagtab)/sizeof(*flagtab); flags++)
335 	if (!strcmp(f, flagtab[flags].from))
336 	  {
337 	    flags = flagtab[flags].to;
338 	    break;
339 	  }
340       if (flags > 7)
341 	flags = 0;
342       /* intern rel */
343       id = pool_rel2id(pool, name, evr, flags, 1);
344     }
345   else
346     id = name;			       /* no operator */
347 
348   /* add new dependency to repo */
349   return repo_addid_dep(pd->repo, olddeps, id, marker);
350 }
351 
352 
353 /*----------------------------------------------------------------*/
354 
355 static void
startElement(struct solv_xmlparser * xmlp,int state,const char * name,const char ** atts)356 startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
357 {
358   struct parsedata *pd = xmlp->userdata;
359   Pool *pool = pd->pool;
360   Solvable *s = pd->solvable;
361 
362   switch (state)
363     {
364 
365     case STATE_NAME:
366       if (pd->kind)		       /* if kind is set (non package) */
367         {
368           strcpy(xmlp->content, pd->kind);
369           xmlp->lcontent = strlen(xmlp->content);
370 	  xmlp->content[xmlp->lcontent++] = ':';   /* prefix name with '<kind>:' */
371 	  xmlp->content[xmlp->lcontent] = 0;
372 	}
373       break;
374 
375     case STATE_PACKAGE:		       /* solvable name */
376       pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
377       pd->srcpackage = 0;
378       pd->kind = NULL;		       /* default is (src)package */
379       if (!strcmp(name, "selection"))
380         pd->kind = "selection";
381       else if (!strcmp(name, "pattern"))
382         pd->kind = "pattern";
383       else if (!strcmp(name, "atom"))
384         pd->kind = "atom";
385       else if (!strcmp(name, "product"))
386         pd->kind = "product";
387       else if (!strcmp(name, "patch"))
388         pd->kind = "patch";
389       else if (!strcmp(name, "application"))
390         pd->kind = "application";
391       else if (!strcmp(name, "srcpackage"))
392 	pd->srcpackage = 1;
393       pd->levrspace = 1;
394       pd->epoch = 0;
395       pd->version = 0;
396       pd->release = 0;
397       pd->freshens = 0;
398 #if 0
399       fprintf(stderr, "package #%d\n", s - pool->solvables);
400 #endif
401       break;
402 
403     case STATE_UPDATE:
404       pd->levrspace = 1;
405       pd->epoch = 0;
406       pd->version = 0;
407       pd->release = 0;
408       break;
409 
410     case STATE_PROVIDES:	       /* start of provides */
411       s->provides = 0;
412       break;
413     case STATE_PROVIDESENTRY:	       /* entry within provides */
414       s->provides = adddep(pool, pd, s->provides, atts, 0);
415       break;
416     case STATE_REQUIRESENTRY:
417       s->requires = adddep(pool, pd, s->requires, atts, -SOLVABLE_PREREQMARKER);
418       break;
419     case STATE_PREREQUIRESENTRY:
420       s->requires = adddep(pool, pd, s->requires, atts, SOLVABLE_PREREQMARKER);
421       break;
422     case STATE_OBSOLETES:
423       s->obsoletes = 0;
424       break;
425     case STATE_OBSOLETESENTRY:
426       s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
427       break;
428     case STATE_CONFLICTS:
429       s->conflicts = 0;
430       break;
431     case STATE_CONFLICTSENTRY:
432       s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
433       break;
434     case STATE_RECOMMENDS:
435       s->recommends = 0;
436       break;
437     case STATE_RECOMMENDSENTRY:
438       s->recommends = adddep(pool, pd, s->recommends, atts, 0);
439       break;
440     case STATE_SUPPLEMENTS:
441       s->supplements= 0;
442       break;
443     case STATE_SUPPLEMENTSENTRY:
444       s->supplements = adddep(pool, pd, s->supplements, atts, 0);
445       break;
446     case STATE_SUGGESTS:
447       s->suggests = 0;
448       break;
449     case STATE_SUGGESTSENTRY:
450       s->suggests = adddep(pool, pd, s->suggests, atts, 0);
451       break;
452     case STATE_ENHANCES:
453       s->enhances = 0;
454       break;
455     case STATE_ENHANCESENTRY:
456       s->enhances = adddep(pool, pd, s->enhances, atts, 0);
457       break;
458     case STATE_FRESHENS:
459       pd->freshens = 0;
460       break;
461     case STATE_FRESHENSENTRY:
462       pd->freshens = adddep(pool, pd, pd->freshens, atts, 0);
463       break;
464     default:
465       break;
466     }
467 }
468 
469 static const char *
findKernelFlavor(struct parsedata * pd,Solvable * s)470 findKernelFlavor(struct parsedata *pd, Solvable *s)
471 {
472   Pool *pool = pd->pool;
473   Id pid, *pidp;
474 
475   if (s->provides)
476     {
477       pidp = pd->repo->idarraydata + s->provides;
478       while ((pid = *pidp++) != 0)
479 	{
480 	  Reldep *prd;
481 	  const char *depname;
482 
483 	  if (!ISRELDEP(pid))
484 	    continue;               /* wrong provides name */
485 	  prd = GETRELDEP(pool, pid);
486 	  depname = pool_id2str(pool, prd->name);
487 	  if (!strncmp(depname, "kernel-", 7))
488 	    return depname + 7;
489 	}
490     }
491 
492   if (s->requires)
493     {
494       pidp = pd->repo->idarraydata + s->requires;
495       while ((pid = *pidp++) != 0)
496 	{
497 	  const char *depname;
498 
499 	  if (!ISRELDEP(pid))
500 	    {
501 	      depname = pool_id2str(pool, pid);
502 	    }
503 	  else
504 	    {
505 	      Reldep *prd = GETRELDEP(pool, pid);
506 	      depname = pool_id2str(pool, prd->name);
507 	    }
508 	  if (!strncmp(depname, "kernel-", 7))
509 	    return depname + 7;
510 	}
511     }
512 
513   return 0;
514 }
515 
516 
517 static void
endElement(struct solv_xmlparser * xmlp,int state,char * content)518 endElement(struct solv_xmlparser *xmlp, int state, char *content)
519 {
520   struct parsedata *pd = xmlp->userdata;
521   Pool *pool = pd->pool;
522   Solvable *s = pd->solvable;
523   Id evr;
524   unsigned int t = 0;
525   const char *flavor;
526 
527   switch (state)
528     {
529 
530     case STATE_PACKAGE:		       /* package complete */
531       if (pd->srcpackage && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
532 	s->arch = ARCH_SRC;
533       if (!s->arch)                    /* default to "noarch" */
534 	s->arch = ARCH_NOARCH;
535 
536       if (!s->evr && pd->version)      /* set solvable evr */
537         s->evr = evr2id(pool, pd,
538                         pd->epoch   ? pd->evrspace + pd->epoch   : 0,
539                         pd->version ? pd->evrspace + pd->version : 0,
540                         pd->release ? pd->evrspace + pd->release : 0);
541       /* ensure self-provides */
542       if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
543         s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
544       repo_rewrite_suse_deps(s, pd->freshens);
545       pd->freshens = 0;
546 
547       /* see bugzilla bnc#190163 */
548       flavor = findKernelFlavor(pd, s);
549       if (flavor)
550 	{
551 	  char *cflavor = solv_strdup(flavor);	/* make pointer safe */
552 
553 	  Id npr;
554 	  Id pid;
555 
556 	  /* this is either a kernel package or a kmp */
557 	  if (s->provides)
558 	    {
559 	      Offset prov = s->provides;
560 	      npr = 0;
561 	      while ((pid = pd->repo->idarraydata[prov++]) != 0)
562 		{
563 		  const char *depname = 0;
564 		  Reldep *prd = 0;
565 
566 		  if (ISRELDEP(pid))
567 		    {
568 		      prd = GETRELDEP(pool, pid);
569 		      depname = pool_id2str(pool, prd->name);
570 		    }
571 		  else
572 		    {
573 		      depname = pool_id2str(pool, pid);
574 		    }
575 
576 
577 		  if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
578 		    {
579 		      char newdep[100];
580 		      snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
581 		      pid = pool_str2id(pool, newdep, 1);
582 		      if (prd)
583 			pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
584 		    }
585 
586 		  npr = repo_addid_dep(pd->repo, npr, pid, 0);
587 		}
588 	      s->provides = npr;
589 	    }
590 #if 1
591 
592 	  if (s->requires)
593 	    {
594 	      Offset reqs = s->requires;
595 	      npr = 0;
596 	      while ((pid = pd->repo->idarraydata[reqs++]) != 0)
597 		{
598 		  const char *depname = 0;
599 		  Reldep *prd = 0;
600 
601 		  if (ISRELDEP(pid))
602 		    {
603 		      prd = GETRELDEP(pool, pid);
604 		      depname = pool_id2str(pool, prd->name);
605 		    }
606 		  else
607 		    {
608 		      depname = pool_id2str(pool, pid);
609 		    }
610 
611 		  if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
612 		    {
613 		      char newdep[100];
614 		      snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
615 		      pid = pool_str2id(pool, newdep, 1);
616 		      if (prd)
617 			pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
618 		    }
619 		  npr = repo_addid_dep(pd->repo, npr, pid, 0);
620 		}
621 	      s->requires = npr;
622 	    }
623 #endif
624 	  free(cflavor);
625 	}
626       break;
627     case STATE_NAME:
628       s->name = pool_str2id(pool, content, 1);
629       break;
630     case STATE_VENDOR:
631       s->vendor = pool_str2id(pool, content, 1);
632       break;
633     case STATE_BUILDTIME:
634       t = atoi(content);
635       if (t)
636 	repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
637       break;
638     case STATE_UPDATE:		       /* new version, keeping all other metadata */
639       evr = evr2id(pool, pd,
640                    pd->epoch   ? pd->evrspace + pd->epoch   : 0,
641                    pd->version ? pd->evrspace + pd->version : 0,
642                    pd->release ? pd->evrspace + pd->release : 0);
643       pd->levrspace = 1;
644       pd->epoch = 0;
645       pd->version = 0;
646       pd->release = 0;
647       /* use highest evr */
648       if (!s->evr || pool_evrcmp(pool, s->evr, evr, EVRCMP_COMPARE) <= 0)
649 	s->evr = evr;
650       break;
651     case STATE_EPOCH:
652     case STATE_VERSION:
653     case STATE_RELEASE:
654       /* ensure buffer space */
655       if (xmlp->lcontent + 1 + pd->levrspace > pd->aevrspace)
656 	{
657 	  pd->aevrspace = xmlp->lcontent + 1 + pd->levrspace + 256;
658 	  pd->evrspace = (char *)solv_realloc(pd->evrspace, pd->aevrspace);
659 	}
660       memcpy(pd->evrspace + pd->levrspace, xmlp->content, xmlp->lcontent + 1);
661       if (state == STATE_EPOCH)
662 	pd->epoch = pd->levrspace;
663       else if (state == STATE_VERSION)
664 	pd->version = pd->levrspace;
665       else
666 	pd->release = pd->levrspace;
667       pd->levrspace += xmlp->lcontent + 1;
668       break;
669     case STATE_ARCH:
670       s->arch = pool_str2id(pool, content, 1);
671       break;
672     default:
673       break;
674     }
675 }
676 
677 /*-------------------------------------------------------------------*/
678 
679 /*
680  * read 'helix' type xml from fp
681  * add packages to pool/repo
682  *
683  */
684 
685 int
repo_add_helix(Repo * repo,FILE * fp,int flags)686 repo_add_helix(Repo *repo, FILE *fp, int flags)
687 {
688   Pool *pool = repo->pool;
689   struct parsedata pd;
690   Repodata *data;
691   unsigned int now;
692 
693   now = solv_timems(0);
694   data = repo_add_repodata(repo, flags);
695 
696   /* prepare parsedata */
697   memset(&pd, 0, sizeof(pd));
698   pd.pool = pool;
699   pd.repo = repo;
700   pd.data = data;
701 
702   pd.evrspace = (char *)solv_malloc(256);
703   pd.aevrspace = 256;
704   pd.levrspace = 1;
705 
706   solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
707   if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
708     pd.ret = pool_error(pd.pool, -1, "repo_helix: %s at line %u", pd.xmlp.errstr, pd.xmlp.line);
709   solv_xmlparser_free(&pd.xmlp);
710 
711   solv_free(pd.evrspace);
712 
713   if (!(flags & REPO_NO_INTERNALIZE))
714     repodata_internalize(data);
715   POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_helix took %d ms\n", solv_timems(now));
716   POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
717   POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
718   return pd.ret;
719 }
720