| package com.pt.utils; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.*; |
| |
| public class BdecodeUtils { |
| public static Object decode(byte[] data) throws IOException { |
| try (ByteArrayInputStream in = new ByteArrayInputStream(data)) { |
| return decodeNext(in); |
| } |
| } |
| |
| private static Object decodeNext(InputStream in) throws IOException { |
| int prefix = in.read(); |
| if (prefix == -1) { |
| throw new IOException("Unexpected end of stream"); |
| } |
| |
| if (prefix >= '0' && prefix <= '9') { |
| // 字符串,回退一个字节给parseString处理 |
| in.reset(); |
| return parseString(in, prefix); |
| } else if (prefix == 'i') { |
| return parseInteger(in); |
| } else if (prefix == 'l') { |
| return parseList(in); |
| } else if (prefix == 'd') { |
| return parseDict(in); |
| } else { |
| throw new IOException("Invalid bencode prefix: " + (char) prefix); |
| } |
| } |
| |
| private static String parseString(InputStream in, int firstDigit) throws IOException { |
| // 读长度前缀 |
| StringBuilder lenStr = new StringBuilder(); |
| lenStr.append((char) firstDigit); |
| int b; |
| while ((b = in.read()) != -1 && b != ':') { |
| lenStr.append((char) b); |
| } |
| int length = Integer.parseInt(lenStr.toString()); |
| |
| // 读内容 |
| byte[] buf = new byte[length]; |
| int read = in.read(buf); |
| if (read < length) throw new IOException("Unexpected end of stream reading string"); |
| return new String(buf); |
| } |
| |
| private static long parseInteger(InputStream in) throws IOException { |
| StringBuilder intStr = new StringBuilder(); |
| int b; |
| while ((b = in.read()) != -1 && b != 'e') { |
| intStr.append((char) b); |
| } |
| return Long.parseLong(intStr.toString()); |
| } |
| |
| private static List<Object> parseList(InputStream in) throws IOException { |
| List<Object> list = new ArrayList<>(); |
| int b; |
| while ((b = in.read()) != 'e') { |
| in.reset(); |
| list.add(decodeNext(in)); |
| } |
| return list; |
| } |
| |
| private static Map<String, Object> parseDict(InputStream in) throws IOException { |
| Map<String, Object> map = new LinkedHashMap<>(); |
| int b; |
| while ((b = in.read()) != 'e') { |
| in.reset(); |
| String key = (String) decodeNext(in); |
| Object value = decodeNext(in); |
| map.put(key, value); |
| } |
| return map; |
| } |
| } |
| |