APIs

Show:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * @module opcua.miscellaneous
 */
const node_opcua_assert_1 = require("node-opcua-assert");
require("util");
const node_opcua_buffer_utils_1 = require("node-opcua-buffer-utils");
const underscore_1 = require("underscore");
const MAXUINT32 = 4294967295; // 2**32 -1;
const noAssert = false;
const performCheck = false;
/**
 * a BinaryStream can be use to perform sequential read or write
 * inside a buffer.
 * The BinaryStream maintains a cursor up to date as the caller
 * operates on the stream using the various read/write methods.
 * It uses the [Little Endian](http://en.wikipedia.org/wiki/Little_endian#Little-endian)
 * convention.
 *
 * data can either be:
 *
 * * a Buffer , in this case the BinaryStream operates on this Buffer
 * * null     , in this case a BinaryStream with 1024 bytes is created
 * * any data , in this case the object is converted into a binary buffer.
 *
 * example:
 *
 *    ``` javascript
 *    var stream = new BinaryStream(32)
 *    ```
 *
 * @class BinaryStream
 * @param {null|Buffer|Number} data
 * @constructor
 *
 *
 *
 */
class BinaryStream {
    constructor(data) {
        if (data === undefined) {
            this._buffer = node_opcua_buffer_utils_1.createFastUninitializedBuffer(1024);
        }
        else if (typeof data === "number") {
            this._buffer = node_opcua_buffer_utils_1.createFastUninitializedBuffer(data); // new Buffer(/*size=*/data);
        }
        else {
            node_opcua_assert_1.default(data instanceof Buffer);
            this._buffer = data;
        }
        this.length = 0;
    }
    /**
     * set the cursor to the begining of the stream
     * @method BinaryStream.rewind
     * @return null
     */
    rewind() {
        this.length = 0;
    }
    /**
     * write a single signed byte (8 bits) to the stream.
     * value must be in the range of [-127,128]
     * @method writeInt8
     * @param value
     */
    writeInt8(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 1, "not enough space in buffer");
        if (performCheck)
            node_opcua_assert_1.default(value >= -128 && value < 128);
        this._buffer.writeInt8(value, this.length, noAssert);
        this.length += 1;
    }
    /**
     * write a single unsigned byte (8 bits) to the stream.
     * @method writeUInt8
     * @param value
     */
    writeUInt8(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 1, "not enough space in buffer");
        if (performCheck)
            node_opcua_assert_1.default(value >= 0 && value < 256, " writeUInt8 : out of bound ");
        this._buffer.writeUInt8(value, this.length, noAssert);
        this.length += 1;
    }
    /**
     * write a single 16 bit signed integer to the stream.
     * @method writeInt16
     * @param  value
     */
    writeInt16(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 2, "not enough space in buffer");
        this._buffer.writeInt16LE(value, this.length, noAssert);
        this.length += 2;
    }
    /**
     * write a single 16 bit unsigned integer to the stream.
     * @method writeUInt16
     * @param  value
     */
    writeUInt16(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 2, "not enough space in buffer");
        this._buffer.writeUInt16LE(value, this.length, noAssert);
        this.length += 2;
    }
    /**
     * write a single 32 bit signed integer to the stream.
     * @method writeInteger
     * @param  value
     */
    writeInteger(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 4, "not enough space in buffer");
        this._buffer.writeInt32LE(value, this.length, noAssert);
        this.length += 4;
    }
    /**
     * write a single 32 bit unsigned integer to the stream.
     * @method writeUInt32
     * @param value
     */
    writeUInt32(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 4, "not enough space in buffer");
        if (performCheck)
            node_opcua_assert_1.default(underscore_1.isFinite(value));
        if (performCheck)
            node_opcua_assert_1.default(value >= 0 && value <= MAXUINT32);
        this._buffer.writeUInt32LE(value, this.length, noAssert);
        this.length += 4;
        /*
          assert(this._buffer[this.length - 4] === value % 256);
          assert(this._buffer[this.length - 3] === (value >>> 8) % 256);
          assert(this._buffer[this.length - 2] === (value >>> 16) % 256);
          assert(this._buffer[this.length - 1] === (value >>> 24) % 256);
          */
    }
    /**
     * write a single 32 bit floating number to the stream.
     * @method writeFloat
     * @param value
     */
    writeFloat(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 4, "not enough space in buffer");
        this._buffer.writeFloatLE(value, this.length, noAssert);
        this.length += 4;
    }
    /**
     * write a single 64 bit floating number to the stream.
     * @method writeDouble
     * @param value
     */
    writeDouble(value) {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 8, "not enough space in buffer");
        this._buffer.writeDoubleLE(value, this.length, noAssert);
        this.length += 8;
    }
    /**
     * @method writeArrayBuffer
     * @param arrayBuf {ArrayBuffer}
     * @param offset   {Number}
     * @param length   {Number}
     */
    writeArrayBuffer(arrayBuf, offset = 0, length = 0) {
        if (performCheck)
            node_opcua_assert_1.default(arrayBuf instanceof ArrayBuffer);
        const byteArr = new Uint8Array(arrayBuf);
        const n = (length || byteArr.length) + offset;
        for (let i = offset; i < n; i++) {
            this._buffer[this.length++] = byteArr[i];
        }
    }
    // writeArrayBuffer(arrayBuf, offset, length) {
    //     offset = offset || 0;
    //
    //     assert(arrayBuf instanceof ArrayBuffer);
    //     const byteArr = new Uint8Array(arrayBuf);
    //     length = length || byteArr.length;
    //     if (length === 0) {
    //         return;
    //     }
    //     this.length += my_memcpy(this._buffer, this.length, byteArr, offset, offset + length);
    // }
    /**
     * read a single signed byte  (8 bits) from the stream.
     * @method readByte
     * @return {Number}
     */
    readByte() {
        const retVal = this._buffer.readInt8(this.length, noAssert);
        this.length += 1;
        return retVal;
    }
    readInt8() {
        return this.readByte();
    }
    /**
     * read a single unsigned byte (8 bits) from the stream.
     * @method readUInt8
     * @return {Number}
     */
    readUInt8() {
        if (performCheck)
            node_opcua_assert_1.default(this._buffer.length >= this.length + 1);
        const retVal = this._buffer.readUInt8(this.length, noAssert);
        this.length += 1;
        return retVal;
    }
    /**
     * read a single signed 16-bit integer from the stream.
     * @method readInt16
     * @return {Number}
     */
    readInt16() {
        const retVal = this._buffer.readInt16LE(this.length, noAssert);
        this.length += 2;
        return retVal;
    }
    /**
     * read a single unsigned 16-bit integer from the stream.
     * @method readUInt16
     * @return {Number}  q
     */
    readUInt16() {
        const retVal = this._buffer.readUInt16LE(this.length, noAssert);
        this.length += 2;
        return retVal;
    }
    /**
     * read a single signed 32-bit integer from the stream.
     * @method readInteger
     * @return {Number}
     */
    readInteger() {
        const retVal = this._buffer.readInt32LE(this.length, noAssert);
        this.length += 4;
        return retVal;
    }
    /**
     * read a single unsigned 32-bit integer from the stream.
     * @method readUInt32
     * @return {number} the value read from the stream
     */
    readUInt32() {
        const retVal = this._buffer.readUInt32LE(this.length, noAssert);
        this.length += 4;
        return retVal;
    }
    /**
     * read a single  32-bit floating point number from the stream.
     * @method readFloat
     * @return  the value read from the stream
     */
    readFloat() {
        const retVal = this._buffer.readFloatLE(this.length, noAssert);
        this.length += 4;
        return retVal;
    }
    /**
     * read a single 64-bit floating point number from the stream.
     * @method readDouble
     * @return  the value read from the stream
     */
    readDouble() {
        const retVal = this._buffer.readDoubleLE(this.length, noAssert);
        this.length += 8;
        return retVal;
    }
    /**
     * write a byte stream to the stream.
     * The method writes the length of the byte array into the stream as a 32 bits integer before the byte stream.
     *
     * @method writeByteStream
     * @param {Buffer} buf the    buffer to write.
     *   the buffer buf.length the buffer to write
     */
    writeByteStream(buf) {
        if (!buf) {
            this.writeInteger(-1);
            return;
        }
        node_opcua_assert_1.default(buf instanceof Buffer);
        this.writeInteger(buf.length);
        // make sure there is enough room in destination buffer
        const remainingBytes = this._buffer.length - this.length;
        /* istanbul ignore next */
        if (remainingBytes < buf.length) {
            throw new Error("BinaryStream.writeByteStream error : not enough bytes left in buffer :  bufferLength is " +
                buf.length +
                " but only " +
                remainingBytes +
                " left");
        }
        buf.copy(this._buffer, this.length, 0, buf.length);
        this.length += buf.length;
    }
    writeString(value) {
        if (value === undefined || value === null) {
            this.writeInteger(-1);
            return;
        }
        const byteLength = calculateByteLength(value);
        this.writeInteger(byteLength);
        // make sure there is enough room in destination buffer
        const remainingBytes = this._buffer.length - this.length;
        /* istanbul ignore next */
        if (remainingBytes < byteLength) {
            throw new Error("BinaryStream.writeByteStream error : not enough bytes left in buffer :  bufferLength is " +
                byteLength +
                " but only " +
                remainingBytes +
                " left");
        }
        if (byteLength > 0) {
            this._buffer.write(value, this.length);
            this.length += byteLength;
        }
    }
    // readArrayBuffer(length: number): ArrayBuffer {
    //     assert(this.length + length <= this._buffer.length, "not enough bytes in buffer");
    //     const byteArr = new Uint8Array(new ArrayBuffer(length));
    //     my_memcpy(byteArr, 0, this._buffer, this.length, this.length + length);
    //     this.length += length;
    //     return byteArr;
    // }
    /**
     * @method readArrayBuffer
     * @param length
     * @returns {Uint8Array}
     */
    readArrayBuffer(length) {
        if (performCheck)
            node_opcua_assert_1.default(this.length + length <= this._buffer.length, "not enough bytes in buffer");
        const slice = this._buffer.slice(this.length, this.length + length);
        if (performCheck)
            node_opcua_assert_1.default(slice.length === length);
        const byteArr = new Uint8Array(slice);
        if (performCheck)
            node_opcua_assert_1.default(byteArr.length === length);
        this.length += length;
        return byteArr;
    }
    /**
     * read a byte stream to the stream.
     * The method reads the length of the byte array from the stream as a 32 bits integer before reading the byte stream.
     *
     * @method readByteStream
     * @return {Buffer}
     */
    readByteStream() {
        const bufLen = this.readUInt32();
        if (bufLen === 0xffffffff) {
            return null;
        }
        if (bufLen === 0) {
            return zeroLengthBuffer;
        }
        // check that there is enough space in the buffer
        const remainingBytes = this._buffer.length - this.length;
        if (remainingBytes < bufLen) {
            throw new Error("BinaryStream.readByteStream error : not enough bytes left in buffer :  bufferLength is " +
                bufLen +
                " but only " +
                remainingBytes +
                " left");
        }
        // create a shared memory buffer ! for speed
        const buf = this._buffer.slice(this.length, this.length + bufLen);
        this.length += bufLen;
        return buf;
    }
    readString() {
        const bufLen = this.readUInt32();
        if (bufLen === 0xffffffff) {
            return null;
        }
        if (bufLen === 0) {
            return "";
        }
        // check that there is enough space in the buffer
        const remainingBytes = this._buffer.length - this.length;
        if (remainingBytes < bufLen) {
            throw new Error("BinaryStream.readByteStream error : not enough bytes left in buffer :  bufferLength is " +
                bufLen +
                " but only " +
                remainingBytes +
                " left");
        }
        const str = this._buffer.toString("utf-8", this.length, this.length + bufLen);
        this.length += bufLen;
        return str;
    }
}
exports.BinaryStream = BinaryStream;
/**
 * @function calculateByteLength
 * calculate the size in bytes of a utf8 string
 * @param str {String}
 */
function calculateByteLength(str) {
    // returns the byte length of an utf8 string
    let s = str.length;
    for (let i = str.length - 1; i >= 0; i--) {
        const code = str.charCodeAt(i);
        if (code > 0x7f && code <= 0x7ff) {
            s++;
        }
        else if (code > 0x7ff && code <= 0xffff) {
            s += 2;
        }
        if (code >= 0xdc00 && code <= 0xdfff) {
            // trail surrogate
            i--;
        }
    }
    return s;
}
const zeroLengthBuffer = node_opcua_buffer_utils_1.createFastUninitializedBuffer(0);
/**
 * a BinaryStreamSizeCalculator can be used to quickly evaluate the required size
 * of a buffer by performing the same sequence of write operation.
 *
 * a BinaryStreamSizeCalculator has the same writeXXX methods as the BinaryStream stream
 * object.
 *
 * @class BinaryStreamSizeCalculator
 * @extends BinaryStream
 * @constructor
 *
 */
class BinaryStreamSizeCalculator {
    constructor() {
        this.length = 0;
    }
    rewind() {
        this.length = 0;
    }
    writeInt8(value) {
        this.length += 1;
    }
    writeUInt8(value) {
        this.length += 1;
    }
    writeInt16(value) {
        this.length += 2;
    }
    writeInteger(value) {
        this.length += 4;
    }
    writeUInt32(value) {
        this.length += 4;
    }
    writeUInt16(value) {
        this.length += 2;
    }
    writeFloat(value) {
        this.length += 4;
    }
    writeDouble(value) {
        this.length += 8;
    }
    writeArrayBuffer(arrayBuf, offset, byteLength) {
        offset = offset || 0;
        node_opcua_assert_1.default(arrayBuf instanceof ArrayBuffer);
        this.length += byteLength || arrayBuf.byteLength;
    }
    writeByteStream(buf) {
        if (!buf) {
            this.writeUInt32(0);
        }
        else {
            this.writeUInt32(buf.length);
            this.length += buf.length;
        }
    }
    writeString(str) {
        if (str === undefined || str === null) {
            this.writeUInt32(-1);
            return;
        }
        const bufLength = calculateByteLength(str);
        this.writeUInt32(bufLength);
        this.length += bufLength;
    }
}
exports.BinaryStreamSizeCalculator = BinaryStreamSizeCalculator;
//# sourceMappingURL=binaryStream.js.map