Skip to content

Commit a559008

Browse files
mertcanaltinruyadorno
authored andcommitted
node-api: add napi_create_buffer_from_arraybuffer method
PR-URL: #54505 Fixes: #54440 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Gabriel Schulhof <gabrielschulhof@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com>
1 parent d8c552a commit a559008

File tree

6 files changed

+134
-12
lines changed

6 files changed

+134
-12
lines changed

doc/api/n-api.md

+31
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,37 @@ is raised.
26962696
JavaScript `TypedArray` objects are described in
26972697
[Section 22.2][] of the ECMAScript Language Specification.
26982698

2699+
#### `node_api_create_buffer_from_arraybuffer`
2700+
2701+
<!-- YAML
2702+
added: REPLACEME
2703+
-->
2704+
2705+
> Stability: 1 - Experimental
2706+
2707+
```c
2708+
napi_status NAPI_CDECL node_api_create_buffer_from_arraybuffer(napi_env env,
2709+
napi_value arraybuffer,
2710+
size_t byte_offset,
2711+
size_t byte_length,
2712+
napi_value* result)
2713+
```
2714+
2715+
* **`[in] env`**: The environment that the API is invoked under.
2716+
* **`[in] arraybuffer`**: The `ArrayBuffer` from which the buffer will be created.
2717+
* **`[in] byte_offset`**: The byte offset within the `ArrayBuffer` from which to start creating the buffer.
2718+
* **`[in] byte_length`**: The length in bytes of the buffer to be created from the `ArrayBuffer`.
2719+
* **`[out] result`**: A `napi_value` representing the created JavaScript `Buffer` object.
2720+
2721+
Returns `napi_ok` if the API succeeded.
2722+
2723+
This API creates a JavaScript `Buffer` object from an existing `ArrayBuffer`.
2724+
The `Buffer` object is a Node.js-specific class that provides a way to work with binary data directly in JavaScript.
2725+
2726+
The byte range `[byte_offset, byte_offset + byte_length)`
2727+
must be within the bounds of the `ArrayBuffer`. If `byte_offset + byte_length`
2728+
exceeds the size of the `ArrayBuffer`, a `RangeError` exception is raised.
2729+
26992730
#### `napi_create_dataview`
27002731

27012732
<!-- YAML

src/node_api.cc

+35
Original file line numberDiff line numberDiff line change
@@ -1427,3 +1427,38 @@ napi_status NAPI_CDECL node_api_get_module_file_name(
14271427
*result = static_cast<node_napi_env>(env)->GetFilename();
14281428
return napi_clear_last_error(env);
14291429
}
1430+
1431+
#ifdef NAPI_EXPERIMENTAL
1432+
1433+
napi_status NAPI_CDECL
1434+
node_api_create_buffer_from_arraybuffer(napi_env env,
1435+
napi_value arraybuffer,
1436+
size_t byte_offset,
1437+
size_t byte_length,
1438+
napi_value* result) {
1439+
NAPI_PREAMBLE(env);
1440+
CHECK_ARG(env, arraybuffer);
1441+
CHECK_ARG(env, result);
1442+
1443+
v8::Local<v8::Value> arraybuffer_value =
1444+
v8impl::V8LocalValueFromJsValue(arraybuffer);
1445+
if (!arraybuffer_value->IsArrayBuffer()) {
1446+
return napi_invalid_arg;
1447+
}
1448+
1449+
v8::Local<v8::ArrayBuffer> arraybuffer_obj =
1450+
arraybuffer_value.As<v8::ArrayBuffer>();
1451+
if (byte_offset + byte_length > arraybuffer_obj->ByteLength()) {
1452+
return napi_throw_range_error(
1453+
env, "ERR_OUT_OF_RANGE", "The byte offset + length is out of range");
1454+
}
1455+
1456+
v8::Local<v8::Object> buffer =
1457+
node::Buffer::New(env->isolate, arraybuffer_obj, byte_offset, byte_length)
1458+
.ToLocalChecked();
1459+
1460+
*result = v8impl::JsValueFromV8LocalValue(buffer);
1461+
return napi_ok;
1462+
}
1463+
1464+
#endif

src/node_api.h

+12
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ napi_create_external_buffer(napi_env env,
135135
void* finalize_hint,
136136
napi_value* result);
137137
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
138+
139+
#ifdef NAPI_EXPERIMENTAL
140+
#define NODE_API_EXPERIMENTAL_HAS_CREATE_BUFFER_FROM_ARRAYBUFFER
141+
142+
NAPI_EXTERN napi_status NAPI_CDECL
143+
node_api_create_buffer_from_arraybuffer(napi_env env,
144+
napi_value arraybuffer,
145+
size_t byte_offset,
146+
size_t byte_length,
147+
napi_value* result);
148+
#endif // NAPI_EXPERIMENTAL
149+
138150
NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env,
139151
size_t length,
140152
const void* data,

test/node-api/test_buffer/binding.gyp

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"targets": [
33
{
44
"target_name": "test_buffer",
5+
"defines": [
6+
'NAPI_EXPERIMENTAL'
7+
],
58
"sources": [ "test_buffer.c" ]
69
},
710
{

test/node-api/test_buffer/test.js

+3
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ const tick = require('util').promisify(require('../../common/tick'));
2828

2929
// To test this doesn't crash
3030
binding.invalidObjectAsBuffer({});
31+
32+
const testBuffer = binding.bufferFromArrayBuffer();
33+
assert(testBuffer instanceof Buffer, 'Expected a Buffer');
3134
})().then(common.mustCall());

test/node-api/test_buffer/test_buffer.c

+50-12
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,23 @@ static const char theText[] =
77
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
88

99
static int deleterCallCount = 0;
10-
static void deleteTheText(napi_env env, void* data, void* finalize_hint) {
11-
NODE_API_ASSERT_RETURN_VOID(
12-
env, data != NULL && strcmp(data, theText) == 0, "invalid data");
10+
11+
static void deleteTheText(node_api_basic_env env,
12+
void* data,
13+
void* finalize_hint) {
14+
NODE_API_BASIC_ASSERT_RETURN_VOID(data != NULL && strcmp(data, theText) == 0,
15+
"invalid data");
16+
1317
(void)finalize_hint;
1418
free(data);
1519
deleterCallCount++;
1620
}
1721

18-
static void noopDeleter(napi_env env, void* data, void* finalize_hint) {
19-
NODE_API_ASSERT_RETURN_VOID(
20-
env, data != NULL && strcmp(data, theText) == 0, "invalid data");
22+
static void noopDeleter(node_api_basic_env env,
23+
void* data,
24+
void* finalize_hint) {
25+
NODE_API_BASIC_ASSERT_RETURN_VOID(data != NULL && strcmp(data, theText) == 0,
26+
"invalid data");
2127
(void)finalize_hint;
2228
deleterCallCount++;
2329
}
@@ -42,9 +48,12 @@ static napi_value newExternalBuffer(napi_env env, napi_callback_info info) {
4248
NODE_API_ASSERT(
4349
env, theCopy, "Failed to copy static text for newExternalBuffer");
4450
NODE_API_CALL(env,
45-
napi_create_external_buffer(
46-
env, sizeof(theText), theCopy, deleteTheText,
47-
NULL /* finalize_hint */, &theBuffer));
51+
napi_create_external_buffer(env,
52+
sizeof(theText),
53+
theCopy,
54+
deleteTheText,
55+
NULL /* finalize_hint */,
56+
&theBuffer));
4857

4958
return theBuffer;
5059
}
@@ -101,9 +110,12 @@ static napi_value bufferInfo(napi_env env, napi_callback_info info) {
101110
static napi_value staticBuffer(napi_env env, napi_callback_info info) {
102111
napi_value theBuffer;
103112
NODE_API_CALL(env,
104-
napi_create_external_buffer(
105-
env, sizeof(theText), (void*)theText, noopDeleter,
106-
NULL /* finalize_hint */, &theBuffer));
113+
napi_create_external_buffer(env,
114+
sizeof(theText),
115+
(void*)theText,
116+
noopDeleter,
117+
NULL /* finalize_hint */,
118+
&theBuffer));
107119
return theBuffer;
108120
}
109121

@@ -123,6 +135,31 @@ static napi_value invalidObjectAsBuffer(napi_env env, napi_callback_info info) {
123135
return notTheBuffer;
124136
}
125137

138+
static napi_value bufferFromArrayBuffer(napi_env env, napi_callback_info info) {
139+
napi_status status;
140+
napi_value arraybuffer;
141+
napi_value buffer;
142+
size_t byte_length = 1024;
143+
void* data = NULL;
144+
size_t buffer_length = 0;
145+
void* buffer_data = NULL;
146+
147+
status = napi_create_arraybuffer(env, byte_length, &data, &arraybuffer);
148+
NODE_API_ASSERT(env, status == napi_ok, "Failed to create arraybuffer");
149+
150+
status = node_api_create_buffer_from_arraybuffer(
151+
env, arraybuffer, 0, byte_length, &buffer);
152+
NODE_API_ASSERT(
153+
env, status == napi_ok, "Failed to create buffer from arraybuffer");
154+
155+
status = napi_get_buffer_info(env, buffer, &buffer_data, &buffer_length);
156+
NODE_API_ASSERT(env, status == napi_ok, "Failed to get buffer info");
157+
158+
NODE_API_ASSERT(env, buffer_length == byte_length, "Buffer length mismatch");
159+
160+
return buffer;
161+
}
162+
126163
static napi_value Init(napi_env env, napi_value exports) {
127164
napi_value theValue;
128165

@@ -140,6 +177,7 @@ static napi_value Init(napi_env env, napi_value exports) {
140177
DECLARE_NODE_API_PROPERTY("bufferInfo", bufferInfo),
141178
DECLARE_NODE_API_PROPERTY("staticBuffer", staticBuffer),
142179
DECLARE_NODE_API_PROPERTY("invalidObjectAsBuffer", invalidObjectAsBuffer),
180+
DECLARE_NODE_API_PROPERTY("bufferFromArrayBuffer", bufferFromArrayBuffer),
143181
};
144182

145183
NODE_API_CALL(env, napi_define_properties(

0 commit comments

Comments
 (0)