add bencode lib to sources

remotes/origin/HEAD
Richard Fuchs 12 years ago
parent 5c310916a2
commit 8708c99e33

@ -25,7 +25,8 @@ CFLAGS+= `dpkg-buildflags --get CFLAGS`
CPPFLAGS+= `dpkg-buildflags --get CPPFLAGS`
LDFLAGS+= `dpkg-buildflags --get LDFLAGS`
SRCS= main.c kernel.c poller.c aux.c control.c streambuf.c call.c control_udp.c redis.c
SRCS= main.c kernel.c poller.c aux.c control.c streambuf.c call.c control_udp.c redis.c \
bencode.c
OBJS= $(SRCS:.c=.o)

@ -0,0 +1,561 @@
#include <stdio.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "bencode.h"
/* set to 0 for alloc debugging, e.g. through valgrind */
#define BENCODE_MIN_BUFFER_PIECE_LEN 512
struct __bencode_buffer_piece {
char *tail;
unsigned int left;
struct __bencode_buffer_piece *next;
char buf[0];
};
static bencode_item_t __bencode_end_marker = {
.type = BENCODE_END_MARKER,
.iov[0].iov_base = "e",
.iov[0].iov_len = 1,
.iov_cnt = 1,
.str_len = 1,
};
static void __bencode_item_init(bencode_item_t *item) {
item->parent = item->child = item->sibling = NULL;
}
static void __bencode_container_init(bencode_item_t *cont) {
cont->iov[0].iov_len = 1;
cont->iov[1].iov_base = "e";
cont->iov[1].iov_len = 1;
cont->iov_cnt = 2;
cont->str_len = 2;
}
static void bencode_dictionary_init(bencode_item_t *dict) {
dict->type = BENCODE_DICTIONARY;
dict->iov[0].iov_base = "d";
__bencode_container_init(dict);
}
static void bencode_list_init(bencode_item_t *list) {
list->type = BENCODE_LIST;
list->iov[0].iov_base = "l";
__bencode_container_init(list);
}
static struct __bencode_buffer_piece *__bencode_piece_new(unsigned int size) {
struct __bencode_buffer_piece *ret;
if (size < BENCODE_MIN_BUFFER_PIECE_LEN)
size = BENCODE_MIN_BUFFER_PIECE_LEN;
ret = BENCODE_MALLOC(sizeof(*ret) + size);
if (!ret)
return NULL;
ret->tail = ret->buf;
ret->left = size;
ret->next = NULL;
return ret;
}
int bencode_buffer_init(bencode_buffer_t *buf) {
buf->pieces = __bencode_piece_new(0);
if (!buf->pieces)
return -1;
return 0;
}
static void *__bencode_alloc(bencode_buffer_t *buf, unsigned int size) {
struct __bencode_buffer_piece *piece;
void *ret;
piece = buf->pieces;
if (size <= piece->left)
goto alloc;
piece = __bencode_piece_new(size);
if (!piece)
return NULL;
piece->next = buf->pieces;
buf->pieces = piece;
assert(size <= piece->left);
alloc:
piece->left -= size;
ret = piece->tail;
piece->tail += size;
return ret;
}
void bencode_buffer_free(bencode_buffer_t *buf) {
struct __bencode_buffer_piece *piece, *next;
for (piece = buf->pieces; piece; piece = next) {
next = piece->next;
BENCODE_FREE(piece);
}
}
static bencode_item_t *__bencode_item_alloc(bencode_buffer_t *buf, unsigned int payload) {
bencode_item_t *ret;
ret = __bencode_alloc(buf, sizeof(struct bencode_item) + payload);
if (!ret)
return NULL;
ret->buffer = buf;
__bencode_item_init(ret);
return ret;
}
bencode_item_t *bencode_dictionary(bencode_buffer_t *buf) {
bencode_item_t *ret;
ret = __bencode_item_alloc(buf, 0);
if (!ret)
return NULL;
bencode_dictionary_init(ret);
return ret;
}
bencode_item_t *bencode_list(bencode_buffer_t *buf) {
bencode_item_t *ret;
ret = __bencode_item_alloc(buf, 0);
if (!ret)
return NULL;
bencode_list_init(ret);
return ret;
}
static void __bencode_container_add(bencode_item_t *parent, bencode_item_t *child) {
assert(child->parent == NULL);
assert(child->sibling == NULL);
child->parent = parent;
child->sibling = parent->child;
parent->child = child;
while (parent) {
parent->iov_cnt += child->iov_cnt;
parent->str_len += child->str_len;
parent = parent->parent;
}
}
bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len) {
bencode_item_t *ret;
int len_len;
assert((len <= 99999) && (len >= 0));
ret = __bencode_item_alloc(buf, strlen(s) + 7);
if (!ret)
return NULL;
len_len = sprintf(ret->__buf, "%d:", len);
ret->type = BENCODE_STRING;
ret->iov[0].iov_base = ret->__buf;
ret->iov[0].iov_len = len_len;
ret->iov[1].iov_base = (void *) s;
ret->iov[1].iov_len = len;
ret->iov_cnt = 2;
ret->str_len = len_len + len;
return ret;
}
bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i) {
bencode_item_t *ret;
int alen, rlen;
alen = 8;
while (1) {
ret = __bencode_item_alloc(buf, alen + 3);
if (!ret)
return NULL;
rlen = snprintf(ret->__buf, alen, "i%llde", i);
if (rlen < alen)
break;
alen <<= 1;
}
ret->type = BENCODE_INTEGER;
ret->iov[0].iov_base = ret->__buf;
ret->iov[0].iov_len = rlen;
ret->iov[1].iov_base = NULL;
ret->iov[1].iov_len = 0;
ret->iov_cnt = 1;
ret->str_len = rlen;
return ret;
}
bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, int keylen, bencode_item_t *val) {
bencode_item_t *str;
assert(dict->type == BENCODE_DICTIONARY);
if (!val)
return NULL;
str = bencode_string_len(dict->buffer, key, keylen);
if (!str)
return NULL;
__bencode_container_add(dict, str);
__bencode_container_add(dict, val);
return val;
}
bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item) {
assert(list->type == BENCODE_LIST);
__bencode_container_add(list, item);
return item;
}
static int __bencode_iovec_dump_rev(struct iovec *out, bencode_item_t *item) {
bencode_item_t *child;
struct iovec *orig = out;
if (item->iov[1].iov_base)
*--out = item->iov[1];
child = item->child;
while (child) {
out -= __bencode_iovec_dump_rev(out, child);
child = child->sibling;
}
assert(item->iov[0].iov_base != NULL);
*--out = item->iov[0];
assert((orig - out) == item->iov_cnt);
return item->iov_cnt;
}
static int __bencode_str_dump_rev(char *out, bencode_item_t *item) {
bencode_item_t *child;
char *orig = out;
if (item->iov[1].iov_base) {
out -= item->iov[1].iov_len;
memcpy(out, item->iov[1].iov_base, item->iov[1].iov_len);
}
child = item->child;
while (child) {
out -= __bencode_str_dump_rev(out, child);
child = child->sibling;
}
assert(item->iov[0].iov_base != NULL);
out -= item->iov[0].iov_len;
memcpy(out, item->iov[0].iov_base, item->iov[0].iov_len);
assert((orig - out) == item->str_len);
return item->str_len;
}
static int __bencode_iovec_dump(struct iovec *out, bencode_item_t *item) {
int len;
/* sibling lists are built in reverse, so dump everything
out backwards, end to start */
out += item->iov_cnt;
len = __bencode_iovec_dump_rev(out, item);
assert(len == item->iov_cnt);
return len;
}
static int __bencode_str_dump(char *out, bencode_item_t *item) {
int len;
char *orig = out;
/* sibling lists are built in reverse, so dump everything
out backwards, end to start */
out += item->str_len;
len = __bencode_str_dump_rev(out, item);
assert(len == item->str_len);
orig[len] = '\0';
return len;
}
struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail) {
struct iovec *ret;
assert(root != NULL);
assert(cnt != NULL);
assert(root->iov_cnt > 0);
ret = __bencode_alloc(root->buffer, sizeof(*ret) * (root->iov_cnt + head + tail));
if (!ret)
return NULL;
*cnt = __bencode_iovec_dump(ret + head, root);
return ret;
}
char *bencode_collapse(bencode_item_t *root, int *len) {
char *ret;
int l;
assert(root != NULL);
assert(root->str_len > 0);
ret = __bencode_alloc(root->buffer, root->str_len + 1);
if (!ret)
return NULL;
l = __bencode_str_dump(ret, root);
if (len)
*len = l;
return ret;
}
char *bencode_collapse_dup(bencode_item_t *root, int *len) {
char *ret;
int l;
assert(root != NULL);
assert(root->str_len > 0);
ret = BENCODE_MALLOC(root->str_len + 1);
if (!ret)
return NULL;
l = __bencode_str_dump(ret, root);
if (len)
*len = l;
return ret;
}
static bencode_item_t *bencode_decode_dictionary(bencode_buffer_t *buf, const char *s, int len) {
bencode_item_t *ret, *item;
if (*s != 'd')
return NULL;
s++;
len--;
ret = __bencode_item_alloc(buf, 0);
if (!ret)
return NULL;
bencode_dictionary_init(ret);
while (len > 0) {
item = bencode_decode(buf, s, len);
if (!item)
return NULL;
s += item->str_len;
len -= item->str_len;
if (item->type == BENCODE_END_MARKER)
break;
if (item->type != BENCODE_STRING)
return NULL;
__bencode_container_add(ret, item);
if (len <= 0)
return NULL;
item = bencode_decode(buf, s, len);
if (!item)
return NULL;
s += item->str_len;
len -= item->str_len;
if (item->type == BENCODE_END_MARKER)
return NULL;
__bencode_container_add(ret, item);
}
return ret;
}
static bencode_item_t *bencode_decode_list(bencode_buffer_t *buf, const char *s, int len) {
bencode_item_t *ret, *item;
if (*s != 'l')
return NULL;
s++;
len--;
ret = __bencode_item_alloc(buf, 0);
if (!ret)
return NULL;
bencode_list_init(ret);
while (len >= 0) {
item = bencode_decode(buf, s, len);
if (!item)
return NULL;
s += item->str_len;
len -= item->str_len;
if (item->type == BENCODE_END_MARKER)
break;
__bencode_container_add(ret, item);
}
return ret;
}
static bencode_item_t *bencode_decode_integer(bencode_buffer_t *buf, const char *s, int len) {
long long int i;
const char *orig = s;
char *end;
bencode_item_t *ret;
if (*s != 'i')
return NULL;
s++;
len--;
if (len <= 0)
return NULL;
if (*s == '0') {
i = 0;
s++;
len--;
goto done;
}
i = strtoll(s, &end, 10);
if (end == s)
return NULL;
len -= (end - s);
s += (end - s);
done:
if (len <= 0)
return NULL;
if (*s != 'e')
return NULL;
s++;
len--;
ret = __bencode_item_alloc(buf, 0);
if (!ret)
return NULL;
ret->type = BENCODE_INTEGER;
ret->iov[0].iov_base = (void *) orig;
ret->iov[0].iov_len = s - orig;
ret->iov[1].iov_base = NULL;
ret->iov[1].iov_len = 0;
ret->iov_cnt = 1;
ret->str_len = s - orig;
ret->value = i;
return ret;
}
static bencode_item_t *bencode_decode_string(bencode_buffer_t *buf, const char *s, int len) {
unsigned long int sl;
char *end;
const char *orig = s;
bencode_item_t *ret;
if (*s == '0') {
sl = 0;
s++;
len--;
goto colon;
}
sl = strtoul(s, &end, 10);
if (end == s)
return NULL;
len -= (end - s);
s += (end - s);
colon:
if (len <= 0)
return NULL;
if (*s != ':')
return NULL;
len--;
s++;
if (len < sl)
return NULL;
ret = __bencode_item_alloc(buf, 0);
if (!ret)
return NULL;
ret->type = BENCODE_STRING;
ret->iov[0].iov_base = (void *) orig;
ret->iov[0].iov_len = s - orig;
ret->iov[1].iov_base = (void *) s;
ret->iov[1].iov_len = sl;
ret->iov_cnt = 2;
ret->str_len = s - orig + sl;
return ret;
}
bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, int len) {
assert(s != NULL);
assert(len > 0);
switch (*s) {
case 'd':
return bencode_decode_dictionary(buf, s, len);
case 'l':
return bencode_decode_list(buf, s, len);
case 'i':
return bencode_decode_integer(buf, s, len);
case 'e':
return &__bencode_end_marker;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return bencode_decode_string(buf, s, len);
default:
return NULL;
}
}
/* XXX inefficient, use a proper hash instead */
bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *keystr, int keylen) {
bencode_item_t *key, *val;
if (!dict)
return NULL;
if (dict->type != BENCODE_DICTIONARY)
return NULL;
for (val = dict->child; val; val = key->sibling) {
key = val->sibling;
assert(key != NULL);
assert(key->type == BENCODE_STRING);
if (keylen != key->iov[1].iov_len)
continue;
if (memcmp(keystr, key->iov[1].iov_base, keylen))
continue;
return val;
}
return NULL;
}

@ -0,0 +1,284 @@
#ifndef _BENCODE_H_
#define _BENCODE_H_
#include <sys/uio.h>
#include <string.h>
#ifndef BENCODE_MALLOC
#define BENCODE_MALLOC malloc
#define BENCODE_FREE free
#endif
struct bencode_buffer;
enum bencode_type;
struct bencode_item;
struct __bencode_buffer_piece;
typedef enum bencode_type bencode_type_t;
typedef struct bencode_buffer bencode_buffer_t;
typedef struct bencode_item bencode_item_t;
enum bencode_type {
BENCODE_INVALID = 0,
BENCODE_STRING, /* byte string */
BENCODE_INTEGER, /* long long int */
BENCODE_LIST, /* flat list of other objects */
BENCODE_DICTIONARY, /* dictionary of key/values pairs. keys are always strings */
BENCODE_END_MARKER, /* used internally only */
};
struct bencode_item {
bencode_type_t type;
struct iovec iov[2]; /* when decoding, iov[1] contains the contents of a string object */
unsigned int iov_cnt;
unsigned int str_len; /* length of the whole ENCODED object. NOT the length of a byte string */
long long int value; /* when decoding an integer, contains the value */
bencode_item_t *parent, *child, *sibling;
bencode_buffer_t *buffer;
char __buf[0];
};
struct bencode_buffer {
struct __bencode_buffer_piece *pieces;
};
/* Initializes a bencode_buffer_t object. This object is used to group together all memory allocations
* made when encoding or decoding. Its memory usage is always growing, until it is freed, at which point
* all objects created through it become invalid. The actual object must be allocated separately, for
* example by being put on the stack.
* Returns 0 on success or -1 on failure (if no memory could be allocated). */
int bencode_buffer_init(bencode_buffer_t *buf);
/* Destroys a previously initialized bencode_buffer_t object. All memory used by the object is freed
* and all objects created through it become invalid. */
void bencode_buffer_free(bencode_buffer_t *buf);
/* Creates a new empty dictionary object. Memory will be allocated from the bencode_buffer_t object.
* Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_dictionary(bencode_buffer_t *buf);
/* Creates a new empty list object. Memory will be allocated from the bencode_buffer_t object.
* Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_list(bencode_buffer_t *buf);
/* Adds a new key/value pair to a dictionary. Memory will be allocated from the same bencode_buffer_t
* object as the dictionary was allocated from. Returns NULL if no memory could be allocated, otherwise
* returns "val".
* The function does not check whether the key being added is already present in the dictionary.
* Also, the function does not reorder keys into lexicographical order; keys will be encoded in
* the same order as they've been added. The key must a null-terminated string.
* The value to be added must not have been previously linked into any other dictionary or list. */
static inline bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val);
/* Identical to bencode_dictionary_add() but doesn't require the key string to be null-terminated */
bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, int keylen, bencode_item_t *val);
/* Convenience function to add a string value to a dictionary */
static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val);
/* Convenience function to add an integer value to a dictionary */
static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val);
/* Adds a new item to a list. Returns "item".
* The item to be added must not have been previously linked into any other dictionary or list. */
bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item);
/* Convenience function to add a string item to a list */
static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s);
/* Creates a new byte-string object. The given string does not have to be null-terminated, instead
* the length of the string is specified by the "len" parameter. Returns NULL if no memory could
* be allocated.
* Strings are not copied or duplicated, so the string pointed to by "s" must remain valid until
* the complete document is finally encoded or sent out. */
bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len);
/* Creates a new byte-string object. The given string must be null-terminated. Otherwise identical
* to bencode_string_len(). */
static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s);
/* Creates a new integer object. Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i);
/* Collapses and encodes the complete document structure under the "root" element (which normally
* is either a dictionary or a list) into an array of "iovec" structures. This array can then be
* passed to functions ala writev() or sendmsg() to output the encoded document as a whole. Memory
* is allocated from the same bencode_buffer_t object as the "root" object was allocated from.
* The "head" and "tail" parameters specify additional "iovec" structures that should be included
* in the allocated array before or after (respectively) the iovec structures used by the encoded
* document. Both parameters can be zero if no additional elements in the array are required.
* Returns a pointer to the allocated array or NULL if no memory could be allocated. The number of
* array elements is returned in "cnt" which must be a valid pointer to an int. This number does
* not include any additional elements allocated through the "head" or "tail" parameters.
*
* Therefore, the contents of the returned array are:
* [0 .. (head - 1)] = unused and uninitialized iovec structures
* [(head) .. (head + cnt - 1)] = the encoded document
* [(head + cnt) .. (head + cnt + tail - 1)] = unused and uninitialized iovec structures
*
* The returned array will be freed when the corresponding bencode_buffer_t object is destroyed. */
struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail);
/* Similar to bencode_iovec(), but instead returns the encoded document as a null-terminated string.
* Memory for the string is allocated from the same bencode_buffer_t object as the "root" object
* was allocated from. If "len" is a non-NULL pointer, the length of the genrated string is returned
* in *len. This is important if the encoded document contains binary data, in which case null
* termination cannot be trusted. The returned string is freed when the corresponding
* bencode_buffer_t object is destroyed. */
char *bencode_collapse(bencode_item_t *root, int *len);
/* Identical to bencode_collapse(), but the memory for the returned string is not allocated from
* a bencode_buffer_t object, but instead using the function defined as BENCODE_MALLOC (normally
* malloc() or pkg_malloc()), similar to strdup(). Using this function, the bencode_buffer_t
* object can be destroyed, but the returned string remains valid and usable. */
char *bencode_collapse_dup(bencode_item_t *root, int *len);
/* Decodes an encoded document from a string into a tree of bencode_item_t objects. The string does
* not need to be null-terminated, instead the length of the string is given through the "len"
* parameter. Memory is allocated from the bencode_buffer_t object. Returns NULL if no memory could
* be allocated or if the document could not be successfully decoded.
*
* The returned element is the "root" of the document tree and normally is either a list object or
* a dictionary object, but can also be a single string or integer object with no other objects
* underneath or besides it (no childred and no siblings). The type of the object can be determined
* by its ->type property.
*
* The number of bytes that could successfully be decoded into an object tree can be accessed through
* the root element's ->str_len property. Normally, this number should be equal to the "len" parameter
* passed, in which case the full string could be decoded. If ->str_len is less than "len", then there
* was additional stray byte data after the end of the encoded document.
*
* The document tree can be traversed through the ->child and ->sibling pointers in each object. The
* ->child pointer will be NULL for string and integer objects, as they don't contain other objects.
* For lists and dictionaries, ->child will be a pointer to the LAST contained object. This last
* contained object's ->sibling pointer will point to the last-but-one contained object of the list
* or the dictionary, and so on. The FIRST contained element of a list of dictionary will have a
* NULL ->sibling pointer.
*
* Lists are built in reverse and so traversing a list by following the ->sibling pointers will
* traverse all the elements in reverse as well. This includes the ordering of key/value pairs in
* dictionary: The first element in the list (where ->child points to) will be the VALUE of the LAST
* key/value pair. The next element (following one ->sibling) will be the KEY of the LAST key/value
* pair (guaranteed to be a string and guaranteed to be present). Following another ->sibling will
* point to the VALUE of the last-but-one key/value pair, and so on.
*
* The decoding function for dictionary object does not check whether keys are unique within the
* dictionary. It also does not care about lexicographical order of the keys.
*
* Decoded string objects will contain the raw decoded byte string in ->iov[1] (including the correct
* length). Strings are NOT null-terminated. Decoded integer objects will contain the decoded value
* in ->value.
*
* All memory is freed when the bencode_buffer_t object is destroyed.
*/
bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, int len);
/* Identical to bencode_decode(), but returns successfully only if the type of the decoded object match
* "expect". */
static inline bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, int len, bencode_type_t expect);
/* Searches the given dictionary object for the given key and returns the respective value. Returns
* NULL if the given object isn't a dictionary or if the key doesn't exist. The key must be a
* null-terminated string. */
static inline bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key);
/* Identical to bencode_dictionary_get() but doesn't require the key to be null-terminated. */
bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *key, int key_len);
/* Identical to bencode_dictionary_get() but returns the value only if its type is a string, and
* returns it as a pointer to the string itself. Returns NULL if the value is of some other type. The
* returned string is NOT null-terminated. Length of the string is returned in *len, which must be a
* valid pointer. The returned string will be valid until dict's bencode_buffer_t object is destroyed. */
static inline const char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, int *len);
/* Identical to bencode_dictionary_get() but returns the string in a newly allocated buffer (using the
* BENCODE_MALLOC function), which remains valid even after bencode_buffer_t is destroyed. */
static inline char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, int *len);
/* Identical to bencode_dictionary_get_string() but expects an integer object. The parameter "defval"
* specified which value should be returned if the key is not found or if the value is not an integer. */
static inline long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval);
/* Identical to bencode_dictionary_get(), but returns the object only if its type matches "expect". */
static inline bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect);
/**************************/
static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s) {
return bencode_string_len(buf, s, strlen(s));
}
static inline bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val) {
if (!key)
return NULL;
return bencode_dictionary_add_len(dict, key, strlen(key), val);
}
static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val) {
if (!val)
return NULL;
return bencode_dictionary_add(dict, key, bencode_string(dict->buffer, val));
}
static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val) {
return bencode_dictionary_add(dict, key, bencode_integer(dict->buffer, val));
}
static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s) {
return bencode_list_add(list, bencode_string(list->buffer, s));
}
static inline bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key) {
if (!key)
return NULL;
return bencode_dictionary_get_len(dict, key, strlen(key));
}
static inline const char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, int *len) {
bencode_item_t *val;
val = bencode_dictionary_get(dict, key);
if (!val || val->type != BENCODE_STRING)
return NULL;
*len = val->iov[1].iov_len;
return val->iov[1].iov_base;
}
static inline char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, int *len) {
const char *s;
char *ret;
s = bencode_dictionary_get_string(dict, key, len);
if (!s)
return NULL;
ret = BENCODE_MALLOC(*len);
if (!ret)
return NULL;
memcpy(ret, s, *len);
return ret;
}
static inline long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval) {
bencode_item_t *val;
val = bencode_dictionary_get(dict, key);
if (!val || val->type != BENCODE_INTEGER)
return defval;
return val->value;
}
static inline bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, int len, bencode_type_t expect) {
bencode_item_t *ret;
ret = bencode_decode(buf, s, len);
if (!ret || ret->type != expect)
return NULL;
return ret;
}
static inline bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect) {
bencode_item_t *ret;
ret = bencode_dictionary_get(dict, key);
if (!ret || ret->type != expect)
return NULL;
return ret;
}
#endif
Loading…
Cancel
Save