+ data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
+ memcpy(data->attrdata + data->attrdatalen, str, l);
+ repodata_set(data, entry, &key, data->attrdatalen);
+ data->attrdatalen += l;
+}
+
+static int
+hexstr2bytes(unsigned char *buf, const char *str, int buflen)
+{
+ int i;
+ for (i = 0; i < buflen; i++)
+ {
+#define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
+ : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
+ : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
+ : -1)
+ int v = c2h(*str);
+ str++;
+ if (v < 0)
+ return 0;
+ buf[i] = v;
+ v = c2h(*str);
+ str++;
+ if (v < 0)
+ return 0;
+ buf[i] = (buf[i] << 4) | v;
+#undef c2h
+ }
+ return buflen;
+}
+
+void
+repodata_set_checksum(Repodata *data, Id entry, Id keyname, Id type,
+ const char *str)
+{
+ int l;
+ switch (type)
+ {
+ case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+ case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+ default: return;
+ }
+ unsigned char buf[l];
+ if (hexstr2bytes(buf, str, l) != l)
+ {
+ fprintf(stderr, "Invalid hex character in %s\n", str);
+ return;
+ }
+ repodata_set_bin_checksum(data, entry, keyname, type, buf);
+}
+
+const char *
+repodata_chk2str(Repodata *data, Id type, const char *buf)
+{
+ int i, l;
+ char *str, *s;
+ switch (type)
+ {
+ case REPOKEY_TYPE_MD5: l = SIZEOF_MD5; break;
+ case REPOKEY_TYPE_SHA1: l = SIZEOF_SHA1; break;
+ default: return id2str(data->repo->pool, ID_EMPTY);
+ }
+ s = str = pool_alloctmpspace(data->repo->pool, 2*l + 1);
+ for (i = 0; i < l; i++, s+=2)
+ {
+ unsigned char v = buf[i];
+ unsigned char w = v >> 4;
+ s[0] = w >= 10 ? (w-10)+'a' : w + '0';
+ w = v & 15;
+ s[1] = w >= 10 ? (w-10)+'a' : w + '0';
+ }
+ *s = 0;
+ return str;
+}
+
+void
+repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
+{
+
+#if 0
+fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
+#endif
+ repoadata_add_array(data, entry, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);