1 /* 2 * Copyright (C) 2010 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 #include <stdlib.h> 18 19 #include "jni.h" 20 #include "JNIHelp.h" 21 22 #include "android_nfc.h" 23 24 namespace android { 25 26 static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o, 27 jbyteArray array) 28 { 29 uint16_t status; 30 uint32_t i; 31 jbyte *raw_msg; 32 jsize raw_msg_size; 33 uint32_t num_of_records = 0; 34 uint8_t **records = NULL; 35 uint8_t *is_chunked = NULL; 36 jint ret = -1; 37 phFriNfc_NdefRecord_t record; 38 39 jclass record_cls; 40 jobjectArray records_array; 41 jmethodID ctor; 42 43 jclass msg_cls; 44 jfieldID mrecords; 45 46 raw_msg_size = e->GetArrayLength(array); 47 raw_msg = e->GetByteArrayElements(array, NULL); 48 if (raw_msg == NULL) 49 return -1; 50 51 /* Get the number of records in the message so we can allocate buffers */ 52 TRACE("phFriNfc_NdefRecord_GetRecords(NULL)"); 53 54 status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg, 55 (uint32_t)raw_msg_size, NULL, NULL, &num_of_records); 56 57 if (status) { 58 LOGE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x", status); 59 goto end; 60 } 61 TRACE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x, with %d records", status, num_of_records); 62 63 is_chunked = (uint8_t*)malloc(num_of_records); 64 if (is_chunked == NULL) 65 goto end; 66 records = (uint8_t**)malloc(num_of_records * sizeof(uint8_t *)); 67 if (records == NULL) 68 goto end; 69 70 /* Now, actually retrieve records position in message */ 71 TRACE("phFriNfc_NdefRecord_GetRecords()"); 72 73 status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg, 74 (uint32_t)raw_msg_size, records, is_chunked, &num_of_records); 75 76 if (status) { 77 LOGE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x", status); 78 goto end; 79 } 80 TRACE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x, with %d records", status, num_of_records); 81 82 /* Build NDEF records array */ 83 record_cls = e->FindClass("android/nfc/NdefRecord"); 84 records_array = e->NewObjectArray((jsize)num_of_records, record_cls, 85 NULL); 86 if (records_array == NULL) 87 goto end; 88 89 ctor = e->GetMethodID(record_cls, "<init>", "(S[B[B[BB)V"); 90 91 for (i = 0; i < num_of_records; i++) { 92 jbyteArray type, id, payload; 93 jobject new_record; 94 95 TRACE("phFriNfc_NdefRecord_Parse()"); 96 97 status = phFriNfc_NdefRecord_Parse(&record, records[i]); 98 99 if (status) { 100 LOGE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status); 101 goto end; 102 } 103 TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status); 104 105 // We don't exactly know what *is* a valid length, but a simple 106 // sanity check is to make sure that the length of the header 107 // plus all fields does not exceed raw_msg_size. The min length 108 // of the header is 3 bytes: TNF, Type Length, Payload Length 109 // (ID length field is optional!) 110 uint64_t indicatedMsgLength = 3 + record.TypeLength + record.IdLength + 111 (uint64_t)record.PayloadLength; 112 if (indicatedMsgLength > 113 (uint64_t)raw_msg_size) { 114 LOGE("phFri_NdefRecord_Parse: invalid length field"); 115 goto end; 116 } 117 118 type = e->NewByteArray(record.TypeLength); 119 if (type == NULL) { 120 LOGD("NFC_Set Record Type Error\n"); 121 goto end; 122 } 123 124 id = e->NewByteArray(record.IdLength); 125 if(id == NULL) { 126 LOGD("NFC_Set Record ID Error\n"); 127 goto end; 128 } 129 130 payload = e->NewByteArray(record.PayloadLength); 131 if(payload == NULL) { 132 LOGD("NFC_Set Record Payload Error\n"); 133 goto end; 134 } 135 136 e->SetByteArrayRegion(type, 0, record.TypeLength, 137 (jbyte *)record.Type); 138 e->SetByteArrayRegion(id, 0, record.IdLength, 139 (jbyte *)record.Id); 140 e->SetByteArrayRegion(payload, 0, record.PayloadLength, 141 (jbyte *)record.PayloadData); 142 143 new_record = e->NewObject(record_cls, ctor, 144 (jshort)record.Tnf, type, id, payload, (jbyte)record.Flags); 145 146 e->SetObjectArrayElement(records_array, i, new_record); 147 148 /* Try not to clutter the Java stack too much */ 149 e->DeleteLocalRef(new_record); 150 e->DeleteLocalRef(type); 151 e->DeleteLocalRef(id); 152 e->DeleteLocalRef(payload); 153 } 154 155 /* Store built array in our NDEFMessage instance */ 156 msg_cls = e->GetObjectClass(o); 157 mrecords = e->GetFieldID(msg_cls, "mRecords", "[Landroid/nfc/NdefRecord;"); 158 159 e->SetObjectField(o, mrecords, (jobject)records_array); 160 161 ret = 0; 162 163 end: 164 if(is_chunked) 165 free(is_chunked); 166 if(records) 167 free(records); 168 e->ReleaseByteArrayElements(array, raw_msg, JNI_ABORT); 169 170 return ret; 171 } 172 173 static JNINativeMethod gMethods[] = { 174 {"parseNdefMessage", "([B)I", (void *)android_nfc_NdefMessage_parseNdefMessage}, 175 }; 176 177 int register_android_nfc_NdefMessage(JNIEnv *e) 178 { 179 return jniRegisterNativeMethods(e, "android/nfc/NdefMessage", gMethods, NELEM(gMethods)); 180 } 181 182 } // namespace android 183