1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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 <fbjni/ByteBuffer.h>
18
19 #include <stdexcept>
20
21 namespace facebook {
22 namespace jni {
23
rewind() const24 void JBuffer::rewind() const {
25 static auto meth =
26 javaClassStatic()->getMethod<alias_ref<JBuffer>()>("rewind");
27 meth(self());
28 }
29
getDirectAddress() const30 void* JBuffer::getDirectAddress() const {
31 if (!self()) {
32 throwNewJavaException(
33 "java/lang/NullPointerException", "java.lang.NullPointerException");
34 }
35 void* addr = Environment::current()->GetDirectBufferAddress(self());
36 FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
37 if (!addr) {
38 throw std::runtime_error(
39 isDirect() ? "Attempt to get direct bytes of non-direct buffer."
40 : "Error getting direct bytes of buffer.");
41 }
42 return addr;
43 }
44
getDirectCapacity() const45 size_t JBuffer::getDirectCapacity() const {
46 if (!self()) {
47 throwNewJavaException(
48 "java/lang/NullPointerException", "java.lang.NullPointerException");
49 }
50 int size = Environment::current()->GetDirectBufferCapacity(self());
51 FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
52 if (size < 0) {
53 throw std::runtime_error(
54 isDirect() ? "Attempt to get direct size of non-direct buffer."
55 : "Error getting direct size of buffer.");
56 }
57 return static_cast<size_t>(size);
58 }
59
isDirect() const60 bool JBuffer::isDirect() const {
61 static auto meth = javaClassStatic()->getMethod<jboolean()>("isDirect");
62 return meth(self());
63 }
64
nativeOrder()65 local_ref<JByteOrder> JByteOrder::nativeOrder() {
66 static auto meth =
67 JByteOrder::javaClassStatic()->getStaticMethod<local_ref<JByteOrder>()>(
68 "nativeOrder");
69 return meth(JByteOrder::javaClassStatic());
70 }
71
bigEndian()72 local_ref<JByteOrder> JByteOrder::bigEndian() {
73 static auto field =
74 JByteOrder::javaClassStatic()->getStaticField<JByteOrder>("BIG_ENDIAN");
75 return JByteOrder::javaClassStatic()->getStaticFieldValue(field);
76 }
77
littleEndian()78 local_ref<JByteOrder> JByteOrder::littleEndian() {
79 static auto field = JByteOrder::javaClassStatic()->getStaticField<JByteOrder>(
80 "LITTLE_ENDIAN");
81 return JByteOrder::javaClassStatic()->getStaticFieldValue(field);
82 }
83
wrapBytes(uint8_t * data,size_t size)84 local_ref<JByteBuffer> JByteBuffer::wrapBytes(uint8_t* data, size_t size) {
85 // env->NewDirectByteBuffer requires that size is positive. Android's
86 // dalvik returns an invalid result and Android's art aborts if size == 0.
87 // Workaround this by using a slow path through Java in that case.
88 if (!size) {
89 return allocateDirect(0);
90 }
91 auto res = adopt_local(static_cast<javaobject>(
92 Environment::current()->NewDirectByteBuffer(data, size)));
93 FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
94 if (!res) {
95 throw std::runtime_error("Direct byte buffers are unsupported.");
96 }
97 return res;
98 }
99
allocateDirect(jint size)100 local_ref<JByteBuffer> JByteBuffer::allocateDirect(jint size) {
101 static auto cls = JByteBuffer::javaClassStatic();
102 static auto meth = cls->getStaticMethod<JByteBuffer(int)>("allocateDirect");
103 return meth(cls, size);
104 }
105
order(alias_ref<JByteOrder> order)106 local_ref<JByteBuffer> JByteBuffer::order(alias_ref<JByteOrder> order) {
107 static auto meth =
108 JByteBuffer::javaClassStatic()
109 ->getMethod<local_ref<JByteBuffer>(alias_ref<JByteOrder>)>("order");
110 return meth(self(), order);
111 }
112
113 } // namespace jni
114 } // namespace facebook
115