brs-js 2.0.1 → 2.0.4

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.
Files changed (81) hide show
  1. package/debug/Conf Spacestation.brs +0 -0
  2. package/debug/Electrks_Feminine_Challenge.brs +0 -0
  3. package/debug/a5bricks.brs +0 -0
  4. package/debug/a5p2.2.brs +0 -0
  5. package/debug/a5p2.brs +0 -0
  6. package/debug/audio.brs +0 -0
  7. package/debug/brick a5.brs +0 -0
  8. package/debug/brick qa.brs +0 -0
  9. package/debug/brsv10.brs +0 -0
  10. package/debug/brsv10brick.brs +0 -0
  11. package/debug/bruteforce.js +254 -0
  12. package/debug/clone.html +36 -0
  13. package/debug/ctf_tileset.brs +0 -0
  14. package/debug/ctf_tileset_5.brs +0 -0
  15. package/debug/evil.brs +0 -0
  16. package/debug/evilwrite.js +390 -0
  17. package/debug/foo.txt +3080 -0
  18. package/debug/kenko_big.brs +0 -0
  19. package/debug/light.brs +0 -0
  20. package/debug/out.json +105 -0
  21. package/debug/read.js +30 -0
  22. package/debug/readSpeed.js +32 -0
  23. package/debug/readTest.js +45 -0
  24. package/debug/temp.brs +0 -0
  25. package/debug/western.brs +0 -0
  26. package/dist/dist.js +1 -1
  27. package/dist/dist.node.js +1 -1
  28. package/dist/dist.web.js +1 -1
  29. package/dist/src/constants.d.ts +6 -0
  30. package/dist/src/constants.d.ts.map +1 -0
  31. package/dist/src/index.d.ts +24 -0
  32. package/dist/src/index.d.ts.map +1 -0
  33. package/dist/src/read.d.ts +3 -0
  34. package/dist/src/read.d.ts.map +1 -0
  35. package/dist/src/read.v1.d.ts +3 -0
  36. package/dist/src/read.v1.d.ts.map +1 -0
  37. package/dist/src/read.v10.d.ts +3 -0
  38. package/dist/src/read.v10.d.ts.map +1 -0
  39. package/dist/src/read.v2.d.ts +3 -0
  40. package/dist/src/read.v2.d.ts.map +1 -0
  41. package/dist/src/read.v3.d.ts +3 -0
  42. package/dist/src/read.v3.d.ts.map +1 -0
  43. package/dist/src/read.v4.d.ts +3 -0
  44. package/dist/src/read.v4.d.ts.map +1 -0
  45. package/dist/src/read.v8.d.ts +3 -0
  46. package/dist/src/read.v8.d.ts.map +1 -0
  47. package/dist/src/read.v9.d.ts +3 -0
  48. package/dist/src/read.v9.d.ts.map +1 -0
  49. package/dist/src/types.d.ts +286 -0
  50. package/dist/src/types.d.ts.map +1 -0
  51. package/dist/src/utils.d.ts +87 -0
  52. package/dist/src/utils.d.ts.map +1 -0
  53. package/dist/src/uuid.d.ts +4 -0
  54. package/dist/src/uuid.d.ts.map +1 -0
  55. package/dist/src/write.d.ts +3 -0
  56. package/dist/src/write.d.ts.map +1 -0
  57. package/examples/ATCFort.brs +0 -0
  58. package/examples/read_example.html +34 -0
  59. package/examples/read_example.js +21 -0
  60. package/examples/write_example.js +25 -0
  61. package/examples/write_planet.html +144 -0
  62. package/examples/write_simplex.html +82 -0
  63. package/examples/write_wedge_sphere.html +173 -0
  64. package/package.json +1 -1
  65. package/src/constants.ts +6 -0
  66. package/src/index.ts +25 -0
  67. package/src/read.ts +57 -0
  68. package/src/read.v1.ts +99 -0
  69. package/src/read.v10.ts +185 -0
  70. package/src/read.v2.ts +102 -0
  71. package/src/read.v3.ts +111 -0
  72. package/src/read.v4.ts +112 -0
  73. package/src/read.v8.ts +172 -0
  74. package/src/read.v9.ts +181 -0
  75. package/src/types.ts +354 -0
  76. package/src/utils.ts +640 -0
  77. package/src/uuid.ts +78 -0
  78. package/src/write.ts +209 -0
  79. package/test/lib.test.js +51 -0
  80. package/test/utils.test.js +209 -0
  81. package/tsconfig.json +1 -5
package/src/utils.ts ADDED
@@ -0,0 +1,640 @@
1
+ import { deflate, inflate } from 'pako';
2
+ import { MAX_INT } from './constants';
3
+ import {
4
+ BRSBytes,
5
+ Bytes,
6
+ UnrealColor,
7
+ UnrealFloat,
8
+ UnrealType,
9
+ Uuid,
10
+ } from './types';
11
+ import { uuidParse, uuidStringify } from './uuid';
12
+
13
+ /*
14
+ Notes:
15
+ - Everything is Little Endian by default because
16
+ UE4 uses it.
17
+ - I'd use Buffer.readUInt16LE if I was making this
18
+ nodejs only. I don't want to require('Buffer/')
19
+
20
+ */
21
+
22
+ // Determine if a string is ascii-only
23
+ function isASCII(text: string): boolean {
24
+ return /^[\x00-\x7F]*$/.test(text);
25
+ }
26
+
27
+ // convert BGRA color to RGBA color
28
+ export const bgra = ([b, g, r, a]: number[]): [
29
+ number,
30
+ number,
31
+ number,
32
+ number
33
+ ] => [r, g, b, a];
34
+
35
+ // Compare equality of byte arrays
36
+ export function isEqual<T>(arrA: Array<T>, arrB: Array<T>): boolean {
37
+ return arrA.length === arrB.length && arrA.every((a: T, i) => arrB[i] === a);
38
+ }
39
+
40
+ function isBRSBytes(data: Bytes): data is BRSBytes {
41
+ return (data as BRSBytes).brsOffset !== undefined;
42
+ }
43
+
44
+ // read `len` bytes and return slice while updating offset
45
+ export function subarray(data: Bytes, len: number, isCopy = false): Uint8Array {
46
+ if (!(data instanceof Uint8Array)) {
47
+ throw new Error(`Invalid data type in bytes reader (${typeof data})`);
48
+ }
49
+
50
+ let bytes: BRSBytes;
51
+ if (!isBRSBytes(data)) {
52
+ bytes = data as BRSBytes;
53
+ bytes.brsOffset = 0;
54
+ } else {
55
+ bytes = data;
56
+ }
57
+
58
+ const chunk = bytes[isCopy ? 'slice' : 'subarray'](
59
+ bytes.brsOffset,
60
+ bytes.brsOffset + len
61
+ );
62
+ bytes.brsOffset += len;
63
+ return chunk;
64
+ }
65
+
66
+ // break a byte array into chunks of a specified size
67
+ export function chunk(arr: Bytes, size: number): BRSBytes[] {
68
+ // relative length based on the offset of the array's data view
69
+ const length = arr.length - (isBRSBytes(arr) ? arr.brsOffset : 0);
70
+
71
+ // out array of chunks pre-allocated
72
+ const out = Array(Math.floor(length / size));
73
+
74
+ for (let i = 0; i < length / size; i++) {
75
+ out[i] = subarray(arr, size, true);
76
+ }
77
+
78
+ return out;
79
+ }
80
+
81
+ // Read a u16 from a byte array
82
+ function read_u16(data: Bytes, littleEndian = true): number {
83
+ const [a, b] = subarray(data, 2);
84
+
85
+ return littleEndian ? (b << 8) | a : (a << 8) | b;
86
+ }
87
+
88
+ // Write a u16 into byte array
89
+ function write_u16(num: number, littleEndian = true): Uint8Array {
90
+ const data = [num & 255, (num >> 8) & 255];
91
+ return new Uint8Array(!littleEndian ? data.reverse() : data);
92
+ }
93
+
94
+ // Read an i32 from a byte array
95
+ function read_i32(data: Bytes, littleEndian = true): number {
96
+ const [a, b, c, d] = subarray(data, 4);
97
+ return littleEndian
98
+ ? (d << 24) | (c << 16) | (b << 8) | a
99
+ : (a << 24) | (b << 16) | (c << 8) | d;
100
+ }
101
+
102
+ // Write an i32 from a byte array
103
+ function write_i32(num: number, littleEndian = true): Uint8Array {
104
+ const data = new Uint8Array([
105
+ num & 255,
106
+ (num >> 8) & 255,
107
+ (num >> 16) & 255,
108
+ (num >> 24) & 255,
109
+ ]);
110
+
111
+ return !littleEndian ? data.reverse() : data;
112
+ }
113
+
114
+ // Decompress a byte array of compressed data
115
+ function read_compressed(data: Bytes): Bytes {
116
+ const uncompressedSize = read_i32(data);
117
+ const compressedSize = read_i32(data);
118
+
119
+ // Throw error for weird compression/uncompression sizes
120
+ if (
121
+ compressedSize < 0 ||
122
+ uncompressedSize < 0 ||
123
+ compressedSize >= uncompressedSize
124
+ ) {
125
+ throw new Error(
126
+ `Invalid compressed section size (comp: ${compressedSize}, uncomp: ${uncompressedSize})`
127
+ );
128
+ }
129
+
130
+ // No compressed data? Return those bytes
131
+ if (compressedSize === 0) {
132
+ return subarray(data, uncompressedSize);
133
+ } else {
134
+ // Decompress the data otherwise
135
+ const compressed = subarray(data, compressedSize);
136
+ return inflate(compressed);
137
+ }
138
+ }
139
+
140
+ // Compress a byte array into fewer bytes
141
+ function write_uncompressed(...args: Uint8Array[]): Uint8Array {
142
+ // Concat the args to one massive array
143
+ const data = concat(...args);
144
+
145
+ // Build the output
146
+ return concat(write_i32(data.length), write_i32(0), data);
147
+ }
148
+
149
+ // Compress a byte array into fewer bytes
150
+ function write_compressed(...args: Uint8Array[]): Uint8Array {
151
+ // Concat the args to one massive array
152
+ const data = concat(...args);
153
+
154
+ // Do the compression
155
+ const compressed = deflate(data);
156
+ const uncompressedSize = data.length;
157
+ const compressedSize = compressed.length;
158
+
159
+ if (uncompressedSize > MAX_INT) {
160
+ throw new Error(`uncompressedSize (${uncompressedSize}) out of range`);
161
+ }
162
+
163
+ if (compressedSize > MAX_INT) {
164
+ throw new Error(`compressedSize (${compressedSize}) out of range`);
165
+ }
166
+
167
+ // Determine if compression increases size
168
+ const badCompress = compressedSize >= uncompressedSize;
169
+
170
+ // Build the output
171
+ return concat(
172
+ write_i32(uncompressedSize),
173
+ write_i32(badCompress ? 0 : compressedSize),
174
+ badCompress ? data : compressed
175
+ );
176
+ }
177
+
178
+ // Read a string from a byte array
179
+ function read_string(data: Bytes): string {
180
+ const raw_size = read_i32(data);
181
+ const is_ucs2 = raw_size < 0;
182
+ const size = is_ucs2 ? -raw_size : raw_size;
183
+
184
+ // Determine if we are using UCS-2
185
+ if (is_ucs2) {
186
+ if (size % 2 !== 0) {
187
+ throw new Error('Invalid UCS-2 data size');
188
+ }
189
+
190
+ // Create ucs2 encoded string
191
+ return String.fromCodePoint(
192
+ // Read the data in 2 byte windows
193
+ ...chunk(subarray(data, size), 2).map(arr => read_u16(arr)) // Convert the two bytes into u16
194
+ );
195
+ } else {
196
+ // Read the data, remove the \u0000 at the end :)
197
+ const strData = subarray(data, size).subarray(0, -1);
198
+
199
+ // Convert into ascii
200
+ return String.fromCharCode.apply(null, strData);
201
+ }
202
+ }
203
+
204
+ // Write a string to bytes
205
+ function write_string(str: string): Uint8Array {
206
+ if (isASCII(str)) {
207
+ return concat(
208
+ write_i32(str.length + 1), // Write string length (+ null term)
209
+ new Uint8Array(str.split('').map(s => s.charCodeAt(0))), // Write string as bytes
210
+ new Uint8Array([0]) // Null terminator
211
+ );
212
+ } else {
213
+ // ucs2 strings denoted by negative length
214
+ const len = -((str.length + 1) * 2);
215
+ return concat(
216
+ write_i32(len), // write length
217
+ // convert string to little endian ucs2
218
+ new Uint8Array(
219
+ str
220
+ .split('')
221
+ .flatMap(s => [s.charCodeAt(0) & 0xff, s.charCodeAt(0) >> 8])
222
+ ),
223
+ new Uint8Array([0]) // Null terminator
224
+ );
225
+ }
226
+ }
227
+
228
+ // Read uuid from 4 LE ints
229
+ function read_uuid(data: Bytes): string {
230
+ return uuidStringify(
231
+ // each chunk is LE
232
+ chunk(subarray(data, 16), 4).flatMap(([a, b, c, d]) => [d, c, b, a])
233
+ );
234
+ }
235
+
236
+ // parse a uuid into 4 LE ints
237
+ function write_uuid(uuid: Uuid) {
238
+ return concat(
239
+ ...chunk(uuidParse(uuid), 4).map(
240
+ ([a, b, c, d]) => new Uint8Array([d, c, b, a])
241
+ )
242
+ );
243
+ }
244
+
245
+ // Read an array of things given a fn
246
+ function read_array<T>(data: Bytes, fn: (_: Bytes) => T): T[] {
247
+ const length = read_i32(data);
248
+ const arr = Array(length);
249
+ for (let i = 0; i < length; i++) {
250
+ arr[i] = fn(data);
251
+ }
252
+ return arr;
253
+ }
254
+
255
+ // iterate an array of things given a fn
256
+ function read_each(data: Bytes, fn: (_: Bytes) => void) {
257
+ const length = read_i32(data);
258
+ for (let i = 0; i < length; i++) {
259
+ fn(data);
260
+ }
261
+ }
262
+
263
+ // Write an array of things to bytes
264
+ function write_array<T>(arr: T[], fn: (_: T) => Uint8Array) {
265
+ return concat(write_i32(arr.length), ...arr.map(o => fn(o)));
266
+ }
267
+
268
+ // Tool for reading byte arrays 1 bit at a time
269
+ class BitReader {
270
+ buffer: Uint8Array;
271
+ pos: number = 0;
272
+
273
+ constructor(data: Uint8Array) {
274
+ this.buffer = data;
275
+ }
276
+
277
+ empty(): boolean {
278
+ return this.pos >= this.buffer.length * 8;
279
+ }
280
+
281
+ // Read one bit as a boolean
282
+ bit(): boolean {
283
+ const bit = (this.buffer[this.pos >> 3] & (1 << (this.pos & 0b111))) !== 0;
284
+ this.pos++;
285
+ return bit;
286
+ }
287
+
288
+ // Align the pos to the nearest byte
289
+ align() {
290
+ this.pos = (this.pos + 7) & ~7;
291
+ }
292
+
293
+ // read an int up to max
294
+ int(max: number): number {
295
+ let value = 0;
296
+ let mask = 1;
297
+
298
+ while (value + mask < max && mask !== 0) {
299
+ if (this.bit()) {
300
+ value |= mask;
301
+ }
302
+ mask <<= 1;
303
+ }
304
+
305
+ return value;
306
+ }
307
+
308
+ // read a packet in from bits
309
+ uint_packed(): number {
310
+ let value = 0;
311
+ for (let i = 0; i < 5; i++) {
312
+ const next = this.bit();
313
+
314
+ let part = 0;
315
+ for (let shift = 0; shift < 7; shift++) {
316
+ part |= (this.bit() ? 1 : 0) << shift;
317
+ }
318
+ value |= part << (7 * i);
319
+ if (!next) {
320
+ break;
321
+ }
322
+ }
323
+
324
+ return value;
325
+ }
326
+
327
+ // an item in a read_positive_int_vector array
328
+ int_packed(): number {
329
+ const value = this.uint_packed();
330
+ return (value >> 1) * ((value & 1) !== 0 ? 1 : -1);
331
+ }
332
+
333
+ // read some bits
334
+ bits(num: number): number[] {
335
+ const arr: number[] = [];
336
+ for (let bit = 0; bit < num; bit++) {
337
+ const shift = bit & 7;
338
+ arr[bit >> 3] =
339
+ (arr[bit >> 3] & ~(1 << shift)) | ((this.bit() ? 1 : 0) << shift);
340
+ }
341
+ return arr;
342
+ }
343
+
344
+ // Read some bytes
345
+ bytes(num: number): Uint8Array {
346
+ return new Uint8Array(this.bytesArr(num));
347
+ }
348
+
349
+ // read some bytes but not as a Uint8Array
350
+ bytesArr(num: number): number[] {
351
+ return this.bits(num * 8);
352
+ }
353
+
354
+ // read an array
355
+ array<T>(fn: (_: BitReader) => T): T[] {
356
+ const length = read_i32(this.bytes(4));
357
+ const arr = Array(length);
358
+ for (let i = 0; i < length; i++) {
359
+ arr[i] = fn(this);
360
+ }
361
+ return arr;
362
+ }
363
+
364
+ // for each
365
+ each(fn: (data: BitReader) => void) {
366
+ const length = read_i32(this.bytes(4));
367
+ for (let i = 0; i < length; i++) {
368
+ fn(this);
369
+ }
370
+ }
371
+
372
+ // read a string
373
+ string(): string {
374
+ const lenBytes = this.bytesArr(4);
375
+ const len = read_i32(new Uint8Array(lenBytes));
376
+ return read_string(new Uint8Array(lenBytes.concat(this.bytesArr(len))));
377
+ }
378
+
379
+ // read a 32-bit float
380
+ float(): number {
381
+ const view = new DataView(new ArrayBuffer(4));
382
+
383
+ // Write the ints to it
384
+ view.setUint16(2, read_u16(this.bytes(2)));
385
+ view.setUint16(0, read_u16(this.bytes(2)));
386
+
387
+ // Read the bits as a float; note that by doing this, we're implicitly
388
+ // converting it from a 32-bit float into JavaScript's native 64-bit double
389
+ return view.getFloat32(0);
390
+ }
391
+
392
+ // read unreal types
393
+ unreal(type: string): UnrealType {
394
+ switch (type) {
395
+ case 'Class':
396
+ case 'Object':
397
+ return this.string();
398
+ case 'Boolean':
399
+ return !!read_i32(this.bytes(4));
400
+ case 'Float':
401
+ return this.float();
402
+ case 'Color':
403
+ return bgra(this.bytesArr(4)) as UnrealColor;
404
+ case 'Byte':
405
+ return this.bytes(1)[0];
406
+ case 'Rotator':
407
+ return [this.float(), this.float(), this.float()];
408
+ }
409
+ throw new Error('Unknown unreal type ' + type);
410
+ }
411
+ }
412
+
413
+ class BitWriter {
414
+ buffer: number[] = [];
415
+ cur: number = 0;
416
+ bitNum: number = 0;
417
+
418
+ // Write a boolean as a bit
419
+ bit(val: boolean) {
420
+ this.cur |= (val ? 1 : 0) << this.bitNum;
421
+ this.bitNum++;
422
+ if (this.bitNum >= 8) {
423
+ this.align();
424
+ }
425
+ }
426
+
427
+ // Write `len` bits from `src` bytes
428
+ bits(src: number[] | Uint8Array, len: number) {
429
+ for (let bit = 0; bit < len; bit++) {
430
+ this.bit((src[bit >> 3] & (1 << (bit & 7))) !== 0);
431
+ }
432
+ }
433
+
434
+ // Write multiple bytes
435
+ bytes(src: number[] | Uint8Array) {
436
+ this.bits(src, 8 * src.length);
437
+ }
438
+
439
+ // Push the current bit into the buffer
440
+ align() {
441
+ if (this.bitNum > 0) {
442
+ this.buffer.push(this.cur);
443
+ this.cur = 0;
444
+ this.bitNum = 0;
445
+ }
446
+ }
447
+
448
+ // Write an int up to the potential max size
449
+ int(value: number, max: number) {
450
+ if (max < 2) {
451
+ throw new Error(
452
+ `Invalid input (BitWriter) -- max (${max}) must be at least 2`
453
+ );
454
+ }
455
+
456
+ if (value >= max) {
457
+ throw new Error(
458
+ `Invalid input (BitWriter) -- value (${value}) is larger than max (${max})`
459
+ );
460
+ }
461
+
462
+ let new_val = 0;
463
+ let mask = 1;
464
+
465
+ while (new_val + mask < max && mask !== 0) {
466
+ this.bit((value & mask) !== 0);
467
+ if ((value & mask) !== 0) {
468
+ new_val |= mask;
469
+ }
470
+
471
+ mask <<= 1;
472
+ }
473
+ }
474
+
475
+ // Write a packed unsigned int
476
+ uint_packed(value: number) {
477
+ do {
478
+ const src = value & 0b1111111;
479
+ value >>= 7;
480
+ this.bit(value !== 0);
481
+ this.bits([src], 7);
482
+ } while (value !== 0);
483
+ }
484
+
485
+ // Write a packed integer
486
+ int_packed(value: number) {
487
+ this.uint_packed((Math.abs(value) << 1) | (value >= 0 ? 1 : 0));
488
+ }
489
+
490
+ // Return built buffer
491
+ finish(): Uint8Array {
492
+ this.align();
493
+ return new Uint8Array(this.buffer);
494
+ }
495
+
496
+ // Return built buffer (and include length)
497
+ finishSection() {
498
+ this.align();
499
+ return concat(write_i32(this.buffer.length), new Uint8Array(this.buffer));
500
+ }
501
+
502
+ // write a string
503
+ string(str: string) {
504
+ this.bytes(write_string(str));
505
+ }
506
+
507
+ float(num: UnrealFloat) {
508
+ // create a float array
509
+ const floatArr = new Float32Array(1);
510
+ // assign the number
511
+ floatArr[0] = num;
512
+ // convert it into a byte array
513
+ const bytes = new Int8Array(floatArr.buffer);
514
+ this.bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
515
+ }
516
+
517
+ // run a function with `this` as a BitReader
518
+ self(fn: (this: BitWriter) => void) {
519
+ fn.bind(this)();
520
+ return this;
521
+ }
522
+
523
+ // write an array
524
+ array<T>(arr: T[], fn: (this: BitWriter, item: T, index: number) => void) {
525
+ this.bytes(write_i32(arr.length));
526
+ arr.forEach(fn.bind(this));
527
+ return this;
528
+ }
529
+
530
+ // write things from an array
531
+ each<T>(arr: T[], fn: (this: BitWriter, item: T, index: number) => void) {
532
+ arr.forEach(fn.bind(this));
533
+ return this;
534
+ }
535
+
536
+ // write unreal types
537
+ unreal(type: string, value: UnrealType) {
538
+ switch (type) {
539
+ case 'Class':
540
+ if (typeof value !== 'string') {
541
+ throw new Error(
542
+ `writing unreal type Class, did not receive string (${value})`
543
+ );
544
+ }
545
+ this.string(value);
546
+ return;
547
+ case 'Object':
548
+ if (typeof value !== 'string') {
549
+ throw new Error(
550
+ `writing unreal type Object, did not receive string (${value})`
551
+ );
552
+ }
553
+ this.string(value);
554
+ return;
555
+ case 'Boolean':
556
+ if (typeof value !== 'boolean') {
557
+ throw new Error(
558
+ `writing unreal type Boolean, did not receive boolean (${value})`
559
+ );
560
+ }
561
+ this.bytes(write_i32(value ? 1 : 0));
562
+ return;
563
+ case 'Float':
564
+ if (typeof value !== 'number') {
565
+ throw new Error(
566
+ `writing unreal type Float, did not receive float (${value})`
567
+ );
568
+ }
569
+ this.float(value);
570
+ return;
571
+ case 'Byte':
572
+ if (typeof value !== 'number') {
573
+ throw new Error(
574
+ `writing unreal type Byte, did not receive Byte (${value})`
575
+ );
576
+ }
577
+ this.bytes([value & 255]);
578
+ return;
579
+ case 'Color':
580
+ if (!Array.isArray(value) || value.length !== 4) {
581
+ throw new Error(
582
+ `writing unreal type Array, did not receive Array (${value})`
583
+ );
584
+ }
585
+ this.bytes(bgra(value));
586
+ return;
587
+ case 'Rotator':
588
+ if (!Array.isArray(value) || value.length !== 3) {
589
+ throw new Error(
590
+ `writing unreal type Array, did not receive Array (${value})`
591
+ );
592
+ }
593
+
594
+ this.float(value[0]);
595
+ this.float(value[1]);
596
+ this.float(value[2]);
597
+ return;
598
+ }
599
+ throw new Error('Unknown unreal type ' + type);
600
+ }
601
+ }
602
+
603
+ // concat uint8arrays together
604
+ export function concat(...arrays: Uint8Array[]): Uint8Array {
605
+ const buffLen = arrays.reduce((sum, value) => sum + value.length, 0);
606
+ const buff = new Uint8Array(buffLen);
607
+
608
+ // for each array - copy it over buff
609
+ // next array is copied right after the previous one
610
+ let length = 0;
611
+ for (const array of arrays) {
612
+ buff.set(array, length);
613
+ length += array.length;
614
+ }
615
+
616
+ return buff;
617
+ }
618
+
619
+ export const read = {
620
+ bytes: subarray,
621
+ u16: read_u16,
622
+ i32: read_i32,
623
+ compressed: read_compressed,
624
+ string: read_string,
625
+ uuid: read_uuid,
626
+ array: read_array,
627
+ each: read_each,
628
+ bits: (data: Bytes) => new BitReader(data),
629
+ };
630
+
631
+ export const write = {
632
+ u16: write_u16,
633
+ i32: write_i32,
634
+ compressed: write_compressed,
635
+ uncompressed: write_uncompressed,
636
+ string: write_string,
637
+ uuid: write_uuid,
638
+ array: write_array,
639
+ bits: () => new BitWriter(),
640
+ };
package/src/uuid.ts ADDED
@@ -0,0 +1,78 @@
1
+ // this code is modified from https://github.com/uuidjs/uuid
2
+
3
+ import { Uuid } from './types';
4
+
5
+ /*
6
+ The MIT License (MIT)
7
+
8
+ Copyright (c) 2010-2020 Robert Kieffer and other contributors
9
+
10
+ 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:
11
+
12
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13
+
14
+ 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.
15
+ */
16
+ const hexTable: string[] = Array.from({ length: 256 }).map((_, i) =>
17
+ (i + 0x100).toString(16).substr(1)
18
+ );
19
+
20
+ // stringify uuid
21
+ export function uuidStringify(arr: number[]): Uuid {
22
+ return (
23
+ hexTable[arr[0]] +
24
+ hexTable[arr[1]] +
25
+ hexTable[arr[2]] +
26
+ hexTable[arr[3]] +
27
+ '-' +
28
+ hexTable[arr[4]] +
29
+ hexTable[arr[5]] +
30
+ '-' +
31
+ hexTable[arr[6]] +
32
+ hexTable[arr[7]] +
33
+ '-' +
34
+ hexTable[arr[8]] +
35
+ hexTable[arr[9]] +
36
+ '-' +
37
+ hexTable[arr[10]] +
38
+ hexTable[arr[11]] +
39
+ hexTable[arr[12]] +
40
+ hexTable[arr[13]] +
41
+ hexTable[arr[14]] +
42
+ hexTable[arr[15]]
43
+ ).toLowerCase();
44
+ }
45
+
46
+ export function uuidParse(uuid: Uuid): Uint8Array {
47
+ let v;
48
+ const arr = new Uint8Array(16);
49
+
50
+ // Parse ########-....-....-....-............
51
+ arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
52
+ arr[1] = (v >>> 16) & 0xff;
53
+ arr[2] = (v >>> 8) & 0xff;
54
+ arr[3] = v & 0xff;
55
+
56
+ // Parse ........-####-....-....-............
57
+ arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
58
+ arr[5] = v & 0xff;
59
+
60
+ // Parse ........-....-####-....-............
61
+ arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
62
+ arr[7] = v & 0xff;
63
+
64
+ // Parse ........-....-....-####-............
65
+ arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
66
+ arr[9] = v & 0xff;
67
+
68
+ // Parse ........-....-....-....-############
69
+ // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)
70
+ arr[10] = ((v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000) & 0xff;
71
+ arr[11] = (v / 0x100000000) & 0xff;
72
+ arr[12] = (v >>> 24) & 0xff;
73
+ arr[13] = (v >>> 16) & 0xff;
74
+ arr[14] = (v >>> 8) & 0xff;
75
+ arr[15] = v & 0xff;
76
+
77
+ return arr;
78
+ }