diff --git a/src/zutil/FileFinder.java b/src/zutil/FileFinder.java index 3c0ec445..6e127b36 100644 --- a/src/zutil/FileFinder.java +++ b/src/zutil/FileFinder.java @@ -1,6 +1,9 @@ package zutil; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; @@ -52,6 +55,28 @@ public class FileFinder { return null; } + + /** + * Reads and returns the content of a file as a String. + * Or use FileUtils.readFileToString(file); + * + * @param file The file to read + * @return The file content + * @throws IOException + */ + public static String getFileContent(File file) throws IOException{ + BufferedReader in = new BufferedReader(new FileReader(file)); + StringBuffer ret = new StringBuffer(); + int tmp; + + while((tmp=in.read()) != -1){ + ret.append((char)tmp); + } + + in.close(); + return ret.toString(); + } + /** * Returns the URL to the given file * diff --git a/src/zutil/network/torrent/Torrent.java b/src/zutil/network/torrent/Torrent.java new file mode 100644 index 00000000..7c9a2036 --- /dev/null +++ b/src/zutil/network/torrent/Torrent.java @@ -0,0 +1,68 @@ +package zutil.network.torrent; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +import zutil.FileFinder; + +public class Torrent { + // Name of the torrent + private String name; + // Comment + private String comment; + // Creation date as unix timestamp + private long date; + // Files in the torrent + private ArrayList file_list; + // Size of of the full torrent (after download) + private long size; + // Signature of the software which created the torrent + private String created_by; + // tracker (the tracker the torrent has been received from) + private String main_tracker; + // List of known trackers for the torrent + private ArrayList tracker_list; + private HashMap info_hash; + // Torrent is marked as 'private'. + private boolean is_private; + + public Torrent(File torrent) throws IOException{ + this(FileFinder.getFileContent(FileFinder.find("C:\\Users\\Ziver\\Desktop\\test.torrent"))); + } + + public Torrent(String data){ + reset(); + decode(data); + } + + private void reset(){ + // Reset + name = ""; + comment = ""; + date = 0; + file_list = new ArrayList(); + size = 0; + created_by = ""; + main_tracker = ""; + tracker_list = new ArrayList(); + info_hash = new HashMap(); + is_private = false; + } + + private void decode(String data){ + HashMap dataMap = (HashMap)TorrentParser.decode(data); + + name = (String)dataMap.get("name"); + comment = (String)dataMap.get("comment"); + date = (Long)dataMap.get("creation date"); + file_list = new ArrayList(); + size = (Long)dataMap.get("length"); + created_by = (String)dataMap.get("created by"); + main_tracker = (String)dataMap.get("announce"); + tracker_list = (ArrayList)dataMap.get("announce-list"); + info_hash = (HashMap)dataMap.get("info"); + is_private = (((Integer)dataMap.get("private")) != 0); + } +} diff --git a/src/zutil/network/torrent/TorrentParser.java b/src/zutil/network/torrent/TorrentParser.java new file mode 100644 index 00000000..0019a4f6 --- /dev/null +++ b/src/zutil/network/torrent/TorrentParser.java @@ -0,0 +1,123 @@ +package zutil.network.torrent; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; + +import zutil.FileFinder; +import zutil.MultiPrintStream; + +/** + * http://wiki.theory.org/BitTorrentSpecification + * @author Ziver + * + */ +public class TorrentParser { + /** + * Example use + */ + public static void main(String[] args){ + try { + String tmp = FileFinder.getFileContent(FileFinder.find("C:\\Users\\Ziver\\Desktop\\test.torrent")); + MultiPrintStream.out.dump(TorrentParser.decode(tmp)); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * Returns the representation of the data in the BEncoded string + * + * @param data The data to be decoded + * @return + */ + public static Object decode(String data){ + return decode_BEncoded(new StringBuffer(data)); + } + + /** + * Returns the representation of the data in the BEncoded string + * + * @param data The data to be decoded + * @param index The index in data to start from + * @return + */ + @SuppressWarnings("unchecked") + private static Object decode_BEncoded(StringBuffer data){ + String tmp; + char c = ' '; + + switch (data.charAt(0)) { + /** + * Integers are prefixed with an i and terminated by an e. For + * example, 123 would bEcode to i123e, -3272002 would bEncode to + * i-3272002e. + */ + case 'i': + //System.out.println("Found Integer at "+index); + data.deleteCharAt(0); + tmp = data.substring(0, data.indexOf("e")); + data.delete(0, tmp.length() + 1); + //System.out.println(tmp); + return new Long(tmp); + /** + * Lists are prefixed with a l and terminated by an e. The list + * should contain a series of bEncoded elements. For example, the + * list of strings ["Monduna", "Bit", "Torrents"] would bEncode to + * l7:Monduna3:Bit8:Torrentse. The list [1, "Monduna", 3, ["Sub", "List"]] + * would bEncode to li1e7:Mondunai3el3:Sub4:Listee + */ + case 'l': + //System.out.println("Found List at "+index); + data.deleteCharAt(0); + LinkedList list = new LinkedList(); + c = data.charAt(0); + while(c != 'e'){ + list.add(decode_BEncoded(data)); + c = data.charAt(0); + } + data.deleteCharAt(0); + //MultiPrintStream.out.dump(list); + if(list.size() == 1) return list.poll(); + else return list; + /** + * Dictionaries are prefixed with a d and terminated by an e. They + * are similar to list, except that items are in key value pairs. The + * dictionary {"key":"value", "Monduna":"com", "bit":"Torrents", "number":7} + * would bEncode to d3:key5:value7:Monduna3:com3:bit:8:Torrents6:numberi7ee + */ + case 'd': + //System.out.println("Found Dictionary at "+index); + data.deleteCharAt(0); + HashMap map = new HashMap(); + c = data.charAt(0); + while(c != 'e'){ + Object tmp2 = decode_BEncoded(data); + map.put(tmp2, decode_BEncoded(data)); + c = data.charAt(0); + } + data.deleteCharAt(0); + //MultiPrintStream.out.dump(map); + return map; + /** + * Strings are prefixed with their length followed by a colon. + * For example, "Monduna" would bEncode to 7:Monduna and "BitTorrents" + * would bEncode to 11:BitTorrents. + */ + default: + //System.out.println("Found String at "+index); + tmp = data.substring(0, data.indexOf(":")); + int length = Integer.parseInt(tmp); + data.delete(0, tmp.length()+1); + String ret = data.substring(0, length); + data.delete(0, length); + //System.out.println(data.substring(i, i+length)); + return ret; + } + } +}