about summary refs log tree commit diff
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/benc.c323
-rw-r--r--misc/benc.h50
-rw-r--r--misc/metainfo.c64
3 files changed, 253 insertions, 184 deletions
diff --git a/misc/benc.c b/misc/benc.c
index 68f7f95..6a57e2e 100644
--- a/misc/benc.c
+++ b/misc/benc.c
@@ -2,6 +2,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -99,7 +100,7 @@ benc_length(const char *p)
             ;
         return next - p + 1;
     default:
-        assert(benc_str(p, &next, &blen, NULL) == 0);
+        assert((next = benc_mem(p, &blen, NULL)) != NULL);
         return next - p + blen;
     }
 }
@@ -127,11 +128,12 @@ benc_next(const char *p)
     return *(p + blen) == 'e' ? NULL : p + blen;
 }
 
-int
-benc_str(const char *p, const char **out, size_t *len, const char**next)
+const char *
+benc_mem(const char *p, size_t *len, const char**next)
 {
+    if (!benc_isstr(p))
+        return NULL;
     size_t blen = 0;
-    assert(isdigit(*p));
     blen = *p - '0';
     p++;
     while (isdigit(*p)) {
@@ -141,53 +143,49 @@ benc_str(const char *p, const char **out, size_t *len, const char**next)
     }
     assert(*p == ':');
     benc_safeset(len, blen);
-    benc_safeset(out, p + 1);
     benc_safeset(next, *(p + blen + 1) == 'e' ? NULL : p + blen + 1);
-    return 0;
+    return p + 1;
 }
 
-int
-benc_strz(const char *p, char **out, size_t *len, const char **next)
+char *
+benc_str(const char *p, size_t *len, const char **next)
 {
-    int err;
     size_t blen;
     const char *bstr;
-
-    if ((err = benc_str(p, &bstr, &blen, next)) == 0) {
-        if ((*out = malloc(blen + 1)) != NULL) {
-            memcpy(*out, bstr, blen);
-            (*out)[blen] = '\0';
-            benc_safeset(len, blen);
-        } else
-            err = ENOMEM;
-    }
-    return err;
+    char *ret;
+    if ((bstr = benc_mem(p, &blen, next)) == NULL)
+        return NULL;
+    if ((ret = malloc(blen + 1)) == NULL)
+        return NULL;
+    bcopy(bstr, ret, blen);
+    ret[blen] = '\0';
+    benc_safeset(len, blen);
+    return ret;
 }
 
-int
-benc_stra(const char *p, char **out, size_t *len, const char **next)
+char *
+benc_mema(const char *p, size_t *len, const char **next)
 {
-    int err;
     size_t blen;
     const char *bstr;
-
-    if ((err = benc_str(p, &bstr, &blen, next)) == 0) {
-        if ((*out = malloc(blen)) != NULL) {
-            memcpy(*out, bstr, blen);
-            benc_safeset(len, blen);
-        } else
-            err = ENOMEM;
-    }
-    return err;
+    char *ret;
+    if ((bstr = benc_mem(p, &blen, next)) == NULL)
+        return NULL;
+    if ((ret = malloc(blen)) == NULL)
+        return NULL;
+    bcopy(bstr, ret, blen);
+    benc_safeset(len, blen);
+    return ret;
 }
 
-int
-benc_int64(const char *p, int64_t *out, const char **next)
+long long
+benc_int(const char *p, const char **next)
 {
     int sign = 1;
-    int64_t res = 0;
+    long long res = 0;
 
-    assert(*p == 'i');
+    if (!benc_isint(p))
+        return 0;
     p++;
     if (*p == '-') {
         sign = -1;
@@ -202,122 +200,79 @@ benc_int64(const char *p, int64_t *out, const char **next)
         p++;
     }
     assert(*p == 'e');
-    benc_safeset(out, res);
-    benc_safeset(next, *(p + 1) == 'e' ? NULL : p + 1);
-
-    return 0;
-}
-
-int
-benc_uint32(const char *p, uint32_t *out, const char **next)
-{
-    int err;
-    int64_t res;
-    if ((err = benc_int64(p, &res, next)) == 0) {
-        if (res >= 0 && res <= 0xffffffffUL)
-            *out = (uint32_t)res;
-        else
-            err = EINVAL;
-    }
-    return err;
+    benc_safeset(next, *(p + 1) == 'e' ? NULL : p + 1);    
+    return res;
 }
 
-int
-benc_dget_any(const char *p, const char *key, const char **val)
+const char *
+benc_dget_any(const char *p, const char *key)
 {
-    int res;
+    int cmp;
     size_t len, blen;
     const char *bstr;
 
-    assert(benc_isdct(p));
+    if (!benc_isdct(p))
+        return NULL;
 
     len = strlen(key);
 
     p = benc_first(p);
     while (p != NULL) {
-        if ((res = benc_str(p, &bstr, &blen, &p)) != 0)
-            return res;
-
-        res = strncmp(bstr, key, blen);
-        if (res == 0 && len == blen) {
-            *val = p;
-            return 0;
-        } else if (res <= 0) {
+        if (!benc_isstr(p))
+            return NULL;
+        bstr = benc_mem(p, &blen, &p);
+
+        cmp = strncmp(bstr, key, blen);
+        if (cmp == 0 && len == blen)
+            return p;
+        else if (cmp <= 0)
             p = benc_next(p);
-        } else
-            return ENOENT;
+        else
+            return NULL;
     }
-    return ENOENT;
+    return NULL;
 }
 
-int
-benc_dget_lst(const char *p, const char *key, const char **val)
-{
-    int err;
-    if ((err = benc_dget_any(p, key, val)) == 0)
-        if (!benc_islst(*val))
-            err = EINVAL;
-    return err;
-}
-
-int
-benc_dget_dct(const char *p, const char *key, const char **val)
+const char *
+benc_dget_lst(const char *p, const char *key)
 {
-    int err;
-    if ((err = benc_dget_any(p, key, val)) == 0)
-        if (!benc_isdct(*val))
-            err = EINVAL;
-    return err;
+    const char *ret = benc_dget_any(p, key);
+    return ret != NULL && benc_islst(ret) ? ret : NULL;
 }
 
-int
-benc_dget_str(const char *p, const char *key, const char **val, size_t *len)
+const char *
+benc_dget_dct(const char *p, const char *key)
 {
-    int err;
-    const char *sp;
-    if ((err = benc_dget_any(p, key, &sp)) == 0)
-        err = benc_isstr(sp) ? benc_str(sp, val, len, NULL) : EINVAL;
-    return err;
+    const char *ret = benc_dget_any(p, key);
+    return ret != NULL && benc_isdct(ret) ? ret : NULL;
 }
 
-int
-benc_dget_stra(const char *p, const char *key, char **val, size_t *len)
+const char *
+benc_dget_mem(const char *p, const char *key, size_t *len)
 {
-    int err;
-    const char *sp;
-    if ((err = benc_dget_any(p, key, &sp)) == 0)
-        err = benc_isstr(sp) ? benc_stra(sp, val, len, NULL) : EINVAL;
-    return err;
+    const char *str = benc_dget_any(p, key);
+    return str != NULL && benc_isstr(str) ? benc_mem(str, len, NULL) : NULL;
 }
 
-int
-benc_dget_strz(const char *p, const char *key, char **val, size_t *len)
+char *
+benc_dget_mema(const char *p, const char *key, size_t *len)
 {
-    int err;
-    const char *sp;
-    if ((err = benc_dget_any(p, key, &sp)) == 0)
-        err = benc_isstr(sp) ? benc_strz(sp, val, len, NULL) : EINVAL;
-    return err;
+    const char *str = benc_dget_any(p, key);
+    return str != NULL && benc_isstr(str) ? benc_mema(str, len, NULL) : NULL;
 }
 
-int
-benc_dget_int64(const char *p, const char *key, int64_t *val)
+char *
+benc_dget_str(const char *p, const char *key, size_t *len)
 {
-    int err;
-    const char *ip;
-    if ((err = benc_dget_any(p, key, &ip)) == 0)
-        err = benc_isint(ip) ? benc_int64(ip, val, NULL) : EINVAL;
-    return err;
+    const char *str = benc_dget_any(p, key);
+    return str != NULL && benc_isstr(str) ? benc_str(str, len, NULL) : NULL;
 }
 
-int
-benc_dget_uint32(const char *p, const char *key, uint32_t *val)
+long long
+benc_dget_int(const char *p, const char *key)
 {
-    int err;
-    const char *ip;
-    if ((err = benc_dget_any(p, key, &ip)) == 0)
-        err = benc_isint(ip) ? benc_uint32(ip, val, NULL) : EINVAL;
-    return err;
+    const char *intp = benc_dget_any(p, key);
+    return intp != NULL && benc_isint(intp) ? benc_int(intp, NULL) : 0;
 }
 
 int
@@ -343,3 +298,131 @@ benc_isstr(const char *p)
 {
     return isdigit(*p);
 }
+
+int
+benc_istype(const char *p, enum be_type type)
+{
+    switch (type) {
+    case BE_ANY:
+        return benc_isdct(p) || benc_isint(p) ||
+            benc_islst(p) || benc_isstr(p);
+    case BE_DCT:
+        return benc_isdct(p);
+    case BE_INT:
+        return benc_isint(p);
+    case BE_LST:
+        return benc_islst(p);
+    case BE_STR:
+        return benc_isstr(p);
+    default:
+        abort();
+    }
+}
+
+int
+benc_dct_chk(const char *p, int count, ...)
+{
+    int i, ok = 1;
+    va_list ap;
+
+    if (!benc_isdct(p))
+        ok = 0;
+
+    va_start(ap, count);
+    for (i = 0; ok && i < count; i++) {
+        enum be_type type = va_arg(ap, enum be_type);
+        int level = va_arg(ap, int);
+        const char *dct = p;
+        const char *key = va_arg(ap, const char *);
+        while (ok && level > 1) {            
+            if ((dct = benc_dget_dct(dct, key)) != NULL) {
+                level--;
+                key = va_arg(ap, const char *);
+            } else
+                ok = 0;
+        }
+        if (ok) {
+            const char *val = benc_dget_any(dct, key);
+            if (val == NULL || !benc_istype(val, type))
+                ok = 0;
+        }
+    }
+    va_end(ap);
+    return ok;
+}
+
+#if 0
+int
+benc_dct_type_check(const char *p, int count, ...)
+{
+    int i;
+    va_list ap;
+
+    benc_validate_dct(p, 2, BE_INT, "code", BE_STR, "hash", 
+
+    if (!benc_isdct(p))
+        return EINVAL;
+
+    va_start(ap, count);
+    for (i = 0; i < count; i++) {
+
+
+    }
+}
+
+int
+benc_dget_many(const char *p, int count, ...)
+{
+    int i;
+    va_list ap;
+    if (!benc_isdct(p))
+        return 0;
+    va_start(ap, count);
+    for (i = 0; i < count; i++) {
+        const char *name = va_arg(ap, const char *);
+        enum be_type type = va_arg(ap, enum be_type);
+        int64_t *iret;
+        size_t *lret;
+        const char **mret;
+        char **aret;
+
+        switch (type) {
+        case BE_INT:
+            iret = va_arg(ap, int64_t *);
+            if (benc_dget_int64(p, name, iret) != 0)
+                goto out;
+            break;
+        case BE_LST:
+            mret = va_arg(ap, const char **);
+            lret = va_arg(ap, size_t *);
+            if (benc_dget_lst(p, name, mret) != 0)
+                goto out;
+            if (lret != NULL)
+                *lret = benc_nelems(*mret);
+            break;
+        case BE_DCT:
+            mret = va_arg(ap, const char **);
+            if (benc_dget_dct(p, name, mret) != 0)
+                goto out;
+            break;
+        case BE_MEM:
+            mret = va_arg(ap, const char **);
+            lret = va_arg(ap, size_t *);
+            if (benc_dget_str(p, name, mret, lret) != 0)
+                goto out;
+            break;
+        case BE_STRZ:
+            aret = va_arg(ap, char **);
+            lret = va_arg(ap, size_t *);
+            if (benc_dget_strz(p, name, aret, lret) != 0)
+                goto out;
+            break;
+        default:
+            abort();
+        }
+    }
+out:
+    va_end(ap);
+    return i;
+}
+#endif
diff --git a/misc/benc.h b/misc/benc.h
index 8088190..69c5f57 100644
--- a/misc/benc.h
+++ b/misc/benc.h
@@ -1,7 +1,21 @@
 #ifndef BTPD_BENC_H
 #define BTPD_BENC_H
 
+enum be_type {
+    BE_ANY,
+    BE_DCT,
+    BE_INT,
+    BE_LST,
+    BE_STR
+};
+
 int benc_validate(const char *p, size_t len);
+int benc_dct_chk(const char *p, int count, ...);
+
+int benc_islst(const char *p);
+int benc_isdct(const char *p);
+int benc_isint(const char *p);
+int benc_isstr(const char *p);
 
 size_t benc_length(const char *p);
 size_t benc_nelems(const char *p);
@@ -9,29 +23,17 @@ size_t benc_nelems(const char *p);
 const char *benc_first(const char *p);
 const char *benc_next(const char *p);
 
-int benc_str(const char *p, const char **mem, size_t *len, const char**next);
-int benc_stra(const char *p, char **out, size_t *len, const char **next);
-int benc_strz(const char *p, char **out, size_t *len, const char **next);
-int benc_int64(const char *p, int64_t *out, const char **next);
-int benc_uint32(const char *p, uint32_t *out, const char **next);
-
-#define benc_off benc_int64
-
-int benc_dget_any(const char *p, const char *key, const char **val);
-int benc_dget_lst(const char *p, const char *key, const char **val);
-int benc_dget_dct(const char *p, const char *key, const char **val);
-int benc_dget_str(const char *p, const char *key,
-                  const char **val, size_t *len);
-int benc_dget_stra(const char *p, const char *key, char **val, size_t *len);
-int benc_dget_strz(const char *p, const char *key, char **val, size_t *len);
-int benc_dget_int64(const char *p, const char *key, int64_t *val);
-int benc_dget_uint32(const char *p, const char *key, uint32_t *val);
-
-#define benc_dget_off benc_dget_int64
-
-int benc_islst(const char *p);
-int benc_isdct(const char *p);
-int benc_isint(const char *p);
-int benc_isstr(const char *p);
+long long benc_int(const char *p, const char **next);
+const char *benc_mem(const char *p, size_t *len, const char **next);
+char *benc_mema(const char *p, size_t *len, const char **next);
+char *benc_str(const char *p, size_t *len, const char **next);
+
+const char *benc_dget_any(const char *p, const char *key);
+const char *benc_dget_lst(const char *p, const char *key);
+const char *benc_dget_dct(const char *p, const char *key);
+long long benc_dget_int(const char *p, const char *key);
+const char *benc_dget_mem(const char *p, const char *key, size_t *len);
+char *benc_dget_mema(const char *p, const char *key, size_t *len);
+char *benc_dget_str(const char *p, const char *key, size_t *len);
 
 #endif
diff --git a/misc/metainfo.c b/misc/metainfo.c
index 1b90247..d8f3a7c 100644
--- a/misc/metainfo.c
+++ b/misc/metainfo.c
@@ -69,22 +69,22 @@ check_path(const char *path, size_t len)
 int
 fill_fileinfo(const char *fdct, struct fileinfo *tfp)
 {
-    int err;
+    //int err;
     size_t npath, plen, len;
     const char *plst, *iter, *str;
 
-    if ((err = benc_dget_off(fdct, "length", &tfp->length)) != 0)
-        return err;
+    if (!benc_dct_chk(fdct, 2, BE_INT, 1, "length", BE_LST, 1, "path"))
+        return EINVAL;
 
-    if ((err = benc_dget_lst(fdct, "path", &plst)) != 0)
-        return err;
+    tfp->length = benc_dget_int(fdct, "length");
+    plst = benc_dget_lst(fdct, "path");
 
     npath = plen = 0;
     iter = benc_first(plst);
     while (iter != NULL) {
         if (!benc_isstr(iter))
             return EINVAL;
-        benc_str(iter, &str, &len, &iter);
+        str = benc_mem(iter, &len, &iter);
         if (!check_path(str, len))
             return EINVAL;
         npath++;
@@ -97,13 +97,13 @@ fill_fileinfo(const char *fdct, struct fileinfo *tfp)
         return ENOMEM;
 
     iter = benc_first(plst);
-    benc_str(iter, &str, &len, &iter);
+    str = benc_mem(iter, &len, &iter);
     memcpy(tfp->path, str, len);
     plen = len;
     npath--;
     while (npath > 0) {
         tfp->path[plen++] = '/';
-        benc_str(iter, &str, &len, &iter);
+        str = benc_mem(iter, &len, &iter);
         memcpy(tfp->path + plen, str, len);
         plen += len;
         npath--;
@@ -135,35 +135,25 @@ int
 fill_metainfo(const char *bep, struct metainfo *tp, int mem_hashes)
 {
     size_t len;
-    int err;
+    int err = 0;
     const char *base_addr = bep;
     const char *hash_addr;
 
-    if (!benc_isdct(bep))
+    if (!benc_dct_chk(bep, 5,
+            BE_STR, 1, "announce",
+            BE_DCT, 1, "info",
+            BE_INT, 2, "info", "piece length",
+            BE_STR, 2, "info", "pieces",
+            BE_STR, 2, "info", "name"))
         return EINVAL;
 
-    if ((err = benc_dget_strz(bep, "announce", &tp->announce, NULL)) != 0)
-        goto out;
-
-    if ((err = benc_dget_dct(bep, "info", &bep)) != 0)
-        goto out;
-
+    tp->announce = benc_dget_str(bep, "announce", NULL);
+    bep = benc_dget_dct(bep, "info");
     SHA1(bep, benc_length(bep), tp->info_hash);
-
-    if ((err = benc_dget_off(bep, "piece length", &tp->piece_length)) != 0)
-        goto out;
-
-    if ((err = benc_dget_str(bep, "pieces", &hash_addr, &len)) != 0)
-        goto out;
-
-    if (len % 20 != 0) {
-        err = EINVAL;
-        goto out;
-    }
+    tp->piece_length = benc_dget_int(bep, "piece length");
+    hash_addr = benc_dget_mem(bep, "pieces", &len);
     tp->npieces = len / 20;
-
     tp->pieces_off = hash_addr - base_addr;
-
     if (mem_hashes) {
         if ((tp->piece_hash = malloc(len)) == NULL) {
             err = ENOMEM;
@@ -171,12 +161,10 @@ fill_metainfo(const char *bep, struct metainfo *tp, int mem_hashes)
         }
         bcopy(hash_addr, tp->piece_hash, len);
     }
+    tp->name = benc_dget_str(bep, "name", NULL);
 
-    if ((err = benc_dget_strz(bep, "name", &tp->name, NULL)) != 0)
-        goto out;
-
-    err = benc_dget_off(bep, "length", &tp->total_length);
-    if (err == 0) {
+    if (benc_dct_chk(bep, 1, BE_INT, 1, "length")) {
+        tp->total_length = benc_dget_int(bep, "length");
         tp->nfiles = 1;
         tp->files = calloc(1, sizeof(struct fileinfo));
         if (tp->files != NULL) {
@@ -190,14 +178,11 @@ fill_metainfo(const char *bep, struct metainfo *tp, int mem_hashes)
             err = ENOMEM;
             goto out;
         }
-    }
-    else if (err == ENOENT) {
+    } else if (benc_dct_chk(bep, 1, BE_LST, 1, "files")) {
         int i;
         const char *flst, *fdct;
 
-        if ((err = benc_dget_lst(bep, "files", &flst)) != 0)
-            goto out;
-
+        flst = benc_dget_lst(bep, "files");
         tp->nfiles = benc_nelems(flst);
         if (tp->nfiles < 1) {
             err = EINVAL;
@@ -258,7 +243,6 @@ load_metainfo(const char *path, off_t size, int mem_hashes,
     if (err == 0)
         if ((*res = calloc(1, sizeof(**res))) == NULL)
             err = ENOMEM;
-
     if (err == 0)
         if ((err = fill_metainfo(buf, *res, mem_hashes)) != 0)
             free(*res);