brs-js 1.4.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/utils.js DELETED
@@ -1,580 +0,0 @@
1
- import pako from 'pako';
2
- import punycode from 'punycode';
3
- import {
4
- uuidStringify,
5
- uuidParse,
6
- } from './uuid';
7
- import { MAX_INT } from './constants';
8
-
9
- /*
10
- Notes:
11
- - Everything is Little Endian by default because
12
- UE4 uses it.
13
- - I'd use Buffer.readUInt16LE if I was making this
14
- nodejs only. I don't want to require('Buffer/')
15
-
16
- */
17
-
18
- // Determine if a string is ascii-only
19
- function isASCII(str) {
20
- return /^[\x00-\x7F]*$/.test(str);
21
- }
22
-
23
- // convert BGRA color to RGBA color
24
- const bgra = ([b, g, r, a]) => [r, g, b, a];
25
-
26
- // Compare equality of byte arrays
27
- export function isEqual(arrA, arrB) {
28
- return arrA.every((a, i) => arrB[i] === a);
29
- }
30
-
31
-
32
- // read `len` bytes and return slice while updating offset
33
- function bytes(data, len, isCopy=false) {
34
- if (!(data instanceof Uint8Array)) {
35
- throw new Error(`Invalid data type in bytes reader (${typeof data})`);
36
- }
37
- if (typeof data.brsOffset === 'undefined')
38
- data.brsOffset = 0;
39
- const chunk = data[isCopy ? 'slice' : 'subarray'](data.brsOffset, data.brsOffset + len);
40
- chunk.brsOffset = 0;
41
- data.brsOffset += len;
42
- return chunk;
43
- }
44
-
45
- // break a byte array into chunks of a specified size
46
- function chunk(arr, size) {
47
- const out = [];
48
-
49
- for (let i = 0; i < arr.length; i += size) {
50
- out.push(bytes(arr, size, true));
51
- }
52
-
53
- return out;
54
- }
55
-
56
- // Read a u16 from a byte array
57
- function read_u16(data, littleEndian=true) {
58
- const [a, b] = bytes(data, 2);
59
-
60
- return littleEndian ? (b << 8 | a) : (a << 8 | b);
61
- }
62
-
63
- // Write a u16 into byte array
64
- function write_u16(num, littleEndian=true) {
65
- const data = [num & 255, (num >> 8) & 255];
66
- return new Uint8Array(!littleEndian ? data.reverse() : data);
67
- }
68
-
69
- // Read an i32 from a byte array
70
- function read_i32(data, littleEndian=true) {
71
- const [a, b, c, d] = bytes(data, 4);
72
- return littleEndian
73
- ? (d << 24 | c << 16 | b << 8 | a)
74
- : (a << 24 | b << 16 | c << 8 | d);
75
- }
76
-
77
- // Write an i32 from a byte array
78
- function write_i32(num, littleEndian=true) {
79
- const data = new Uint8Array([
80
- num & 255,
81
- (num >> 8) & 255,
82
- (num >> 16) & 255,
83
- (num >> 24) & 255,
84
- ]);
85
-
86
- return !littleEndian ? data.reverse() : data;
87
- }
88
-
89
- // Decompress a byte array of compressed data
90
- function read_compressed(data) {
91
- const uncompressedSize = read_i32(data);
92
- const compressedSize = read_i32(data);
93
-
94
- // Throw error for weird compression/uncompression sizes
95
- if (compressedSize < 0 || uncompressedSize < 0 || compressedSize >= uncompressedSize) {
96
- throw new Error(`Invalid compressed section size (comp: ${compressedSize}, uncomp: ${uncompressedSize})`);
97
- }
98
-
99
- // No compressed data? Return those bytes
100
- if (compressedSize === 0) {
101
- return bytes(data, uncompressedSize);
102
- } else {
103
- // Decompress the data otherwise
104
- const compressed = bytes(data, compressedSize);
105
- return pako.inflate(compressed);
106
- }
107
- }
108
-
109
- // Compress a byte array into fewer bytes
110
- function write_compressed(...args) {
111
- // Concat the args to one massive array
112
- const data = concat(...args);
113
-
114
- // Do the compression
115
- const compressed = pako.deflate(data);
116
- const uncompressedSize = data.length;
117
- const compressedSize = compressed.length;
118
-
119
- if (uncompressedSize > MAX_INT) {
120
- throw new Error(`uncompressedSize (${uncompressedSize}) out of range`);
121
- }
122
-
123
- if (compressedSize > MAX_INT) {
124
- throw new Error(`compressedSize (${compression}) out of range`);
125
- }
126
-
127
- // Determine if compression increases size
128
- const badCompress = compressedSize >= uncompressedSize;
129
-
130
- // Build the output
131
- return concat(
132
- write_i32(uncompressedSize),
133
- write_i32(badCompress ? 0 : compressedSize),
134
- badCompress ? data : compressed,
135
- );
136
- }
137
-
138
- // Read a string from a byte array
139
- function read_string(data) {
140
- const raw_size = read_i32(data);
141
- const is_ucs2 = raw_size < 0;
142
- const size = is_ucs2 ? -raw_size : raw_size;
143
-
144
- // Determine if we are using UCS-2
145
- if (is_ucs2) {
146
- if (size % 2 !== 0) {
147
- throw new Error('Invalid UCS-2 data size');
148
- }
149
-
150
- // Create ucs2 encoded string
151
- return punycode.ucs2.encode(
152
- // Read the data in 2 byte windows
153
- chunk(bytes(data, size), 2)
154
- .map(arr => read_u16(arr)) // Convert the two bytes into u16
155
- );
156
- } else {
157
- // Read the data, remove the \u0000 at the end :)
158
- const strData = bytes(data, size).subarray(0, -1);
159
-
160
- // Convert into ascii
161
- return String.fromCharCode.apply(null, strData);
162
- }
163
- }
164
-
165
- // Write a string to bytes
166
- function write_string(str) {
167
- if (isASCII(str)) {
168
- return concat(
169
- write_i32(str.length + 1), // Write string length (+ null term)
170
- new Uint8Array(str.split('').map(s => s.charCodeAt(0))), // Write string as bytes
171
- new Uint8Array([0]), // Null terminator
172
- );
173
- } else {
174
- // ucs2 strings denoted by negative length
175
- const len = -((str.length + 1) * 2);
176
- return concat(
177
- write_i32(len), // write length
178
- punycode.ucs2.decode(str), // write decoded string
179
- new Uint8Array([0]), // Null terminator
180
- )
181
- }
182
- }
183
-
184
- // Read uuid from 4 LE ints
185
- function read_uuid(data) {
186
- return uuidStringify(chunk(bytes(data, 16), 4)
187
- .flatMap(arr => {
188
- arr.reverse();
189
- return Array.from(arr);
190
- })); // each chunk is LE
191
- }
192
-
193
- // parse a uuid into 4 LE ints
194
- function write_uuid(uuid) {
195
- return concat(
196
- ...chunk(uuidParse(uuid), 4)
197
- .map(arr => {
198
- arr.reverse(); // convert into 4 LE ints;
199
- return new Uint8Array(arr);
200
- })
201
- );
202
- }
203
-
204
- // Read an array of things given a fn
205
- function read_array(data, fn) {
206
- const length = read_i32(data);
207
- const arr = Array(length);
208
- for (let i = 0; i < length; i++) {
209
- arr[i] = fn(data);
210
- }
211
- return arr;
212
- }
213
-
214
- // iterate an array of things given a fn
215
- function read_each(data, fn) {
216
- const length = read_i32(data);
217
- for (let i = 0; i < length; i++) {
218
- fn(data);
219
- }
220
- }
221
-
222
- // Write an array of things to bytes
223
- function write_array(arr, fn) {
224
- return concat(
225
- write_i32(arr.length),
226
- ...arr.map(o => fn(o))
227
- );
228
- }
229
-
230
- // Tool for reading byte arrays 1 bit at a time
231
- class BitReader {
232
- constructor(data) {
233
- this.buffer = new Uint8Array(data);
234
- this.pos = 0;
235
- }
236
-
237
- empty() {
238
- return this.pos >= this.buffer.length * 8;
239
- }
240
-
241
- // Read one bit as a boolean
242
- bit() {
243
- const bit = (this.buffer[this.pos >> 3] & (1 << (this.pos & 0b111))) !== 0;
244
- this.pos++;
245
- return bit;
246
- }
247
-
248
- // Align the pos to the nearest byte
249
- align() {
250
- this.pos = (this.pos + 7) & ~7;
251
- }
252
-
253
- // read an int up to max
254
- int(max) {
255
- let value = 0;
256
- let mask = 1;
257
-
258
- while (value + mask < max && mask !== 0) {
259
- if (this.bit()) {
260
- value |= mask;
261
- }
262
- mask <<= 1;
263
- }
264
-
265
- return value;
266
- }
267
-
268
- // read a packet in from bits
269
- uint_packed() {
270
- let value = 0;
271
- for (let i = 0; i < 5; i++) {
272
- const next = this.bit();
273
-
274
- let part = 0;
275
- for (let shift = 0; shift < 7; shift++) {
276
- part |= (this.bit() ? 1 : 0) << shift;
277
- }
278
- value |= part << (7 * i);
279
- if (!next) {
280
- break;
281
- }
282
- }
283
-
284
- return value;
285
- }
286
-
287
- // an item in a read_positive_int_vector array
288
- int_packed() {
289
- const value = this.uint_packed();
290
- return (value >> 1) * (value & 1 !== 0 ? 1 : -1);
291
- }
292
-
293
- // read some bits
294
- bits(num) {
295
- const arr = [];
296
- for (let bit = 0; bit < num; bit++) {
297
- const shift = bit & 7;
298
- arr[bit >> 3] = (arr[bit >> 3] & ~(1 << shift)) | ((this.bit() ? 1 : 0) << shift);
299
- }
300
- return arr;
301
- }
302
-
303
- // Read some bytes
304
- bytes(num) {
305
- return new Uint8Array(this.bits(num * 8));
306
- }
307
-
308
- // read some bytes but not as a Uint8Array
309
- bytesArr(num) {
310
- return this.bits(num * 8);
311
- }
312
-
313
- // read an array
314
- array(fn) {
315
- const length = read_i32(this.bytes(4));
316
- const arr = Array(length);
317
- for(let i = 0; i < length; i++) {
318
- arr[i] = fn(this);
319
- }
320
- return arr;
321
- }
322
-
323
- // for each
324
- each(fn) {
325
- const length = read_i32(this.bytes(4));
326
- for(let i = 0; i < length; i++) {
327
- fn(this);
328
- }
329
- }
330
-
331
- // read a string
332
- string() {
333
- const lenBytes = this.bytesArr(4);
334
- const len = read_i32(new Uint8Array(lenBytes));
335
- return read_string(new Uint8Array(lenBytes.concat(this.bytesArr(len))));
336
- }
337
-
338
- // read a 32-bit float
339
- float() {
340
- const view = new DataView(new ArrayBuffer(4));
341
-
342
- // Write the ints to it
343
- view.setUint16(2, read_u16(this.bytes(2)));
344
- view.setUint16(0, read_u16(this.bytes(2)));
345
-
346
- // Read the bits as a float; note that by doing this, we're implicitly
347
- // converting it from a 32-bit float into JavaScript's native 64-bit double
348
- return view.getFloat32(0);
349
- }
350
-
351
- // read unreal types
352
- unreal(type) {
353
- switch(type) {
354
- case 'Class': case 'Object':
355
- return this.string();
356
- case 'Boolean':
357
- return !!read_i32(new Uint8Array(this.bytes(4)));
358
- case 'Float':
359
- return this.float();
360
- case 'Color':
361
- return bgra(this.bytes(4));
362
- case 'Byte':
363
- return this.bytes(1)[0];
364
- case 'Rotator':
365
- return [this.float(), this.float(), this.float()];
366
- }
367
- throw new Error('Unknown unreal type ' + type);
368
- }
369
- }
370
-
371
- class BitWriter {
372
- constructor() {
373
- this.buffer = [];
374
- this.cur = 0;
375
- this.bitNum = 0;
376
-
377
- }
378
-
379
- // Write a boolean as a bit
380
- bit(val) {
381
- this.cur |= (val ? 1 : 0) << this.bitNum;
382
- this.bitNum++;
383
- if (this.bitNum >= 8) {
384
- this.align();
385
- }
386
- }
387
-
388
- // Write `len` bits from `src` bytes
389
- bits(src, len) {
390
- for (let bit = 0; bit < len; bit++) {
391
- this.bit((src[bit >> 3] & (1 << (bit & 7))) !== 0);
392
- }
393
- }
394
-
395
- // Write multiple bytes
396
- bytes(src) {
397
- this.bits(src, 8 * src.length);
398
- }
399
-
400
- // Push the current bit into the buffer
401
- align() {
402
- if (this.bitNum > 0) {
403
- this.buffer.push(this.cur);
404
- this.cur = 0;
405
- this.bitNum = 0;
406
- }
407
- }
408
-
409
- // Write an int up to the potential max size
410
- int(value, max) {
411
- if (max < 2) {
412
- throw new Error(`Invalid input (BitWriter) -- max (${max}) must be at least 2`)
413
- }
414
-
415
- if (value >= max) {
416
- throw new Error(`Invalid input (BitWriter) -- value (${value}) is larger than max (${max})`)
417
- }
418
-
419
- let new_val = 0;
420
- let mask = 1;
421
-
422
- while ((new_val + mask) < max && mask !== 0) {
423
- this.bit((value & mask) !== 0);
424
- if ((value & mask) !== 0) {
425
- new_val |= mask;
426
- }
427
-
428
- mask <<= 1;
429
- }
430
- }
431
-
432
- // Write a packed unsigned int
433
- uint_packed(value) {
434
- do {
435
- const src = value & 0b1111111;
436
- value >>= 7;
437
- this.bit(value !== 0);
438
- this.bits([src], 7);
439
- } while (value !== 0);
440
- }
441
-
442
- // Write a packed integer
443
- int_packed(value) {
444
- this.uint_packed((Math.abs(value) << 1) | (value >= 0 ? 1 : 0));
445
- }
446
-
447
- // Return built buffer
448
- finish() {
449
- this.align();
450
- return this.buffer;
451
- }
452
-
453
- // Return built buffer (and include length)
454
- finishSection() {
455
- this.align();
456
- return concat(write_i32(this.buffer.length), this.buffer);
457
- }
458
-
459
- // write a string
460
- string(str) { this.bytes(write_string(str)); }
461
-
462
- float(num) {
463
- // create a float array
464
- const floatArr = new Float32Array(1);
465
- // assign the number
466
- floatArr[0] = num;
467
- // convert it into a byte array
468
- const bytes = new Int8Array(floatArr.buffer);
469
- this.bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
470
- }
471
-
472
- // use
473
- self(fn) {
474
- fn.bind(this)();
475
- return this;
476
- }
477
-
478
- // write an array
479
- array(arr, fn) {
480
- this.bytes(write_i32(arr.length));
481
- arr.forEach(fn.bind(this));
482
- return this;
483
- }
484
-
485
- // write things from an array
486
- each(arr, fn) {
487
- arr.forEach(fn.bind(this));
488
- return this;
489
- }
490
-
491
- // write unreal types
492
- unreal(type, value) {
493
- switch(type) {
494
- case 'Class':
495
- if (typeof value !== 'string') {
496
- throw new Error(`writing unreal type Class, did not receive string (${value})`);
497
- }
498
- this.string(value);
499
- return;
500
- case 'Object':
501
- if (typeof value !== 'string') {
502
- throw new Error(`writing unreal type Object, did not receive string (${value})`);
503
- }
504
- this.string(value);
505
- return;
506
- case 'Boolean':
507
- if (typeof value !== 'boolean') {
508
- throw new Error(`writing unreal type Boolean, did not receive boolean (${value})`);
509
- }
510
- this.bytes(write_i32(value ? 1 : 0));
511
- return;
512
- case 'Float':
513
- if (typeof value !== 'number') {
514
- throw new Error(`writing unreal type Float, did not receive float (${value})`);
515
- }
516
- this.float(value);
517
- return;
518
- case 'Byte':
519
- if (typeof value !== 'number') {
520
- throw new Error(`writing unreal type Byte, did not receive Byte (${value})`);
521
- }
522
- this.bytes([value & 255]);
523
- return;
524
- case 'Color':
525
- if (typeof value !== 'object' && value.length === 4) {
526
- throw new Error(`writing unreal type Array, did not receive Array (${value})`);
527
- }
528
- this.bytes(bgra(value));
529
- return;
530
- case 'Rotator':
531
- if (typeof value !== 'object' && value.length === 3) {
532
- throw new Error(`writing unreal type Array, did not receive Array (${value})`);
533
- }
534
-
535
- this.float(value[0]);
536
- this.float(value[1]);
537
- this.float(value[2]);
538
- return;
539
- }
540
- throw new Error('Unknown unreal type ' + type);
541
- }
542
- }
543
-
544
- // concat uint8arrays together
545
- export function concat(...arrays) {
546
- const buffLen = arrays.reduce((sum, value) => sum + value.length, 0);
547
- const buff = new Uint8Array(buffLen);
548
-
549
- // for each array - copy it over buff
550
- // next array is copied right after the previous one
551
- let length = 0;
552
- for(const array of arrays) {
553
- buff.set(array, length);
554
- length += array.length;
555
- }
556
-
557
- return buff;
558
- };
559
-
560
- export const read = {
561
- bytes,
562
- u16: read_u16,
563
- i32: read_i32,
564
- compressed: read_compressed,
565
- string: read_string,
566
- uuid: read_uuid,
567
- array: read_array,
568
- each: read_each,
569
- bits: data => new BitReader(data),
570
- };
571
-
572
- export const write = {
573
- u16: write_u16,
574
- i32: write_i32,
575
- compressed: write_compressed,
576
- string: write_string,
577
- uuid: write_uuid,
578
- array: write_array,
579
- bits: data => new BitWriter(),
580
- };
package/src/uuid.js DELETED
@@ -1,74 +0,0 @@
1
- // this code is modified from https://github.com/uuidjs/uuid
2
- /*
3
- The MIT License (MIT)
4
-
5
- Copyright (c) 2010-2020 Robert Kieffer and other contributors
6
-
7
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
-
9
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
-
11
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
- */
13
- const hexTable = Array.from({length: 256}).map((_, i) =>
14
- (i + 0x100).toString(16).substr(1));
15
-
16
- // stringify uuid
17
- export function uuidStringify(arr) {
18
- return (
19
- hexTable[arr[0]] +
20
- hexTable[arr[1]] +
21
- hexTable[arr[2]] +
22
- hexTable[arr[3]] +
23
- '-' +
24
- hexTable[arr[4]] +
25
- hexTable[arr[5]] +
26
- '-' +
27
- hexTable[arr[6]] +
28
- hexTable[arr[7]] +
29
- '-' +
30
- hexTable[arr[8]] +
31
- hexTable[arr[9]] +
32
- '-' +
33
- hexTable[arr[10]] +
34
- hexTable[arr[11]] +
35
- hexTable[arr[12]] +
36
- hexTable[arr[13]] +
37
- hexTable[arr[14]] +
38
- hexTable[arr[15]]
39
- ).toLowerCase();
40
- }
41
-
42
- export function uuidParse(uuid) {
43
- let v;
44
- const arr = new Uint8Array(16);
45
-
46
- // Parse ########-....-....-....-............
47
- arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
48
- arr[1] = (v >>> 16) & 0xff;
49
- arr[2] = (v >>> 8) & 0xff;
50
- arr[3] = v & 0xff;
51
-
52
- // Parse ........-####-....-....-............
53
- arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
54
- arr[5] = v & 0xff;
55
-
56
- // Parse ........-....-####-....-............
57
- arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
58
- arr[7] = v & 0xff;
59
-
60
- // Parse ........-....-....-####-............
61
- arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
62
- arr[9] = v & 0xff;
63
-
64
- // Parse ........-....-....-....-############
65
- // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)
66
- arr[10] = ((v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000) & 0xff;
67
- arr[11] = (v / 0x100000000) & 0xff;
68
- arr[12] = (v >>> 24) & 0xff;
69
- arr[13] = (v >>> 16) & 0xff;
70
- arr[14] = (v >>> 8) & 0xff;
71
- arr[15] = v & 0xff;
72
-
73
- return arr;
74
- }