12ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson/* 22ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * Copyright (C) 2011 The Android Open Source Project 32ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * 42ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * Licensed under the Apache License, Version 2.0 (the "License"); 52ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * you may not use this file except in compliance with the License. 62ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * You may obtain a copy of the License at 72ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * 82ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * http://www.apache.org/licenses/LICENSE-2.0 92ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * 102ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * Unless required by applicable law or agreed to in writing, software 112ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * distributed under the License is distributed on an "AS IS" BASIS, 122ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * See the License for the specific language governing permissions and 142ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * limitations under the License. 152ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson */ 162ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 172ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonpackage com.android.nfc.snep; 182ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 192ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport android.nfc.FormatException; 202ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport android.nfc.NdefMessage; 212ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 222ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport java.io.ByteArrayOutputStream; 232ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport java.io.DataOutputStream; 242ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport java.io.IOException; 252ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport java.nio.ByteBuffer; 262ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 272ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonpublic final class SnepMessage { 282ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte VERSION_MAJOR = (byte) 0x1; 292ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte VERSION_MINOR = (byte) 0x0; 302ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte VERSION = (0xF0 & (VERSION_MAJOR << 4)) | (0x0F & VERSION_MINOR); 312ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 322ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte REQUEST_CONTINUE = (byte) 0x00; 332ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte REQUEST_GET = (byte) 0x01; 342ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte REQUEST_PUT = (byte) 0x02; 3577c513146427bc51db8245b89022057520a55cebMartijn Coenen public static final byte REQUEST_REJECT = (byte) 0x7F; 362ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 372ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_CONTINUE = (byte) 0x80; 382ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_SUCCESS = (byte) 0x81; 392ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_NOT_FOUND = (byte) 0xC0; 402ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_EXCESS_DATA = (byte) 0xC1; 412ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_BAD_REQUEST = (byte) 0xC2; 422ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_NOT_IMPLEMENTED = (byte) 0xE0; 432ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_UNSUPPORTED_VERSION = (byte) 0xE1; 442ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static final byte RESPONSE_REJECT = (byte) 0xFF; 452ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 462ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private static final int HEADER_LENGTH = 6; 472ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final byte mVersion; 482ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final byte mField; 492ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final int mLength; 502ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final int mAcceptableLength; 512ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final NdefMessage mNdefMessage; 522ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 532ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static SnepMessage getGetRequest(int acceptableLength, NdefMessage ndef) { 542ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return new SnepMessage(VERSION, REQUEST_GET, 4 + ndef.toByteArray().length, 552ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson acceptableLength, ndef); 562ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 572ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 582ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static SnepMessage getPutRequest(NdefMessage ndef) { 592ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return new SnepMessage(VERSION, REQUEST_PUT, ndef.toByteArray().length, 0, ndef); 602ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 612ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 622ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static SnepMessage getMessage(byte field) { 632ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return new SnepMessage(VERSION, field, 0, 0, null); 642ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 652ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 662ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static SnepMessage getSuccessResponse(NdefMessage ndef) { 672ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (ndef == null) { 682ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return new SnepMessage(VERSION, RESPONSE_SUCCESS, 0, 0, null); 692ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } else { 702ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return new SnepMessage(VERSION, RESPONSE_SUCCESS, ndef.toByteArray().length, 0, ndef); 712ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 722ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 732ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 742ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public static SnepMessage fromByteArray(byte[] data) throws FormatException { 752ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return new SnepMessage(data); 762ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 772ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 782ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private SnepMessage(byte[] data) throws FormatException { 792ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson ByteBuffer input = ByteBuffer.wrap(data); 802ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson int ndefOffset; 812ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson int ndefLength; 822ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 832ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mVersion = input.get(); 842ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mField = input.get(); 852ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mLength = input.getInt(); 862ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (mField == REQUEST_GET) { 872ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = input.getInt(); 882ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson ndefOffset = HEADER_LENGTH + 4; 892ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson ndefLength = mLength - 4; 902ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } else { 912ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = -1; 922ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson ndefOffset = HEADER_LENGTH; 932ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson ndefLength = mLength; 942ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 952ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 962ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (ndefLength > 0) { 972ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson byte[] bytes = new byte[ndefLength]; 982ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson System.arraycopy(data, ndefOffset, bytes, 0, ndefLength); 992ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mNdefMessage = new NdefMessage(bytes); 1002ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } else { 1012ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mNdefMessage = null; 1022ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1032ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1042ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1052ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson SnepMessage(byte version, byte field, int length, int acceptableLength, 1062ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson NdefMessage ndefMessage) { 1072ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mVersion = version; 1082ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mField = field; 1092ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mLength = length; 1102ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = acceptableLength; 1112ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mNdefMessage = ndefMessage; 1122ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1132ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1142ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public byte[] toByteArray() { 1152ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson byte[] bytes; 1162ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (mNdefMessage != null) { 1172ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson bytes = mNdefMessage.toByteArray(); 1182ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } else { 1192ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson bytes = new byte[0]; 1202ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1212ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1222ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson ByteArrayOutputStream buffer; 1232ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson try { 1242ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (mField == REQUEST_GET) { 1252ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson buffer = new ByteArrayOutputStream(bytes.length + HEADER_LENGTH + 4); 1262ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } else { 1272ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson buffer = new ByteArrayOutputStream(bytes.length + HEADER_LENGTH); 1282ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1292ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1302ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson DataOutputStream output = new DataOutputStream(buffer); 1312ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson output.writeByte(mVersion); 1322ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson output.writeByte(mField); 1332ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (mField == REQUEST_GET) { 1342ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson output.writeInt(bytes.length + 4); 1352ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson output.writeInt(mAcceptableLength); 1362ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } else { 1372ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson output.writeInt(bytes.length); 1382ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1392ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson output.write(bytes); 1402ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } catch(IOException e) { 1412ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return null; 1422ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1432ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1442ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return buffer.toByteArray(); 1452ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1462ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1472ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public NdefMessage getNdefMessage() { 1482ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return mNdefMessage; 1492ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1502ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1512ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public byte getField() { 1522ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return mField; 1532ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1542ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1552ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public byte getVersion() { 1562ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return mVersion; 1572ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1582ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1592ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public int getLength() { 1602ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return mLength; 1612ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1622ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1632ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public int getAcceptableLength() { 1642ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson if (mField != REQUEST_GET) { 1652ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson throw new UnsupportedOperationException( 1662ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson "Acceptable Length only available on get request messages."); 1672ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1682ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson return mAcceptableLength; 1692ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1702ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson} 171