Skip to content

Commit a08a759

Browse files
author
Mihail Slavchev
committed
add support for ByteBuffer to ArrayBuffer conversion
1 parent 7e5dec0 commit a08a759

7 files changed

Lines changed: 206 additions & 43 deletions

File tree

src/jni/Android.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ LOCAL_MODULE := NativeScript
6565
LOCAL_SRC_FILES := com_tns_AssetExtractor.cpp AssetExtractor.cpp\
6666
com_tns_Platform.cpp NativePlatform.cpp \
6767
com_tns_JsDebugger.cpp \
68-
JEnv.cpp DirectBuffer.cpp NativeScriptException.cpp \
68+
JEnv.cpp DirectBuffer.cpp ArrayBufferHelper.cpp NativeScriptException.cpp \
6969
JsDebugger.cpp SimpleAllocator.cpp \
7070
NativeScriptRuntime.cpp MetadataNode.cpp MetadataTreeNode.cpp MetadataReader.cpp \
7171
MethodCache.cpp JavaObjectArrayCache.cpp \

src/jni/ArrayBufferHelper.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include "ArrayBufferHelper.h"
2+
#include "JEnv.h"
3+
#include "V8GlobalHelpers.h"
4+
#include "NativeScriptException.h"
5+
#include <sstream>
6+
7+
8+
using namespace v8;
9+
using namespace tns;
10+
11+
ArrayBufferHelper::ArrayBufferHelper(ObjectManager *objectManager)
12+
: m_objectManager(objectManager), m_ByteBufferClass(nullptr), m_isDirectMethodID(nullptr)
13+
{
14+
}
15+
16+
void ArrayBufferHelper::CreateConvertFunctions(const Local<Object>& global)
17+
{
18+
auto isolate = Isolate::GetCurrent();
19+
auto extData = External::New(isolate, this);
20+
auto fromFunc = FunctionTemplate::New(isolate, CreateFromCallbackStatic, extData)->GetFunction();
21+
auto ctx = isolate->GetCurrentContext();
22+
auto arrBufferCtorFunc = global->Get(ConvertToV8String("ArrayBuffer")).As<Function>();
23+
arrBufferCtorFunc->Set(ctx, ConvertToV8String("from"), fromFunc);
24+
}
25+
26+
void ArrayBufferHelper::CreateFromCallbackStatic(const FunctionCallbackInfo<Value>& info)
27+
{
28+
try
29+
{
30+
auto extData = info.Data().As<External>();
31+
auto thiz = reinterpret_cast<ArrayBufferHelper*>(extData->Value());
32+
thiz->CreateFromCallbackImpl(info);
33+
}
34+
catch (NativeScriptException& e)
35+
{
36+
e.ReThrowToV8();
37+
}
38+
catch (std::exception e) {
39+
std::stringstream ss;
40+
ss << "Error: c++ exception: " << e.what() << std::endl;
41+
NativeScriptException nsEx(ss.str());
42+
nsEx.ReThrowToV8();
43+
}
44+
catch (...) {
45+
NativeScriptException nsEx(std::string("Error: c++ exception!"));
46+
nsEx.ReThrowToV8();
47+
}
48+
}
49+
50+
void ArrayBufferHelper::CreateFromCallbackImpl(const FunctionCallbackInfo<Value>& info)
51+
{
52+
auto isolate = info.GetIsolate();
53+
auto len = info.Length();
54+
55+
if (len != 1)
56+
{
57+
throw NativeScriptException("Wrong number of arguments (1 expected)");
58+
}
59+
60+
auto arg = info[0];
61+
62+
if (!arg->IsObject())
63+
{
64+
throw NativeScriptException("Wrong type of argument (object expected)");
65+
}
66+
67+
auto argObj = arg.As<Object>();
68+
69+
auto obj = m_objectManager->GetJavaObjectByJsObject(argObj);
70+
71+
if (obj.IsNull())
72+
{
73+
throw NativeScriptException("Wrong type of argument (object expected)");
74+
}
75+
76+
JEnv env;
77+
78+
if (m_ByteBufferClass == nullptr)
79+
{
80+
m_ByteBufferClass = env.FindClass("java/nio/ByteBuffer");
81+
assert(m_ByteBufferClass != nullptr);
82+
}
83+
84+
auto isByteBuffer = env.IsInstanceOf(obj, m_ByteBufferClass);
85+
86+
if (!isByteBuffer)
87+
{
88+
throw NativeScriptException("Wrong type of argument (ByteBuffer expected)");
89+
}
90+
91+
if (m_isDirectMethodID == nullptr)
92+
{
93+
m_isDirectMethodID = env.GetMethodID(m_ByteBufferClass, "isDirect", "()Z");
94+
assert(m_isDirectMethodID != nullptr);
95+
}
96+
97+
auto ret = env.CallBooleanMethod(obj, m_isDirectMethodID);
98+
99+
auto isDirectBuffer = ret == JNI_TRUE;
100+
101+
if (!isDirectBuffer)
102+
{
103+
throw NativeScriptException("Direct ByteBuffer expected)");
104+
}
105+
106+
auto data = env.GetDirectBufferAddress(obj);
107+
auto size = env.GetDirectBufferCapacity(obj);
108+
109+
auto arrayBuffer = ArrayBuffer::New(isolate, data, size);
110+
auto ctx = isolate->GetCurrentContext();
111+
arrayBuffer->Set(ctx, ConvertToV8String("nativeObject"), argObj);
112+
113+
info.GetReturnValue().Set(arrayBuffer);
114+
}

src/jni/ArrayBufferHelper.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef ARRAYBUFFERHELPER_H_
2+
#define ARRAYBUFFERHELPER_H_
3+
4+
#include "v8.h"
5+
#include "ObjectManager.h"
6+
7+
namespace tns
8+
{
9+
class ArrayBufferHelper
10+
{
11+
public:
12+
ArrayBufferHelper(ObjectManager *objectManager);
13+
14+
void CreateConvertFunctions(const v8::Local<v8::Object>& global);
15+
16+
private:
17+
18+
static void CreateFromCallbackStatic(const v8::FunctionCallbackInfo<v8::Value>& info);
19+
20+
void CreateFromCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info);
21+
22+
ObjectManager *m_objectManager;
23+
24+
jclass m_ByteBufferClass;
25+
26+
jmethodID m_isDirectMethodID;
27+
};
28+
}
29+
30+
31+
#endif /* ARRAYBUFFERHELPER_H_ */

src/jni/NativePlatform.cpp

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ Isolate* NativePlatform::PrepareV8Runtime(JEnv& env, const string& filesPath, js
382382

383383
ArrayHelper::Init(g_objectManager, context);
384384

385+
s_arrayBufferHeper = ArrayBufferHelper(g_objectManager);
386+
s_arrayBufferHeper.CreateConvertFunctions(global);
387+
385388
return isolate;
386389
}
387390

@@ -398,45 +401,5 @@ jobject NativePlatform::ConvertJsValueToJavaObject(JEnv& env, const Local<Value>
398401
return javaResult;
399402
}
400403

401-
void NativePlatform::PrepareExtendFunction(Isolate *isolate, jstring filesPath)
402-
{
403-
string fullPath = ArgConverter::jstringToString(filesPath);
404-
fullPath.append("/internal/prepareExtend.js");
405-
406-
int length;
407-
bool isNew;
408-
const char* content = File::ReadText(fullPath, length, isNew);
409-
410-
TryCatch tc;
411-
auto cmd = ConvertToV8String(content, length);
412-
413-
if (isNew)
414-
{
415-
delete[] content;
416-
}
417-
418-
auto origin = ConvertToV8String(fullPath);
419-
DEBUG_WRITE("Compiling prepareExtend.js script");
420-
421-
auto script = Script::Compile(cmd, origin);
422-
DEBUG_WRITE("Compile prepareExtend.js script");
423-
424-
if (script.IsEmpty() || tc.HasCaught())
425-
{
426-
DEBUG_WRITE("Cannot compile prepareExtend.js script");
427-
return;
428-
}
429-
430-
DEBUG_WRITE("Compiled prepareExtend.js script");
431-
432-
script->Run();
433-
434-
if (tc.HasCaught())
435-
{
436-
throw NativeScriptException(tc);
437-
}
438-
439-
DEBUG_WRITE("Executed prepareExtend.js script");
440-
}
441-
442404
Isolate* NativePlatform::s_isolate = nullptr;
405+
ArrayBufferHelper NativePlatform::s_arrayBufferHeper = ArrayBufferHelper(nullptr);

src/jni/NativePlatform.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "JniLocalRef.h"
66
#include "ObjectManager.h"
77
#include "SimpleAllocator.h"
8+
#include "ArrayBufferHelper.h"
89

910
jobject ConvertJsValueToJavaObject(tns::JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
1011

@@ -26,11 +27,12 @@ namespace tns
2627
bool LogEnabled = true;
2728
private:
2829

29-
static void PrepareExtendFunction(v8::Isolate *isolate, jstring filesPath);
3030
static v8::Isolate* PrepareV8Runtime(JEnv& env, const std::string& filesPath, jstring packageName, jobject jsDebugger);
3131
static jobject ConvertJsValueToJavaObject(JEnv& env, const v8::Local<v8::Value>& value, int classReturnType);
3232

3333
static v8::Isolate *s_isolate;
34+
35+
static ArrayBufferHelper s_arrayBufferHeper;
3436
};
3537
}
3638

test-app/assets/app/mainpage.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ require("./tests/testNativeModules");
4141
require("./tests/requireExceptionTests");
4242
require("./tests/java-array-test");
4343
require("./tests/field-access-test");
44+
require("./tests/byte-buffer-test");
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
describe("Tests mapped ByteBuffer conversion", function () {
2+
it("should convert ByteBuffer to ArrayBuffer", function () {
3+
var bb = java.nio.ByteBuffer.allocateDirect(12);
4+
var ab = ArrayBuffer.from(bb);
5+
var int8arr = new Int8Array(ab);
6+
expect(int8arr.length).toBe(12);
7+
var int32arr = new Int32Array(ab);
8+
expect(int32arr.length).toBe(3);
9+
});
10+
11+
it("should share the same memory of all typed arrays", function () {
12+
var bb = java.nio.ByteBuffer.allocateDirect(12);
13+
var ab = ArrayBuffer.from(bb);
14+
var int8arr = new Int8Array(ab);
15+
expect(int8arr.length).toBe(12);
16+
var int32arr = new Int32Array(ab);
17+
expect(int32arr.length).toBe(3);
18+
int8arr[0] = 0x11;
19+
int8arr[1] = 0x22;
20+
int8arr[2] = 0x33;
21+
int8arr[3] = 0x44;
22+
var value = int32arr[0];
23+
expect(value).toBe(0x44332211);
24+
});
25+
26+
it("should keep original ByteBuffer after conversion", function () {
27+
var bb = java.nio.ByteBuffer.allocateDirect(12);
28+
var ab = ArrayBuffer.from(bb);
29+
var same = bb === ab.nativeObject;
30+
expect(same).toBe(true);
31+
});
32+
33+
it("should throw exception when ArrayBuffer.from is called with wrong number of arguments", function () {
34+
var exceptionCaught = false;
35+
try {
36+
var ab = ArrayBuffer.from(1, 2);
37+
} catch(e) {
38+
exceptionCaught = true
39+
}
40+
expect(exceptionCaught).toBe(true);
41+
});
42+
43+
it("should throw exception when ArrayBuffer.from is called with wrong argument type", function () {
44+
var exceptionCaught = false;
45+
try {
46+
var ab = ArrayBuffer.from({});
47+
} catch(e) {
48+
exceptionCaught = true
49+
}
50+
expect(exceptionCaught).toBe(true);
51+
});
52+
});

0 commit comments

Comments
 (0)