Skip to content

Commit bedaacf

Browse files
committed
add napi_create_buffer_from_arraybuffer (nodejs/node#54505)
1 parent 34e2a22 commit bedaacf

4 files changed

Lines changed: 131 additions & 0 deletions

File tree

packages/emnapi/include/node/node_api.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,18 @@ napi_create_external_buffer(napi_env env,
145145
void* finalize_hint,
146146
napi_value* result);
147147
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
148+
149+
#ifdef NAPI_EXPERIMENTAL
150+
#define NODE_API_EXPERIMENTAL_HAS_CREATE_BUFFER_FROM_ARRAYBUFFER
151+
152+
NAPI_EXTERN napi_status NAPI_CDECL
153+
node_api_create_buffer_from_arraybuffer(napi_env env,
154+
napi_value arraybuffer,
155+
size_t byte_offset,
156+
size_t byte_length,
157+
napi_value* result);
158+
#endif // NAPI_EXPERIMENTAL
159+
148160
NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env,
149161
size_t length,
150162
const void* data,

packages/emnapi/src/value/create.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,63 @@ export function napi_create_external_buffer (
412412
)
413413
}
414414

415+
/**
416+
* @__sig ippppp
417+
*/
418+
export function node_api_create_buffer_from_arraybuffer (
419+
env: napi_env,
420+
arraybuffer: napi_value,
421+
byte_offset: size_t,
422+
byte_length: size_t,
423+
result: Pointer<napi_value>
424+
): napi_status {
425+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
426+
let value: number
427+
428+
return $PREAMBLE!(env, (envObject) => {
429+
$CHECK_ARG!(envObject, arraybuffer)
430+
$CHECK_ARG!(envObject, result)
431+
from64('byte_offset')
432+
from64('byte_length')
433+
byte_offset = byte_offset >>> 0
434+
byte_length = byte_length >>> 0
435+
const handle = emnapiCtx.handleStore.get(arraybuffer)!
436+
const buffer = handle.value
437+
if (!(buffer instanceof ArrayBuffer)) {
438+
return envObject.setLastError(napi_status.napi_invalid_arg)
439+
}
440+
441+
if ((byte_length + byte_offset) > buffer.byteLength) {
442+
const err: RangeError & { code?: string } = new RangeError('The byte offset + length is out of range')
443+
err.code = 'ERR_OUT_OF_RANGE'
444+
throw err
445+
}
446+
447+
const Buffer = emnapiCtx.feature.Buffer!
448+
if (!Buffer) {
449+
throw emnapiCtx.createNotSupportBufferError('node_api_create_buffer_from_arraybuffer', '')
450+
}
451+
const out = Buffer.from(buffer, byte_offset, byte_length)
452+
if (buffer === wasmMemory.buffer) {
453+
if (!emnapiExternalMemory.wasmMemoryViewTable.has(out)) {
454+
emnapiExternalMemory.wasmMemoryViewTable.set(out, {
455+
Ctor: Buffer,
456+
address: byte_offset,
457+
length: byte_length,
458+
ownership: ReferenceOwnership.kUserland,
459+
runtimeAllocated: 0
460+
})
461+
}
462+
}
463+
from64('result')
464+
465+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
466+
value = emnapiCtx.addToCurrentScope(out).id
467+
makeSetValue('result', 0, 'value', '*')
468+
return envObject.getReturnStatus()
469+
})
470+
}
471+
415472
/**
416473
* @__sig ippppp
417474
*/

packages/test/buffer/binding.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,64 @@ static napi_value getMemoryDataAsArray(napi_env env, napi_callback_info info) {
190190
return ret;
191191
}
192192

193+
NAPI_EXTERN napi_status NAPI_CDECL
194+
node_api_create_buffer_from_arraybuffer(napi_env env,
195+
napi_value arraybuffer,
196+
size_t byte_offset,
197+
size_t byte_length,
198+
napi_value* result);
199+
200+
static napi_value testBufferFromArrayBuffer(napi_env env,
201+
napi_callback_info info) {
202+
napi_status status;
203+
napi_value arraybuffer;
204+
void* data;
205+
napi_value buffer;
206+
size_t byte_length = 1024;
207+
size_t byte_offset = 0;
208+
209+
status = napi_create_arraybuffer(env, byte_length, &data, &arraybuffer);
210+
NODE_API_ASSERT(env, status == napi_ok, "Failed to create arraybuffer");
211+
212+
status = node_api_create_buffer_from_arraybuffer(
213+
env, arraybuffer, byte_offset, byte_length, &buffer);
214+
NODE_API_ASSERT(
215+
env, status == napi_ok, "Failed to create buffer from arraybuffer");
216+
217+
void* buffer_data;
218+
size_t buffer_length;
219+
status = napi_get_buffer_info(env, buffer, &buffer_data, &buffer_length);
220+
NODE_API_ASSERT(env, status == napi_ok, "Failed to get buffer info");
221+
NODE_API_ASSERT(env, buffer_length == byte_length, "Buffer length mismatch");
222+
223+
bool is_buffer;
224+
status = napi_is_buffer(env, buffer, &is_buffer);
225+
NODE_API_ASSERT(env, status == napi_ok, "Failed to check if value is buffer");
226+
NODE_API_ASSERT(env, is_buffer, "Expected a Buffer but did not get one");
227+
228+
status = node_api_create_buffer_from_arraybuffer(
229+
env, arraybuffer, byte_length, byte_length + 1, &buffer);
230+
NODE_API_ASSERT(env,
231+
status == 10,
232+
"Expected range error for invalid byte offset");
233+
napi_value last_error;
234+
status = napi_get_and_clear_last_exception(env, &last_error);
235+
NODE_API_ASSERT(env, status == napi_ok, "Failed to call napi_get_and_clear_last_exception");
236+
237+
napi_value non_arraybuffer;
238+
status = napi_create_uint32(env, 123, &non_arraybuffer);
239+
NODE_API_ASSERT(
240+
env, status == napi_ok, "Failed to create non-arraybuffer value");
241+
242+
status = node_api_create_buffer_from_arraybuffer(
243+
env, non_arraybuffer, byte_offset, byte_length, &buffer);
244+
NODE_API_ASSERT(env,
245+
status == napi_invalid_arg,
246+
"Expected invalid arg error for non-arraybuffer input");
247+
248+
return arraybuffer;
249+
}
250+
193251
static napi_value Init(napi_env env, napi_value exports) {
194252
napi_value theValue;
195253

@@ -208,6 +266,8 @@ static napi_value Init(napi_env env, napi_value exports) {
208266
DECLARE_NODE_API_PROPERTY("staticBuffer", staticBuffer),
209267
DECLARE_NODE_API_PROPERTY("invalidObjectAsBuffer", invalidObjectAsBuffer),
210268
DECLARE_NODE_API_PROPERTY("getMemoryDataAsArray", getMemoryDataAsArray),
269+
DECLARE_NODE_API_PROPERTY("testBufferFromArrayBuffer",
270+
testBufferFromArrayBuffer),
211271
};
212272

213273
NODE_API_CALL(env, napi_define_properties(

packages/test/buffer/buffer.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,6 @@ module.exports = load('buffer').then(async binding => {
5858
assert.deepStrictEqual(binding.getMemoryDataAsArray(buffer), Array(6).fill(99))
5959
assert.deepStrictEqual(binding.getMemoryDataAsArray(typedArray), Array(6).fill(99))
6060
assert.deepStrictEqual(binding.getMemoryDataAsArray(dataView), Array(6).fill(99))
61+
62+
binding.testBufferFromArrayBuffer()
6163
})

0 commit comments

Comments
 (0)