blob: 4c3ad9955afff95dc69dbdf0383dc0cedea79157 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.nfc.snep;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import com.android.nfc.NfcService;
import com.android.nfc.sneptest.DtaSnepClient;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
public final class SnepMessage {
public static final byte VERSION_MAJOR = (byte) 0x1;
public static final byte VERSION_MINOR = (byte) 0x0;
public static final byte VERSION = (0xF0 & (VERSION_MAJOR << 4)) | (0x0F & VERSION_MINOR);
public static final byte REQUEST_CONTINUE = (byte) 0x00;
public static final byte REQUEST_GET = (byte) 0x01;
public static final byte REQUEST_PUT = (byte) 0x02;
public static final byte REQUEST_RFU = (byte) 0x03;
public static final byte REQUEST_REJECT = (byte) 0x7F;
public static final byte RESPONSE_CONTINUE = (byte) 0x80;
public static final byte RESPONSE_SUCCESS = (byte) 0x81;
public static final byte RESPONSE_NOT_FOUND = (byte) 0xC0;
public static final byte RESPONSE_EXCESS_DATA = (byte) 0xC1;
public static final byte RESPONSE_BAD_REQUEST = (byte) 0xC2;
public static final byte RESPONSE_NOT_IMPLEMENTED = (byte) 0xE0;
public static final byte RESPONSE_UNSUPPORTED_VERSION = (byte) 0xE1;
public static final byte RESPONSE_REJECT = (byte) 0xFF;
private static final byte[] NDEF_SHORT_TEST_RECORD = new byte[]{(byte)0xD1,(byte)0x01,(byte)0x1E,(byte)0x54,(byte)0x02,(byte)0x6C,(byte)0x61, // NDEF Header
(byte)0x4C,(byte)0x6F,(byte)0x72,(byte)0x65,(byte)0x6D,(byte)0x20,(byte)0x69,(byte)0x70,(byte)0x73,(byte)0x75, // Payload
(byte)0x6D,(byte)0x20,(byte)0x64,(byte)0x6F,(byte)0x6C,(byte)0x6F,(byte)0x72,(byte)0x20,(byte)0x73,(byte)0x69,
(byte)0x74,(byte)0x20,(byte)0x61,(byte)0x6D,(byte)0x65,(byte)0x74,(byte)0x2E};
private static final byte[] NDEF_TEST_RECORD = new byte[]{(byte)0xC1,(byte)0x01,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x1E,(byte)0x54,(byte)0x02,(byte)0x6C,(byte)0x61, // NDEF Header
(byte)0x4C,(byte)0x6F,(byte)0x72,(byte)0x65,(byte)0x6D,(byte)0x20,(byte)0x69,(byte)0x70,(byte)0x73,(byte)0x75, // Payload
(byte)0x6D,(byte)0x20,(byte)0x64,(byte)0x6F,(byte)0x6C,(byte)0x6F,(byte)0x72,(byte)0x20,(byte)0x73,(byte)0x69,
(byte)0x74,(byte)0x20,(byte)0x61,(byte)0x6D,(byte)0x65,(byte)0x74,(byte)0x2E};
private static final int HEADER_LENGTH = 6;
public static final int MAL_IUT = 0x0400;
public static final int MAL = 0xFFFFFFFF;
private final byte mVersion;
private final byte mField;
private final int mLength;
private final int mAcceptableLength;
private final NdefMessage mNdefMessage;
public static SnepMessage getGetRequest(int acceptableLength, NdefMessage ndef) {
return new SnepMessage(VERSION, REQUEST_GET, 4 + ndef.toByteArray().length,
acceptableLength, ndef);
}
public static SnepMessage getPutRequest(NdefMessage ndef) {
return new SnepMessage(VERSION, REQUEST_PUT, ndef.toByteArray().length, 0, ndef);
}
public static SnepMessage getMessage(byte field) {
return new SnepMessage(VERSION, field, 0, 0, null);
}
public static SnepMessage getSuccessResponse(NdefMessage ndef) {
if (ndef == null) {
return new SnepMessage(VERSION, RESPONSE_SUCCESS, 0, 0, null);
} else {
return new SnepMessage(VERSION, RESPONSE_SUCCESS, ndef.toByteArray().length, 0, ndef);
}
}
public static SnepMessage fromByteArray(byte[] data) throws FormatException {
return new SnepMessage(data);
}
public static NdefMessage getLargeNdef() throws UnsupportedEncodingException {
String snepTestData2 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at"
+" lorem nunc, ut venenatis quam. Etiam id dolor quam, at viverra dolor."
+" Phasellus eu lacus ligula, quis euismod erat. Sed feugiat, ligula at"
+" mollis aliquet, justo lacus condimentum eros, non tincidunt neque"
+" ipsum eu risus. Sed adipiscing dui euismod tellus ullamcorper ornare."
+" Phasellus mattis risus et lectus euismod eu fermentum sem cursus."
+" Phasellus tristique consectetur mauris eu porttitor. Sed lobortis"
+" porttitor orci.";
String lang = "la";
byte[] textBytes = snepTestData2.getBytes();
byte[] langBytes = lang.getBytes("US-ASCII");
int langLength = langBytes.length;
int textLength = textBytes.length;
byte[] payload = new byte[1 + langLength + textLength];
payload[0] = (byte) langLength;
System.arraycopy(langBytes, 0, payload, 1, langLength);
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
NdefRecord data2 = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
return new NdefMessage(new NdefRecord[]{data2});
}
public static NdefMessage getSmallNdef() throws UnsupportedEncodingException {
String snepTestData1 = "Lorem ipsum dolor sit amet.";
String lang = "la";
byte[] textBytes = snepTestData1.getBytes();
byte[] langBytes = lang.getBytes("US-ASCII");
int langLength = langBytes.length;
int textLength = textBytes.length;
byte[] payload = new byte[1 + langLength + textLength];
payload[0] = (byte) langLength;
System.arraycopy(langBytes, 0, payload, 1, langLength);
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
NdefRecord data1 = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
return new NdefMessage(new NdefRecord[]{data1});
}
private SnepMessage(byte[] data) throws FormatException {
ByteBuffer input = ByteBuffer.wrap(data);
int ndefOffset;
int ndefLength;
mVersion = input.get();
mField = input.get();
mLength = input.getInt();
if (mField == REQUEST_GET) {
mAcceptableLength = input.getInt();
ndefOffset = HEADER_LENGTH + 4;
ndefLength = mLength - 4;
} else {
mAcceptableLength = -1;
ndefOffset = HEADER_LENGTH;
ndefLength = mLength;
}
if (ndefLength > 0) {
byte[] bytes = new byte[ndefLength];
System.arraycopy(data, ndefOffset, bytes, 0, ndefLength);
mNdefMessage = new NdefMessage(bytes);
} else {
mNdefMessage = null;
}
}
SnepMessage(byte version, byte field, int length, int acceptableLength,
NdefMessage ndefMessage) {
mVersion = version;
mField = field;
mLength = length;
mAcceptableLength = acceptableLength;
mNdefMessage = ndefMessage;
}
public byte[] toByteArray() {
byte[] bytes;
if (mNdefMessage != null) {
if (NfcService.sIsDtaMode && DtaSnepClient.mTestCaseId != 0) {
if (DtaSnepClient.mTestCaseId == 5 || DtaSnepClient.mTestCaseId == 6) {
bytes = mNdefMessage.toByteArray();
} else {
if (NfcService.sIsShortRecordLayout) {
bytes = NDEF_SHORT_TEST_RECORD;
} else {
bytes = NDEF_TEST_RECORD;
}
}
} else {
bytes = mNdefMessage.toByteArray();
}
} else {
bytes = new byte[0];
}
ByteArrayOutputStream buffer;
try {
if (mField == REQUEST_GET) {
buffer = new ByteArrayOutputStream(bytes.length + HEADER_LENGTH + 4);
} else {
buffer = new ByteArrayOutputStream(bytes.length + HEADER_LENGTH);
}
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(mVersion);
output.writeByte(mField);
if (mField == REQUEST_GET) {
output.writeInt(bytes.length + 4);
output.writeInt(mAcceptableLength);
} else {
output.writeInt(bytes.length);
}
output.write(bytes);
} catch(IOException e) {
return null;
}
return buffer.toByteArray();
}
public NdefMessage getNdefMessage() {
return mNdefMessage;
}
public byte getField() {
return mField;
}
public byte getVersion() {
return mVersion;
}
public int getLength() {
return mLength;
}
public int getAcceptableLength() {
if (mField != REQUEST_GET) {
throw new UnsupportedOperationException(
"Acceptable Length only available on get request messages.");
}
return mAcceptableLength;
}
}