blob: c77f8b45f34d87eb0aa7b3177556f03c4f9ce106 [file] [log] [blame]
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;
}
}