From 51b913eb2ff91adfe8cd5e417759a6057c5a8a21 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Thu, 13 Nov 2008 16:17:55 +0000 Subject: XBitTorrent --- bencode.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 bencode.c (limited to 'bencode.c') diff --git a/bencode.c b/bencode.c new file mode 100644 index 0000000..d03523b --- /dev/null +++ b/bencode.c @@ -0,0 +1,285 @@ +/* $Id$ */ +/* + * Copyright (c) 2005 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "bencode.h" +#include "tools.h" + +#ifndef lint +static const char rcsid[] = "@(#)$Id$"; +#endif /* not lint */ + +static struct btnode *dispatch(char **); +static struct btnode *getdict(char **); +static struct btnode *getlist(char **); +static struct btnode *getint(char **); +static struct btnode *getstr(char **); +static off_t getnum(char **); +#if DEBUG +static char *indent(int); /* used only for debug purposes */ +#endif /* DEBUG */ + +struct btnode * +btbencode(char *str) +{ + return dispatch(&str); +} + +void +btfreenode(struct btnode *np) +{ + if (np == NULL) + return; + + if (np->next != NULL) + btfreenode(np->next); + + switch (np->type) { + case NODE_DICT: + btfreenode(np->dict.key); + btfreenode(np->dict.val); + break; + case NODE_LIST: + btfreenode(np->list); + break; + case NODE_INT: + /* nothing */ + break; + case NODE_STR: + free(np->str); + break; + } + free(np); +} + +struct btnode * +btfinddict(struct btnode *np, char *key) +{ + if (np == NULL || key == NULL) + return NULL; + + if (np->type != NODE_DICT) + return NULL; + + if (np->dict.key == NULL) + return NULL; + + /* the key is always string */ + if (np->dict.key->type != NODE_STR) + return NULL; + + if (np->dict.key->str == NULL) + return NULL; + + /* there is only one key entry per dict possible */ + if (strncmp(np->dict.key->str, key, + strlen(np->dict.key->str)) == 0) + return np->dict.val; + + return btfinddict(np->next, key); +} + +static struct btnode * +dispatch(char **c) +{ + switch (*(*c)++) { + case 'd': + return getdict(c); + case 'l': + return getlist(c); + case 'i': + return getint(c); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --*c; + return getstr(c); + case 'e': + default: + return NULL; + } + /* NOTREACHED */ +} + +static struct btnode * +getdict(char **c) +{ + struct btnode *np; + char *off; + + if ((np = calloc(1, sizeof(struct btnode))) == NULL) + return NULL; + + np->type = NODE_DICT; + + if ((np->dict.key = dispatch(c)) == NULL) { + free(np); /* empty dictonary */ + return NULL; + } + + off = *c; + np->dict.val = dispatch(c); + if (np->dict.val != NULL) { + np->dict.val->aux.off = off; + np->dict.val->aux.len = *c - off; + } + + np->next = getdict(c); + + return np; +} + +static struct btnode * +getlist(char **c) +{ + struct btnode *np; + + if ((np = calloc(1, sizeof(struct btnode))) == NULL) + return NULL; + + np->type = NODE_LIST; + + if ((np->list = dispatch(c)) == NULL) { + free(np); /* empty list */ + return NULL; + } + + np->next = getlist(c); + + return np; +} + +static struct btnode * +getint(char **c) +{ + struct btnode *np; + + if ((np = calloc(1, sizeof(struct btnode))) == NULL) + return NULL; + + np->type = NODE_INT; + np->num = getnum(c); + + return np; +} + +static off_t +getnum(char **c) +{ + off_t n = 0; + int mflag = 0; + + if (**c == '-') { + mflag = 1; + ++*c; + } + + while (**c >= '0' && **c <= '9') { + n *= 10; + n += *(*c)++ - '0'; + } + ++*c; /* skip the last char (usually `e' or `:') */ + + return mflag ? -n : n; +} + +static struct btnode * +getstr(char **c) +{ + off_t len; + struct btnode *np; + + if ((len = getnum(c)) <= 0) + return NULL; + + if ((np = calloc(1, sizeof(struct btnode))) == NULL) + return NULL; + + np->type = NODE_STR; + np->len = len; + + if ((np->str = calloc(len + 1, sizeof(char))) == NULL) { + free(np); + return NULL; + } + + memcpy(np->str, *c, len); + np->str[len] = NULL; + *c += len; + + return np; +} + +#if DEBUG +static char * +indent(int n) +{ + int i = 0; + static char buf[80] = { NULL }; + + while (i < n && i < 79) + buf[i++] = ' '; + buf[i] = NULL; + + return buf; +} + +void +btdumpnode(struct btnode *np) +{ + const char *type[] = { "Dictonary", "List", "Integer", "String" }; + static int i = 0; + + if (np == NULL) + return; + printf("%s%s\n", indent(i), type[np->type]); + switch (np->type) { + case NODE_DICT: + i += 8; + btdumpnode(np->dict.key); + btdumpnode(np->dict.val); + i -= 8; + break; + case NODE_LIST: + i += 8; + btdumpnode(np->list); + i -= 8; + break; + case NODE_INT: + printf("%s%lld\n", indent(i + 4), np->num); + break; + case NODE_STR: + printf("%s(%d) %s\n", indent(i + 4), np->len, np->str); + break; + } + + if (np->next != NULL) + btdumpnode(np->next); +} +#endif /* DEBUG */ -- cgit v1.2.3