blob: 41099cb503af841ac6eda67bd6ccbea12212ee85 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include "jni.h"
#include "JNIHelp.h"
#include "android_nfc.h"
namespace android {
static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
jbyteArray array)
{
uint16_t status;
uint32_t i;
jbyte *raw_msg;
jsize raw_msg_size;
uint32_t num_of_records = 0;
uint8_t **records = NULL;
uint8_t *is_chunked = NULL;
jint ret = -1;
phFriNfc_NdefRecord_t record;
jclass record_cls;
jobjectArray records_array;
jmethodID ctor;
jclass msg_cls;
jfieldID mrecords;
raw_msg_size = e->GetArrayLength(array);
raw_msg = e->GetByteArrayElements(array, NULL);
if (raw_msg == NULL)
return -1;
/* Get the number of records in the message so we can allocate buffers */
TRACE("phFriNfc_NdefRecord_GetRecords(NULL)");
status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg,
(uint32_t)raw_msg_size, NULL, NULL, &num_of_records);
if (status) {
LOGE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x", status);
goto end;
}
TRACE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x, with %d records", status, num_of_records);
is_chunked = (uint8_t*)malloc(num_of_records);
if (is_chunked == NULL)
goto end;
records = (uint8_t**)malloc(num_of_records * sizeof(uint8_t *));
if (records == NULL)
goto end;
/* Now, actually retrieve records position in message */
TRACE("phFriNfc_NdefRecord_GetRecords()");
status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg,
(uint32_t)raw_msg_size, records, is_chunked, &num_of_records);
if (status) {
LOGE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x", status);
goto end;
}
TRACE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x, with %d records", status, num_of_records);
/* Build NDEF records array */
record_cls = e->FindClass("android/nfc/NdefRecord");
records_array = e->NewObjectArray((jsize)num_of_records, record_cls,
NULL);
if (records_array == NULL)
goto end;
ctor = e->GetMethodID(record_cls, "<init>", "(S[B[B[BB)V");
for (i = 0; i < num_of_records; i++) {
jbyteArray type, id, payload;
jobject new_record;
TRACE("phFriNfc_NdefRecord_Parse()");
status = phFriNfc_NdefRecord_Parse(&record, records[i]);
if (status) {
LOGE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
goto end;
}
TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
// We don't exactly know what *is* a valid length, but a simple
// sanity check is to make sure that the length of the header
// plus all fields does not exceed raw_msg_size. The min length
// of the header is 3 bytes: TNF, Type Length, Payload Length
// (ID length field is optional!)
uint64_t indicatedMsgLength = 3 + record.TypeLength + record.IdLength +
(uint64_t)record.PayloadLength;
if (indicatedMsgLength >
(uint64_t)raw_msg_size) {
LOGE("phFri_NdefRecord_Parse: invalid length field");
goto end;
}
type = e->NewByteArray(record.TypeLength);
if (type == NULL) {
LOGD("NFC_Set Record Type Error\n");
goto end;
}
id = e->NewByteArray(record.IdLength);
if(id == NULL) {
LOGD("NFC_Set Record ID Error\n");
goto end;
}
payload = e->NewByteArray(record.PayloadLength);
if(payload == NULL) {
LOGD("NFC_Set Record Payload Error\n");
goto end;
}
e->SetByteArrayRegion(type, 0, record.TypeLength,
(jbyte *)record.Type);
e->SetByteArrayRegion(id, 0, record.IdLength,
(jbyte *)record.Id);
e->SetByteArrayRegion(payload, 0, record.PayloadLength,
(jbyte *)record.PayloadData);
new_record = e->NewObject(record_cls, ctor,
(jshort)record.Tnf, type, id, payload, (jbyte)record.Flags);
e->SetObjectArrayElement(records_array, i, new_record);
/* Try not to clutter the Java stack too much */
e->DeleteLocalRef(new_record);
e->DeleteLocalRef(type);
e->DeleteLocalRef(id);
e->DeleteLocalRef(payload);
}
/* Store built array in our NDEFMessage instance */
msg_cls = e->GetObjectClass(o);
mrecords = e->GetFieldID(msg_cls, "mRecords", "[Landroid/nfc/NdefRecord;");
e->SetObjectField(o, mrecords, (jobject)records_array);
ret = 0;
end:
if(is_chunked)
free(is_chunked);
if(records)
free(records);
e->ReleaseByteArrayElements(array, raw_msg, JNI_ABORT);
return ret;
}
static JNINativeMethod gMethods[] = {
{"parseNdefMessage", "([B)I", (void *)android_nfc_NdefMessage_parseNdefMessage},
};
int register_android_nfc_NdefMessage(JNIEnv *e)
{
return jniRegisterNativeMethods(e, "android/nfc/NdefMessage", gMethods, NELEM(gMethods));
}
} // namespace android