85 lines
2.5 KiB
JavaScript
Raw Normal View History

2025-04-28 12:25:20 +08:00
'use strict';
/**
* Module dependencies.
*/
const Type = require('./type');
const assert = require('assert');
const debug = require('debug')('ffi:cif_var');
const ref = require('ref-napi');
const bindings = require('./bindings');
const POINTER_SIZE = ref.sizeof.pointer;
const ffi_prep_cif_var = bindings.ffi_prep_cif_var;
const FFI_CIF_SIZE = bindings.FFI_CIF_SIZE;
const FFI_DEFAULT_ABI = bindings.FFI_DEFAULT_ABI;
// status codes
const FFI_OK = bindings.FFI_OK;
const FFI_BAD_TYPEDEF = bindings.FFI_BAD_TYPEDEF;
const FFI_BAD_ABI = bindings.FFI_BAD_ABI;
/**
* JS wrapper for the `ffi_prep_cif_var` function.
* Returns a Buffer instance representing a variadic `ffi_cif *` instance.
*/
function CIF_var (rtype, types, numFixedArgs, abi) {
debug('creating `ffi_cif *` instance with `ffi_prep_cif_var()`');
// the return and arg types are expected to be coerced at this point...
assert(!!rtype, 'expected a return "type" object as the first argument');
assert(Array.isArray(types), 'expected an Array of arg "type" objects as the second argument');
assert(numFixedArgs >= 1, 'expected the number of fixed arguments to be at least 1');
// the buffer that will contain the return `ffi_cif *` instance
const cif = Buffer.alloc(FFI_CIF_SIZE);
const numTotalArgs = types.length;
const _argtypesptr = Buffer.alloc(numTotalArgs * POINTER_SIZE);
const _rtypeptr = Type(rtype);
for (let i = 0; i < numTotalArgs; i++) {
const ffiType = Type(types[i]);
_argtypesptr.writePointer(ffiType, i * POINTER_SIZE);
}
// prevent GC of the arg type and rtn type buffers (not sure if this is required)
cif.rtnTypePtr = _rtypeptr;
cif.argTypesPtr = _argtypesptr;
if (typeof abi === 'undefined') {
debug('no ABI specified (this is OK), using FFI_DEFAULT_ABI');
abi = FFI_DEFAULT_ABI;
}
const status = ffi_prep_cif_var(cif, numFixedArgs, numTotalArgs, _rtypeptr, _argtypesptr, abi);
if (status !== FFI_OK) {
switch (status) {
case FFI_BAD_TYPEDEF:
{
const err = new Error('ffi_prep_cif_var() returned an FFI_BAD_TYPEDEF error');
err.code = 'FFI_BAD_TYPEDEF';
err.errno = status;
throw err;
}
case FFI_BAD_ABI:
{
const err = new Error('ffi_prep_cif_var() returned an FFI_BAD_ABI error');
err.code = 'FFI_BAD_ABI';
err.errno = status;
throw err;
}
default:
{
const err = new Error('ffi_prep_cif_var() returned an error: ' + status);
err.errno = status;
throw err;
}
}
}
return cif;
}
module.exports = CIF_var;