diff options
| author | ssmith | 2006-05-07 20:22:22 -0700 |
|---|---|---|
| committer | ssmith | 2006-05-07 20:22:22 -0700 |
| commit | be5e8817ca5570b66f57f2d56148c88ae73a8531 (patch) | |
| tree | 52119c8c318044871e3063930d9bbdb84e87b415 | |
Initial version of bencode module.
| -rw-r--r-- | Makefile | 19 | ||||
| -rw-r--r-- | bencode.erl | 55 | ||||
| -rw-r--r-- | tests.erl | 50 |
3 files changed, 124 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7e34b06 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ + +EUNITPATH=/home/ssmith/software/eunit-1.1 + +ERLC=erlc +ERLFLAGS=-I$(EUNITPATH)/inc + +SRC=bencode.erl tests.erl +BEAM=$(SRC:.erl=.beam) + +all: $(BEAM) + +%.beam : %.erl + $(ERLC) $(ERLFLAGS) $< + +test: $(BEAM) + erl -noshell -pa $(EUNITPATH)/ebin -s tests -s init stop + +clean: + rm -f $(BEAM) *~ diff --git a/bencode.erl b/bencode.erl new file mode 100644 index 0000000..aaf737e --- /dev/null +++ b/bencode.erl @@ -0,0 +1,55 @@ + +-module(bencode). + +-export([bdecode/1]). + +-import(string, [substr/2, substr/3, to_integer/1, chr/2]). + +%% String +bdecode([Char | _Rest] = Str) when Char >= $0, Char =< $9 -> + ColIdx = chr(Str, $:), + IntStr = substr(Str, 1, ColIdx-1), + {Len, _} = to_integer(IntStr), + Result = substr(Str, ColIdx+1, Len), + Rest = substr(Str, ColIdx+Len+1), + {{string, Result}, Rest}; + +%% Int +bdecode([Char | Rest]) when Char == $i -> + End = chr(Rest, $e), + {Result, _} = to_integer(substr(Rest, 1, End-1)), + {{int, Result}, substr(Rest, End+1)}; + +%% List +bdecode([Char | Rest]) when Char == $l -> + {List, Rem} = dolist(Rest), + {{list, List}, Rem}; + +%% Dict +bdecode([Char | Rest]) when Char == $d -> + {Dict, Rem} = dodict(Rest), + {{dict, Dict}, Rem}. + + +dolist(Str) -> + dolist(Str, []). + +dolist([Char | Rest], List) when Char == $e -> + {List, Rest}; + +dolist(Str, List) -> + {Result, Rest} = bdecode(Str), + dolist(Rest, lists:append(List, [Result])). + + +dodict(Str) -> + dodict(Str, dict:new()). + +dodict([Char | Rest], Dict) when Char == $e -> + {Dict, Rest}; + +dodict(Str, Dict) -> + {{string, Key}, Rest} = bdecode(Str), + {Val, Rest2} = bdecode(Rest), + dodict(Rest2, dict:store(Key, Val, Dict)). + diff --git a/tests.erl b/tests.erl new file mode 100644 index 0000000..92f5646 --- /dev/null +++ b/tests.erl @@ -0,0 +1,50 @@ + +-module(tests). + +-include("eunit.hrl"). + +-export([start/0, + test_int1/0, test_int2/0, test_int3/0, test_int4/0, + test_string1/0, test_string2/0, + test_list1/0, test_list2/0, test_list3/0, test_list4/0, test_list5/0, + test_dict1/0]). + +%% Integer decoding tests +test_int1() -> + ?match({{int, 999}, []}, bencode:bdecode("i999e")). +test_int2() -> + ?match({{int, 0}, []}, bencode:bdecode("i0e")). +test_int3() -> + ?match({{int, 123}, "abc"}, bencode:bdecode("i123eabc")). +test_int4() -> + ?match({{int, -10}, []}, bencode:bdecode("i-10e")). + +%% String decoding tests +test_string1() -> + ?match({{string, ""}, []}, bencode:bdecode("0:")). +test_string2() -> + ?match({{string, "abcde"}, []}, bencode:bdecode("5:abcde")). + +%% List decoding tests +test_list1() -> + ?match({{list, []}, []}, bencode:bdecode("le")). +test_list2() -> + ?match({{list, [{int,1}]}, []}, bencode:bdecode("li1ee")). +test_list3() -> + ?match({{list, [{int,1}]}, []}, bencode:bdecode("li1ee")). +test_list4() -> + ?match({{list, [{int,1}, {int,2}]}, []}, bencode:bdecode("li1ei2ee")). +test_list5() -> + ?match({{list, [{int,1}, + {list, [{int, 2}, {int, 3}]}]}, + []}, + bencode:bdecode("li1eli2ei3eee")). + +%% Dict decoding tests +test_dict1() -> + {{dict, Dict}, []} = bencode:bdecode("d3:agei25e4:eyes4:bluee"), + ?match([{"age", {int, 25}}, {"eyes", {string, "blue"}}], dict:to_list(Dict)). + +%% Entry point +start() -> + eunit:run([tests], {prefix, "test_"}). |
