bt解析 开源 java_解析torrent种子信息

package kan;

/*

* BeDecoder.java

*

* Created on May 30, 2003, 2:44 PM

* Copyright (C) 2003, 2004, 2005, 2006 Aelitis, All Rights Reserved.

*

* This program is free software; you can redistribute it and/or

* modify it under the terms of the GNU General Public License

* as published by the Free Software Foundation; either version 2

* of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*

* AELITIS, SAS au capital de 46,603.30 euros

* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.

*/

import java.io.BufferedInputStream;

import java.io.ByteArrayInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.PrintWriter;

import java.nio.ByteBuffer;

import java.nio.CharBuffer;

import java.nio.charset.Charset;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

/**

* A set of utility methods to decode a bencoded array of byte into a Map.

* integer are represented as Long, String as byte[], dictionnaries as Map, and

* list as List.

*

* @author TdC_VgA

*

*/

@SuppressWarnings(value={"rawtypes", "unchecked", "unused"})

public class BDecoder {

public static Charset BYTE_CHARSET = Charset.forName("UTF-8");;

public static Charset DEFAULT_CHARSET = Charset.forName("UTF-8");;

private boolean recovery_mode;

public static Map decode(byte[] data) throws IOException {

return (new BDecoder().decodeByteArray(data));

}

public static Map decode(BufferedInputStream is) throws IOException {

return (new BDecoder().decodeStream(is));

}

public BDecoder() { }

public Map decodeByteArray(byte[] data) throws IOException {

return (decode(new ByteArrayInputStream(data)));

}

public Map decodeStream(BufferedInputStream data) throws IOException {

Object res = decodeInputStream(data, 0);

if (res == null) {

throw (new IOException("BDecoder: zero length file"));

} else if (!(res instanceof Map)) {

throw (new IOException("BDecoder: top level isn't a Map"));

}

return ((Map) res);

}

private Map decode(ByteArrayInputStream data) throws IOException {

Object res = decodeInputStream(data, 0);

if (res == null) {

throw (new IOException("BDecoder: zero length file"));

} else if (!(res instanceof Map)) {

throw (new IOException("BDecoder: top level isn't a Map"));

}

return ((Map) res);

}

private Object decodeInputStream(InputStream bais, int nesting)

throws IOException {

if (nesting == 0 && !bais.markSupported()) {

throw new IOException("InputStream must support the mark() method");

}

// set a mark

bais.mark(Integer.MAX_VALUE);

// read a byte

int tempByte = bais.read();

// decide what to do

switch (tempByte) {

case 'd':

// create a new dictionary object

Map tempMap = new HashMap();

try {

// get the key

byte[] tempByteArray = null;

while ((tempByteArray =

(byte[]) decodeInputStream(bais,nesting + 1)) != null) {

// decode some more

Object value = decodeInputStream(bais, nesting + 1);

// add the value to the map

CharBuffer cb =

BYTE_CHARSET.decode(ByteBuffer.wrap(tempByteArray));

String key = new String(cb.array(), 0, cb.limit());

tempMap.put(key, value);

}

bais.mark(Integer.MAX_VALUE);

tempByte = bais.read();

bais.reset();

if (nesting > 0 && tempByte == -1) {

throw (new IOException(

"BDecoder: invalid input data, 'e' missing from end of dictionary"));

}

} catch (Throwable e) {

if (!recovery_mode) {

if (e instanceof IOException) {

throw ((IOException) e);

}

throw (new IOException(e.toString()));

}

}

// return the map

return tempMap;

case 'l':

// create the list

List tempList = new ArrayList();

try {

// create the key

Object tempElement = null;

while ((tempElement = decodeInputStream(bais, nesting + 1)) != null) {

// add the element

tempList.add(tempElement);

}

bais.mark(Integer.MAX_VALUE);

tempByte = bais.read();

bais.reset();

if (nesting > 0 && tempByte == -1) {

throw (new IOException(

"BDecoder: invalid input data, 'e' missing from end of list"));

}

} catch (Throwable e) {

if (!recovery_mode) {

if (e instanceof IOException) {

throw ((IOException) e);

}

throw (new IOException(e.toString()));

}

}

// return the list

return tempList;

case 'e':

case -1:

return null;

case 'i':

return new Long(getNumberFromStream(bais, 'e'));

case '0':

case '1':

case '2':

case '3':

case '4':

case '5':

case '6':

case '7':

case '8':

case '9':

// move back one

bais.reset();

// get the string

return getByteArrayFromStream(bais);

default: {

int rem_len = bais.available();

if (rem_len > 256) {

rem_len = 256;

}

byte[] rem_data = new byte[rem_len];

bais.read(rem_data);

throw (new IOException("BDecoder: unknown command '" + tempByte

+ ", remainder = " + new String(rem_data, DEFAULT_CHARSET)));

}

}

}

private long getNumberFromStream(

InputStream bais, char parseChar)throws IOException {

StringBuffer sb = new StringBuffer(3);

int tempByte = bais.read();

while ((tempByte != parseChar) && (tempByte >= 0)) {

sb.append((char) tempByte);

tempByte = bais.read();

}

// are we at the end of the stream?

if (tempByte < 0) {

return -1;

}

return Long.parseLong(sb.toString());

}

// This one causes lots of "Query Information" calls to the filesystem

private long getNumberFromStreamOld(

InputStream bais, char parseChar) throws IOException {

int length = 0;

// place a mark

bais.mark(Integer.MAX_VALUE);

int tempByte = bais.read();

while ((tempByte != parseChar) && (tempByte >= 0)) {

tempByte = bais.read();

length++;

}

// are we at the end of the stream?

if (tempByte < 0) {

return -1;

}

// reset the mark

bais.reset();

// get the length

byte[] tempArray = new byte[length];

int count = 0;

int len = 0;

// get the string

while (count != length

&& (len = bais.read(tempArray, count, length - count)) > 0) {

count += len;

}

// jump ahead in the stream to compensate for the :

bais.skip(1);

// return the value

CharBuffer cb =

DEFAULT_CHARSET.decode(ByteBuffer.wrap(tempArray));

String str_value = new String(cb.array(), 0, cb.limit());

return Long.parseLong(str_value);

}

private byte[] getByteArrayFromStream(

InputStream bais) throws IOException {

int length = (int) getNumberFromStream(bais, ':');

if (length < 0) {

return null;

}

// note that torrent hashes can be big (consider a 55GB file with 2MB

// pieces

// this generates a pieces hash of 1/2 meg

if (length > 8 * 1024 * 1024) {

throw new IOException("Byte array length too large (" + length + ")");

}

byte[] tempArray = new byte[length];

int count = 0;

int len = 0;

// get the string

while (count != length

&& (len = bais.read(tempArray, count, length - count)) > 0) {

count += len;

}

if (count != tempArray.length) {

throw (new IOException(

"BDecoder::getByteArrayFromStream: truncated"));

}

return tempArray;

}

public void setRecoveryMode(boolean r) {

recovery_mode = r;

}

private void print(PrintWriter writer, Object obj) {

print(writer, obj, "", false);

}

private void print(

PrintWriter writer, Object obj, String indent, boolean skip_indent) {

String use_indent = skip_indent ? "" : indent;

if (obj instanceof Long) {

writer.println(use_indent + obj);

} else if (obj instanceof byte[]) {

byte[] b = (byte[]) obj;

if (b.length == 20) {

writer.println(use_indent + " { " + b + " }");

} else if (b.length < 64) {

writer.println(new String(b, DEFAULT_CHARSET));

} else {

writer.println("[byte array length " + b.length);

}

} else if (obj instanceof String) {

writer.println(use_indent + obj);

} else if (obj instanceof List) {

List l = (List) obj;

writer.println(use_indent + "[");

for (int i = 0; i < l.size(); i++) {

writer.print(indent + " (" + i + ") ");

print(writer, l.get(i), indent + " ", true);

}

writer.println(indent + "]");

} else {

Map m = (Map) obj;

Iterator it = m.keySet().iterator();

while (it.hasNext()) {

String key = (String) it.next();

if (key.length() > 256) {

writer.print(indent + key.substring(0, 256) + "... = ");

} else {

writer.print(indent + key + " = ");

}

print(writer, m.get(key), indent + " ", true);

}

}

}

private static void print(File f, File output) {

try {

BDecoder decoder = new BDecoder();

decoder.setRecoveryMode(false);

PrintWriter pw = new PrintWriter(new FileWriter(output));

decoder.print(pw,

decoder.decodeStream(

new BufferedInputStream(new FileInputStream(f))));

pw.flush();

} catch (Throwable e) {

}

}

public static void main(String[] args) {

//print(new File(

//"C:\\Temp\\8565658FA6C187A602A5360A69F11933624DD9B5.dat.bak"),

//new File("C:\\Temp\\bdecoder.log"));

//print(new File("D:/Users/Desktop/WorkSpace/torrent/1.torrent"), new File("D:/Users/kanlianhui689/Desktop/WorkSpace/torrent/1.text"));

print(new File("D:/Users/Desktop/WorkSpace/torrent/1.torrent"), new File("D:/Users/kanlianhui689/Desktop/WorkSpace/torrent/1.text"));

}

}


版权声明:本文为weixin_42277672原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。