package protocolP2P; import protocolP2P.Payload; import protocolP2P.HashAlgorithm; import java.io.UnsupportedEncodingException; import localException.TransmissionError; import localException.SizeError; import localException.ProtocolError; import localException.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); /* Read filename */ filename = BytesArrayTools.readString(packet, FILENAME_POSITION, filenameSize); /* Read algo list */ int size = getPayloadSize(packet); String[] algoListStr = BytesArrayTools.readStringArray(packet, FILENAME_POSITION + filenameSize, size, "\n"); int i = 0; algoList = new HashAlgorithm[algoListStr.length]; for(String algo : algoListStr) { algoList[i] = HashAlgorithm.fromName(algo); i++; } } /** 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(); String[] algoListStr = new String[algoList.length]; int i = 0; for (HashAlgorithm h : algoList) { algoListStr[i] = h.getName(); i++; } int size = FILENAME_POSITION + filenameSize + BytesArrayTools.computeStringArraySize(algoListStr, "\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); // write filename size BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize); // write filename BytesArrayTools.write(packet, filename, FILENAME_POSITION); // write algo list BytesArrayTools.write(packet, algoListStr, FILENAME_POSITION + filename.length(), "\n"); return packet; } /** AlgoList getter. * @return List of HashAlgorithms */ public HashAlgorithm[] getAlgoList() { return algoList; } /** Filename getter. * @return filename */ public String getFilename() { return filename; } }