/******************************************************************************
* Copyright (c) 2006 Remy Suen
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0, which
* accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html, and also the MIT license, which
* also accompanies this distribution. This dual licensing scheme allows a
* developer to choose either license for use when developing applications with
* this code.
*
* Contributors:
* Remy Suen <remy.suen@gmail.com> - initial API and implementation
******************************************************************************/
package org.eclipse.bittorrent.internal.encode;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
public final class Decode {
/**
* Reads four bytes in succesion within the specified byte array and return
* the corresponding integer value.
*
* @param bytes
* the byte array with the four bytes to decode
* @param index
* the starting index of the four-byte value
* @return the integer that is encoded within the four bytes of the array
*/
public static int decodeFourByteNumber(byte[] bytes, int index) {
return (bytes[index] & 0xff) * 16777216 + (bytes[index + 1] & 0xff)
* 65536 + (bytes[index + 2] & 0xff) * 256
+ (bytes[index + 3] & 0xff);
}
public static int decodeSignedByte(int num) {
num = num & 0xff;
if (num < 128) {
return num + 127;
}
String str = Integer.toString(num, 2);
char[] array = new char[8];
for (int j = 0; j < str.length(); j++) {
array[j] = str.charAt(7 - j);
}
return Integer.parseInt(new String(array), 2);
}
private static String getInteger(String input) {
return input.substring(1, input.indexOf('e'));
}
private static String getString(String input) {
int index = input.indexOf(':') + 1;
int length = Integer.parseInt(input.substring(0, index - 1));
return input.substring(index, index + length);
}
private static List getList(String string) {
List list = new ArrayList() {
private static final long serialVersionUID = 1093559083643494037L;
public String toString() {
StringBuffer buffer = new StringBuffer();
synchronized (buffer) {
buffer.append('l');
for (int i = 0; i < size(); i++) {
Object obj = get(i);
if (obj instanceof String) {
String string = (String) obj;
buffer.append(string.length()).append(':').append(
string);
} else if (obj instanceof Long) {
buffer.append('i' + String.valueOf(obj) + 'e');
} else if (obj instanceof List
|| obj instanceof BEncodedDictionary) {
buffer.append(obj.toString());
}
}
buffer.append('e');
}
return buffer.toString();
}
};
char ch = string.charAt(0);
while (ch != 'e') {
if (Character.isDigit(ch)) {
if (ch == '0') {
list.add(""); //$NON-NLS-1$
string = string.substring(2);
} else {
String value = getString(string);
string = string.substring(string.indexOf(value)
+ value.length());
list.add(value);
}
} else if (ch == 'd') {
BEncodedDictionary dictionary = parse(string.substring(1));
list.add(dictionary);
String value = dictionary.toString();
string = string.substring(value.length());
} else if (ch == 'l') {
List aList = getList(string.substring(1));
list.add(aList);
string = string.substring(aList.toString().length());
} else if (ch == 'i') {
String value = getInteger(string);
string = string.substring(value.length() + 2);
list.add(new Long(value));
}
ch = string.charAt(0);
}
return list;
}
private static String parse(String string, BEncodedDictionary dictionary) {
String key = getString(string);
string = string.substring(string.indexOf(key) + key.length());
char ch = string.charAt(0);
if (Character.isDigit(ch)) {
if (ch == '0') {
dictionary.put(key, ""); //$NON-NLS-1$
string = string.substring(2);
} else {
String value = getString(string);
string = string.substring(string.indexOf(value)
+ value.length());
dictionary.put(key, value);
}
} else if (ch == 'd') {
BEncodedDictionary aDictionary = parse(string.substring(1));
dictionary.put(key, aDictionary);
string = string.substring(aDictionary.toString().length());
} else if (ch == 'l') {
List list = getList(string.substring(1));
dictionary.put(key, list);
string = string.substring(list.toString().length());
} else if (ch == 'i') {
String value = getInteger(string);
string = string.substring(value.length() + 2);
dictionary.put(key, new Long(value));
}
return string;
}
private static BEncodedDictionary parse(String string) {
BEncodedDictionary dictionary = new BEncodedDictionary();
while (string.charAt(0) != 'e') {
string = parse(string, dictionary);
}
return dictionary;
}
public static BEncodedDictionary bDecode(String string) {
if (string.charAt(0) != 'd') {
throw new IllegalArgumentException("The string must begin with a "
+ "dictionary");
}
return parse(string.substring(1));
}
public static BEncodedDictionary bDecode(InputStream inputStream)
throws IOException {
return bDecode(read(new BufferedReader(new InputStreamReader(
inputStream, "ISO-8859-1")))); //$NON-NLS-1$
}
private static String read(Reader reader) throws IOException {
StringBuffer buffer = new StringBuffer();
int ch = reader.read();
synchronized (buffer) {
while (ch != -1) {
buffer.append((char) ch);
ch = reader.read();
}
}
reader.close();
return buffer.toString();
}
/**
* Private constructor to prevent instantiation.
*/
private Decode() {
// do nothing
}
}