package protocolP2P; import protocolP2P.Payload; import protocolP2P.HashAlgorithm; import java.io.UnsupportedEncodingException; import exception.TransmissionError; import exception.SizeError; import exception.ProtocolError; import exception.InternalError; import tools.BytesArrayTools; /** Representation of payload for hash request. * @author Louis Royer * @author Flavien Haas * @author JS Auge * @version 1.0 */ public class HashRequest extends Payload { private String filename; private HashAlgorithm[] algoList; private static final int FILENAME_SIZE_POSITION = PAYLOAD_START_POSITION; private static final int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4; /** Constructor (typically used by the server) with a filename parameter. * @param filename name of the file to download. Must not be empty. * @param algoList List of hash algorithms used * @throws InternalError * */ public HashRequest(String filename, HashAlgorithm[] algoList) throws InternalError { super(RequestResponseCode.HASH_REQUEST); /* assert to help debugging */ assert filename.length() != 0 : "Size of filename in HashRequest must not be empty"; if (filename.length() == 0) { throw new InternalError(); } this.filename = filename; assert algoList.length != 0 : "Hash algorithms list must not be empty"; if (algoList.length == 0) { throw new InternalError(); } this.algoList = algoList; } /** Constructor (typically used by client) with a byte[] parameter containing the Packet received. * @param packet the full Packet received * @throws SizeError * @throws InternalError * @throws ProtocolError * @throws TransmissionError */ protected HashRequest(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError { super(packet); /* assert to help debugging */ assert requestResponseCode == RequestResponseCode.HASH_REQUEST : "HashRequest subclass is incompatible with this Packet, request/response code must be checked before using this constructor"; /* InternalErrorException */ if (requestResponseCode!= RequestResponseCode.HASH_REQUEST) { throw new InternalError(); } /* Read filename */ int filenameSize = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION); try { filename = new String(packet, FILENAME_POSITION, filenameSize, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new InternalError(); } int size = getPayloadSize(packet); try { String[] l = (new String(packet, FILENAME_POSITION + filenameSize, size, "UTF-8")).split("\n"); int i = 0; for(String algo : l) { algoList[i] = HashAlgorithm.fromName(algo); i++; } } catch (UnsupportedEncodingException e) { throw new InternalError(); } } /** Returns a byte[] containing Packet with padding. * This Packet is still incomplete and should not be send directly. * ProtocolP2PPacket will use this method to generate the complete Packet. * @return Packet with padding * @throws InternalError */ protected byte[] toPacket() throws InternalError { // compute size int filenameSize = filename.length(); int size = FILENAME_POSITION + filenameSize; for (HashAlgorithm h : algoList) { size += h.getName().length(); size += 1; // size for '\n' } size -=1; // remove trailing '\n' byte[] packet = new byte[size + 1]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size setPayloadSize(size - FILENAME_SIZE_POSITION, packet); BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize); // Write filename int bCount = FILENAME_POSITION; try { byte[] sb = filename.getBytes("UTF-8"); for(byte b : sb) { packet[bCount] = b; bCount += 1; } } catch (UnsupportedEncodingException e) { throw new InternalError(); } boolean firstIter = true; for(HashAlgorithm h : algoList) { String s = h.getName(); if (!firstIter) { firstIter = false; try { packet[bCount] = "\n".getBytes("UTF-8")[0]; // separator } catch (UnsupportedEncodingException e) { throw new InternalError(); } bCount += 1; } // Copy algoname try { byte[] sb = s.getBytes("UTF-8"); for(byte b : sb) { packet[bCount] = b; bCount += 1; } } catch (UnsupportedEncodingException e) { throw new InternalError(); } } return packet; } /** AlgoList getter. * @return List of HashAlgorithms */ public HashAlgorithm[] getAlgoList() { return algoList; } /** Filename getter. * @return filename */ public String getFilename() { return filename; } }