1 %%%-------------------------------------------------------------------
3 %%% Author : Jesper Louis Andersen <jlouis@succubus>
4 %%% License : See COPYING
5 %%% Description : Functions for handling bcoded values
7 %%% Created : 24 Jan 2007 by Jesper Louis Andersen <jlouis@succubus>
8 %%%-------------------------------------------------------------------
9 -module(etorrent_bcoding
).
10 -author("Jesper Louis Andersen <jesper.louis.andersen@gmail.com>").
14 -export([encode
/1, decode
/1, search_dict
/2, search_dict_default
/3,
17 %%====================================================================
19 %%====================================================================
20 %%--------------------------------------------------------------------
22 %% Description: Encode an erlang term into a String
23 %%--------------------------------------------------------------------
26 {string
, String
} -> encode_string(String
);
27 {integer, Integer
} -> encode_integer(Integer
);
28 {list, Items
} -> encode_list([encode(I
) || I
<- Items
]);
29 {dict
, Items
} -> encode_dict(encode_dict_items(Items
))
32 %%--------------------------------------------------------------------
34 %% Description: Decode a string to an erlang term.
35 %%--------------------------------------------------------------------
37 {Res
, []} = decode_b(String
),
40 %%--------------------------------------------------------------------
41 %% Function: search_dict/1
42 %% Description: Search the dict for a key. Returns the value or crashes.
43 %%--------------------------------------------------------------------
44 search_dict(Key
, {dict
, Elems
}) ->
45 case lists:keysearch(Key
, 1, Elems
) of
52 search_dict_default(Key
, Dict
, Default
) ->
53 case search_dict(Key
, Dict
) of
60 %%--------------------------------------------------------------------
62 %% Description: Parse a file into a Torrent structure.
63 %%--------------------------------------------------------------------
65 {ok
, IODev
} = file:open(File
, [read
]),
66 Data
= read_data(IODev
),
67 ok
= file:close(IODev
),
70 %%====================================================================
72 %%====================================================================
77 lists:concat([L
, ':', Str
]).
79 encode_integer(Int
) ->
80 lists:concat(['i', Int
, 'e']).
83 lists:concat(["l", lists:concat(Items
), "e"]).
86 lists:concat(["d", lists:concat(Items
), "e"]).
88 encode_dict_items([]) ->
90 encode_dict_items([{I1
, I2
} | Rest
]) ->
93 [I
, J
| encode_dict_items(Rest
)].
97 decode_b([H
| Rest
]) ->
100 decode_integer(Rest
);
108 %% This might fail, and so what ;)
109 attempt_string_decode([S
|Rest
])
116 attempt_string_decode(String
) ->
117 {Number
, Data
} = lists:splitwith(charPred($
:), String
),
118 {ParsedNumber
, _
} = string:to_integer(Number
),
120 {StrData
, Rest
} = lists:split(ParsedNumber
, Rest1
),
121 {{string
, StrData
}, Rest
}.
123 decode_integer(String
) ->
124 {IntegerPart
, RestPart
} = lists:splitwith(charPred($e
), String
),
125 {Int
, _
} = string:to_integer(IntegerPart
),
126 {{integer, Int
}, tl(RestPart
)}.
128 decode_list(String
) ->
129 {ItemTree
, Rest
} = decode_list_items(String
, []),
130 {{list, ItemTree
}, Rest
}.
132 decode_list_items([], Accum
) -> {lists:reverse(Accum
), []};
133 decode_list_items(Items
, Accum
) ->
134 case decode_b(Items
) of
135 {end_of_data
, Rest
} ->
136 {lists:reverse(Accum
), Rest
};
137 {I
, Rest
} -> decode_list_items(Rest
, [I
| Accum
])
140 decode_dict(String
) ->
141 {Items
, Rest
} = decode_dict_items(String
, []),
142 {{dict
, lists:reverse(Items
)}, Rest
}.
144 decode_dict_items([], Accum
) ->
146 decode_dict_items(String
, Accum
) ->
147 case decode_b(String
) of
148 {end_of_data
, Rest
} ->
150 {Key
, Rest1
} -> {Value
, Rest2
} = decode_b(Rest1
),
151 decode_dict_items(Rest2
, [{Key
, Value
} | Accum
])
155 eat_lines(IODev
, []).
157 eat_lines(IODev
, Accum
) ->
158 case io:get_chars(IODev
, ">", 8192) of
160 lists:concat(lists:reverse(Accum
));
162 eat_lines(IODev
, [String
| Accum
])