@k67/kaitai-struct-ts 0.5.0 → 0.6.0
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/README.md +29 -39
- package/dist/index.d.mts +229 -197
- package/dist/index.d.ts +229 -197
- package/dist/index.js +110 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
@@ -1,199 +1,3 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Binary stream reader for Kaitai Struct
|
3
|
-
* @module stream/KaitaiStream
|
4
|
-
* @author Fabiano Pinto
|
5
|
-
* @license MIT
|
6
|
-
*/
|
7
|
-
/**
|
8
|
-
* KaitaiStream provides methods for reading binary data with proper type handling
|
9
|
-
* and endianness support. It's the core class for parsing binary formats.
|
10
|
-
*
|
11
|
-
* Supports reading:
|
12
|
-
* - Unsigned integers (u1, u2, u4, u8) in both little and big endian
|
13
|
-
* - Signed integers (s1, s2, s4, s8) in both little and big endian
|
14
|
-
* - Floating point numbers (f4, f8) in both little and big endian
|
15
|
-
* - Byte arrays (fixed length, until terminator, or all remaining)
|
16
|
-
* - Strings with various encodings
|
17
|
-
* - Bit-level data
|
18
|
-
*
|
19
|
-
* @class KaitaiStream
|
20
|
-
* @example
|
21
|
-
* ```typescript
|
22
|
-
* const buffer = new Uint8Array([0x01, 0x02, 0x03, 0x04])
|
23
|
-
* const stream = new KaitaiStream(buffer)
|
24
|
-
*
|
25
|
-
* const byte = stream.readU1() // Read 1 byte
|
26
|
-
* const word = stream.readU2le() // Read 2 bytes little-endian
|
27
|
-
* const str = stream.readStr(5, 'UTF-8') // Read 5-byte string
|
28
|
-
* ```
|
29
|
-
*/
|
30
|
-
declare class KaitaiStream {
|
31
|
-
private buffer;
|
32
|
-
private view;
|
33
|
-
private _pos;
|
34
|
-
private _bits;
|
35
|
-
private _bitsLeft;
|
36
|
-
/**
|
37
|
-
* Create a new KaitaiStream from a buffer
|
38
|
-
* @param buffer - ArrayBuffer or Uint8Array containing the binary data
|
39
|
-
*/
|
40
|
-
constructor(buffer: ArrayBuffer | Uint8Array);
|
41
|
-
/**
|
42
|
-
* Current position in the stream
|
43
|
-
*/
|
44
|
-
get pos(): number;
|
45
|
-
set pos(value: number);
|
46
|
-
/**
|
47
|
-
* Total size of the stream in bytes
|
48
|
-
*/
|
49
|
-
get size(): number;
|
50
|
-
/**
|
51
|
-
* Check if we've reached the end of the stream
|
52
|
-
*/
|
53
|
-
isEof(): boolean;
|
54
|
-
/**
|
55
|
-
* Seek to a specific position in the stream
|
56
|
-
* @param pos - Position to seek to
|
57
|
-
*/
|
58
|
-
seek(pos: number): void;
|
59
|
-
/**
|
60
|
-
* Ensure we have enough bytes available
|
61
|
-
* @param count - Number of bytes needed
|
62
|
-
*/
|
63
|
-
private ensureBytes;
|
64
|
-
/**
|
65
|
-
* Read 1-byte unsigned integer (0 to 255)
|
66
|
-
*/
|
67
|
-
readU1(): number;
|
68
|
-
/**
|
69
|
-
* Read 2-byte unsigned integer, little-endian
|
70
|
-
*/
|
71
|
-
readU2le(): number;
|
72
|
-
/**
|
73
|
-
* Read 2-byte unsigned integer, big-endian
|
74
|
-
*/
|
75
|
-
readU2be(): number;
|
76
|
-
/**
|
77
|
-
* Read 4-byte unsigned integer, little-endian
|
78
|
-
*/
|
79
|
-
readU4le(): number;
|
80
|
-
/**
|
81
|
-
* Read 4-byte unsigned integer, big-endian
|
82
|
-
*/
|
83
|
-
readU4be(): number;
|
84
|
-
/**
|
85
|
-
* Read 8-byte unsigned integer, little-endian
|
86
|
-
* Returns BigInt for values > Number.MAX_SAFE_INTEGER
|
87
|
-
*/
|
88
|
-
readU8le(): bigint;
|
89
|
-
/**
|
90
|
-
* Read 8-byte unsigned integer, big-endian
|
91
|
-
* Returns BigInt for values > Number.MAX_SAFE_INTEGER
|
92
|
-
*/
|
93
|
-
readU8be(): bigint;
|
94
|
-
/**
|
95
|
-
* Read 1-byte signed integer (-128 to 127)
|
96
|
-
*/
|
97
|
-
readS1(): number;
|
98
|
-
/**
|
99
|
-
* Read 2-byte signed integer, little-endian
|
100
|
-
*/
|
101
|
-
readS2le(): number;
|
102
|
-
/**
|
103
|
-
* Read 2-byte signed integer, big-endian
|
104
|
-
*/
|
105
|
-
readS2be(): number;
|
106
|
-
/**
|
107
|
-
* Read 4-byte signed integer, little-endian
|
108
|
-
*/
|
109
|
-
readS4le(): number;
|
110
|
-
/**
|
111
|
-
* Read 4-byte signed integer, big-endian
|
112
|
-
*/
|
113
|
-
readS4be(): number;
|
114
|
-
/**
|
115
|
-
* Read 8-byte signed integer, little-endian
|
116
|
-
* Returns BigInt for values outside Number.MAX_SAFE_INTEGER range
|
117
|
-
*/
|
118
|
-
readS8le(): bigint;
|
119
|
-
/**
|
120
|
-
* Read 8-byte signed integer, big-endian
|
121
|
-
* Returns BigInt for values outside Number.MAX_SAFE_INTEGER range
|
122
|
-
*/
|
123
|
-
readS8be(): bigint;
|
124
|
-
/**
|
125
|
-
* Read 4-byte IEEE 754 single-precision float, little-endian
|
126
|
-
*/
|
127
|
-
readF4le(): number;
|
128
|
-
/**
|
129
|
-
* Read 4-byte IEEE 754 single-precision float, big-endian
|
130
|
-
*/
|
131
|
-
readF4be(): number;
|
132
|
-
/**
|
133
|
-
* Read 8-byte IEEE 754 double-precision float, little-endian
|
134
|
-
*/
|
135
|
-
readF8le(): number;
|
136
|
-
/**
|
137
|
-
* Read 8-byte IEEE 754 double-precision float, big-endian
|
138
|
-
*/
|
139
|
-
readF8be(): number;
|
140
|
-
/**
|
141
|
-
* Read a fixed number of bytes
|
142
|
-
* @param length - Number of bytes to read
|
143
|
-
*/
|
144
|
-
readBytes(length: number): Uint8Array;
|
145
|
-
/**
|
146
|
-
* Read all remaining bytes until end of stream
|
147
|
-
*/
|
148
|
-
readBytesFull(): Uint8Array;
|
149
|
-
/**
|
150
|
-
* Read bytes until a terminator byte is found
|
151
|
-
* @param term - Terminator byte value
|
152
|
-
* @param include - Include terminator in result
|
153
|
-
* @param consume - Consume terminator from stream
|
154
|
-
* @param eosError - Throw error if EOS reached before terminator
|
155
|
-
*/
|
156
|
-
readBytesterm(term: number, include?: boolean, consume?: boolean, eosError?: boolean): Uint8Array;
|
157
|
-
/**
|
158
|
-
* Read a fixed-length string
|
159
|
-
* @param length - Number of bytes to read
|
160
|
-
* @param encoding - Character encoding (default: UTF-8)
|
161
|
-
*/
|
162
|
-
readStr(length: number, encoding?: string): string;
|
163
|
-
/**
|
164
|
-
* Read a null-terminated string
|
165
|
-
* @param encoding - Character encoding (default: UTF-8)
|
166
|
-
* @param term - Terminator byte (default: 0)
|
167
|
-
* @param include - Include terminator in result
|
168
|
-
* @param consume - Consume terminator from stream
|
169
|
-
* @param eosError - Throw error if EOS reached before terminator
|
170
|
-
*/
|
171
|
-
readStrz(encoding?: string, term?: number, include?: boolean, consume?: boolean, eosError?: boolean): string;
|
172
|
-
/**
|
173
|
-
* Align bit reading to byte boundary
|
174
|
-
*/
|
175
|
-
alignToByte(): void;
|
176
|
-
/**
|
177
|
-
* Read specified number of bits as unsigned integer (big-endian)
|
178
|
-
* @param n - Number of bits to read (1-64)
|
179
|
-
*/
|
180
|
-
readBitsIntBe(n: number): bigint;
|
181
|
-
/**
|
182
|
-
* Read specified number of bits as unsigned integer (little-endian)
|
183
|
-
* @param n - Number of bits to read (1-64)
|
184
|
-
*/
|
185
|
-
readBitsIntLe(n: number): bigint;
|
186
|
-
/**
|
187
|
-
* Get the underlying buffer
|
188
|
-
*/
|
189
|
-
getBuffer(): Uint8Array;
|
190
|
-
/**
|
191
|
-
* Create a substream from current position with specified size
|
192
|
-
* @param size - Size of the substream in bytes
|
193
|
-
*/
|
194
|
-
substream(size: number): KaitaiStream;
|
195
|
-
}
|
196
|
-
|
197
1
|
/**
|
198
2
|
* @fileoverview Type definitions for Kaitai Struct YAML schema (.ksy files)
|
199
3
|
* @module parser/schema
|
@@ -505,6 +309,203 @@ declare function isFloatType(type: string): boolean;
|
|
505
309
|
*/
|
506
310
|
declare function isStringType(type: string): boolean;
|
507
311
|
|
312
|
+
/**
|
313
|
+
* @fileoverview Binary stream reader for Kaitai Struct
|
314
|
+
* @module stream/KaitaiStream
|
315
|
+
* @author Fabiano Pinto
|
316
|
+
* @license MIT
|
317
|
+
*/
|
318
|
+
/**
|
319
|
+
* KaitaiStream provides methods for reading binary data with proper type handling
|
320
|
+
* and endianness support. It's the core class for parsing binary formats.
|
321
|
+
*
|
322
|
+
* Supports reading:
|
323
|
+
* - Unsigned integers (u1, u2, u4, u8) in both little and big endian
|
324
|
+
* - Signed integers (s1, s2, s4, s8) in both little and big endian
|
325
|
+
* - Floating point numbers (f4, f8) in both little and big endian
|
326
|
+
* - Byte arrays (fixed length, until terminator, or all remaining)
|
327
|
+
* - Strings with various encodings
|
328
|
+
* - Bit-level data
|
329
|
+
*
|
330
|
+
* @class KaitaiStream
|
331
|
+
* @example
|
332
|
+
* ```typescript
|
333
|
+
* const buffer = new Uint8Array([0x01, 0x02, 0x03, 0x04])
|
334
|
+
* const stream = new KaitaiStream(buffer)
|
335
|
+
*
|
336
|
+
* const byte = stream.readU1() // Read 1 byte
|
337
|
+
* const word = stream.readU2le() // Read 2 bytes little-endian
|
338
|
+
* const str = stream.readStr(5, 'UTF-8') // Read 5-byte string
|
339
|
+
* ```
|
340
|
+
*/
|
341
|
+
declare class KaitaiStream {
|
342
|
+
private buffer;
|
343
|
+
private view;
|
344
|
+
private _pos;
|
345
|
+
private _bits;
|
346
|
+
private _bitsLeft;
|
347
|
+
private _size;
|
348
|
+
/**
|
349
|
+
* Create a new KaitaiStream from a buffer
|
350
|
+
* @param buffer - ArrayBuffer or Uint8Array containing the binary data
|
351
|
+
*/
|
352
|
+
constructor(buffer: ArrayBuffer | Uint8Array);
|
353
|
+
/**
|
354
|
+
* Current position in the stream
|
355
|
+
*/
|
356
|
+
get pos(): number;
|
357
|
+
set pos(value: number);
|
358
|
+
/**
|
359
|
+
* Total size of the stream in bytes
|
360
|
+
*/
|
361
|
+
get size(): number;
|
362
|
+
/**
|
363
|
+
* Check if we've reached the end of the stream
|
364
|
+
*/
|
365
|
+
isEof(): boolean;
|
366
|
+
/**
|
367
|
+
* Seek to a specific position in the stream
|
368
|
+
* @param pos - Position to seek to
|
369
|
+
*/
|
370
|
+
seek(pos: number): void;
|
371
|
+
/**
|
372
|
+
* Ensure we have enough bytes available
|
373
|
+
* @param count - Number of bytes needed
|
374
|
+
*/
|
375
|
+
private ensureBytes;
|
376
|
+
/**
|
377
|
+
* Read 1-byte unsigned integer (0 to 255)
|
378
|
+
*/
|
379
|
+
readU1(): number;
|
380
|
+
/**
|
381
|
+
* Read 2-byte unsigned integer, little-endian
|
382
|
+
*/
|
383
|
+
readU2le(): number;
|
384
|
+
/**
|
385
|
+
* Read 2-byte unsigned integer, big-endian
|
386
|
+
*/
|
387
|
+
readU2be(): number;
|
388
|
+
/**
|
389
|
+
* Read 4-byte unsigned integer, little-endian
|
390
|
+
*/
|
391
|
+
readU4le(): number;
|
392
|
+
/**
|
393
|
+
* Read 4-byte unsigned integer, big-endian
|
394
|
+
*/
|
395
|
+
readU4be(): number;
|
396
|
+
/**
|
397
|
+
* Read 8-byte unsigned integer, little-endian
|
398
|
+
* Returns BigInt for values > Number.MAX_SAFE_INTEGER
|
399
|
+
*/
|
400
|
+
readU8le(): bigint;
|
401
|
+
/**
|
402
|
+
* Read 8-byte unsigned integer, big-endian
|
403
|
+
* Returns BigInt for values > Number.MAX_SAFE_INTEGER
|
404
|
+
*/
|
405
|
+
readU8be(): bigint;
|
406
|
+
/**
|
407
|
+
* Read 1-byte signed integer (-128 to 127)
|
408
|
+
*/
|
409
|
+
readS1(): number;
|
410
|
+
/**
|
411
|
+
* Read 2-byte signed integer, little-endian
|
412
|
+
*/
|
413
|
+
readS2le(): number;
|
414
|
+
/**
|
415
|
+
* Read 2-byte signed integer, big-endian
|
416
|
+
*/
|
417
|
+
readS2be(): number;
|
418
|
+
/**
|
419
|
+
* Read 4-byte signed integer, little-endian
|
420
|
+
*/
|
421
|
+
readS4le(): number;
|
422
|
+
/**
|
423
|
+
* Read 4-byte signed integer, big-endian
|
424
|
+
*/
|
425
|
+
readS4be(): number;
|
426
|
+
/**
|
427
|
+
* Read 8-byte signed integer, little-endian
|
428
|
+
* Returns BigInt for values outside Number.MAX_SAFE_INTEGER range
|
429
|
+
*/
|
430
|
+
readS8le(): bigint;
|
431
|
+
/**
|
432
|
+
* Read 8-byte signed integer, big-endian
|
433
|
+
* Returns BigInt for values outside Number.MAX_SAFE_INTEGER range
|
434
|
+
*/
|
435
|
+
readS8be(): bigint;
|
436
|
+
/**
|
437
|
+
* Read 4-byte IEEE 754 single-precision float, little-endian
|
438
|
+
*/
|
439
|
+
readF4le(): number;
|
440
|
+
/**
|
441
|
+
* Read 4-byte IEEE 754 single-precision float, big-endian
|
442
|
+
*/
|
443
|
+
readF4be(): number;
|
444
|
+
/**
|
445
|
+
* Read 8-byte IEEE 754 double-precision float, little-endian
|
446
|
+
*/
|
447
|
+
readF8le(): number;
|
448
|
+
/**
|
449
|
+
* Read 8-byte IEEE 754 double-precision float, big-endian
|
450
|
+
*/
|
451
|
+
readF8be(): number;
|
452
|
+
/**
|
453
|
+
* Read a fixed number of bytes
|
454
|
+
* @param length - Number of bytes to read
|
455
|
+
*/
|
456
|
+
readBytes(length: number): Uint8Array;
|
457
|
+
/**
|
458
|
+
* Read all remaining bytes until end of stream
|
459
|
+
*/
|
460
|
+
readBytesFull(): Uint8Array;
|
461
|
+
/**
|
462
|
+
* Read bytes until a terminator byte is found
|
463
|
+
* @param term - Terminator byte value
|
464
|
+
* @param include - Include terminator in result
|
465
|
+
* @param consume - Consume terminator from stream
|
466
|
+
* @param eosError - Throw error if EOS reached before terminator
|
467
|
+
*/
|
468
|
+
readBytesterm(term: number, include?: boolean, consume?: boolean, eosError?: boolean): Uint8Array;
|
469
|
+
/**
|
470
|
+
* Read a fixed-length string
|
471
|
+
* @param length - Number of bytes to read
|
472
|
+
* @param encoding - Character encoding (default: UTF-8)
|
473
|
+
*/
|
474
|
+
readStr(length: number, encoding?: string): string;
|
475
|
+
/**
|
476
|
+
* Read a null-terminated string
|
477
|
+
* @param encoding - Character encoding (default: UTF-8)
|
478
|
+
* @param term - Terminator byte (default: 0)
|
479
|
+
* @param include - Include terminator in result
|
480
|
+
* @param consume - Consume terminator from stream
|
481
|
+
* @param eosError - Throw error if EOS reached before terminator
|
482
|
+
*/
|
483
|
+
readStrz(encoding?: string, term?: number, include?: boolean, consume?: boolean, eosError?: boolean): string;
|
484
|
+
/**
|
485
|
+
* Align bit reading to byte boundary
|
486
|
+
*/
|
487
|
+
alignToByte(): void;
|
488
|
+
/**
|
489
|
+
* Read specified number of bits as unsigned integer (big-endian)
|
490
|
+
* @param n - Number of bits to read (1-64)
|
491
|
+
*/
|
492
|
+
readBitsIntBe(n: number): bigint;
|
493
|
+
/**
|
494
|
+
* Read specified number of bits as unsigned integer (little-endian)
|
495
|
+
* @param n - Number of bits to read (1-64)
|
496
|
+
*/
|
497
|
+
readBitsIntLe(n: number): bigint;
|
498
|
+
/**
|
499
|
+
* Get the underlying buffer
|
500
|
+
*/
|
501
|
+
getBuffer(): Uint8Array;
|
502
|
+
/**
|
503
|
+
* Create a substream from current position with specified size
|
504
|
+
* @param size - Size of the substream in bytes
|
505
|
+
*/
|
506
|
+
substream(size: number): KaitaiStream;
|
507
|
+
}
|
508
|
+
|
508
509
|
/**
|
509
510
|
* @fileoverview Parser for Kaitai Struct YAML (.ksy) files
|
510
511
|
* @module parser/KsyParser
|
@@ -534,6 +535,22 @@ declare class KsyParser {
|
|
534
535
|
* @throws {ValidationError} If schema validation fails
|
535
536
|
*/
|
536
537
|
parse(yaml: string, options?: ParseOptions$1): KsySchema;
|
538
|
+
/**
|
539
|
+
* Process parametric type syntax in schema.
|
540
|
+
* Converts "type_name(arg1, arg2)" to structured format.
|
541
|
+
*
|
542
|
+
* @param schema - Schema to process
|
543
|
+
* @private
|
544
|
+
*/
|
545
|
+
private processParametricTypes;
|
546
|
+
/**
|
547
|
+
* Parse parametric type syntax from a type string.
|
548
|
+
* Converts "type_name(arg1, arg2)" to type + type-args.
|
549
|
+
*
|
550
|
+
* @param attr - Attribute to process
|
551
|
+
* @private
|
552
|
+
*/
|
553
|
+
private parseParametricType;
|
537
554
|
/**
|
538
555
|
* Validate a schema object.
|
539
556
|
*
|
@@ -742,6 +759,8 @@ declare class Context {
|
|
742
759
|
declare class TypeInterpreter {
|
743
760
|
private schema;
|
744
761
|
private parentMeta?;
|
762
|
+
private expressionCache;
|
763
|
+
private readonly MAX_CACHE_SIZE;
|
745
764
|
/**
|
746
765
|
* Create a new type interpreter.
|
747
766
|
*
|
@@ -973,7 +992,7 @@ declare class NotImplementedError extends KaitaiError {
|
|
973
992
|
* @module kaitai-struct-ts
|
974
993
|
* @author Fabiano Pinto
|
975
994
|
* @license MIT
|
976
|
-
* @version 0.
|
995
|
+
* @version 0.6.0
|
977
996
|
*
|
978
997
|
* @description
|
979
998
|
* A runtime interpreter for Kaitai Struct binary format definitions in TypeScript.
|
@@ -1029,6 +1048,19 @@ interface ParseOptions {
|
|
1029
1048
|
validate?: boolean;
|
1030
1049
|
/** Whether to treat warnings as errors (default: false) */
|
1031
1050
|
strict?: boolean;
|
1051
|
+
/**
|
1052
|
+
* Imported schemas for type imports.
|
1053
|
+
* Map of schema IDs to their parsed schemas.
|
1054
|
+
* @example
|
1055
|
+
* ```typescript
|
1056
|
+
* const imports = {
|
1057
|
+
* 'common_types': parsedCommonSchema,
|
1058
|
+
* 'header': parsedHeaderSchema
|
1059
|
+
* }
|
1060
|
+
* parse(ksyYaml, buffer, { imports })
|
1061
|
+
* ```
|
1062
|
+
*/
|
1063
|
+
imports?: Record<string, KsySchema>;
|
1032
1064
|
}
|
1033
1065
|
|
1034
1066
|
export { type AttributeSpec, BUILTIN_TYPES, Context, EOFError, type EndianExpression, type Endianness, type EnumSpec, type InstanceSpec, KaitaiError, KaitaiStream, KsyParser, type KsySchema, type MetaSpec, NotImplementedError, type ParamSpec, ParseError, type ParseOptions, type ProcessObject, type ProcessSpec, type RepeatSpec, type ValidationError$1 as SchemaValidationError, type SwitchType, TypeInterpreter, ValidationError, type ValidationResult, type ValidationWarning, getBaseType, getTypeEndianness, isBuiltinType, isFloatType, isIntegerType, isStringType, parse };
|
package/dist/index.js
CHANGED
@@ -193,6 +193,7 @@ var KaitaiStream = class _KaitaiStream {
|
|
193
193
|
if (buffer instanceof ArrayBuffer) {
|
194
194
|
this.buffer = new Uint8Array(buffer);
|
195
195
|
this.view = new DataView(buffer);
|
196
|
+
this._size = buffer.byteLength;
|
196
197
|
} else {
|
197
198
|
this.buffer = buffer;
|
198
199
|
this.view = new DataView(
|
@@ -200,6 +201,7 @@ var KaitaiStream = class _KaitaiStream {
|
|
200
201
|
buffer.byteOffset,
|
201
202
|
buffer.byteLength
|
202
203
|
);
|
204
|
+
this._size = buffer.byteLength;
|
203
205
|
}
|
204
206
|
}
|
205
207
|
/**
|
@@ -216,13 +218,13 @@ var KaitaiStream = class _KaitaiStream {
|
|
216
218
|
* Total size of the stream in bytes
|
217
219
|
*/
|
218
220
|
get size() {
|
219
|
-
return this.
|
221
|
+
return this._size;
|
220
222
|
}
|
221
223
|
/**
|
222
224
|
* Check if we've reached the end of the stream
|
223
225
|
*/
|
224
226
|
isEof() {
|
225
|
-
return this._pos >= this.
|
227
|
+
return this._pos >= this._size;
|
226
228
|
}
|
227
229
|
/**
|
228
230
|
* Seek to a specific position in the stream
|
@@ -642,6 +644,7 @@ var KsyParser = class {
|
|
642
644
|
throw new ParseError("KSY file must contain an object");
|
643
645
|
}
|
644
646
|
const schema = parsed;
|
647
|
+
this.processParametricTypes(schema);
|
645
648
|
if (validate) {
|
646
649
|
const result = this.validate(schema, { strict });
|
647
650
|
if (!result.valid) {
|
@@ -659,6 +662,65 @@ var KsyParser = class {
|
|
659
662
|
}
|
660
663
|
return schema;
|
661
664
|
}
|
665
|
+
/**
|
666
|
+
* Process parametric type syntax in schema.
|
667
|
+
* Converts "type_name(arg1, arg2)" to structured format.
|
668
|
+
*
|
669
|
+
* @param schema - Schema to process
|
670
|
+
* @private
|
671
|
+
*/
|
672
|
+
processParametricTypes(schema) {
|
673
|
+
if (schema.seq) {
|
674
|
+
for (const attr of schema.seq) {
|
675
|
+
if (typeof attr.type === "string") {
|
676
|
+
this.parseParametricType(attr);
|
677
|
+
}
|
678
|
+
}
|
679
|
+
}
|
680
|
+
if (schema.instances) {
|
681
|
+
for (const instance of Object.values(schema.instances)) {
|
682
|
+
if (typeof instance.type === "string") {
|
683
|
+
this.parseParametricType(instance);
|
684
|
+
}
|
685
|
+
}
|
686
|
+
}
|
687
|
+
if (schema.types) {
|
688
|
+
for (const type of Object.values(schema.types)) {
|
689
|
+
this.processParametricTypes(type);
|
690
|
+
}
|
691
|
+
}
|
692
|
+
}
|
693
|
+
/**
|
694
|
+
* Parse parametric type syntax from a type string.
|
695
|
+
* Converts "type_name(arg1, arg2)" to type + type-args.
|
696
|
+
*
|
697
|
+
* @param attr - Attribute to process
|
698
|
+
* @private
|
699
|
+
*/
|
700
|
+
parseParametricType(attr) {
|
701
|
+
if (typeof attr.type !== "string") return;
|
702
|
+
const match = attr.type.match(/^([a-z_][a-z0-9_]*)\((.*)\)$/i);
|
703
|
+
if (!match) return;
|
704
|
+
const [, typeName, argsStr] = match;
|
705
|
+
const args = [];
|
706
|
+
if (argsStr.trim()) {
|
707
|
+
const argParts = argsStr.split(",").map((s) => s.trim());
|
708
|
+
for (const arg of argParts) {
|
709
|
+
const num = Number(arg);
|
710
|
+
if (!isNaN(num)) {
|
711
|
+
args.push(num);
|
712
|
+
} else if (arg === "true") {
|
713
|
+
args.push(true);
|
714
|
+
} else if (arg === "false") {
|
715
|
+
args.push(false);
|
716
|
+
} else {
|
717
|
+
args.push(arg);
|
718
|
+
}
|
719
|
+
}
|
720
|
+
}
|
721
|
+
attr.type = typeName;
|
722
|
+
attr["type-args"] = args;
|
723
|
+
}
|
662
724
|
/**
|
663
725
|
* Validate a schema object.
|
664
726
|
*
|
@@ -1954,6 +2016,10 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
1954
2016
|
constructor(schema, parentMeta) {
|
1955
2017
|
this.schema = schema;
|
1956
2018
|
this.parentMeta = parentMeta;
|
2019
|
+
// Performance optimization: cache for constant expressions
|
2020
|
+
// Limited size to prevent memory leaks
|
2021
|
+
this.expressionCache = /* @__PURE__ */ new Map();
|
2022
|
+
this.MAX_CACHE_SIZE = 1e3;
|
1957
2023
|
if (!schema.meta && !parentMeta) {
|
1958
2024
|
throw new ParseError("Schema must have meta section");
|
1959
2025
|
}
|
@@ -2058,7 +2124,10 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2058
2124
|
);
|
2059
2125
|
}
|
2060
2126
|
}
|
2061
|
-
const value = this.parseAttribute(
|
2127
|
+
const value = this.parseAttribute(
|
2128
|
+
instance,
|
2129
|
+
context
|
2130
|
+
);
|
2062
2131
|
return value;
|
2063
2132
|
} finally {
|
2064
2133
|
if (instance.pos !== void 0) {
|
@@ -2095,6 +2164,11 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2095
2164
|
if (attr.io) {
|
2096
2165
|
throw new NotImplementedError("Custom I/O streams");
|
2097
2166
|
}
|
2167
|
+
if (!attr.type && !attr.size && !attr["size-eos"] && !attr.contents) {
|
2168
|
+
throw new ParseError(
|
2169
|
+
`Attribute "${attr.id || "unknown"}" must have type, size, size-eos, or contents`
|
2170
|
+
);
|
2171
|
+
}
|
2098
2172
|
if (attr.repeat) {
|
2099
2173
|
return this.parseRepeated(attr, context);
|
2100
2174
|
}
|
@@ -2144,7 +2218,13 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2144
2218
|
throw new ParseError("repeat-until expression is required");
|
2145
2219
|
}
|
2146
2220
|
let index = 0;
|
2221
|
+
const maxIterations = 1e6;
|
2147
2222
|
while (true) {
|
2223
|
+
if (index >= maxIterations) {
|
2224
|
+
throw new ParseError(
|
2225
|
+
`repeat-until exceeded maximum iterations (${maxIterations}). Possible infinite loop.`
|
2226
|
+
);
|
2227
|
+
}
|
2148
2228
|
context.set("_index", index);
|
2149
2229
|
const value = this.parseAttribute(
|
2150
2230
|
{ ...attr, repeat: void 0, "repeat-until": void 0 },
|
@@ -2219,6 +2299,11 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2219
2299
|
if (size < 0) {
|
2220
2300
|
throw new ParseError(`size must be non-negative, got ${size}`);
|
2221
2301
|
}
|
2302
|
+
if (stream.pos + size > stream.size) {
|
2303
|
+
throw new ParseError(
|
2304
|
+
`Not enough data: need ${size} bytes at position ${stream.pos}, but only ${stream.size - stream.pos} bytes available`
|
2305
|
+
);
|
2306
|
+
}
|
2222
2307
|
if (type === "str" || !type) {
|
2223
2308
|
const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
|
2224
2309
|
let data;
|
@@ -2340,6 +2425,13 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2340
2425
|
const meta = this.schema.meta || this.parentMeta;
|
2341
2426
|
const metaEndian = meta?.endian;
|
2342
2427
|
const endian = typeEndian || (typeof metaEndian === "string" ? metaEndian : "le");
|
2428
|
+
if (type.startsWith("b") && type.length > 1) {
|
2429
|
+
const bits = parseInt(type.substring(1), 10);
|
2430
|
+
if (!isNaN(bits) && bits >= 1 && bits <= 64) {
|
2431
|
+
const value = endian === "be" ? stream.readBitsIntBe(bits) : stream.readBitsIntLe(bits);
|
2432
|
+
return bits <= 32 ? Number(value) : value;
|
2433
|
+
}
|
2434
|
+
}
|
2343
2435
|
if (isIntegerType(type)) {
|
2344
2436
|
return this.readInteger(base, endian, stream);
|
2345
2437
|
}
|
@@ -2435,8 +2527,21 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2435
2527
|
return value;
|
2436
2528
|
}
|
2437
2529
|
if (typeof value === "string") {
|
2530
|
+
if (!value.includes("_") && !value.includes(".")) {
|
2531
|
+
const cached = this.expressionCache.get(value);
|
2532
|
+
if (cached !== void 0) {
|
2533
|
+
return cached;
|
2534
|
+
}
|
2535
|
+
}
|
2438
2536
|
try {
|
2439
|
-
|
2537
|
+
const result = evaluateExpression(value, context);
|
2538
|
+
if (!value.includes("_") && !value.includes(".")) {
|
2539
|
+
if (this.expressionCache.size >= this.MAX_CACHE_SIZE) {
|
2540
|
+
this.expressionCache.clear();
|
2541
|
+
}
|
2542
|
+
this.expressionCache.set(value, result);
|
2543
|
+
}
|
2544
|
+
return result;
|
2440
2545
|
} catch (error) {
|
2441
2546
|
throw new ParseError(
|
2442
2547
|
`Failed to evaluate expression "${value}": ${error instanceof Error ? error.message : String(error)}`
|
@@ -2577,7 +2682,7 @@ function parse(ksyYaml, buffer, options = {}) {
|
|
2577
2682
|
* @module kaitai-struct-ts
|
2578
2683
|
* @author Fabiano Pinto
|
2579
2684
|
* @license MIT
|
2580
|
-
* @version 0.
|
2685
|
+
* @version 0.6.0
|
2581
2686
|
*
|
2582
2687
|
* @description
|
2583
2688
|
* A runtime interpreter for Kaitai Struct binary format definitions in TypeScript.
|