node.js - 如何使用 Node.js 读取非字节对齐整数?

标签 node.js flash binaryfiles

我正在尝试使用 Node.JS 读取二进制 SWF 文件。作为specification the 17th page底部提到,一些整数使用可变长度位字段进行编码,并且根据定义,它们中的大多数不是字节对齐的。

问题在于 Node.js 的 Buffer 只提供了读取字节对齐整数的函数。所以我尝试编写一个可以一点一点读取的包装对象。然而,它看起来确实很hacky。下面是我写的对象原型(prototype):

/*jslint node:true, bitwise:true */

'use strict';

var util = require('util');
var maxBits = 32;

function BitBuffer() {
    Buffer.apply(this, arguments);

    this.cursor = 0;
    this.bitCursor = 0;
}

util.inherits(BitBuffer, Buffer);
module.exports = BitBuffer;

function padBits(bits, length, bit) {
    var leftPad = '', repeatLength, i;

    bits = bits.toString(2);
    length = length || 8;
    bit = bit || '0';

    if (bits.length >= length) {
        return bits;
    } else {
        repeatLength = length - bits.length;

        for (i = 0; i < repeatLength; i += 1) {
            leftPad += bit;
        }

        return leftPad + bits;
    }
}

BitBuffer.prototype.move = function (bits) {
    var bytes = Math.floor((this.bitCursor + bits) / 8);

    this.bitCursor += bits;

    if (this.bitCursor > 8) {
        this.cursor += bytes;
        this.bitCursor -= bytes * 8;
    }

    if (this.cursor >= this.length) {
        this.rewind();
        return false;
    }

    return true;
};

BitBuffer.prototype.align = function () {
    if (this.bitCursor > 0) {
        this.bitCursor = 0;
        this.cursor += 1;
    }
};

BitBuffer.prototype.rewind = function () {
    this.cursor = this.bitCursor = 0;
};

BitBuffer.prototype.readBits = function (bits) {
    var bytes = Math.ceil((this.bitCursor + bits) / 8), result = 0,
        length, buffer, i;

    if (bits > maxBits) {
        throw new RangeError('Cannot read more than ' + maxBits + ' bits');
    }

    buffer = this.slice(this.cursor, this.cursor + bytes);
    result = padBits(buffer[0]).substr(this.bitCursor);
    length = buffer.length;

    for (i = 1; i < length; i += 1) {
        result += padBits(buffer[i]);
    }

    result = result.substr(0, bits);
    return (this.move(bits)) ? parseInt(result, 2) : false;
};

BitBuffer.prototype.readUB = BitBuffer.prototype.readBits;

BitBuffer.prototype.readSB = function (bits) {
    var readBits = this.readBits(bits),
        stringBits = readBits.toString(2);

    if (readBits === false) {
        return false;
    }

    // add automatically removed zeros
    if (stringBits.length < bits) {
        stringBits = padBits(stringBits, bits);
    }

    // negative, pad to 32 bits then invert bits
    if (stringBits[0] === '1') {
        return -~parseInt(padBits(stringBits, maxBits, '1'), 2) - 1;
    } else {
        return readBits;
    }
};

BitBuffer.prototype.readFB = function (bits) {
    var highBits, lowBits, result;

    if (bits < 17) {
        throw new RangeError('Should be at least 17 bits long');
    }

    highBits = this.readSB(bits - 16);
    lowBits = this.readUB(16);
    lowBits *= Math.pow(10, -lowBits.toString(10).length);

    return (highBits >= 0) ?
            highBits + lowBits : highBits - lowBits;
};

// wrap read functions
(function () {
    var nativeReadFunctions = {
        'readInt8': 8,
        'readInt16LE': 16,
        'readInt16BE': 16,
        'readInt32LE': 32,
        'readInt32BE': 32,
        'readUInt8': 8,
        'readUInt16LE': 16,
        'readUInt16BE': 16,
        'readUInt32LE': 32,
        'readUInt32BE': 32,
        'readDoubleLE': 64,
        'readDoubleBE': 64,
        'readFloatLE': 32,
        'readFloatBE': 32
    }, method;

    function wrapNativeRead(method, length) {
        return function (noAssert) {
            var cursor;

            this.align();
            cursor = this.cursor;
            this.move(length);

            return Buffer.prototype[method].call(
                this,
                this.cursor,
                noAssert
            );
        };
    }

    for (method in nativeReadFunctions) {
        if (nativeReadFunctions.hasOwnProperty(method)) {
            BitBuffer.prototype[method] =
                wrapNativeRead(method, nativeReadFunctions[method]);
        }
    }
}());

编写自己的对象是好方法吗?

最佳答案

除了您的实现非常好之外,您应该了解在您的实现中 this.buffer === this 并且您应该更改以下几行:

// inside BitBuffer prototype constructor

this.buffer = new Buffer(param1, param2);

// change to

Buffer.call(this, param1, param2); // The right way to call the super constructor

// inside BitBuffer.prototype.readBits

buffer = this.buffer.slice(this.cursor, this.cursor + bytes);

// change to

buffer = this.slice(this.cursor, this.cursor + bytes);

关于node.js - 如何使用 Node.js 读取非字节对齐整数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24996425/

相关文章:

c++ - 将从二进制文件读取的字符串转换为整数

c - C语言读取二进制文件

javascript - JavaScript 中的继承

facebook - 当我将 swf 播放器与我的应用程序一起发布到墙上时,它会在新窗口中打开

node.js - 在node.js中解密使用A128CBC-HS256加密的JWT

flash - Flash 中的 'static void Main' 是什么?

actionscript-3 - SWF 本地可信沙箱和 adobe air

ios - 无效的二进制错误

javascript - 响应 native 上传图像的网络请求失败

node.js - Memcache v/s redis 用于维护持久 session ?