Methods Summary |
---|
public static java.util.Map | decode(byte[] data)
return( new BDecoder().decodeByteArray( data ));
|
public static java.util.Map | decode(java.io.BufferedInputStream is)
return( new BDecoder().decodeStream( is ));
|
private java.util.Map | decode(java.io.ByteArrayInputStream data)
Object res = decodeInputStream(data, 0);
if ( res == null ){
throw( new BEncodingException( "BDecoder: zero length file" ));
}else if ( !(res instanceof Map )){
throw( new BEncodingException( "BDecoder: top level isn't a Map" ));
}
return((Map)res );
|
public java.util.Map | decodeByteArray(byte[] data)
return( decode(new ByteArrayInputStream(data)));
|
private java.lang.Object | decodeInputStream(java.io.InputStream bais, int nesting)
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);
// keys often repeat a lot - intern to save space
String key = StringInterner.intern( tempByteArray );
if ( key == null ){
CharBuffer cb = Constants.BYTE_CHARSET.decode(ByteBuffer.wrap(tempByteArray));
key = new String(cb.array(),0,cb.limit());
key = StringInterner.intern( key );
}
tempMap.put( key, value);
}
bais.mark(Integer.MAX_VALUE);
tempByte = bais.read();
bais.reset();
if ( nesting > 0 && tempByte == -1 ){
throw( new BEncodingException( "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( Debug.getNestedExceptionMessage(e)));
}
}
//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 BEncodingException( "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( Debug.getNestedExceptionMessage(e)));
}
}
//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 BEncodingException(
"BDecoder: unknown command '" + tempByte + ", remainder = " + new String( rem_data )));
}
}
|
public java.util.Map | decodeStream(java.io.BufferedInputStream data)
Object res = decodeInputStream(data, 0);
if ( res == null ){
throw( new BEncodingException( "BDecoder: zero length file" ));
}else if ( !(res instanceof Map )){
throw( new BEncodingException( "BDecoder: top level isn't a Map" ));
}
return((Map)res );
|
public static java.util.Map | decodeStrings(java.util.Map map)Converts any byte[] entries into UTF-8 strings
if (map == null ){
return( null );
}
Iterator it = map.entrySet().iterator();
while( it.hasNext()){
Map.Entry entry = (Map.Entry)it.next();
Object value = entry.getValue();
if ( value instanceof byte[]){
try{
entry.setValue( new String((byte[])value,"UTF-8" ));
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}else if ( value instanceof Map ){
decodeStrings((Map)value );
}else if ( value instanceof List ){
decodeStrings((List)value );
}
}
return( map );
|
public static java.util.List | decodeStrings(java.util.List list)
if ( list == null ){
return( null );
}
for (int i=0;i<list.size();i++){
Object value = list.get(i);
if ( value instanceof byte[]){
try{
String str = new String((byte[])value, "UTF-8" );
list.set( i, str );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}else if ( value instanceof Map ){
decodeStrings((Map)value );
}else if ( value instanceof List ){
decodeStrings((List)value );
}
}
return( list );
|
private byte[] | getByteArrayFromStream(java.io.InputStream bais)
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;
|
private long | getNumberFromStream(java.io.InputStream bais, char parseChar)
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;
}
String str = sb.toString();
// support some borked impls that sometimes don't bother encoding anything
if ( str.length() == 0 ){
return( 0 );
}
return Long.parseLong(str);
|
public static void | main(java.lang.String[] args)
print( new File( "C:\\Temp\\xxx.torrent" ),
new File( "C:\\Temp\\xxx.txt" ));
|
private void | print(java.io.PrintWriter writer, java.lang.Object obj)
print( writer, obj, "", false );
|
private void | print(java.io.PrintWriter writer, java.lang.Object obj, java.lang.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 + " { "+ ByteFormatter.nicePrint( b )+ " }" );
}else if ( b.length < 64 ){
writer.println( new String(b) );
}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(java.io.File f, java.io.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 ){
e.printStackTrace();
}
|
public void | setRecoveryMode(boolean r)
recovery_mode = r;
|