-- 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