• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

node-opcua / node-opcua / 21614566440

03 Feb 2026 02:33AM UTC coverage: 90.811% (+0.03%) from 90.779%
21614566440

push

github

erossignon
chore: update packages

11135 of 14142 branches covered (78.74%)

30230 of 33289 relevant lines covered (90.81%)

386412.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.19
/packages/node-opcua-binary-stream/source/binaryStream.ts
1
/**
2
 * @module node-opcua-binary-stream
3
 */
4
import "util";
6✔
5

6
import { assert } from "node-opcua-assert";
6✔
7
import { createFastUninitializedBuffer } from "node-opcua-buffer-utils";
6✔
8

9
const MAXUINT32 = 4294967295; // 2**32 -1;
6✔
10
const performCheck = false;
6✔
11

12
/**
13
 * a BinaryStream can be use to perform sequential read or write
14
 * inside a buffer.
15
 * The BinaryStream maintains a cursor up to date as the caller
16
 * operates on the stream using the various read/write methods.
17
 * It uses the [Little Endian](http://en.wikipedia.org/wiki/Little_endian#Little-endian)
18
 * It uses the [Little Endian](http://en.wikipedia.org/wiki/Little_endian#Little-endian)
19
 * convention.
20
 *
21
 * data can either be:
22
 *
23
 * * a Buffer , in this case the BinaryStream operates on this Buffer
24
 * * null     , in this case a BinaryStream with 1024 bytes is created
25
 * * any data , in this case the object is converted into a binary buffer.
26
 *
27
 * example:
28
 *
29
 *    ``` javascript
30
 *    var stream = new BinaryStream(32)
31
 *    ```
32
 *
33
 
34
 */
35
export class BinaryStream {
6✔
36
    public static maxByteStringLength = 16 * 1024 * 1024;
6✔
37
    public static maxStringLength = 16 * 1024 * 1024;
6✔
38
    /**
39
     * the current position inside the buffer
40
     */
41
    public length: number;
42

43
    /**
44
     * @internal
45
     */
46
    public buffer: Buffer;
47

48
    constructor(data: undefined | Buffer | number) {
49
        if (data === undefined) {
879,510✔
50
            this.buffer = createFastUninitializedBuffer(1024);
335✔
51
        } else if (typeof data === "number") {
879,175✔
52
            this.buffer = createFastUninitializedBuffer(data);
100,369✔
53
        } else {
54
            assert(data instanceof Buffer);
778,806✔
55
            this.buffer = data;
778,806✔
56
        }
57
        this.length = 0;
879,510✔
58
    }
59

60
    /**
61
     * set the cursor to the begining of the stream
62

63
     */
64
    public rewind(): void {
65
        this.length = 0;
255,044✔
66
    }
67

68
    /**
69
     * write a single signed byte (8 bits) to the stream.
70
     * value must be in the range of [-127,128]
71
     * @param value the value to write
72
     */
73
    public writeInt8(value: number): void {
74
        // istanbul ignore next
75
        if (performCheck) {
76
            assert(this.buffer.length >= this.length + 1, "not enough space in buffer");
77
            assert(value >= -128 && value < 128);
78
        }
79
        this.buffer.writeInt8(value, this.length);
978✔
80
        this.length += 1;
978✔
81
    }
82

83
    /**
84
     * write a single unsigned byte (8 bits) to the stream.
85
     * @param value  the value to write
86
     */
87
    public writeUInt8(value: number): void {
88
        // istanbul ignore next
89
        if (performCheck) {
90
            assert(this.buffer.length >= this.length + 1, "not enough space in buffer");
91
            assert(value >= 0 && value < 256, " writeUInt8 : out of bound ");
92
        }
93
        this.buffer.writeUInt8(value, this.length);
24,643,069✔
94
        this.length += 1;
24,643,069✔
95
    }
96

97
    /**
98
     * write a single 16 bit signed integer to the stream.
99
     * @param  value  the value to write
100
     */
101
    public writeInt16(value: number): void {
102
        // istanbul ignore next
103
        if (performCheck) {
104
            assert(this.buffer.length >= this.length + 2, "not enough space in buffer");
105
        }
106
        this.buffer.writeInt16LE(value, this.length);
997✔
107
        this.length += 2;
997✔
108
    }
109

110
    /**
111
     * write a single 16 bit unsigned integer to the stream.
112
     * @param  value  the value to write
113
     */
114
    public writeUInt16(value: number): void {
115
        // istanbul ignore next
116
        if (performCheck) {
117
            assert(this.buffer.length >= this.length + 2, "not enough space in buffer");
118
        }
119
        this.buffer.writeUInt16LE(value, this.length);
4,895,832✔
120
        this.length += 2;
4,895,832✔
121
    }
122

123
    /**
124
     * write a single 32 bit signed integer to the stream.
125
     * @param  value  the value to write
126
     */
127
    public writeInteger(value: number): void {
128
        // istanbul ignore next
129
        if (performCheck) {
130
            assert(this.buffer.length >= this.length + 4, "not enough space in buffer");
131
        }
132
        this.buffer.writeInt32LE(value, this.length);
5,707,790✔
133
        this.length += 4;
5,707,790✔
134
    }
135

136
    /**
137
     * write a single 32 bit unsigned integer to the stream.
138
     *
139
     * @param  value the value to write
140
     */
141
    public writeUInt32(value: number): void {
142
        // istanbul ignore next
143
        if (performCheck) {
144
            assert(this.buffer.length >= this.length + 4, "not enough space in buffer");
145
            assert(isFinite(value));
146
            assert(value >= 0 && value <= MAXUINT32);
147
        }
148
        this.buffer.writeUInt32LE(value, this.length);
31,293,929✔
149
        this.length += 4;
31,293,929✔
150
        /*
151
          assert(this.buffer[this.length - 4] === value % 256);
152
          assert(this.buffer[this.length - 3] === (value >>> 8) % 256);
153
          assert(this.buffer[this.length - 2] === (value >>> 16) % 256);
154
          assert(this.buffer[this.length - 1] === (value >>> 24) % 256);
155
          */
156
    }
157

158
    /**
159
     * write a single 32 bit floating number to the stream.
160
     * @param  value  the value to write
161
     */
162
    public writeFloat(value: number): void {
163
        // istanbul ignore next
164
        if (performCheck) {
165
            assert(this.buffer.length >= this.length + 4, "not enough space in buffer");
166
        }
167
        this.buffer.writeFloatLE(value, this.length);
5,961,777✔
168
        this.length += 4;
5,961,777✔
169
    }
170

171
    /**
172
     * write a single 64 bit floating number to the stream.
173
     * @param  value  the value to write
174
     */
175
    public writeDouble(value: number): void {
176
        // istanbul ignore next
177
        if (performCheck) {
178
            assert(this.buffer.length >= this.length + 8, "not enough space in buffer");
179
        }
180
        this.buffer.writeDoubleLE(value, this.length);
100,251✔
181
        this.length += 8;
100,251✔
182
    }
183

184
    /**
185
     * @param arrayBuf a buffer or byte array write
186
     * @param offset   the offset position (default =0)
187
     * @param length   the number of byte to write
188
     */
189
    public writeArrayBuffer(arrayBuf: ArrayBuffer, offset = 0, length = 0): void {
13,316✔
190
        // istanbul ignore next
191
        if (performCheck) {
192
            assert(arrayBuf instanceof ArrayBuffer);
193
        }
194
        const byteArr = new Uint8Array(arrayBuf);
13,471✔
195
        const n = (length || byteArr.length) + offset;
13,471✔
196
        for (let i = offset; i < n; i++) {
13,471✔
197
            this.buffer[this.length++] = byteArr[i];
411,145,089✔
198
        }
199
    }
200

201
    // writeArrayBuffer(arrayBuf, offset, length) {
202
    //     offset = offset || 0;
203
    //
204
    //     assert(arrayBuf instanceof ArrayBuffer);
205
    //     const byteArr = new Uint8Array(arrayBuf);
206
    //     length = length || byteArr.length;
207
    //     if (length === 0) {
208
    //         return;
209
    //     }
210
    //     this.length += my_memcpy(this.buffer, this.length, byteArr, offset, offset + length);
211
    // }
212

213
    /**
214
     * read a single signed byte  (8 bits) from the stream.
215
     * @return the value read
216
     */
217
    public readByte(): number {
218
        const retVal = this.buffer.readInt8(this.length);
978✔
219
        this.length += 1;
978✔
220
        return retVal;
978✔
221
    }
222

223
    public readInt8(): number {
224
        return this.readByte();
978✔
225
    }
226

227
    /**
228
     * read a single unsigned byte (8 bits) from the stream.
229
     */
230
    public readUInt8(): number {
231
        // istanbul ignore next
232
        if (performCheck) {
233
            assert(this.buffer.length >= this.length + 1);
234
        }
235
        const retVal = this.buffer.readUInt8(this.length);
10,010,762✔
236
        this.length += 1;
10,010,762✔
237
        return retVal;
10,010,762✔
238
    }
239

240
    /**
241
     * read a single signed 16-bit integer from the stream.
242
     */
243
    public readInt16(): number {
244
        const retVal = this.buffer.readInt16LE(this.length);
1,008✔
245
        this.length += 2;
1,008✔
246
        return retVal;
1,008✔
247
    }
248

249
    /**
250
     * read a single unsigned 16-bit integer from the stream.
251
     */
252
    public readUInt16(): number {
253
        const retVal = this.buffer.readUInt16LE(this.length);
2,789,286✔
254
        this.length += 2;
2,789,286✔
255
        return retVal;
2,789,286✔
256
    }
257

258
    /**
259
     * read a single signed 32-bit integer from the stream.
260
     */
261
    public readInteger(): number {
262
        const retVal = this.buffer.readInt32LE(this.length);
1,948,123✔
263
        this.length += 4;
1,948,122✔
264
        return retVal;
1,948,122✔
265
    }
266

267
    /**
268
     * read a single unsigned 32-bit integer from the stream.
269
     */
270
    public readUInt32(): number {
271
        const retVal = this.buffer.readUInt32LE(this.length);
9,667,361✔
272
        this.length += 4;
9,667,360✔
273
        return retVal;
9,667,360✔
274
    }
275

276
    /**
277
     * read a single  32-bit floating point number from the stream.
278
     */
279
    public readFloat(): number {
280
        const retVal = this.buffer.readFloatLE(this.length);
1,067✔
281
        this.length += 4;
1,067✔
282
        return retVal;
1,067✔
283
    }
284

285
    /**
286
     * read a single 64-bit floating point number from the stream.
287
     */
288
    public readDouble(): number {
289
        const retVal = this.buffer.readDoubleLE(this.length);
1,658,709✔
290
        this.length += 8;
1,658,708✔
291
        return retVal;
1,658,708✔
292
    }
293

294
    /**
295
     * write a byte stream to the stream.
296
     * The method writes the length of the byte array into the stream as a 32 bits integer before the byte stream.
297
     *
298
     * @param buf the buffer to write.
299
     */
300
    public writeByteStream(buf: Buffer): void {
301
        if (!buf) {
1,411,540✔
302
            this.writeInteger(-1);
1,088,174✔
303
            return;
1,088,174✔
304
        }
305
        assert(buf instanceof Buffer);
323,366✔
306
        this.writeInteger(buf.length);
323,366✔
307
        // make sure there is enough room in destination buffer
308
        const remainingBytes = this.buffer.length - this.length;
323,366✔
309

310
        /* istanbul ignore next */
311
        if (remainingBytes < buf.length) {
312
            throw new Error(
313
                "BinaryStream.writeByteStream error : not enough bytes left in buffer :  bufferLength is " +
314
                buf.length +
315
                " but only " +
316
                remainingBytes +
317
                " left"
318
            );
319
        }
320
        buf.copy(this.buffer, this.length, 0, buf.length);
323,366✔
321
        this.length += buf.length;
323,366✔
322
    }
323

324
    public writeString(value: null | string): void {
325
        if (value === undefined || value === null) {
4,361,405✔
326
            this.writeUInt32(0xffffffff);
3,051,593✔
327
            return;
3,051,593✔
328
        }
329
        const byteLength = calculateByteLength(value);
1,309,812✔
330
        this.writeInteger(byteLength);
1,309,812✔
331
        if (byteLength === 0) {
1,309,812✔
332
            return;
329,792✔
333
        }
334
        // make sure there is enough room in destination buffer
335
        const remainingBytes = this.buffer.length - this.length;
980,020✔
336
        /* istanbul ignore next */
337
        if (remainingBytes < byteLength) {
338
            throw new Error(
339
                "BinaryStream.writeByteStream error : not enough bytes left in buffer :  bufferLength is " +
340
                byteLength +
341
                " but only " +
342
                remainingBytes +
343
                " left"
344
            );
345
        }
346
        this.buffer.write(value, this.length);
980,020✔
347
        this.length += byteLength;
980,020✔
348
    }
349

350
    // readArrayBuffer(length: number): ArrayBuffer {
351
    //     assert(this.length + length <= this.buffer.length, "not enough bytes in buffer");
352
    //     const byteArr = new Uint8Array(new ArrayBuffer(length));
353
    //     my_memcpy(byteArr, 0, this.buffer, this.length, this.length + length);
354
    //     this.length += length;
355
    //     return byteArr;
356
    // }
357
    /**
358

359
     * @param length
360
     */
361
    public readBuffer(length: number): Buffer {
362
        if (this.length + length > this.buffer.length) {
6,986!
363
            throw new Error("BinaryStream: buffer overrun detected");
×
364
        }
365
        const buf = this.buffer.subarray(this.length, this.length + length);
6,986✔
366
        this.length += length;
6,986✔
367
        return buf;
6,986✔
368
    }
369

370
    public readArrayBuffer(length: number): Uint8Array {
371
        if (length > BinaryStream.maxByteStringLength) {
65✔
372
            throw new Error(`maxStringLength(${BinaryStream.maxByteStringLength}) has been exceeded in BinaryStream.readArrayBuffer len=${length}`);
1✔
373
        }
374
        // istanbul ignore next
375
        if (performCheck) {
376
            assert(this.length + length <= this.buffer.length, "not enough bytes in buffer");
377
        }
378
        const slice = this.buffer.subarray(this.length, this.length + length);
64✔
379
        // istanbul ignore next
380
        if (performCheck) {
381
            assert(slice.length === length);
382
        }
383
        const byteArr = new Uint8Array(slice);
64✔
384
        // istanbul ignore next
385
        if (performCheck) {
386
            assert(byteArr.length === length);
387
        }
388
        this.length += length;
64✔
389
        return byteArr;
64✔
390
    }
391

392
    /**
393
     * read a byte stream to the stream.
394
     * The method reads the length of the byte array from the stream as a 32 bits integer
395
     * before reading the byte stream.
396
     *
397
     */
398
    public readByteStream(): Buffer | null {
399
        const bufLen = this.readUInt32();
1,412,320✔
400
        if (bufLen === 0xffffffff) {
1,412,320✔
401
            return null;
1,088,280✔
402
        }
403
        if (bufLen === 0) {
324,040✔
404
            return zeroLengthBuffer;
12✔
405
        }
406
        if (bufLen > BinaryStream.maxByteStringLength) {
324,028✔
407
            throw new Error(`maxStringLength(${BinaryStream.maxByteStringLength}) has been exceeded in BinaryStream.readArrayBuffer len=${bufLen}`);
1✔
408
        }
409
        // check that there is enough space in the buffer
410
        const remainingBytes = this.buffer.length - this.length;
324,027✔
411
        // istanbul ignore next
412
        if (remainingBytes < bufLen) {
413
            throw new Error(
414
                "BinaryStream.readByteStream error : not enough bytes left in buffer :  bufferLength is " +
415
                bufLen +
416
                " but only " +
417
                remainingBytes +
418
                " left"
419
            );
420
        }
421
        // create a shared memory buffer ! for speed
422
        const buf = this.buffer.subarray(this.length, this.length + bufLen);
324,027✔
423
        this.length += bufLen;
324,027✔
424
        return buf;
324,027✔
425
    }
426

427
    public readString(): string | null {
428
        const bufLen = this.readUInt32();
3,316,351✔
429
        if (bufLen === 0xffffffff) {
3,316,351✔
430
            return null;
2,004,974✔
431
        }
432
        if (bufLen === 0) {
1,311,377✔
433
            return "";
329,531✔
434
        }
435
        if (bufLen > BinaryStream.maxStringLength) {
981,846✔
436
            throw new Error(`maxStringLength(${BinaryStream.maxStringLength}) has been exceeded in BinaryStream.readString len=${bufLen}`);
6✔
437
        }
438
        // check that there is enough space in the buffer
439
        const remainingBytes = this.buffer.length - this.length;
981,840✔
440
        // istanbul ignore next
441
        if (remainingBytes < bufLen) {
442
            throw new Error(
443
                "BinaryStream.readByteStream error : not enough bytes left in buffer :  bufferLength is " +
444
                bufLen +
445
                " but only " +
446
                remainingBytes +
447
                " left"
448
            );
449
        }
450
        const str = this.buffer.toString("utf-8", this.length, this.length + bufLen);
981,838✔
451
        this.length += bufLen;
981,838✔
452
        return str;
981,838✔
453
    }
454
}
455

456
/**
457
 * @function calculateByteLength
458
 * calculate the size in bytes of a utf8 string
459
 * @param str {String}
460
 * @internal
461
 */
462
export function calculateByteLength(str: string): number {
6✔
463
    // returns the byte length of an utf8 string
464
    let s = str.length;
3,495,722✔
465
    for (let i = s - 1; i >= 0; i--) {
3,495,722✔
466
        const code = str.charCodeAt(i);
101,260,151✔
467
        if (code > 0x7f && code <= 0x7ff) {
101,260,151✔
468
            s++;
7,735,240✔
469
        } else if (code > 0x7ff && code <= 0xffff) {
93,524,911✔
470
            s += 2;
8,840,043✔
471
        }
472
        if (code >= 0xdc00 && code <= 0xdfff) {
101,260,151✔
473
            // trail surrogate
474
            i--;
276,267✔
475
        }
476
    }
477
    return s;
3,495,722✔
478
}
479

480
const zeroLengthBuffer = createFastUninitializedBuffer(0);
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc