-- Thanks to prec in #lua for the majority of this.
-- Reference:
-- http://wiki.theory.org/BitTorrentSpecification#bencoding
local type_decoder
local function decode(s, pos)
pos = pos or 1
local dd = type_decoder[s:sub(pos,pos)]
if not dd then
error(string.format("encoding error at position %d: >>%s[...]<<",
pos, s:sub(pos, pos + 10)))
end
return dd(s, pos)
end
local function decode_integer(s, pos)
local _, pos, n = assert(s:find("^i(-?%d+)e", pos))
return tonumber(n), pos+1 --rest
end
local function decode_string(s, pos)
local _, pos, len = assert(s:find("^(%d+):", pos))
return s:sub(pos + 1, pos + len), pos + len + 1
end
local function decode_list(s, pos)
local l = {}
--local _, pos = assert(s:find("^l.", pos))
pos = pos+1
l["__begpos"] = pos-1
while not s:match("^e", pos) do
l[#l + 1], pos = decode(s, pos)
end
_, pos = assert(s:find("^e", pos))
l["__endpos"] = pos
return l, pos
end
local function decode_dict(s, pos)
local d = {}
local _, pos = assert(s:find("^d.", pos))
d["__begpos"] = pos-1
while not s:match("^e", pos) do
local k
k, pos = decode(s, pos)
assert(type(k) == "string")
d[k], pos = decode(s, pos)
end
_, pos = assert(s:find("^e", pos))
d["__endpos"] = pos
return d, pos
end
local function encode_dict(data)
local dict = "d"
for k,v in pairs(data) do
v = tonumber(v) or v -- is this required; can a string be a number?
if(type(v) == "number") then
dict = dict..#k..':'..k..'i'..v..'e'
elseif(type(v) == "string") then
dict = dict..#k..':'..k..#v..':'..v
end
end
dict = dict .. 'e'
return dict
end
type_decoder = {
i = decode_integer, l = decode_list, d = decode_dict,
["0"] = decode_string, ["1"] = decode_string,
["2"] = decode_string, ["3"] = decode_string,
["4"] = decode_string, ["5"] = decode_string,
["6"] = decode_string, ["7"] = decode_string,
["8"] = decode_string, ["9"] = decode_string,
}
debencode = decode