85 lines
2.5 KiB
JavaScript
85 lines
2.5 KiB
JavaScript
|
'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;
|