add repodata_set_deltalocation and use it in the parsers
[platform/upstream/libsolv.git] / src / repodata.c
index 3753a26..a812ba8 100644 (file)
@@ -42,6 +42,7 @@ void
 repodata_initdata(Repodata *data, Repo *repo, int localpool)
 {
   memset(data, 0, sizeof (*data));
+  data->repodataid = data - repo->repodata;
   data->repo = repo;
   data->localpool = localpool;
   if (localpool)
@@ -90,26 +91,9 @@ repodata_freedata(Repodata *data)
 
   solv_free(data->attrdata);
   solv_free(data->attriddata);
-}
-
-Repodata *
-repodata_create(Repo *repo, int localpool)
-{
-  Repodata *data;
+  solv_free(data->attrnum64data);
 
-  if (!repo->nrepodata)
-    {
-      repo->nrepodata = 2;     /* start with id 1 */
-      repo->repodata = solv_calloc(repo->nrepodata, sizeof(*data));
-    }
-  else
-    {
-      repo->nrepodata++;
-      repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
-    }
-  data = repo->repodata + repo->nrepodata - 1;
-  repodata_initdata(data, repo, localpool);
-  return data;
+  solv_free(data->dircache);
 }
 
 void
@@ -117,9 +101,16 @@ repodata_free(Repodata *data)
 {
   Repo *repo = data->repo;
   int i = data - repo->repodata;
+  if (i == 0)
+    return;
   repodata_freedata(data);
   if (i < repo->nrepodata - 1)
-    memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
+    {
+      /* whoa! this changes the repodataids! */
+      memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
+      for (; i < repo->nrepodata - 1; i++)
+       repo->repodata[i].repodataid = i;
+    }
   repo->nrepodata--;
   if (repo->nrepodata == 1)
     {
@@ -259,13 +250,27 @@ static inline const char *strchrnul(const char *str, char x)
 }
 #endif
 
+#define DIRCACHE_SIZE 41       /* < 1k */
+
+#ifdef DIRCACHE_SIZE
+struct dircache {
+  Id ids[DIRCACHE_SIZE];
+  char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
+};
+#endif
+
 Id
 repodata_str2dir(Repodata *data, const char *dir, int create)
 {
   Id id, parent;
+#ifdef DIRCACHE_SIZE
+  const char *dirs;
+#endif
   const char *dire;
 
   parent = 0;
+  if (!*dir)
+    return 0;
   while (*dir == '/' && dir[1] == '/')
     dir++;
   if (*dir == '/' && !dir[1])
@@ -274,6 +279,31 @@ repodata_str2dir(Repodata *data, const char *dir, int create)
         return 1;
       return dirpool_add_dir(&data->dirpool, 0, 1, create);
     }
+#ifdef DIRCACHE_SIZE
+  dirs = dir;
+  if (data->dircache)
+    {
+      int l;
+      struct dircache *dircache = data->dircache;
+      l = strlen(dir);
+      while (l > 0)
+       {
+         if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
+           {
+             parent = dircache->ids[l];
+             dir += l;
+             if (!*dir)
+               return parent;
+             while (*dir == '/')
+               dir++;
+             break;
+           }
+         while (--l)
+           if (dir[l] == '/')
+             break;
+       }
+    }
+#endif
   while (*dir)
     {
       dire = strchrnul(dir, '/');
@@ -286,6 +316,19 @@ repodata_str2dir(Repodata *data, const char *dir, int create)
       parent = dirpool_add_dir(&data->dirpool, parent, id, create);
       if (!parent)
        return 0;
+#ifdef DIRCACHE_SIZE
+      if (!data->dircache)
+       data->dircache = solv_calloc(1, sizeof(struct dircache));
+      if (data->dircache)
+       {
+         int l = dire - dirs;
+         if (l < DIRCACHE_SIZE)
+           {
+             data->dircache->ids[l] = parent;
+             memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
+           }
+       }
+#endif
       if (!*dire)
        break;
       dir = dire + 1;
@@ -295,6 +338,12 @@ repodata_str2dir(Repodata *data, const char *dir, int create)
   return parent;
 }
 
+void
+repodata_free_dircache(Repodata *data)
+{
+  data->dircache = solv_free(data->dircache);
+}
+
 const char *
 repodata_dir2str(Repodata *data, Id did, const char *suf)
 {
@@ -494,7 +543,7 @@ maybe_load_repodata(Repodata *data, Id keyname)
       if (keyname)
        {
          int i;
-         for (i = 0; i < data->nkeys; i++)
+         for (i = 1; i < data->nkeys; i++)
            if (keyname == data->keys[i].name)
              break;
          if (i == data->nkeys)
@@ -629,26 +678,32 @@ repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
 }
 
 int
-repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
+repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
 {
   unsigned char *dp;
   Repokey *key;
-  KeyValue kv;
+  unsigned int high, low;
 
   *value = 0;
   dp = find_key_data(data, solvid, keyname, &key);
   if (!dp)
     return 0;
-  if (key->type == REPOKEY_TYPE_NUM
-      || key->type == REPOKEY_TYPE_U32
-      || key->type == REPOKEY_TYPE_CONSTANT)
+  switch (key->type)
     {
-      kv.num = 0;
-      dp = data_fetch(dp, &kv, key);
-      *value = kv.num;
+    case REPOKEY_TYPE_NUM:
+      data_read_num64(dp, &low, &high);
+      *value = (unsigned long long)high << 32 | low;
+      return 1;
+    case REPOKEY_TYPE_U32:
+      data_read_u32(dp, &low);
+      *value = low;
+      return 1;
+    case REPOKEY_TYPE_CONSTANT:
+      *value = key->size;
       return 1;
+    default:
+      return 0;
     }
-  return 0;
 }
 
 int
@@ -679,6 +734,8 @@ repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
   dp = find_key_data(data, solvid, keyname, &key);
   if (!dp)
     return 0;
+  if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
+    return 0;
   *typep = key->type;
   return dp;
 }
@@ -723,6 +780,28 @@ repodata_localize_id(Repodata *data, Id id, int create)
   return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
 }
 
+Id
+repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
+{
+  Id *ap;
+  if (!data->attrs)
+    return 0;
+  ap = data->attrs[solvid - data->start];
+  if (!ap)
+    return 0;
+  for (; *ap; ap += 2)
+    {
+      if (data->keys[*ap].name != keyname)
+       continue;
+      if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
+       return voidid;
+      if (data->keys[*ap].type == REPOKEY_TYPE_ID)
+       return ap[1];
+      return 0;
+    }
+  return 0;
+}
+
 
 /************************************************************************
  * data search
@@ -915,22 +994,6 @@ repodata_setpos_kv(Repodata *data, KeyValue *kv)
  * data iterator functions
  */
 
-static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
-  { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { RPM_RPMDBID,          REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
-};
-
 static inline Id *
 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
 {
@@ -1118,12 +1181,12 @@ enum {
   di_entersub,
   di_leavesub,
 
-  di_nextsolvableattr,
   di_nextsolvablekey,
-  di_entersolvablekey
+  di_entersolvablekey,
+  di_nextsolvableattr
 };
 
-/* see repo.h for documentation */
+/* see dataiterator.h for documentation */
 int
 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
 {
@@ -1305,7 +1368,9 @@ dataiterator_step(Dataiterator *di)
              di->repodataid = 1;       /* reset repodata iterator */
              if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
                {
-                 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
+                 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
+
+                 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
                  di->data = 0;
                  goto di_entersolvablekey;
                }
@@ -1413,7 +1478,7 @@ dataiterator_step(Dataiterator *di)
        case di_enterarray: di_enterarray:
          if (di->key->name == REPOSITORY_SOLVABLES)
            goto di_nextkey;
-         di->ddp = data_read_id(di->ddp, &di->kv.num);
+         di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
          di->kv.eof = 0;
          di->kv.entry = -1;
          /* FALLTHROUGH */
@@ -1474,16 +1539,6 @@ dataiterator_step(Dataiterator *di)
 
         /* special solvable attr handling follows */
 
-       case di_nextsolvableattr:
-         di->kv.id = *di->idp++;
-          di->kv.entry++;
-         if (!*di->idp)
-           {
-             di->kv.eof = 1;
-             di->state = di_nextsolvablekey;
-           }
-         break;
-
        case di_nextsolvablekey: di_nextsolvablekey:
          if (di->keyname || di->key->name == RPM_RPMDBID)
            goto di_enterrepodata;
@@ -1492,19 +1547,32 @@ dataiterator_step(Dataiterator *di)
 
        case di_entersolvablekey: di_entersolvablekey:
          di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
-         if (!di->idp || !di->idp[0])
+         if (!di->idp || !*di->idp)
            goto di_nextsolvablekey;
-         di->kv.id = di->idp[0];
-         di->kv.num = di->idp[0];
-         di->idp++;
-         if (!di->kv.eof && !di->idp[0])
-           di->kv.eof = 1;
-         di->kv.entry = 0;
          if (di->kv.eof)
-           di->state = di_nextsolvablekey;
-         else
-           di->state = di_nextsolvableattr;
+           {
+             /* not an array */
+             di->kv.id = *di->idp;
+             di->kv.num = *di->idp;    /* for rpmdbid */
+             di->kv.num2 = 0;          /* for rpmdbid */
+             di->kv.entry = 0;
+             di->state = di_nextsolvablekey;
+             break;
+           }
+         di->kv.entry = -1;
+         /* FALLTHROUGH */
+
+       case di_nextsolvableattr:
+         di->state = di_nextsolvableattr;
+         di->kv.id = *di->idp++;
+         di->kv.entry++;
+         if (!*di->idp)
+           {
+             di->kv.eof = 1;
+             di->state = di_nextsolvablekey;
+           }
          break;
+
        }
 
       if (di->matcher.match)
@@ -1525,6 +1593,11 @@ dataiterator_step(Dataiterator *di)
          if (!datamatcher_match(&di->matcher, di->kv.str))
            continue;
        }
+      else
+       {
+         if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
+           repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
+       }
       /* found something! */
       return 1;
     }
@@ -1836,6 +1909,7 @@ repodata_extend_block(Repodata *data, Id start, Id num)
 #define REPODATA_ATTRS_BLOCK 31
 #define REPODATA_ATTRDATA_BLOCK 1023
 #define REPODATA_ATTRIDDATA_BLOCK 63
+#define REPODATA_ATTRNUM64DATA_BLOCK 15
 
 
 Id
@@ -1928,13 +2002,19 @@ repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
 }
 
 void
-repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
+repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
 {
   Repokey key;
   key.name = keyname;
   key.type = REPOKEY_TYPE_NUM;
   key.size = 0;
   key.storage = KEY_STORAGE_INCORE;
+  if (num >= 0x80000000)
+    {
+      data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
+      data->attrnum64data[data->attrnum64datalen] = num;
+      num = 0x80000000 | data->attrnum64datalen++;
+    }
   repodata_set(data, solvid, &key, (Id)num);
 }
 
@@ -2010,6 +2090,8 @@ repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
   Repokey key;
   unsigned char *dp;
 
+  if (len < 0)
+    return;
   key.name = keyname;
   key.type = REPOKEY_TYPE_BINARY;
   key.size = 0;
@@ -2150,7 +2232,7 @@ evrid2vrstr(Pool *pool, Id evrid)
     return evr;
   for (p = evr; *p >= '0' && *p <= '9'; p++)
     ;
-  return p != evr && *p == ':' ? p + 1 : evr;
+  return p != evr && *p == ':' && p[1] ? p + 1 : evr;
 }
 
 void
@@ -2222,6 +2304,138 @@ repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, c
   repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
 }
 
+static inline void repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
+{
+  Id id;
+  if (data->localpool)
+    id = stringpool_strn2id(&data->spool, str, l, 1);
+  else
+    id = pool_strn2id(data->repo->pool, str, l, 1);
+  repodata_set_id(data, solvid, keyname, id);
+}
+
+/* XXX: medianr is currently not stored */
+void
+repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
+{
+  int l = 0;
+  const char *evr, *suf, *s;
+
+  if (!dir)
+    {
+      if ((dir = strrchr(file, '/')) != 0)
+       {
+          l = dir - file;
+         dir = file;
+         file = dir + l + 1;
+         if (!l)
+           l++;
+       }
+    }
+  else
+    l = strlen(dir);
+  if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
+    {
+      dir += 2;
+      l -= 2;
+    }
+  if (l == 1 && dir[0] == '.')
+    l = 0;
+  if (dir && l)
+    repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
+  evr = strchr(file, '-');
+  if (evr)
+    {
+      for (s = evr - 1; s > file; s--)
+       if (*s == '-')
+         {
+           evr = s;
+           break;
+         }
+    }
+  suf = strrchr(file, '.');
+  if (suf)
+    {
+      for (s = suf - 1; s > file; s--)
+       if (*s == '.')
+         {
+           suf = s;
+           break;
+         }
+      if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
+       {
+         /* We accept one more item as suffix.  */
+         for (s = suf - 1; s > file; s--)
+           if (*s == '.')
+             {
+               suf = s;
+               break;
+             }
+       }
+    }
+  if (!evr)
+    suf = 0;
+  if (suf && evr && suf < evr)
+    suf = 0;
+  repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
+  if (evr)
+    repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
+  if (suf)
+    repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
+}
+
+void
+repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
+{
+  Pool *pool = data->repo->pool;
+  Solvable *s = pool->solvables + solvid;
+  const char *p, *sevr, *sarch, *name, *evr;
+
+  p = strrchr(sourcepkg, '.');
+  if (!p || strcmp(p, ".rpm") != 0)
+    {
+      if (*sourcepkg)
+        repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
+      return;
+    }
+  p--;
+  while (p > sourcepkg && *p != '.')
+    p--;
+  if (*p != '.' || p == sourcepkg)
+    return;
+  sarch = p-- + 1;
+  while (p > sourcepkg && *p != '-')
+    p--;
+  if (*p != '-' || p == sourcepkg)
+    return;
+  p--;
+  while (p > sourcepkg && *p != '-')
+    p--;
+  if (*p != '-' || p == sourcepkg)
+    return;
+  sevr = p + 1;
+  pool = s->repo->pool;
+
+  name = pool_id2str(pool, s->name);
+  if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
+    repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
+  else
+    repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
+
+  evr = evrid2vrstr(pool, s->evr);
+  if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
+    repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
+  else
+    repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
+
+  if (!strcmp(sarch, "src.rpm"))
+    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
+  else if (!strcmp(sarch, "nosrc.rpm"))
+    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
+  else
+    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
+}
+
 void
 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
 {
@@ -2315,7 +2529,7 @@ repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
 }
 
 void
-repodata_delete_uninternalized(Repodata *data, Id solvid, Id keyname)
+repodata_set_deleted_uninternalized(Repodata *data, Id solvid, Id keyname)
 {
   Id *pp, *ap, **app;
   app = repodata_get_attrp(data, solvid);
@@ -2341,7 +2555,7 @@ repodata_delete_uninternalized(Repodata *data, Id solvid, Id keyname)
 
 /* XXX: does not work correctly, needs fix in iterators! */
 void
-repodata_delete(Repodata *data, Id solvid, Id keyname)
+repodata_set_deleted(Repodata *data, Id solvid, Id keyname)
 {
   Repokey key;
   key.name = keyname;
@@ -2356,7 +2570,7 @@ void
 repodata_merge_attrs(Repodata *data, Id dest, Id src)
 {
   Id *keyp;
-  if (dest == src || !(keyp = data->attrs[src - data->start]))
+  if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
     return;
   for (; *keyp; keyp += 2)
     repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
@@ -2367,13 +2581,24 @@ void
 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
 {
   Id *keyp;
-  if (dest == src || !(keyp = data->attrs[src - data->start]))
+  if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
     return;
   for (; *keyp; keyp += 2)
     if (!keyidmap || MAPTST(keyidmap, keyp[0]))
       repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
 }
 
+/* swap (uninternalized) attrs from src and dest */
+void
+repodata_swap_attrs(Repodata *data, Id dest, Id src)
+{
+  Id *tmpattrs;
+  if (!data->attrs || dest == src)
+    return;
+  tmpattrs = data->attrs[dest - data->start];
+  data->attrs[dest - data->start] = data->attrs[src - data->start];
+  data->attrs[src - data->start] = tmpattrs;
+}
 
 
 /**********************************************************************/
@@ -2388,8 +2613,9 @@ struct extdata {
 };
 
 static void
-data_addid(struct extdata *xd, Id x)
+data_addid(struct extdata *xd, Id sx)
 {
+  unsigned int x = (unsigned int)sx;
   unsigned char *dp;
 
   xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
@@ -2410,11 +2636,43 @@ data_addid(struct extdata *xd, Id x)
 }
 
 static void
-data_addideof(struct extdata *xd, Id x, int eof)
+data_addid64(struct extdata *xd, unsigned long long x)
+{
+  if (x >= 0x100000000)
+    {
+      if ((x >> 35) != 0)
+       {
+         data_addid(xd, (Id)(x >> 35));
+         xd->buf[xd->len - 1] |= 128;
+       }
+      data_addid(xd, (Id)((unsigned int)x | 0x80000000));
+      xd->buf[xd->len - 5] = (x >> 28) | 128;
+    }
+  else
+    data_addid(xd, (Id)x);
+}
+
+static void
+data_addideof(struct extdata *xd, Id sx, int eof)
 {
-  if (x >= 64)
-    x = (x & 63) | ((x & ~63) << 1);
-  data_addid(xd, (eof ? x : x | 64));
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+
+  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
+  dp = xd->buf + xd->len;
+
+  if (x >= (1 << 13))
+    {
+      if (x >= (1 << 27))
+        *dp++ = (x >> 27) | 128;
+      if (x >= (1 << 20))
+        *dp++ = (x >> 20) | 128;
+      *dp++ = (x >> 13) | 128;
+    }
+  if (x >= (1 << 6))
+    *dp++ = (x >> 6) | 128;
+  *dp++ = eof ? (x & 63) : (x & 63) | 64;
+  xd->len = dp - xd->buf;
 }
 
 static void
@@ -2464,8 +2722,14 @@ repodata_serialize_key(Repodata *data, struct extdata *newincore,
     case REPOKEY_TYPE_SHA256:
       data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
       break;
-    case REPOKEY_TYPE_ID:
     case REPOKEY_TYPE_NUM:
+      if (val & 0x80000000)
+       {
+         data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
+         break;
+       }
+      /* FALLTHROUGH */
+    case REPOKEY_TYPE_ID:
     case REPOKEY_TYPE_DIR:
       data_addid(xd, val);
       break;
@@ -2473,7 +2737,7 @@ repodata_serialize_key(Repodata *data, struct extdata *newincore,
       {
        Id len;
        unsigned char *dp = data_read_id(data->attrdata + val, &len);
-       dp += len;
+       dp += (unsigned int)len;
        data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
       }
       break;
@@ -2502,8 +2766,9 @@ repodata_serialize_key(Repodata *data, struct extdata *newincore,
        schemaid = 0;
        for (ida = data->attriddata + val; *ida; ida++)
          {
+           Id *kp;
            sp = schema;
-           Id *kp = data->xattrs[-*ida];
+           kp = data->xattrs[-*ida];
            if (!kp)
              continue;
            num++;
@@ -2773,8 +3038,10 @@ fprintf(stderr, "schemadata %p\n", data->schemadata);
   data->attrs = solv_free(data->attrs);
   data->attrdata = solv_free(data->attrdata);
   data->attriddata = solv_free(data->attriddata);
+  data->attrnum64data = solv_free(data->attrnum64data);
   data->attrdatalen = 0;
   data->attriddatalen = 0;
+  data->attrnum64datalen = 0;
 }
 
 void
@@ -2878,7 +3145,7 @@ repodata_create_stubs(Repodata *data)
          repodata_set_void(sdata, SOLVID_META, di.key->name);
          break;
        case REPOKEY_TYPE_NUM:
-         repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
+         repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
          break;
        case REPOKEY_TYPE_MD5:
        case REPOKEY_TYPE_SHA1:
@@ -2900,7 +3167,7 @@ repodata_create_stubs(Repodata *data)
              xkey.name = xkeyname;
               xkey.type = di.kv.id;
               xkey.storage = KEY_STORAGE_INCORE;
-              xkey.size = 0; 
+              xkey.size = 0;
               repodata_key2id(sdata, &xkey, 1);
               xkeyname = 0;
            }
@@ -2914,6 +3181,12 @@ repodata_create_stubs(Repodata *data)
   solv_free(stubdataids);
 }
 
+unsigned int
+repodata_memused(Repodata *data)
+{
+  return data->incoredatalen + data->vincorelen;
+}
+
 /*
 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
 */