多态参数

输入多态性

Koffi 2.1 中的新功能

许多 C 函数使用void *参数来传递多态对象和数组,这意味着数据格式的更改可能会根据另一个参数或某种结构标记成员而变化。

Koffi 提供了两个功能来处理这个问题:

  • 缓冲区和类型化 JS 数组可以在任何需要指针的地方用作值。有关输入或输出的更多信息,请参阅动态数组。

  • 您可以用koffi.as(value, type)来告诉 Koffi 实际上需要哪种类型。

下面的示例显示了如何使用koffi.as()读取 PNG 文件的标头fread()

// ES6 syntax: import koffi from 'koffi';
const koffi = require('koffi');

const lib = koffi.load('libc.so.6');

const FILE = koffi.opaque('FILE');

const PngHeader = koffi.pack('PngHeader', {
    signature: koffi.array('uint8_t', 8),
    ihdr: koffi.pack({
        length: 'uint32_be_t',
        chunk: koffi.array('char', 4),
        width: 'uint32_be_t',
        height: 'uint32_be_t',
        depth: 'uint8_t',
        color: 'uint8_t',
        compression: 'uint8_t',
        filter: 'uint8_t',
        interlace: 'uint8_t',
        crc: 'uint32_be_t'
    })
});

const fopen = lib.func('FILE *fopen(const char *path, const char *mode)');
const fclose = lib.func('int fclose(FILE *fp)');
const fread = lib.func('size_t fread(_Out_ void *ptr, size_t size, size_t nmemb, FILE *fp)');

let filename = process.argv[2];
if (filename == null)
    throw new Error('Usage: node png.js <image.png>');

let hdr = {};
{
    let fp = fopen(filename, 'rb');
    if (!fp)
        throw new Error(`Failed to open '${filename}'`);

    try {
        let len = fread(koffi.as(hdr, 'PngHeader *'), 1, koffi.sizeof(PngHeader), fp);
        if (len < koffi.sizeof(PngHeader))
            throw new Error('Failed to read PNG header');
    } finally {
        fclose(fp);
    }
}

console.log('PNG header:', hdr);

输出缓冲器

Koffi 2.3 中的新功能

您可以使用缓冲区和类型化数组作为输出(和输入/输出)指针参数。只需将缓冲区作为参数传递,本机函数就会收到指向其内容的指针。

本机函数返回后,您可以使用以下示例koffi.decode(value, type)解码内容:

// ES6 syntax: import koffi from 'koffi';
const koffi = require('koffi');

const lib = koffi.load('libc.so.6');

const Vec3 = koffi.struct('Vec3', {
    x: 'float32',
    y: 'float32',
    z: 'float32'
})

const memcpy = lib.func('void *memcpy(_Out_ void *dest, const void *src, size_t size)');

let vec1 = { x: 1, y: 2, z: 3 };
let vec2 = null;

// Copy the vector in a convoluted way through memcpy
{
    let src = koffi.as(vec1, 'Vec3 *');
    let dest = Buffer.allocUnsafe(koffi.sizeof(Vec3));

    memcpy(dest, src, koffi.sizeof(Vec3));

    vec2 = koffi.decode(dest, Vec3);
}

// CHange vector1, leaving copy alone
[vec1.x, vec1.y, vec1.z] = [vec1.z, vec1.y, vec1.x];

console.log(vec1); // { x: 3, y: 2, z: 1 }
console.log(vec2); // { x: 1, y: 2, z: 3 }

有关解码函数的更多信息,请参阅解码变量。

Last updated