字符串被如此编码:<字符串长度>:字符串正文.这种表示法没有任何的分界符.
例子:如"8:announce"指"announce".
整数:
整数被如此编码:<i>整数值<e>.可以为负数,如'i-3e'
例子:'i3e' 指 3.
列表:
列表是如此被表示的:<l>Bencode Value<e>,
列表可以用来表示多个对象.
列表内容可以包括字符串,整数,字典,甚至列表本身.
例子:'l4:spam4:eggse' 指 [ "spam", eggs" ]
字典:
字典是一个一对一的映射.它表示了一个主键(必须为字符串)和一个数据项(可以为任何Bencode值)的关系.字典可以用来表示一个对象的多种属性.
字典是如此被编码:<d><bencoded string><bencoded element><e>
注意:字典必须根据主键预排序.
package com.norkts.torrents; import java.io.*; import java.nio.ByteBuffer; import java.util.*; /** * bencode解码实现 * @author norkts<[email protected]> * @date 2017-06-21 * @version 1.0 */ public class BencodeDecoder { public static Object decode(byte[] data){ ByteBuffer buffer = ByteBuffer.wrap(data); return decode(buffer); } public static Object decode(ByteBuffer buffer){ Stack<Object> endStack = new Stack<Object>(); while (buffer.hasRemaining()){ byte ch = buffer.get(); if(ch >= '0' & ch <= '9'){ buffer.position(buffer.position() - 1); //string byte[] lenByte = readUntil(buffer, ':'); int len = Integer.parseInt(new String(lenByte)); lenByte = new byte[len]; buffer.get(lenByte); String str = new String(lenByte); if(endStack.empty()){ endStack.push(new LinkedList<Object>()); } setStackVal(endStack, str); //继续执行下一次 continue; } if(ch == 'i'){ //字符串处理 byte[] temp = readUntil(buffer, 'e'); Long val = Long.parseLong(new String(temp)); if(endStack.empty()){ endStack.push(new LinkedList<Object>()); } setStackVal(endStack, val); continue; } if(ch == 'l'){ //列表处理 endStack.push(new LinkedList<Object>()); continue; } if(ch == 'd'){ //字典类型开始解码 endStack.push(new LinkedHashMap<Object, Object>()); continue; } if(ch == 'e'){ Object last = endStack.pop(); if(endStack.empty()){ return last; } setStackVal(endStack, last); } } return endStack.empty() ? null : endStack.pop(); } private static byte[] readUntil(ByteBuffer buff, char end){ ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true){ byte ch = buff.get(); if(ch == end){ break; } baos.write(ch); } return baos.toByteArray(); } private static void setStackVal(Stack<Object> stack, Object val){ Object prev = stack.peek(); if(prev instanceof List){ ((List)prev).add(val); }else if(prev instanceof Map){ Pair<Object, Object> entry = new Pair<Object, Object>(val, null); stack.push(entry); }else if(prev instanceof Pair){ Pair<Object, Object> entry = (Pair<Object, Object>)stack.pop(); entry.setVal(val); prev = stack.peek(); ((Map<Object, Object>)prev).put(entry.getKey(), entry.getVal()); } } static class Pair<K,V>{ private K key; private V val; public Pair(K k, V v){ this.key = k; this.val = v; } public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getVal() { return val; } public void setVal(V val) { this.val = val; } } public static void main(String[] argv){ /* Object obj = BencodeDecoder.decode("l:3:abci45678el:3:xxxi123ed3:key3:val4:name5:zhangeee".getBytes()); System.out.println(obj); obj = BencodeDecoder.decode("d3:key3:val4:name5:zhang3:mapd3:key3:vali123e4:xxxxee".getBytes()); System.out.println(obj);*/ try { File f = new File("Q:\\study\\torrents\\0000405710f78d75c5d1dd9cc69ffdd7d1561bb1.torrent"); FileInputStream inputStream = new FileInputStream(f); ByteBuffer buff = ByteBuffer.allocate((int)f.length()); inputStream.getChannel().read(buff); inputStream.close(); buff.flip(); Object o = BencodeDecoder.decode(buff); System.out.println(o); System.out.println((((Map<String, Object>)((Map<String, Object>)o).get("info"))).keySet()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }