/* * Copyright (C) 2024 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 #include #include "JniConstants.h" static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) { return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env)); } static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) { return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env)); } static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) { jclass byteBufferClass = JniConstants_NioByteBufferClass(env); jclass shortBufferClass = JniConstants_NioShortBufferClass(env); jclass charBufferClass = JniConstants_NioCharBufferClass(env); jclass intBufferClass = JniConstants_NioIntBufferClass(env); jclass floatBufferClass = JniConstants_NioFloatBufferClass(env); jclass longBufferClass = JniConstants_NioLongBufferClass(env); jclass doubleBufferClass = JniConstants_NioDoubleBufferClass(env); // Check the type of the Buffer if ((*env)->IsInstanceOf(env, nioBuffer, byteBufferClass)) { return 0; } else if ((*env)->IsInstanceOf(env, nioBuffer, shortBufferClass) || (*env)->IsInstanceOf(env, nioBuffer, charBufferClass)) { return 1; } else if ((*env)->IsInstanceOf(env, nioBuffer, intBufferClass) || (*env)->IsInstanceOf(env, nioBuffer, floatBufferClass)) { return 2; } else if ((*env)->IsInstanceOf(env, nioBuffer, longBufferClass) || (*env)->IsInstanceOf(env, nioBuffer, doubleBufferClass)) { return 3; } return 0; } jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) { jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env); jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod); if (hasArray) { jmethodID arrayMethod = JniConstants_NioBuffer_array(env); return (*env)->CallObjectMethod(env, nioBuffer, arrayMethod); } else { return NULL; } } int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) { jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env); jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod); if (hasArray) { jmethodID arrayOffsetMethod = JniConstants_NioBuffer_arrayOffset(env); jint arrayOffset = (*env)->CallIntMethod(env, nioBuffer, arrayOffsetMethod); const int position = GetBufferPosition(env, nioBuffer); jint elementSizeShift = GetBufferElementSizeShift(env, nioBuffer); return (arrayOffset + position) << elementSizeShift; } else { return 0; } } jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) { // in Java 11, the address field of a HeapByteBuffer contains a non-zero value despite // HeapByteBuffer being a non-direct buffer. In that case, this should still return 0. jmethodID isDirectMethod = JniConstants_NioBuffer_isDirect(env); jboolean isDirect = (*env)->CallBooleanMethod(env, nioBuffer, isDirectMethod); if (isDirect == JNI_FALSE) { return 0L; } jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env)); if (baseAddress != 0) { const int position = GetBufferPosition(env, nioBuffer); const int shift = GetBufferElementSizeShift(env, nioBuffer); baseAddress += position << shift; } return baseAddress; } jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer, jint* position, jint* limit, jint* elementSizeShift) { *position = GetBufferPosition(env, nioBuffer); *limit = GetBufferLimit(env, nioBuffer); *elementSizeShift = GetBufferElementSizeShift(env, nioBuffer); return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env)); }