--- /dev/null
+#include<bencode.h>
+
+ssize_t bdecode_integer(const uint8_t *buf, size_t buf_len, long long int *output) {
+ if(NULL==buf) { return -1; }
+ if(buf_len<=0) { return -1; }
+ if(NULL==output) { return -1; }
+
+ const uint8_t *p = NULL;
+ for(size_t i=0;i<buf_len;i++) {
+ // 0 padded integers are invalid
+ if((1==i)&&(buf[i]=='0')&&(buf_len>3)) { return -1; }
+ if(buf[i]=='e') {
+ p = &(buf[i]);
+ }
+ }
+
+ if(NULL==p) { return -1; }
+
+ ssize_t len = p - (buf+1);
+ uint8_t *num_string = (uint8_t*) strndup((const char*)&(buf[1]),len);
+ *output = atoll((char *)num_string);
+ free(num_string);
+
+ len += 2;
+
+ return len;
+}
+
+ssize_t bdecode_string(const uint8_t *buf, size_t buf_len, uint8_t *output, size_t output_size) {
+ if(NULL==buf) { return -1; }
+ if(buf_len<=0) { return -1; }
+ if(NULL==output) { return -1; }
+
+ const uint8_t *p = NULL;
+ for(size_t i=0;i<buf_len;i++) {
+ if(buf[i]==':') {
+ p = &(buf[i]);
+ break;
+ }
+ }
+
+ if(NULL==p) { return -1; }
+ uint8_t *num_string = (uint8_t*) strndup((const char*)buf,p-buf);
+ int str_len = atoi((char *)num_string);
+ ssize_t len = str_len;
+ free(num_string);
+
+ if((str_len<=0)||(len>output_size)) { return -1; }
+
+ p++;
+ memcpy(output,p,str_len);
+
+ return len;
+}
+
+enum bencode_type bdecode_type(const uint8_t *buf, size_t len) {
+ switch(buf[0]) {
+ case 'i':
+ return BENCODE_INTEGER;
+ case 'l':
+ return BENCODE_LIST;
+ case 'd':
+ return BENCODE_DICTIONARY;
+ default:
+ return BENCODE_STRING;
+ }
+}
--- /dev/null
+#include<bencode.h>
+
+static size_t size_int(int i);
+
+ssize_t bencode_dict_end(uint8_t *output, size_t output_size) {
+ if(NULL==output) { return -1; }
+ if(output_size<=1) { return -1; }
+
+ output[0] = 'e';
+
+ return 1;
+}
+
+ssize_t bencode_dict_start(uint8_t *output, size_t output_size) {
+ if(NULL==output) { return -1; }
+ if(output_size<=1) { return -1; }
+
+ output[0] = 'd';
+
+ return 1;
+}
+
+ssize_t bencode_int(int to_encode, uint8_t *output, size_t output_size) {
+ size_t i;
+ int ret;
+
+ if(NULL==output) { return -1; }
+
+ i = size_int(to_encode);
+ i += 2;
+
+ if((ret = snprintf((char*)output,output_size,"i%de",to_encode))<0) { return -1; }
+ if(ret!=i) { return -1; }
+
+ return i;
+}
+
+ssize_t bencode_list_end(uint8_t *output, size_t output_size) {
+ if(NULL==output) { return -1; }
+ if(output_size<=1) { return -1; }
+
+ output[0] = 'e';
+
+ return 1;
+}
+
+ssize_t bencode_list_start(uint8_t *output, size_t output_size) {
+ if(NULL==output) { return -1; }
+ if(output_size<=1) { return -1; }
+
+ output[0] = 'l';
+
+ return 1;
+}
+
+ssize_t bencode_string(const uint8_t *str, size_t len, uint8_t *output, size_t output_size) {
+ size_t i;
+ int ret;
+
+ if(NULL==str) { return -1; }
+ if(len<=0) { return -1; }
+ if(NULL==output) { return -1; }
+ if(len>output_size) { return -1; }
+
+ i = size_int(len);
+ i++;
+ i += len;
+
+ if((ret = snprintf((char*)output,output_size,"%lu:%s",len,(const char*)str))<0) { return -1; }
+
+ if(ret!=i) { return -1; }
+
+ return i;
+}
+
+
+static size_t size_int(int i) {
+ i = abs(i);
+ size_t j = 0;
+ while(i>0) {
+ i /= 10;
+ j++;
+ }
+ return j;
+}
--- /dev/null
+#include<test_utils.h>
+
+#include<bencode.h>
+
+int main();
+static void bdecode_integer_basic_test();
+static void bdecode_string_basic_test();
+static void bdecode_type_basic_test();
+static void bencode_dict_basic_test();
+static void bencode_list_basic_test();
+static void bencode_string_basic_test();
+
+int main() {
+ setup_env();
+
+ bdecode_integer_basic_test();
+ bdecode_string_basic_test();
+ bdecode_type_basic_test();
+ bencode_dict_basic_test();
+ bencode_list_basic_test();
+ bencode_string_basic_test();
+
+ clean_env();
+
+ return EXIT_SUCCESS;
+}
+
+static void bdecode_integer_basic_test() {
+ uint8_t str1[] = "i10e";
+ uint8_t str2[] = "i0e";
+ uint8_t str3[] = "i0023423e";
+ uint8_t str4[] = "i10928390128301e";
+ long long int i;
+
+ assert(bdecode_integer(NULL,sizeof(str1)-1,&i)==-1);
+ assert(bdecode_integer(str1,0,&i)==-1);
+ assert(bdecode_integer(str1,sizeof(str1)-1,NULL)==-1);
+ assert(bdecode_integer(str1,sizeof(str1)-1,&i)==4);
+ assert(i==10);
+
+ assert(bdecode_integer(str2,sizeof(str2)-1,&i)==3);
+ assert(i==0);
+
+ assert(bdecode_integer(str3,sizeof(str3)-1,&i)==-1);
+
+ assert(bdecode_integer(str4,sizeof(str4)-1,&i)==16);
+ assert(i==10928390128301);
+}
+
+static void bdecode_string_basic_test() {
+ uint8_t buf[1024];
+ uint8_t str1[] = "4:spam";
+
+ assert(bdecode_string(NULL,sizeof(str1)-1,buf,1024)==-1);
+ assert(bdecode_string(str1,0,buf,1024)==-1);
+ assert(bdecode_string(str1,sizeof(str1)-1,NULL,1024)==-1);
+ assert(bdecode_string(str1,sizeof(str1)-1,buf,0)==-1);
+ assert(bdecode_string(str1,sizeof(str1)-1,buf,3)==-1);
+ assert(bdecode_string(str1,sizeof(str1)-1,buf,4)==4);
+ assert(bdecode_string(str1,sizeof(str1)-1,buf,1024)==4);
+}
+
+static void bdecode_type_basic_test() {
+ uint8_t str1[] = "4:spam";
+ uint8_t str2[] = "i12093e";
+ uint8_t str3[] = "l4:spam4:eggse";
+ uint8_t str4[] = "d3:cow3:moo4:spam4:eggse";
+
+ assert(BENCODE_STRING==bdecode_type(str1,sizeof(str1)-1));
+ assert(BENCODE_INTEGER==bdecode_type(str2,sizeof(str2)-1));
+ assert(BENCODE_LIST==bdecode_type(str3,sizeof(str3)-1));
+ assert(BENCODE_DICTIONARY==bdecode_type(str4,sizeof(str4)-1));
+}
+
+static void bencode_dict_basic_test() {
+ uint8_t buf[1024];
+ uint8_t *p;
+
+ memset(buf,0,1024);
+
+ p = buf;
+ assert(bencode_dict_start(NULL,1024)==-1);
+ assert(bencode_dict_start(p,0)==-1);
+ assert(bencode_dict_start(p,1024)==1);
+ p++;
+
+ uint8_t str1[] = "cow";
+ assert(bencode_string(str1,3,p,1023)==5);
+ p += 5;
+
+ uint8_t str2[] = "moo";
+ assert(bencode_string(str2,3,p,1018)==5);
+ p += 5;
+
+ uint8_t str3[] = "spam";
+ assert(bencode_string(str3,4,p,1013)==6);
+ p += 6;
+
+ uint8_t str4[] = "eggs";
+ assert(bencode_string(str4,4,p,1007)==6);
+ p += 6;
+
+ assert(bencode_dict_end(NULL,1001)==-1);
+ assert(bencode_dict_end(p,0)==-1);
+ assert(bencode_dict_end(p,1001)==1);
+
+ assert(memcmp(buf,"d3:cow3:moo4:spam4:eggse",24)==0);
+}
+
+static void bencode_list_basic_test() {
+ uint8_t buf[1024];
+ uint8_t *p;
+
+ memset(buf,0,1024);
+
+ p = buf;
+ assert(bencode_list_start(NULL,1024)==-1);
+ assert(bencode_list_start(p,0)==-1);
+ assert(bencode_list_start(p,1024)==1);
+ p++;
+
+ uint8_t str1[] = "spam";
+ assert(bencode_string(str1,4,p,1023)==6);
+ p += 6;
+
+ uint8_t str2[] = "eggs";
+ assert(bencode_string(str2,4,p,1017)==6);
+ p += 6;
+
+ assert(bencode_list_end(NULL,1011)==-1);
+ assert(bencode_list_end(p,0)==-1);
+ assert(bencode_list_end(p,1011)==1);
+
+ assert(memcmp(buf,"l4:spam4:eggse",14)==0);
+}
+
+static void bencode_string_basic_test() {
+ uint8_t buf[1024];
+
+ memset(buf,0,1024);
+
+ uint8_t str1[] = "testlkajslfkdjasdfl test string";
+ assert(bencode_string(NULL,31,buf,1024)==-1);
+ assert(bencode_string(str1,0,buf,1024)==-1);
+ assert(bencode_string(str1,31,NULL,1024)==-1);
+ assert(bencode_string(str1,31,buf,0)==-1);
+ assert(bencode_string(str1,31,buf,1024)==34);
+
+ assert(memcmp("31:testlkajslfkdjasdfl test string",buf,34)==0);
+}