summaryrefslogtreecommitdiff
path: root/bencode.erl
blob: a992b0c316eebf307bf7ac322f58758972e34345 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

-module(bencode).

-export([bdecode/1, bencode/1]).

-import(string, [substr/2, substr/3, to_integer/1, chr/2]).

%% %% %% %% %% %% %% %% Decoding %% %% %% %% %% %% %% %%

keyenc(Key) when is_list(Key) ->
    bencode({string, Key});
keyenc(Key) when is_atom(Key) ->
    bencode({string, atom_to_list(Key)});
keyenc({string, _} = Key) ->
    bencode(Key).


bencode({int, Val}) ->
    "i" ++ integer_to_list(Val) ++ "e";

bencode({string, Val}) ->
    integer_to_list(length(Val)) ++ ":" ++ Val;

bencode({list, Val}) ->
    "l" ++ lists:flatten(lists:map(fun bencode/1, Val)) ++ "e";

bencode({dict, Dict}) ->
    SFun = fun({Key1, _}, {Key2, _}) ->
		   Key1 < Key2
	   end,
    List = lists:sort(SFun, dict:to_list(Dict)),
    MFun = fun({Key, Val}) ->
		   keyenc(Key) ++ bencode(Val)
	   end,
    "d" ++ lists:flatten(lists:map(MFun, List)) ++ "e".


%% %% %% %% %% %% %% %% Decoding %% %% %% %% %% %% %% %%

%% 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} = declist(Rest),
    {{list, List}, Rem};

%% Dict
bdecode([Char | Rest]) when Char == $d ->
    {Dict, Rem} = decdict(Rest),
    {{dict, Dict}, Rem}.


declist(Str) ->
    declist(Str, []).

declist([Char | Rest], List) when Char == $e ->
    {List, Rest};

declist(Str, List) ->
    {Result, Rest} = bdecode(Str),
    declist(Rest, lists:append(List, [Result])).


decdict(Str) ->
    decdict(Str, dict:new()).

decdict([Char | Rest], Dict) when Char == $e ->
    {Dict, Rest};

decdict(Str, Dict) ->
    {{string, Key}, Rest} = bdecode(Str),
    {Val, Rest2} = bdecode(Rest),
    decdict(Rest2, dict:store(Key, Val, Dict)).