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