Home | History | Annotate | Download | only in jni
      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