Working with ArrayBuffer Using Node-API
Introduction
ArrayBuffer in ArkTS is a type of object that represents a generic, fixed-length buffer of raw binary data. It provides a way to effectively represent and manipulate raw binary data in ArkTS.
Basic Concepts
- ArrayBuffer: An ArrayBuffer object represents a generic, fixed-length buffer of raw binary data. The ArrayBuffer content cannot be directly operated. Instead, you need to use a TypedArray or DataView object to interpret the buffer data in specific formats. ArrayBuffer is used to process a large amount of binary data, such as files and network data packets.
- Lifecycle and memory management: When using Node-API to process ArrayBuffer objects, note that the lifecycle of the created arrayBufferPtr is managed by the engine and cannot be deleted by users. Otherwise, a double free error may occur.
Available APIs
The following table lists the APIs used to manipulate data of the ArrayBuffer type.
| API | Description |
|---|---|
| napi_is_arraybuffer | Checks whether a value is an ArrayBuffer object. Note that this API cannot be used to check whether a value is a TypedArray object. To check whether a value is a TypedArray object, use napi_is_typedarray. |
| napi_get_arraybuffer_info | Obtains information of an ArrayBuffer object, including the pointer to the data and the data length. |
| napi_detach_arraybuffer | Detaches the underlying data from an ArrayBuffer object. After the data is detached, you can operate the data in C/C++. |
| napi_is_detached_arraybuffer | Checks whether an ArrayBuffer object has been detached. |
| napi_create_arraybuffer | Creates an ArkTS ArrayBuffer object with the specified byte length. |
Example
If you are just starting out with Node-API, see Node-API Development Process. The following demonstrates only the C++ and ArkTS code related to ArrayBuffer management.
napi_is_arraybuffer
Call napi_is_arraybuffer to check whether a JS value is an ArrayBuffer object.
CPP code:
#include "napi/native_api.h"
static napi_value IsArrayBuffer(napi_env env, napi_callback_info info)
{
// Obtain a parameter.
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
// Call napi_is_arraybuffer to check whether the input parameter is an **ArrayBuffer** object.
bool result = false;
napi_status status = napi_is_arraybuffer(env, args[0], &result);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "Node-API napi_is_arraybuffer fail");
return nullptr;
}
// Convert the result to napi_value and return it.
napi_value returnValue = nullptr;
napi_get_boolean(env, result, &returnValue);
return returnValue;
}
API declaration:
// index.d.ts
export const isArrayBuffer: <T>(arrayBuffer: T) => boolean | void;
ArkTS code:
import hilog from '@ohos.hilog'
import testNapi from 'libentry.so'
try {
let value = new ArrayBuffer(1);
let data = "123";
hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_arraybuffer: %{public}s', testNapi.isArrayBuffer(value));
hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_arraybuffer: %{public}s', testNapi.isArrayBuffer(data));
} catch (error) {
hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_arraybuffer error: %{public}s', error.message);
}
napi_get_arraybuffer_info
Call napi_get_arraybuffer_info to obtain the underlying data buffer and length of an ArrayBuffer object.
CPP code:
#include "napi/native_api.h"
static napi_value GetArrayBufferInfo(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
// Check whether the parameter is an ArrayBuffer object.
bool isArrayBuffer = false;
napi_is_arraybuffer(env, args[0], &isArrayBuffer);
if (!isArrayBuffer) {
napi_throw_type_error(env, nullptr, "Argument must be an ArrayBuffer");
return nullptr;
}
void *data = nullptr;
size_t byteLength = 0;
// Obtain the underlying data buffer and length of the ArrayBuffer object.
napi_status status = napi_get_arraybuffer_info(env, args[0], &data, &byteLength);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "Failed to get ArrayBuffer info");
return nullptr;
}
// Create a result object.
napi_value result = nullptr;
napi_create_object(env, &result);
// Set the byte length property of the data buffer.
napi_value byteLengthValue = nullptr;
napi_create_uint32(env, byteLength, &byteLengthValue);
napi_set_named_property(env, result, "byteLength", byteLengthValue);
napi_value bufferData;
napi_create_arraybuffer(env, byteLength, &data, &bufferData);
napi_set_named_property(env, result, "buffer", bufferData);
return result;
}
API declaration:
// index.d.ts
export class ArrayBufferInfo {
byteLength: number;
buffer: Object;
}
export const getArrayBufferInfo: (data: ArrayBuffer) => ArrayBufferInfo | void;
ArkTS code:
import hilog from '@ohos.hilog'
import testNapi from 'libentry.so'
const buffer = new ArrayBuffer(10);
hilog.info(0x0000, 'testTag', 'Test Node-API get_arrayBuffer_info:%{public}s ', JSON.stringify(testNapi.getArrayBufferInfo(buffer)));
napi_detach_arraybuffer
Call napi_detach_arraybuffer to detach the underlying data from an ArrayBuffer object.
napi_is_detached_arraybuffer
Call napi_is_detached_arraybuffer to check whether an ArrayBuffer object has been detached.
CPP code:
#include "napi/native_api.h"
static napi_value DetachedArrayBuffer(napi_env env, napi_callback_info info)
{
// Call napi_detach_arraybuffer to detach the underlying data from an ArrayBuffer object.
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_value arrayBuffer = args[0];
napi_detach_arraybuffer(env, arrayBuffer);
// Pass out the detached ArrayBuffer object.
return arrayBuffer;
}
static napi_value IsDetachedArrayBuffer(napi_env env, napi_callback_info info)
{
// Call napi_is_detached_arraybuffer to check whether the specified ArrayBuffer object has been detached.
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_value arrayBuffer = args[0];
bool result = false;
napi_is_detached_arraybuffer(env, arrayBuffer, &result);
// Call napi_get_boolean to convert the return value to napi_value, and pass out the napi_value for printing.
napi_value returnValue;
napi_get_boolean(env, result, &returnValue);
return returnValue;
}
API declaration:
// index.d.ts
export const detachedArrayBuffer: (buffer:ArrayBuffer) => ArrayBuffer;
export const isDetachedArrayBuffer: (arrayBuffer: ArrayBuffer) => boolean;
ArkTS code:
import hilog from '@ohos.hilog'
import testNapi from 'libentry.so'
try {
const bufferArray = new ArrayBuffer(8);
hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_detached_arraybuffer one: %{public}s', testNapi.isDetachedArrayBuffer(bufferArray));
hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_detached_arraybuffer two: %{public}s ', testNapi.isDetachedArrayBuffer(testNapi.detachedArrayBuffer(bufferArray)));
} catch (error) {
hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_detached_arraybuffer error: %{public}s', error.message);
}
napi_create_arraybuffer
Call napi_create_arraybuffer to create an ArkTS ArrayBuffer object with the specified byte length in C/C++. If the caller wants to directly operate the buffer, return the underlying buffer to the caller. To write data to this buffer from ArkTS, you need to create a TypedArray or DataView object.
NOTE
If byte_length of napi_create_arraybuffer is 0 or an excessively large value, nullptr will be returned in data. Therefore, it is necessary to check whether data is empty before using it.
CPP code:
#include "napi/native_api.h"
static napi_value CreateArrayBuffer(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = {nullptr};
napi_value result = nullptr;
// Parse the input parameters.
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
int32_t value;
size_t length;
// Convert the parameter passed from ArkTS to the size_t type and use it as the parameter of napi_create_arraybuffer.
napi_get_value_int32(env, argv[0], &value);
length = size_t(value);
void *data;
// Create an ArrayBuffer object.
napi_create_arraybuffer(env, length, &data, &result);
if (data != nullptr) {
// Check data before using it for subsequent operations.
}
// Return the ArrayBuffer object.
return result;
}
API declaration:
// index.d.ts
export const createArrayBuffer: (size: number) => ArrayBuffer;
ArkTS code:
import hilog from '@ohos.hilog'
import testNapi from 'libentry.so'
hilog.info(0x0000, 'testTag', 'Test Node-API napi_create_arraybuffer:%{public}s', testNapi.createArrayBuffer(10).toString());
To print logs in the native CPP, add the following information to the CMakeLists.txt file and add the header file by using #include "hilog/log.h".
// CMakeLists.txt
add_definitions( "-DLOG_DOMAIN=0xd0d0" )
add_definitions( "-DLOG_TAG=\"testTag\"" )
target_link_libraries(entry PUBLIC libhilog_ndk.z.so)