A simple bencode parser which uses hash tables for dictionaries.
Hash algorithm used is FNV-1a (32 bit).
Also note that all string related data is read/returned as unsigned char*
and not as char*
.
NOTE: You need the openssl library installed so that info_hash can be calculated
be_dict *dict = decode_file(const char *file);
This will return the outermost dictionary in the torrent file or NULL
if an
error occurs. Note that this does not differentiate between the cases where
the file doesn't exist or a syntax error occurs.
unsigned char *buffer;
size_t len;
be_type type;
// ... Initialize the buffer and length
be_dict *dict = decode(&buffer, &len, &type);
This will return NULL
only when a syntax error is present. This way, you can
check for syntax errors and problems with reading files separately. But you
will need to check the type
manually.
Should always be done after the outermost dictionary is used. There's no need
to free
individual values or lists. Do this once after everything is done.
dict_destroy(dict);
dict = NULL;
DO NOT free
, list_free
or dict_destroy
anything other than the
outermost dictionary. It will cause double-freeing when freeing the outermost
dictionary later. Set your outer dictionary to NULL
after destroying it to
prevent double-freeing as well.
be_type type;
void *val = dict_get(be_dict *dict, unsigned char *key, be_type *type);
Returns the value of the key or NULL
if it doesn't exist. Stores the type
of the value in the be_type
pointer provided. You can cast the returned
value depending on type
.
Linked lists are used for storing lists here. Iterating over a list which you got from a dictionary can be done by:
be_type type;
be_list *list = (be_list*)dict_get(dict, key, &type);
while(list != NULL) {
be_node node = list->node;
void *node_val = node.val;
be_type type = node.type;
list = list->next;
}
Strings are stored in a struct
that contain the string itself and the
length of the string.
be_type type;
be_string *string = (be_string*)dict_get(dict, key, &type);
size_t len = string->len;
unsigned char *val = string->str;
Integers are stored as long long int
here.
be_type type;
long long int i = (long long int)dict_get(dict, key, &type);
The info hash of the torrent file is stored in the struct be_dict
as an
array of unsigned char
. You can access it by dict->info_hash
. Please
check if dict->has_info_hash
is set to 1
before doing anything with the
actual hash to prevent undefined behaviour. You can dump the info hash (or
any string, really) in hex form with the hex_dump
method.
test.c
is more of a demonstration file. You should have a look
to see how some things work. You can compile and run it by:
make && make test
Using valgrind to detect any memory leaks is recommended (makefile already uses valgrind). Please report if you find any.
Be sure to check all returned values for NULL
and confirm the types before
actually using the values further. You could also store the returned void*
,
check the type and then cast it.
Please read bencode.h
for documentation on other functions
(which you may or may not need).