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 testUsing 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).