Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

koffi

Package Overview
Dependencies
Maintainers
1
Versions
224
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koffi - npm Package Compare versions

Comparing version 2.3.5 to 2.3.6-beta.1

src/cnoke/src/builder.js

7

CHANGELOG.md

@@ -7,2 +7,9 @@ # Changelog

#### Koffi 2.3.6
**Main changes:**
- Fix broken TS definition file
- Keep all prebuilt binaries and load correct one at runtime
#### Koffi 2.3.5

@@ -9,0 +16,0 @@

8

package.json
{
"name": "koffi",
"version": "2.3.5",
"version": "2.3.6-beta.1",
"stable": "2.3.5",

@@ -28,6 +28,6 @@ "description": "Fast and simple C FFI (foreign function interface) for Node.js",

"cnoke": {
"prebuild": "src/koffi/build/{{version}}/koffi_{{platform}}_{{arch}}.tar.gz",
"require": "./src/koffi/build/koffi.node",
"napi": 8
"napi": 8,
"require": "./src/koffi/build/{{version}}/koffi_{{platform}}_{{arch}}/koffi.node",
"output": "./build/{{version}}/koffi_{{platform}}_{{arch}}"
}
}

@@ -18,43 +18,17 @@ #!/usr/bin/env node

const crypto = require('crypto');
const fs = require('fs');
const http = require('https');
const os = require('os');
const path = require('path');
const process = require('process');
const zlib = require('zlib');
const { spawnSync } = require('child_process');
const { Buffer } = require('buffer');
const { Builder } = require('./src/index.js');
// Globals
const VALID_COMMANDS = ['build', 'configure', 'clean'];
const DEFAULT_MODE = 'RelWithDebInfo';
const default_mode = 'RelWithDebInfo';
let app_dir = null;
let project_dir = null;
let package_dir = null;
let cache_dir = null;
let build_dir = null;
let work_dir = null;
let runtime_version = null;
let arch = null;
let toolset = null;
let prefer_clang = false;
let mode = default_mode;
let targets = [];
let verbose = false;
let prebuild = false;
let prebuild_url = null;
let prebuild_req = null;
let cmake_bin = null;
// Main
main();
async function main() {
let command = build;
let config = {};
let command = 'build';
// Default options
config.mode = DEFAULT_MODE;
// Parse options

@@ -65,6 +39,7 @@ {

if (process.argv.length >= 3 && process.argv[2][0] != '-') {
switch (process.argv[2]) {
case 'build': { command = build; i++; } break;
case 'configure': { command = configure; i++; } break;
case 'clean': { command = clean; i++; } break;
let cmd = process.argv[2];
if (VALID_COMMANDS.includes(cmd)) {
command = cmd;
i++;
}

@@ -102,4 +77,4 @@ }

project_dir = fs.realpathSync(value);
} else if ((command == build || command == configure) && (arg == '-v' || arg == '--runtime-version')) {
config.project_dir = fs.realpathSync(value);
} else if ((command == 'build' || command == 'configure') && (arg == '-v' || arg == '--runtime-version')) {
if (value == null)

@@ -110,16 +85,16 @@ throw new Error(`Missing value for ${arg}`);

runtime_version = value;
} else if ((command == build || command == configure) && (arg == '-a' || arg == '--arch')) {
config.runtime_version = value;
} else if ((command == 'build' || command == 'configure') && (arg == '-a' || arg == '--arch')) {
if (value == null)
throw new Error(`Missing value for ${arg}`);
arch = value;
} else if ((command == build || command == configure) && (arg == '-t' || arg == '--toolset')) {
config.arch = value;
} else if ((command == 'build' || command == 'configure') && (arg == '-t' || arg == '--toolset')) {
if (value == null)
throw new Error(`Missing value for ${arg}`);
toolset = value;
} else if ((command == build || command == configure) && (arg == '-C' || arg == '--prefer-clang')) {
prefer_clang = true;
} else if ((command == build || command == configure) && (arg == '-B' || arg == '--config')) {
config.toolset = value;
} else if ((command == 'build' || command == 'configure') && (arg == '-C' || arg == '--prefer-clang')) {
config.prefer_clang = true;
} else if ((command == 'build' || command == 'configure') && (arg == '-B' || arg == '--config')) {
if (value == null)

@@ -129,5 +104,5 @@ throw new Error(`Missing value for ${arg}`);

switch (value.toLowerCase()) {
case 'relwithdebinfo': { mode = 'RelWithDebInfo'; } break;
case 'debug': { mode = 'Debug'; } break;
case 'release': { mode = 'Release'; } break;
case 'relwithdebinfo': { config.mode = 'RelWithDebInfo'; } break;
case 'debug': { config.mode = 'Debug'; } break;
case 'release': { config.mode = 'Release'; } break;

@@ -138,19 +113,13 @@ default: {

}
} else if ((command == build || command == configure) && (arg == '-D' || arg == '--debug')) {
mode = 'Debug';
} else if (command == build && arg == '--verbose') {
verbose = true;
} else if (command == build && arg == '--prebuild') {
prebuild = true;
prebuild_url = value;
} else if (command == build && arg == '--require') {
} else if ((command == 'build' || command == 'configure') && (arg == '-D' || arg == '--debug')) {
config.mode = 'Debug';
} else if (command == 'build' && arg == '--verbose') {
config.verbose = true;
} else if (command == 'build' && arg == '--prebuild') {
config.prebuild = true;
} else if (command == 'build' && (arg == '-T' || arg == '--target')) {
if (value == null)
throw new Error(`Missing value for ${arg}`);
prebuild_req = value;
} else if (command == build && (arg == '-T' || arg == '--target')) {
if (value == null)
throw new Error(`Missing value for ${arg}`);
targets = [value];
config.targets = [value];
} else {

@@ -166,20 +135,5 @@ if (arg[0] == '-') {

if (runtime_version == null)
runtime_version = process.version;
if (runtime_version.startsWith('v'))
runtime_version = runtime_version.substr(1);
if (arch == null)
arch = determine_arch();
app_dir = __dirname.replace(/\\/g, '/');
if (project_dir == null)
project_dir = process.cwd();
project_dir = project_dir.replace(/\\/g, '/');
package_dir = find_parent_directory(project_dir, 'package.json');
cache_dir = get_cache_directory();
build_dir = project_dir + '/build';
work_dir = build_dir + `/v${runtime_version}_${arch}`;
try {
await command();
let builder = new Builder(config);
await builder[command]();
} catch (err) {

@@ -204,10 +158,9 @@ console.error(err);

-B, --config <CONFIG> Change build type: RelWithDebInfo, Debug, Release
(default: ${default_mode})
(default: ${DEFAULT_MODE})
-D, --debug Shortcut for --config Debug
--prebuild [URL] Enable use of prebuilt binaries
--require <PATH> Require specified module, drop prebuild if it fails
--prebuild Use prebuilt binari if available
-a, --arch <ARCH> Change architecture and ABI
(default: ${determine_arch()})
(default: ${cnoke.determine_arch()})
-v, --runtime-version <VERSION> Change node version

@@ -230,748 +183,1 @@ (default: ${process.version})

}
// Commands
async function configure(retry = true) {
let args = [project_dir];
check_cmake();
check_compatibility();
console.log(`>> Node: ${runtime_version}`);
console.log(`>> Target: ${process.platform}_${arch}`);
// Prepare build directory
fs.mkdirSync(cache_dir, { recursive: true, mode: 0o755 });
fs.mkdirSync(build_dir, { recursive: true, mode: 0o755 });
fs.mkdirSync(work_dir, { recursive: true, mode: 0o755 });
retry &= fs.existsSync(work_dir + '/CMakeCache.txt');
// Download Node headers
{
let basename = `node-v${runtime_version}-headers.tar.gz`;
let urls = [
`https://nodejs.org/dist/v${runtime_version}/${basename}`,
`https://unofficial-builds.nodejs.org/download/release/v${runtime_version}/${basename}`
];
let destname = `${cache_dir}/${basename}`;
if (!fs.existsSync(destname))
await download(urls, destname);
await extract_targz(destname, work_dir + '/headers', 1);
}
// Download Node import library (Windows)
if (process.platform === 'win32') {
let dirname;
switch (arch) {
case 'ia32': { dirname = 'win-x86'; } break;
case 'x64': { dirname = 'win-x64'; } break;
case 'arm64': { dirname = 'win-arm64'; } break;
default: {
throw new Error(`Unsupported architecture '${arch}' for Node on Windows`);
} break;
}
let destname = `${cache_dir}/node_v${runtime_version}_${arch}.lib`;
if (!fs.existsSync(destname)) {
let urls = [
`https://nodejs.org/dist/v${runtime_version}/${dirname}/node.lib`,
`https://unofficial-builds.nodejs.org/download/release/v${runtime_version}/${dirname}/node.lib`
];
await download(urls, destname);
}
fs.copyFileSync(destname, work_dir + '/node.lib');
}
args.push(`-DCMAKE_MODULE_PATH=${app_dir}/assets`);
args.push(`-DNODE_JS_INCLUDE_DIRS=${work_dir}/headers/include/node`);
// Set platform flags
switch (process.platform) {
case 'win32': {
fs.copyFileSync(`${app_dir}/assets/win_delay_hook.c`, work_dir + '/win_delay_hook.c');
args.push(`-DNODE_JS_SOURCES=${work_dir}/win_delay_hook.c`);
args.push(`-DNODE_JS_LIBRARIES=${work_dir}/node.lib`);
switch (arch) {
case 'ia32': {
args.push('-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe;/SAFESEH:NO');
args.push('-A', 'Win32');
} break;
case 'arm64': {
args.push('-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe;/SAFESEH:NO');
args.push('-A', 'ARM64');
} break;
case 'x64': {
args.push('-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe');
args.push('-A', 'x64');
} break;
}
} break;
case 'darwin': {
args.push('-DNODE_JS_LINK_FLAGS=-undefined;dynamic_lookup');
switch (arch) {
case 'arm64': { args.push('-DCMAKE_OSX_ARCHITECTURES=arm64'); } break;
case 'x64': { args.push('-DCMAKE_OSX_ARCHITECTURES=x86_64'); } break;
}
} break;
}
if (process.platform != 'win32') {
// Prefer Ninja if available
if (spawnSync('ninja', ['--version']).status === 0)
args.push('-G', 'Ninja');
// Use CCache if available
if (spawnSync('ccache', ['--version']).status === 0) {
args.push('-DCMAKE_C_COMPILER_LAUNCHER=ccache');
args.push('-DCMAKE_CXX_COMPILER_LAUNCHER=ccache');
}
}
if (prefer_clang) {
if (process.platform == 'win32') {
args.push('-T', 'ClangCL');
} else {
args.push('-DCMAKE_C_COMPILER=clang');
args.push('-DCMAKE_CXX_COMPILER=clang++');
}
}
if (toolset != null)
args.push('-T', toolset);
args.push(`-DCMAKE_BUILD_TYPE=${mode}`);
for (let type of ['ARCHIVE', 'RUNTIME', 'LIBRARY']) {
for (let suffix of ['', '_DEBUG', '_RELEASE', '_RELWITHDEBINFO'])
args.push(`-DCMAKE_${type}_OUTPUT_DIRECTORY${suffix}=${build_dir}`);
}
args.push('--no-warn-unused-cli');
console.log('>> Running configuration');
let proc = spawnSync(cmake_bin, args, { cwd: work_dir, stdio: 'inherit' });
if (proc.status !== 0) {
unlink_recursive(work_dir);
if (retry)
return configure(false);
throw new Error('Failed to run configure step');
}
}
async function build() {
check_compatibility();
if (prebuild) {
let pkg = read_package_json();
if (prebuild_url == null) {
if (pkg.cnoke.prebuild == null)
throw new Error('Missing prebuild URL');
prebuild_url = pkg.cnoke.prebuild;
}
fs.mkdirSync(build_dir, { recursive: true, mode: 0o755 });
let url = prebuild_url.replace(/{{([a-zA-Z_][a-zA-Z_0-9]*)}}/g, (match, p1) => {
switch (p1) {
case 'version': {
let pkg = read_package_json();
return pkg.version || '';
} break;
case 'platform': return process.platform;
case 'arch': return arch;
default: return match;
}
});
let basename = path.basename(url);
try {
let archive_filename = null;
if (url.startsWith('file:/')) {
if (url.startsWith('file://localhost/')) {
url = url.substr(16);
} else {
let offset = 6;
while (offset < 9 && url[offset] == '/')
offset++;
url = url.substr(offset - 1);
}
if (process.platform == 'win32' && url.match(/^\/[a-zA-Z]+:[\\\/]/))
url = url.substr(1);
}
if (url.match(/^[a-z]+:\/\//)) {
archive_filename = build_dir + '/' + basename;
await download(url, archive_filename);
} else {
if (path_is_absolute(url)) {
archive_filename = url;
} else if (package_dir != null) {
archive_filename = package_dir + '/' + url;
} else {
archive_filename = project_dir + '/' + url;
}
if (!fs.existsSync(archive_filename))
throw new Error('Cannot find local prebuilt archive');
}
console.log('>> Extracting prebuilt binaries...');
await extract_targz(archive_filename, build_dir, 1);
// Make sure the binary works
if (prebuild_req == null)
prebuild_req = pkg.cnoke.require;
if (prebuild_req != null) {
let proc = spawnSync(process.execPath, ['-e', 'require(process.argv[1])', prebuild_req]);
if (proc.status === 0)
return;
} else {
return;
}
// Clean it up if it does not, before source build. Only delete files, it is safer and it is enough!
let entries = fs.readdirSync(build_dir, { withFileTypes: true });
for (let entry of entries) {
if (!entry.isDirectory()) {
let filename = path.join(build_dir, entry.name);
fs.unlinkSync(filename);
}
}
console.error('Failed to load prebuilt binary, rebuilding from source');
} catch (err) {
console.error('Failed to find prebuilt binary for your platform, building manually');
}
}
check_cmake();
if (!fs.existsSync(work_dir + '/CMakeCache.txt'))
await configure();
// In case Make gets used
if (process.env.MAKEFLAGS == null)
process.env.MAKEFLAGS = '-j' + os.cpus().length;
let args = [
'--build', work_dir,
'--config', mode
];
if (verbose)
args.push('--verbose');
for (let target of targets)
args.push('--target', target);
console.log('>> Running build');
let proc = spawnSync(cmake_bin, args, { stdio: 'inherit' });
if (proc.status !== 0)
throw new Error('Failed to run build step');
}
async function clean() {
unlink_recursive(build_dir);
}
// Utility
function get_cache_directory() {
if (process.platform == 'win32') {
let cache_dir = process.env['APPDATA'];
if (cache_dir == null)
throw new Error('Missing APPDATA environment variable');
cache_dir = path.join(cache_dir, 'cnoke');
return cache_dir;
} else {
let cache_dir = process.env['XDG_CACHE_HOME'];
if (cache_dir == null) {
let home = process.env['HOME'];
if (home == null)
throw new Error('Missing HOME environment variable');
cache_dir = path.join(home, '.cache');
}
cache_dir = path.join(cache_dir, 'cnoke');
return cache_dir;
}
}
function check_cmake() {
if (cmake_bin != null)
return;
// Check for CMakeLists.txt
if (!fs.existsSync(project_dir + '/CMakeLists.txt'))
throw new Error('This directory does not appear to have a CMakeLists.txt file');
// Check for CMake
{
let proc = spawnSync('cmake', ['--version']);
if (proc.status === 0) {
cmake_bin = 'cmake';
} else {
if (process.platform == 'win32') {
// I really don't want to depend on anything in CNoke, and Node.js does not provide
// anything to read from the registry. This is okay, REG.exe exists since Windows XP.
let proc = spawnSync('reg', ['query', 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Kitware\\CMake', '/v', 'InstallDir']);
if (proc.status === 0) {
let matches = proc.stdout.toString('utf-8').match(/InstallDir[ \t]+REG_[A-Z_]+[ \t]+(.*)+/);
if (matches != null) {
let bin = path.join(matches[1].trim(), 'bin\\cmake.exe');
if (fs.existsSync(bin))
cmake_bin = bin;
}
}
}
if (cmake_bin == null)
throw new Error('CMake does not seem to be available');
}
}
console.log(`>> Using CMake binary: ${cmake_bin}`);
}
function check_compatibility() {
let pkg = read_package_json();
if (pkg.cnoke.node != null && cmp_version(runtime_version, pkg.cnoke.node) < 0)
throw new Error(`Project ${pkg.name} requires Node.js >= ${pkg.cnoke.node}`);
if (pkg.cnoke.napi != null) {
let major = parseInt(runtime_version, 10);
let required = get_napi_version(pkg.cnoke.napi, major);
if (required == null)
throw new Error(`Project ${pkg.name} does not support the Node ${major}.x branch (old or missing N-API)`);
if (cmp_version(runtime_version, required) < 0)
throw new Error(`Project ${pkg.name} requires Node >= ${required} in the Node ${major}.x branch (with N-API >= ${pkg.engines.napi})`);
}
}
function read_package_json() {
let pkg = {};
if (package_dir != null) {
try {
let json = fs.readFileSync(package_dir + '/package.json', { encoding: 'utf-8' });
pkg = JSON.parse(json);
} catch (err) {
if (err.code != 'ENOENT')
throw err;
}
}
if (pkg.cnoke == null)
pkg.cnoke = {};
return pkg;
}
function unlink_recursive(path) {
try {
if (fs.rmSync != null) {
fs.rmSync(path, { recursive: true, maxRetries: process.platform == 'win32' ? 3 : 0 });
} else {
fs.rmdirSync(path, { recursive: true, maxRetries: process.platform == 'win32' ? 3 : 0 });
}
} catch (err) {
if (err.code !== 'ENOENT')
throw err;
}
}
async function download(url, dest) {
if (Array.isArray(url)) {
let urls = url;
for (let url of urls) {
try {
await download(url, dest);
return;
} catch (err) {
if (err.code != 404)
throw err;
}
}
throw new Error('All URLs returned error 404');
}
console.log('>> Downloading ' + url);
let [tmp_name, file] = open_temporary_stream(dest);
try {
await new Promise((resolve, reject) => {
let request = http.get(url, response => {
if (response.statusCode != 200) {
let err = new Error(`Download failed: ${response.statusMessage} [${response.statusCode}]`);
err.code = response.statusCode;
reject(err);
return;
}
response.pipe(file);
file.on('finish', () => file.close(() => {
try {
fs.renameSync(file.path, dest);
} catch (err) {
if (err.code != 'EBUSY')
reject(err);
}
resolve();
}));
});
request.on('error', reject);
file.on('error', reject);
});
} catch (err) {
file.close();
try {
fs.unlinkSync(tmp_name);
} catch (err) {
if (err.code != 'ENOENT')
throw err;
}
throw err;
}
}
function open_temporary_stream(prefix) {
let buf = Buffer.allocUnsafe(4);
for (;;) {
try {
crypto.randomFillSync(buf);
let suffix = buf.toString('hex').padStart(8, '0');
let filename = `${prefix}.${suffix}`;
let file = fs.createWriteStream(filename, { flags: 'wx', mode: 0o644 });
return [filename, file];
} catch (err) {
if (err.code != 'EEXIST')
throw err;
}
}
}
function read_file_header(filename, read) {
let fd = null;
try {
let fd = fs.openSync(filename);
let buf = Buffer.allocUnsafe(read);
let len = fs.readSync(fd, buf);
return buf.subarray(0, len);
} finally {
if (fd != null)
fs.closeSync(fd);
}
}
function extract_targz(filename, dest_dir, strip = 0) {
let reader = fs.createReadStream(filename).pipe(zlib.createGunzip());
return new Promise((resolve, reject) => {
let header = null;
let extended = {};
reader.on('readable', () => {
try {
for (;;) {
if (header == null) {
let buf = reader.read(512);
if (buf == null)
break;
// Two zeroed 512-byte blocks end the stream
if (!buf[0])
continue;
header = {
filename: buf.toString('utf-8', 0, 100).replace(/\0/g, ''),
mode: parseInt(buf.toString('ascii', 100, 109), 8),
size: parseInt(buf.toString('ascii', 124, 137), 8),
type: String.fromCharCode(buf[156])
};
// UStar filename prefix
/*if (buf.toString('ascii', 257, 263) == 'ustar\0') {
let prefix = buf.toString('utf-8', 345, 500).replace(/\0/g, '');
console.log(prefix);
header.filename = prefix ? (prefix + '/' + header.filename) : header.filename;
}*/
Object.assign(header, extended);
extended = {};
// Safety checks
header.filename = header.filename.replace(/\\/g, '/');
if (!header.filename.length)
throw new Error(`Insecure empty filename inside TAR archive`);
if (header.filename[0] == '/')
throw new Error(`Insecure filename starting with / inside TAR archive`);
if (path_has_dotdot(header.filename))
throw new Error(`Insecure filename containing '..' inside TAR archive`);
for (let i = 0; i < strip; i++)
header.filename = header.filename.substr(header.filename.indexOf('/') + 1);
}
let aligned = Math.floor((header.size + 511) / 512) * 512;
let data = header.size ? reader.read(aligned) : null;
if (data == null) {
if (header.size)
break;
data = Buffer.alloc(0);
}
data = data.subarray(0, header.size);
if (header.type == '0' || header.type == '7') {
let filename = dest_dir + '/' + header.filename;
let dirname = path.dirname(filename);
fs.mkdirSync(dirname, { recursive: true, mode: 0o755 });
fs.writeFileSync(filename, data, { mode: header.mode });
} else if (header.type == '5') {
let filename = dest_dir + '/' + header.filename;
fs.mkdirSync(filename, { recursive: true, mode: header.mode });
} else if (header.type == 'L') { // GNU tar
extended.filename = data.toString('utf-8').replace(/\0/g, '');
} else if (header.type == 'x') { // PAX entry
let str = data.toString('utf-8');
try {
while (str.length) {
let matches = str.match(/^([0-9]+) ([a-zA-Z0-9\._]+)=(.*)\n/);
let skip = parseInt(matches[1], 10);
let key = matches[2];
let value = matches[3];
switch (key) {
case 'path': { extended.filename = value; } break;
case 'size': { extended.size = parseInt(value, 10); } break;
}
str = str.substr(skip).trimStart();
}
} catch (err) {
throw new Error('Malformed PAX entry');
}
}
header = null;
}
} catch (err) {
reject(err);
}
});
reader.on('error', reject);
reader.on('end', resolve);
});
}
function path_is_absolute(path) {
if (process.platform == 'win32' && path.match(/^[a-zA-Z]:/))
path = path.substr(2);
return is_path_separator(path[0]);
}
function path_has_dotdot(path) {
let start = 0;
for (;;) {
let offset = path.indexOf('..', start);
if (offset < 0)
break;
start = offset + 2;
if (offset && !is_path_separator(path[offset - 1]))
continue;
if (offset + 2 < path.length && !is_path_separator(path[offset + 2]))
continue;
return true;
}
return false;
}
function is_path_separator(c) {
if (c == '/')
return true;
if (process.platform == 'win32' && c == '\\')
return true;
return false;
}
function find_parent_directory(dirname, basename)
{
if (process.platform == 'win32')
dirname = dirname.replace(/\\/g, '/');
do {
if (fs.existsSync(dirname + '/' + basename))
return dirname;
dirname = path.dirname(dirname);
} while (!dirname.endsWith('/'));
return null;
}
function determine_arch() {
let arch = process.arch;
if (arch == 'riscv32' || arch == 'riscv64') {
let buf = read_file_header(process.execPath, 512);
let header = decode_elf_header(buf);
let float_abi = (header.e_flags & 0x6) >> 1;
switch (float_abi) {
case 0: { arch += 'sf'; } break;
case 1: { arch += 'hf32'; } break;
case 2: { arch += 'hf64'; } break;
case 3: { arch += 'hf128'; } break;
}
} else if (arch == 'arm') {
arch = 'arm32';
let buf = read_file_header(process.execPath, 512);
let header = decode_elf_header(buf);
if (header.e_flags & 0x400) {
arch += 'hf';
} else if (header.e_flags & 0x200) {
arch += 'sf';
} else {
throw new Error('Unknown ARM floating-point ABI');
}
}
return arch;
}
function decode_elf_header(buf) {
let header = {};
if (buf.length < 16)
throw new Error('Truncated header');
if (buf[0] != 0x7F || buf[1] != 69 || buf[2] != 76 || buf[3] != 70)
throw new Error('Invalid magic number');
if (buf[6] != 1)
throw new Error('Invalid ELF version');
if (buf[5] != 1)
throw new Error('Big-endian architectures are not supported');
let machine = buf.readUInt16LE(18);
switch (machine) {
case 3: { header.e_machine = 'ia32'; } break;
case 40: { header.e_machine = 'arm'; } break;
case 62: { header.e_machine = 'amd64'; } break;
case 183: { header.e_machine = 'arm64'; } break;
case 243: {
switch (buf[4]) {
case 1: { header.e_machine = 'riscv32'; } break;
case 2: { header.e_machine = 'riscv64'; } break;
}
} break;
default: throw new Error('Unknown ELF machine type');
}
switch (buf[4]) {
case 1: { // 32 bit
buf = buf.subarray(0, 68);
if (buf.length < 68)
throw new Error('Truncated ELF header');
header.ei_class = 32;
header.e_flags = buf.readUInt32LE(36);
} break;
case 2: { // 64 bit
buf = buf.subarray(0, 120);
if (buf.length < 120)
throw new Error('Truncated ELF header');
header.ei_class = 64;
header.e_flags = buf.readUInt32LE(48);
} break;
default: throw new Error('Invalid ELF class');
}
return header;
}
// Versioning
function get_napi_version(napi, major) {
if (napi > 8)
return null;
// https://nodejs.org/api/n-api.html#node-api-version-matrix
const support = {
6: ['6.14.2', '6.14.2', '6.14.2'],
8: ['8.6.0', '8.10.0', '8.11.2'],
9: ['9.0.0', '9.3.0', '9.11.0'],
10: ['10.0.0', '10.0.0', '10.0.0', '10.16.0', '10.17.0', '10.20.0', '10.23.0'],
11: ['11.0.0', '11.0.0', '11.0.0', '11.8.0'],
12: ['12.0.0', '12.0.0', '12.0.0', '12.0.0', '12.11.0', '12.17.0', '12.19.0', '12.22.0'],
13: ['13.0.0', '13.0.0', '13.0.0', '13.0.0', '13.0.0'],
14: ['14.0.0', '14.0.0', '14.0.0', '14.0.0', '14.0.0', '14.0.0', '14.12.0', '14.17.0'],
15: ['15.0.0', '15.0.0', '15.0.0', '15.0.0', '15.0.0', '15.0.0', '15.0.0', '15.12.0']
};
const max = Math.max(...Object.keys(support).map(k => parseInt(k, 10)));
if (major > max)
return major + '.0.0';
if (support[major] == null)
return null;
let required = support[major][napi - 1] || null;
return required;
}
// Ignores prerelease suffixes
function cmp_version(ver1, ver2) {
ver1 = String(ver1).replace(/-.*$/, '').split('.').reduce((acc, v, idx) => acc + parseInt(v, 10) * Math.pow(10, 2 * (5 - idx)), 0);
ver2 = String(ver2).replace(/-.*$/, '').split('.').reduce((acc, v, idx) => acc + parseInt(v, 10) * Math.pow(10, 2 * (5 - idx)), 0);
let cmp = Math.min(Math.max(ver1 - ver2, -1), 1);
return cmp;
}

@@ -17,2 +17,3 @@ {

"author": "Niels Martignène <niels.martignene@protonmail.com>",
"index": "src/index.js",
"bin": "cnoke.js",

@@ -19,0 +20,0 @@ "license": "LGPL-3.0",

@@ -81,6 +81,6 @@ // This program is free software: you can redistribute it and/or modify

export function union(name: string, def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
export function union(def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
// export function union(name: string, def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
// export function union(def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
export function array(ref: TypeSpec, len: number, hint?: ArrayHint | null);
export function array(ref: TypeSpec, len: number, hint?: ArrayHint | null): IKoffiCType;

@@ -87,0 +87,0 @@ export function opaque(name: string): IKoffiCType;

@@ -16,8 +16,27 @@ // This program is free software: you can redistribute it and/or modify

if (process.versions.napi == null || process.versions.napi < 8)
throw new Error('This platform does not support N-API 8');
const package = require('../package.json');
const cnoke = require('../../cnoke');
const util = require('util');
let filename = __dirname + '/../build/koffi.node';
if (process.versions.napi == null || process.versions.napi < 8) {
let major = parseInt(process.versions.node, 10);
let required = cnoke.get_napi_version(8, major);
if (required != null) {
throw new Error(`Project ${pkg.name} requires Node >= ${required} in the Node ${major}.x branch (N-API >= 8)`);
} else {
throw new Error(`Project ${pkg.name} does not support the Node ${major}.x branch (N-API < 8)`);
}
}
let arch = cnoke.determine_arch();
let filename = __dirname + `/../build/${package.version}/koffi_${process.platform}_${arch}/koffi.node`;
// Development build
if (!fs.existsSync(filename)) {
let alternative = __dirname + '/../build/koffi.node';
if (fs.existsSync(alternative))
filename = alternative;
}
let native = require(filename);

@@ -24,0 +43,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc