package ch.uzh.csg.nfclib.messages;


/**
 * This is the lower layer protocol message. It is responsible for sending
 * Messages between two devices via NFC. It is build to allow message
 * fragmentation and reassembly, based on the communication device's NFC message
 * size capabilities. The status values in the header can be combined (OR, AND,
 * etc.) to transmit more than one status to the counterpart. The header
 * contains also a sequence number in order to detect multiple transmission of
 * the same messages or the lost of a message.
 */
public class NfcMessage extends ProtocolMessage {
	
	public static final byte DEFAULT = 0x01;
	public static final byte AID_SELECTED =	0x02;
	public static final byte START_PROTOCOL = 0x04;
	public static final byte RETRANSMIT = 0x08;
	public static final byte HAS_MORE_FRAGMENTS = 0x10;
	public static final byte GET_NEXT_FRAGMENT = 0x20;
	public static final byte WAIT_FOR_ANSWER = 0x40;
	public static final byte ERROR = (byte) 0x80; //-128
	
	public static final int HEADER_LENGTH = 2;
	
	public NfcMessage(byte[] data) {
		setHeaderLength(HEADER_LENGTH);
		setData(data);
	}
	
	/**
	 * Creates a new NfcMessage.
	 * 
	 * @param status
	 *            the status to be contained in the header
	 * @param sequenceNumber
	 *            the sequence number of this message to be contained in the
	 *            header
	 * @param payload
	 *            the payload of this message
	 */
	public NfcMessage(byte status, byte sequenceNumber, byte[] payload) {
		byte[] data;
		if (payload != null && payload.length > 0) {
			data = new byte[payload.length+HEADER_LENGTH];
			System.arraycopy(payload, 0, data, HEADER_LENGTH, payload.length);
		} else {
			data = new byte[HEADER_LENGTH];
		}
		
		data[0] = status;
		data[1] = sequenceNumber;
		
		setHeaderLength(HEADER_LENGTH);
		setData(data);
	}
	
	/**
	 * Returns the sequence number of this NfcMessage. If the data is null, then
	 * 0x00 is returned.
	 */
	public byte getSequenceNumber() {
		if (getData() == null || getData().length < 2)
			return 0x00;
		else
			return getData()[1];
	}
	
	/**
	 * Sets the sequence number of this NfcMessage to the given value (only if
	 * data is not null and is at least as long as the header length).
	 * 
	 * @param sqNr
	 *            the new sequence number of this NfcMessage
	 */
	public void setSequenceNumber(byte sqNr) {
		byte[] data = getData();
		if (data != null && data.length > 1) {
			data[1] = sqNr;
		}
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("NfcMessage: ");
		sb.append("head: ");
		sb.append(", status: ").append(Integer.toHexString(getData()[0] & 0xFF));
		sb.append(", sequence: ").append(Integer.valueOf(getData()[1] & 0xFF));
		sb.append("/ payload length:").append(getData().length-HEADER_LENGTH);
		return sb.toString();
	}
	
}

@@ -2637,24 +2637,150 @@
 ssage: %22);%0D%0A
+%09%09if (getData() == null %7C%7C getData().length %3C 2) %7B%0D%0A%09%09%09sb.append(%22corrupt message!%22);%0D%0A%09%09%09return sb.toString();%0D%0A%09%09%7D else %7B%0D%0A%09
 %09%09sb.append(
@@ -2787,24 +2787,25 @@
 %22head: %22);%0D%0A
+%09
 %09%09sb.append(
@@ -2863,32 +2863,33 @@
 0%5D & 0xFF));%0D%0A%09%09
+%09
 sb.append(%22, seq
@@ -2945,16 +2945,17 @@
 xFF));%0D%0A
+%09
 %09%09sb.app
@@ -3022,16 +3022,17 @@
 TH);%0D%0A%09%09
+%09
 return s
@@ -3042,22 +3042,27 @@
 oString();%0D%0A
+%09%09%7D%0D%0A
 %09%7D%0D%0A%09%0D%0A%7D%0D%0A

Fix source of NPE in NfcMessage.