183 lines
5.6 KiB
C++
183 lines
5.6 KiB
C++
|
/*
|
||
|
* 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[B)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);
|
||
|
|
||
|
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
|