+ pool_debug(mypool, SAT_ERROR, "read_rel_idarray: array overflow\n");
+ data->error = SOLV_ERROR_OVERFLOW;
+ return 0;
+ }
+ *store++ = 0;
+ return store;
+ }
+ x = 0;
+ }
+}
+#endif
+
+static inline unsigned char *
+data_read_id_max(unsigned char *dp, Id *ret, Id *map, int max, int *error)
+{
+ Id x;
+ dp = data_read_id(dp, &x);
+ if (max && x >= max)
+ {
+ pool_debug(mypool, SAT_ERROR, "data_read_idarray: id too large (%u/%u)\n", x, max);
+ *error = SOLV_ERROR_ID_RANGE;
+ x = 0;
+ }
+ *ret = map ? map[x] : x;
+ return dp;
+}
+
+unsigned char *
+data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, int *error)
+{
+ Id *store = *storep;
+ unsigned int x = 0;
+ int c;
+
+ for (;;)
+ {
+ c = *dp++;
+ if ((c & 128) != 0)
+ {
+ x = (x << 7) ^ c ^ 128;
+ continue;
+ }
+ x = (x << 6) | (c & 63);
+ if (max && x >= max)
+ {
+ pool_debug(mypool, SAT_ERROR, "data_read_idarray: id too large (%u/%u)\n", x, max);
+ *error = SOLV_ERROR_ID_RANGE;
+ break;
+ }
+ *store++ = x;
+ if ((c & 64) == 0)
+ break;
+ x = 0;
+ }
+ *store++ = 0;
+ *storep = store;
+ return dp;
+}
+
+unsigned char *
+data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, int *error, Id marker)
+{
+ Id *store = *storep;
+ Id old = 0;
+ unsigned int x = 0;
+ int c;
+
+ for (;;)
+ {
+ c = *dp++;
+ if ((c & 128) != 0)
+ {
+ x = (x << 7) ^ c ^ 128;
+ continue;
+ }
+ x = (x << 6) | (c & 63);
+ if (x == 0)
+ {
+ if (!(c & 64))
+ break;
+ if (marker)
+ *store++ = marker;
+ old = 0;
+ continue;
+ }
+ x = old + (x - 1);
+ old = x;
+ if (max && x >= max)
+ {
+ pool_debug(mypool, SAT_ERROR, "data_read_rel_idarray: id too large (%u/%u)\n", x, max);
+ *error = SOLV_ERROR_ID_RANGE;
+ break;
+ }
+ *store++ = map ? map[x] : x;
+ if (!(c & 64))
+ break;
+ x = 0;
+ }
+ *store++ = 0;
+ *storep = store;
+ return dp;
+}
+
+
+static Id *
+read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
+{
+ unsigned int x = 0;
+ int c;
+
+ if (data->error)
+ return 0;
+ for (;;)
+ {
+ c = getc(data->fp);
+ if (c == EOF)
+ {
+ pool_debug(mypool, SAT_ERROR, "unexpected EOF\n");
+ data->error = SOLV_ERROR_EOF;
+ return 0;
+ }
+ if ((c & 128) != 0)
+ {
+ x = (x << 7) ^ c ^ 128;
+ continue;
+ }
+ x = (x << 6) | (c & 63);
+ if (max && x >= max)
+ {
+ pool_debug(mypool, SAT_ERROR, "read_idarray: id too large (%u/%u)\n", x, max);
+ data->error = SOLV_ERROR_ID_RANGE;
+ return 0;
+ }
+ if (map)
+ x = map[x];
+ if (store == end)
+ {
+ pool_debug(mypool, SAT_ERROR, "read_idarray: array overflow\n");
+ return 0;
+ }
+ *store++ = x;
+ if ((c & 64) == 0)
+ {
+ if (x == 0) /* already have trailing zero? */
+ return store;
+ if (store == end)
+ {
+ pool_debug(mypool, SAT_ERROR, "read_idarray: array overflow\n");
+ data->error = SOLV_ERROR_OVERFLOW;
+ return 0;
+ }
+ *store++ = 0;
+ return store;
+ }
+ x = 0;
+ }
+}
+
+static void
+read_str(Repodata *data, char **inbuf, unsigned *len)
+{
+ unsigned char *buf = (unsigned char*)*inbuf;
+ if (!buf)
+ {
+ buf = sat_malloc(1024);
+ *len = 1024;
+ }
+ int c;
+ unsigned ofs = 0;
+ while((c = getc(data->fp)) != 0)
+ {
+ if (c == EOF)
+ {
+ pool_debug (mypool, SAT_ERROR, "unexpected EOF\n");
+ data->error = SOLV_ERROR_EOF;
+ return;
+ }
+ /* Plus 1 as we also want to add the 0. */
+ if (ofs + 1 >= *len)
+ {
+ *len += 256;
+ /* Don't realloc on the inbuf, it might be on the stack. */
+ if (buf == (unsigned char*)*inbuf)
+ {
+ buf = sat_malloc(*len);
+ memcpy(buf, *inbuf, *len - 256);
+ }
+ else
+ buf = sat_realloc(buf, *len);
+ }
+ buf[ofs++] = c;
+ }
+ buf[ofs++] = 0;
+ *inbuf = (char*)buf;
+}
+
+static void
+skip_item(Repodata *data, unsigned type, unsigned numid, unsigned numrel)
+{
+ switch (type)
+ {
+ case REPOKEY_TYPE_VOID:
+ case REPOKEY_TYPE_CONSTANT:
+ case REPOKEY_TYPE_CONSTANTID:
+ break;
+ case REPOKEY_TYPE_ID:
+ read_id(data, numid + numrel); /* just check Id */
+ break;
+ case REPOKEY_TYPE_DIR:
+ read_id(data, numid + data->dirpool.ndirs); /* just check Id */
+ break;
+ case REPOKEY_TYPE_NUM:
+ read_id(data, 0);
+ break;
+ case REPOKEY_TYPE_U32:
+ read_u32(data);
+ break;
+ case REPOKEY_TYPE_STR:
+ while (read_u8(data) != 0)
+ ;
+ break;
+ case REPOKEY_TYPE_IDARRAY:
+ case REPOKEY_TYPE_REL_IDARRAY:
+ while ((read_u8(data) & 0xc0) != 0)
+ ;
+ break;
+ case REPOKEY_TYPE_DIRNUMNUMARRAY:
+ for (;;)
+ {
+ read_id(data, numid + data->dirpool.ndirs); /* just check Id */
+ read_id(data, 0);
+ if (!(read_id(data, 0) & 0x40))
+ break;
+ }
+ break;
+ case REPOKEY_TYPE_DIRSTRARRAY:
+ for (;;)
+ {
+ Id id = read_id(data, 0);
+ while (read_u8(data) != 0)
+ ;
+ if (!(id & 0x40))
+ break;
+ }
+ break;
+ default:
+ pool_debug(mypool, SAT_ERROR, "unknown type %d\n", type);
+ data->error = SOLV_ERROR_CORRUPT;
+ break;
+ }
+}
+
+static int
+key_cmp (const void *pa, const void *pb)
+{
+ Repokey *a = (Repokey *)pa;
+ Repokey *b = (Repokey *)pb;
+ return a->name - b->name;
+}
+
+static void repodata_load_solv(Repodata *data);
+
+static void
+parse_external_repodata(Repodata *maindata, Id *keyp, Repokey *keys, Id *idmap, unsigned numid, unsigned numrel)
+{
+ Repo *repo = maindata->repo;
+ Id key, id;
+ Id *ida, *ide;
+ Repodata *data;
+ int i, n;
+
+ repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata + 1, sizeof (*data));
+ data = repo->repodata + repo->nrepodata++;
+ memset(data, 0, sizeof(*data));
+ data->repo = repo;
+ data->pagefd = -1;
+ data->state = REPODATA_STUB;
+ data->loadcallback = repodata_load_solv;
+
+ while ((key = *keyp++) != 0)
+ {
+ id = keys[key].name;
+ switch (keys[key].type)
+ {
+ case REPOKEY_TYPE_IDARRAY:
+ if (id != REPODATA_KEYS)
+ {
+ skip_item(maindata, REPOKEY_TYPE_IDARRAY, numid, numrel);
+ break;
+ }
+ /* read_idarray writes a terminating 0, that's why the + 1 */
+ ida = sat_calloc(keys[key].size + 1, sizeof(Id));
+ ide = read_idarray(maindata, numid, idmap, ida, ida + keys[key].size + 1);
+ n = ide - ida - 1;
+ if (n & 1)
+ {
+ pool_debug (mypool, SAT_ERROR, "invalid attribute data\n");
+ maindata->error = SOLV_ERROR_CORRUPT;
+ return;
+ }
+ data->nkeys = 1 + (n >> 1);
+ data->keys = sat_malloc2(data->nkeys, sizeof(data->keys[0]));
+ memset(data->keys, 0, sizeof(Repokey));
+ for (i = 1, ide = ida; i < data->nkeys; i++)
+ {
+ data->keys[i].name = *ide++;
+ data->keys[i].type = *ide++;
+ data->keys[i].size = 0;
+ data->keys[i].storage = 0;
+ }
+ sat_free(ida);
+ if (data->nkeys > 2)
+ qsort(data->keys + 1, data->nkeys - 1, sizeof(data->keys[0]), key_cmp);
+ break;
+ case REPOKEY_TYPE_STR:
+ if (id != REPODATA_LOCATION)
+ skip_item(maindata, REPOKEY_TYPE_STR, numid, numrel);
+ else
+ {
+ char buf[1024];
+ unsigned len = sizeof(buf);
+ char *filename = buf;
+ read_str(maindata, &filename, &len);
+ data->location = strdup(filename);
+ if (filename != buf)
+ free(filename);