• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.nfc.snep;
18 
19 import android.nfc.FormatException;
20 import android.nfc.NdefMessage;
21 import android.nfc.NdefRecord;
22 
23 import com.android.nfc.NfcService;
24 import com.android.nfc.sneptest.DtaSnepClient;
25 
26 import java.io.ByteArrayOutputStream;
27 import java.io.DataOutputStream;
28 import java.io.IOException;
29 import java.io.UnsupportedEncodingException;
30 import java.nio.ByteBuffer;
31 
32 public final class SnepMessage {
33     public static final byte VERSION_MAJOR = (byte) 0x1;
34     public static final byte VERSION_MINOR = (byte) 0x0;
35     public static final byte VERSION = (0xF0 & (VERSION_MAJOR << 4)) | (0x0F & VERSION_MINOR);
36 
37     public static final byte REQUEST_CONTINUE = (byte) 0x00;
38     public static final byte REQUEST_GET = (byte) 0x01;
39     public static final byte REQUEST_PUT = (byte) 0x02;
40     public static final byte REQUEST_RFU = (byte) 0x03;
41     public static final byte REQUEST_REJECT = (byte) 0x7F;
42 
43     public static final byte RESPONSE_CONTINUE = (byte) 0x80;
44     public static final byte RESPONSE_SUCCESS = (byte) 0x81;
45     public static final byte RESPONSE_NOT_FOUND = (byte) 0xC0;
46     public static final byte RESPONSE_EXCESS_DATA = (byte) 0xC1;
47     public static final byte RESPONSE_BAD_REQUEST = (byte) 0xC2;
48     public static final byte RESPONSE_NOT_IMPLEMENTED = (byte) 0xE0;
49     public static final byte RESPONSE_UNSUPPORTED_VERSION = (byte) 0xE1;
50     public static final byte RESPONSE_REJECT = (byte) 0xFF;
51 
52     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
53             (byte)0x4C,(byte)0x6F,(byte)0x72,(byte)0x65,(byte)0x6D,(byte)0x20,(byte)0x69,(byte)0x70,(byte)0x73,(byte)0x75, // Payload
54             (byte)0x6D,(byte)0x20,(byte)0x64,(byte)0x6F,(byte)0x6C,(byte)0x6F,(byte)0x72,(byte)0x20,(byte)0x73,(byte)0x69,
55             (byte)0x74,(byte)0x20,(byte)0x61,(byte)0x6D,(byte)0x65,(byte)0x74,(byte)0x2E};
56 
57     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
58             (byte)0x4C,(byte)0x6F,(byte)0x72,(byte)0x65,(byte)0x6D,(byte)0x20,(byte)0x69,(byte)0x70,(byte)0x73,(byte)0x75, // Payload
59             (byte)0x6D,(byte)0x20,(byte)0x64,(byte)0x6F,(byte)0x6C,(byte)0x6F,(byte)0x72,(byte)0x20,(byte)0x73,(byte)0x69,
60             (byte)0x74,(byte)0x20,(byte)0x61,(byte)0x6D,(byte)0x65,(byte)0x74,(byte)0x2E};
61 
62     private static final int HEADER_LENGTH = 6;
63     public static final int MAL_IUT = 0x0400;
64     public static final int MAL = 0xFFFFFFFF;
65     private final byte mVersion;
66     private final byte mField;
67     private final int mLength;
68     private final int mAcceptableLength;
69     private final NdefMessage mNdefMessage;
70 
getGetRequest(int acceptableLength, NdefMessage ndef)71     public static SnepMessage getGetRequest(int acceptableLength, NdefMessage ndef) {
72         return new SnepMessage(VERSION, REQUEST_GET, 4 + ndef.toByteArray().length,
73                 acceptableLength, ndef);
74     }
75 
getPutRequest(NdefMessage ndef)76     public static SnepMessage getPutRequest(NdefMessage ndef) {
77         return new SnepMessage(VERSION, REQUEST_PUT, ndef.toByteArray().length, 0, ndef);
78     }
79 
getMessage(byte field)80     public static SnepMessage getMessage(byte field) {
81         return new SnepMessage(VERSION, field, 0, 0, null);
82     }
83 
getSuccessResponse(NdefMessage ndef)84     public static SnepMessage getSuccessResponse(NdefMessage ndef) {
85         if (ndef == null) {
86             return new SnepMessage(VERSION, RESPONSE_SUCCESS, 0, 0, null);
87         } else {
88             return new SnepMessage(VERSION, RESPONSE_SUCCESS, ndef.toByteArray().length, 0, ndef);
89         }
90     }
91 
fromByteArray(byte[] data)92     public static SnepMessage fromByteArray(byte[] data) throws FormatException {
93         return new SnepMessage(data);
94     }
95 
getLargeNdef()96     public static NdefMessage getLargeNdef() throws UnsupportedEncodingException {
97         String snepTestData2 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at"
98                 +" lorem nunc, ut venenatis quam. Etiam id dolor quam, at viverra dolor."
99                 +" Phasellus eu lacus ligula, quis euismod erat. Sed feugiat, ligula at"
100                 +" mollis aliquet, justo lacus condimentum eros, non tincidunt neque"
101                 +" ipsum eu risus. Sed adipiscing dui euismod tellus ullamcorper ornare."
102                 +" Phasellus mattis risus et lectus euismod eu fermentum sem cursus."
103                 +" Phasellus tristique consectetur mauris eu porttitor. Sed lobortis"
104                 +" porttitor orci.";
105         String lang = "la";
106         byte[] textBytes = snepTestData2.getBytes();
107         byte[] langBytes = lang.getBytes("US-ASCII");
108         int langLength = langBytes.length;
109         int textLength = textBytes.length;
110 
111         byte[] payload = new byte[1 + langLength + textLength];
112         payload[0] = (byte) langLength;
113 
114         System.arraycopy(langBytes, 0, payload, 1, langLength);
115         System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
116 
117         NdefRecord data2 = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
118         return new NdefMessage(new NdefRecord[]{data2});
119     }
120 
getSmallNdef()121     public static NdefMessage getSmallNdef() throws UnsupportedEncodingException {
122         String snepTestData1 = "Lorem ipsum dolor sit amet.";
123         String lang = "la";
124         byte[] textBytes = snepTestData1.getBytes();
125         byte[] langBytes = lang.getBytes("US-ASCII");
126         int langLength = langBytes.length;
127         int textLength = textBytes.length;
128 
129         byte[] payload = new byte[1 + langLength + textLength];
130         payload[0] = (byte) langLength;
131 
132         System.arraycopy(langBytes, 0, payload, 1, langLength);
133         System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
134 
135         NdefRecord data1 = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
136         return new NdefMessage(new NdefRecord[]{data1});
137     }
138 
SnepMessage(byte[] data)139     private SnepMessage(byte[] data) throws FormatException {
140         ByteBuffer input = ByteBuffer.wrap(data);
141         int ndefOffset;
142         int ndefLength;
143 
144         mVersion = input.get();
145         mField = input.get();
146         mLength = input.getInt();
147         if (mField == REQUEST_GET) {
148             mAcceptableLength = input.getInt();
149             ndefOffset = HEADER_LENGTH + 4;
150             ndefLength = mLength - 4;
151         } else {
152             mAcceptableLength = -1;
153             ndefOffset = HEADER_LENGTH;
154             ndefLength = mLength;
155         }
156 
157         if (ndefLength > 0) {
158             byte[] bytes = new byte[ndefLength];
159             System.arraycopy(data, ndefOffset, bytes, 0, ndefLength);
160             mNdefMessage = new NdefMessage(bytes);
161         } else {
162             mNdefMessage = null;
163         }
164     }
165 
SnepMessage(byte version, byte field, int length, int acceptableLength, NdefMessage ndefMessage)166     SnepMessage(byte version, byte field, int length, int acceptableLength,
167             NdefMessage ndefMessage) {
168         mVersion = version;
169         mField = field;
170         mLength = length;
171         mAcceptableLength = acceptableLength;
172         mNdefMessage = ndefMessage;
173     }
174 
toByteArray()175     public byte[] toByteArray() {
176         byte[] bytes;
177         if (mNdefMessage != null) {
178             if (NfcService.sIsDtaMode && DtaSnepClient.mTestCaseId != 0) {
179                if (DtaSnepClient.mTestCaseId == 5 || DtaSnepClient.mTestCaseId == 6) {
180                    bytes = mNdefMessage.toByteArray();
181                } else {
182                    if (NfcService.sIsShortRecordLayout) {
183                        bytes = NDEF_SHORT_TEST_RECORD;
184                    } else {
185                        bytes = NDEF_TEST_RECORD;
186                    }
187                }
188             } else {
189                 bytes = mNdefMessage.toByteArray();
190             }
191         } else {
192             bytes = new byte[0];
193         }
194 
195         ByteArrayOutputStream buffer;
196         try {
197             if (mField == REQUEST_GET) {
198                 buffer = new ByteArrayOutputStream(bytes.length + HEADER_LENGTH + 4);
199             } else {
200                 buffer = new ByteArrayOutputStream(bytes.length + HEADER_LENGTH);
201             }
202 
203             DataOutputStream output = new DataOutputStream(buffer);
204             output.writeByte(mVersion);
205             output.writeByte(mField);
206             if (mField == REQUEST_GET) {
207                 output.writeInt(bytes.length + 4);
208                 output.writeInt(mAcceptableLength);
209             } else {
210                 output.writeInt(bytes.length);
211             }
212             output.write(bytes);
213         } catch(IOException e) {
214             return null;
215         }
216 
217         return buffer.toByteArray();
218     }
219 
getNdefMessage()220     public NdefMessage getNdefMessage() {
221         return mNdefMessage;
222     }
223 
getField()224     public byte getField() {
225         return mField;
226     }
227 
getVersion()228     public byte getVersion() {
229         return mVersion;
230     }
231 
getLength()232     public int getLength() {
233         return mLength;
234     }
235 
getAcceptableLength()236     public int getAcceptableLength() {
237         if (mField != REQUEST_GET) {
238             throw new UnsupportedOperationException(
239                     "Acceptable Length only available on get request messages.");
240         }
241         return mAcceptableLength;
242     }
243 }
244