import java.io.IOException; import java.io.RandomAccessFile; import java.io.File; import java.nio.ByteBuffer; import java.util.Random; import GivenTools.ToolKit; import GivenTools.TorrentInfo; /** * The Class Utils handles miscellaneous functions that help us * perform tasks throughout the torrent client. * * @author Deepak, Mike, Josh */ public class Utils extends ToolKit { /** The Constant HEX_CHARS. */ public static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** * To hex string. * * Converts a byte array to a hex string * * @param bytes the bytes * @return the string */ public static String toHexString(byte[] bytes) { if (bytes == null) { return null; } if (bytes.length == 0) { return ""; } StringBuilder sb = new StringBuilder(bytes.length * 3); for (byte b : bytes) { byte hi = (byte) ((b >> 4) & 0x0f); byte lo = (byte) (b & 0x0f); sb.append('%').append(HEX_CHARS[hi]).append(HEX_CHARS[lo]); } return sb.toString(); } /** * Gen peer id. * * Generates a random peer id to identify ourself * * @return the byte[] */ protected static byte[] genPeerId() { Random rand = new Random(System.currentTimeMillis()); byte[] peerId = new byte[20]; peerId[0] = 'G'; peerId[1] = 'P'; peerId[2] = '0'; peerId[3] = '2'; for (int i = 4; i < 20; ++i) { peerId[i] = (byte) ('A' + rand.nextInt(26)); } return peerId; } /** * Bitfield to bool array. * * Converts a given bitfield to a boolean array * * @param bitfield the bitfield * @param numPieces the num pieces * @return the boolean[] */ public static boolean[] bitfieldToBoolArray(byte[] bitfield, int numPieces) { if (bitfield == null) return null; else { boolean[] retArray = new boolean[numPieces]; for (int i = 0; i < retArray.length; i++) { int byteIndex = i / 8; int bitIndex = i % 8; if (((bitfield[byteIndex] << bitIndex) & 0x80) == 0x80) retArray[i] = true; else retArray[i] = false; } return retArray; } } /** * Bool to bitfield array. * * Converts a given boolean array to a bitfield * * @param verifiedPieces the verified pieces * @return the byte[] */ public static byte[] boolToBitfieldArray(boolean[] verifiedPieces) { int length = verifiedPieces.length / 8; if (verifiedPieces.length % 8 != 0) { ++length; } int index = 0; byte[] bitfield = new byte[length]; for (int i = 0; i < bitfield.length; ++i) { for (int j = 7; j >= 0; --j) { if (index >= verifiedPieces.length) { return bitfield; } if (verifiedPieces[index++]) { bitfield[i] |= (byte) (1 << j); } } } return bitfield; } /** * Check pieces. * * Check the pieces of the file we have on disk so that we can increment * downloaded stats and send appropriate bitfield * * @return the boolean[] * @throws IOException Signals that an I/O exception has occurred. */ public static boolean[] checkPieces(TorrentInfo torrentInfo, File outputFile) throws IOException { int numPieces = torrentInfo.piece_hashes.length; int pieceLength = torrentInfo.piece_length; int fileLength = torrentInfo.file_length; ByteBuffer[] pieceHashes = torrentInfo.piece_hashes; int lastPieceLength = fileLength % pieceLength == 0 ? pieceLength : fileLength % pieceLength; byte[] piece = null; boolean[] verifiedPieces = new boolean[numPieces]; for (int i = 0; i < numPieces; i++) { if (i != numPieces - 1) { piece = new byte[pieceLength]; piece = readFile(i, 0, pieceLength, torrentInfo, outputFile); } else { piece = new byte[lastPieceLength]; piece = readFile(i, 0, lastPieceLength, torrentInfo, outputFile); } if (Manager.verifySHA1(piece, pieceHashes[i], i)) { verifiedPieces[i] = true; RUBTClient.log("Verified piece " + i); } } for(int i = 0; i < verifiedPieces.length; i++){ if(verifiedPieces[i] != false){ if(torrentInfo.file_length % torrentInfo.piece_length != 0 && i == torrentInfo.piece_hashes.length -1){ RUBTClient.addProgress(torrentInfo.file_length % torrentInfo.piece_length); RUBTClient.addAmountDownloaded(torrentInfo.file_length % torrentInfo.piece_length); } else { RUBTClient.addProgress(torrentInfo.piece_length); RUBTClient.addAmountDownloaded(torrentInfo.piece_length); } } } return verifiedPieces; } /** * Read file. * * Reads a piece from file on the disk in instances * where we are uploading a piece or if we are * checking the pieces of the file we already have * * @param index the index * @param offset the offset * @param length the length * @return the byte[] * @throws IOException Signals that an I/O exception has occurred. */ public static byte[] readFile(int index, int offset, int length, TorrentInfo torrentInfo, File outputFile) throws IOException { RandomAccessFile raf = new RandomAccessFile(outputFile, "r"); byte[] data = new byte[length]; raf.seek(torrentInfo.piece_length * index + offset); raf.read(data); raf.close(); return data; } }