@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.mjs
CHANGED
@@ -151,6 +151,7 @@ var KaitaiStream = class _KaitaiStream {
|
|
151
151
|
if (buffer instanceof ArrayBuffer) {
|
152
152
|
this.buffer = new Uint8Array(buffer);
|
153
153
|
this.view = new DataView(buffer);
|
154
|
+
this._size = buffer.byteLength;
|
154
155
|
} else {
|
155
156
|
this.buffer = buffer;
|
156
157
|
this.view = new DataView(
|
@@ -158,6 +159,7 @@ var KaitaiStream = class _KaitaiStream {
|
|
158
159
|
buffer.byteOffset,
|
159
160
|
buffer.byteLength
|
160
161
|
);
|
162
|
+
this._size = buffer.byteLength;
|
161
163
|
}
|
162
164
|
}
|
163
165
|
/**
|
@@ -174,13 +176,13 @@ var KaitaiStream = class _KaitaiStream {
|
|
174
176
|
* Total size of the stream in bytes
|
175
177
|
*/
|
176
178
|
get size() {
|
177
|
-
return this.
|
179
|
+
return this._size;
|
178
180
|
}
|
179
181
|
/**
|
180
182
|
* Check if we've reached the end of the stream
|
181
183
|
*/
|
182
184
|
isEof() {
|
183
|
-
return this._pos >= this.
|
185
|
+
return this._pos >= this._size;
|
184
186
|
}
|
185
187
|
/**
|
186
188
|
* Seek to a specific position in the stream
|
@@ -600,6 +602,7 @@ var KsyParser = class {
|
|
600
602
|
throw new ParseError("KSY file must contain an object");
|
601
603
|
}
|
602
604
|
const schema = parsed;
|
605
|
+
this.processParametricTypes(schema);
|
603
606
|
if (validate) {
|
604
607
|
const result = this.validate(schema, { strict });
|
605
608
|
if (!result.valid) {
|
@@ -617,6 +620,65 @@ var KsyParser = class {
|
|
617
620
|
}
|
618
621
|
return schema;
|
619
622
|
}
|
623
|
+
/**
|
624
|
+
* Process parametric type syntax in schema.
|
625
|
+
* Converts "type_name(arg1, arg2)" to structured format.
|
626
|
+
*
|
627
|
+
* @param schema - Schema to process
|
628
|
+
* @private
|
629
|
+
*/
|
630
|
+
processParametricTypes(schema) {
|
631
|
+
if (schema.seq) {
|
632
|
+
for (const attr of schema.seq) {
|
633
|
+
if (typeof attr.type === "string") {
|
634
|
+
this.parseParametricType(attr);
|
635
|
+
}
|
636
|
+
}
|
637
|
+
}
|
638
|
+
if (schema.instances) {
|
639
|
+
for (const instance of Object.values(schema.instances)) {
|
640
|
+
if (typeof instance.type === "string") {
|
641
|
+
this.parseParametricType(instance);
|
642
|
+
}
|
643
|
+
}
|
644
|
+
}
|
645
|
+
if (schema.types) {
|
646
|
+
for (const type of Object.values(schema.types)) {
|
647
|
+
this.processParametricTypes(type);
|
648
|
+
}
|
649
|
+
}
|
650
|
+
}
|
651
|
+
/**
|
652
|
+
* Parse parametric type syntax from a type string.
|
653
|
+
* Converts "type_name(arg1, arg2)" to type + type-args.
|
654
|
+
*
|
655
|
+
* @param attr - Attribute to process
|
656
|
+
* @private
|
657
|
+
*/
|
658
|
+
parseParametricType(attr) {
|
659
|
+
if (typeof attr.type !== "string") return;
|
660
|
+
const match = attr.type.match(/^([a-z_][a-z0-9_]*)\((.*)\)$/i);
|
661
|
+
if (!match) return;
|
662
|
+
const [, typeName, argsStr] = match;
|
663
|
+
const args = [];
|
664
|
+
if (argsStr.trim()) {
|
665
|
+
const argParts = argsStr.split(",").map((s) => s.trim());
|
666
|
+
for (const arg of argParts) {
|
667
|
+
const num = Number(arg);
|
668
|
+
if (!isNaN(num)) {
|
669
|
+
args.push(num);
|
670
|
+
} else if (arg === "true") {
|
671
|
+
args.push(true);
|
672
|
+
} else if (arg === "false") {
|
673
|
+
args.push(false);
|
674
|
+
} else {
|
675
|
+
args.push(arg);
|
676
|
+
}
|
677
|
+
}
|
678
|
+
}
|
679
|
+
attr.type = typeName;
|
680
|
+
attr["type-args"] = args;
|
681
|
+
}
|
620
682
|
/**
|
621
683
|
* Validate a schema object.
|
622
684
|
*
|
@@ -1912,6 +1974,10 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
1912
1974
|
constructor(schema, parentMeta) {
|
1913
1975
|
this.schema = schema;
|
1914
1976
|
this.parentMeta = parentMeta;
|
1977
|
+
// Performance optimization: cache for constant expressions
|
1978
|
+
// Limited size to prevent memory leaks
|
1979
|
+
this.expressionCache = /* @__PURE__ */ new Map();
|
1980
|
+
this.MAX_CACHE_SIZE = 1e3;
|
1915
1981
|
if (!schema.meta && !parentMeta) {
|
1916
1982
|
throw new ParseError("Schema must have meta section");
|
1917
1983
|
}
|
@@ -2016,7 +2082,10 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2016
2082
|
);
|
2017
2083
|
}
|
2018
2084
|
}
|
2019
|
-
const value = this.parseAttribute(
|
2085
|
+
const value = this.parseAttribute(
|
2086
|
+
instance,
|
2087
|
+
context
|
2088
|
+
);
|
2020
2089
|
return value;
|
2021
2090
|
} finally {
|
2022
2091
|
if (instance.pos !== void 0) {
|
@@ -2053,6 +2122,11 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2053
2122
|
if (attr.io) {
|
2054
2123
|
throw new NotImplementedError("Custom I/O streams");
|
2055
2124
|
}
|
2125
|
+
if (!attr.type && !attr.size && !attr["size-eos"] && !attr.contents) {
|
2126
|
+
throw new ParseError(
|
2127
|
+
`Attribute "${attr.id || "unknown"}" must have type, size, size-eos, or contents`
|
2128
|
+
);
|
2129
|
+
}
|
2056
2130
|
if (attr.repeat) {
|
2057
2131
|
return this.parseRepeated(attr, context);
|
2058
2132
|
}
|
@@ -2102,7 +2176,13 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2102
2176
|
throw new ParseError("repeat-until expression is required");
|
2103
2177
|
}
|
2104
2178
|
let index = 0;
|
2179
|
+
const maxIterations = 1e6;
|
2105
2180
|
while (true) {
|
2181
|
+
if (index >= maxIterations) {
|
2182
|
+
throw new ParseError(
|
2183
|
+
`repeat-until exceeded maximum iterations (${maxIterations}). Possible infinite loop.`
|
2184
|
+
);
|
2185
|
+
}
|
2106
2186
|
context.set("_index", index);
|
2107
2187
|
const value = this.parseAttribute(
|
2108
2188
|
{ ...attr, repeat: void 0, "repeat-until": void 0 },
|
@@ -2177,6 +2257,11 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2177
2257
|
if (size < 0) {
|
2178
2258
|
throw new ParseError(`size must be non-negative, got ${size}`);
|
2179
2259
|
}
|
2260
|
+
if (stream.pos + size > stream.size) {
|
2261
|
+
throw new ParseError(
|
2262
|
+
`Not enough data: need ${size} bytes at position ${stream.pos}, but only ${stream.size - stream.pos} bytes available`
|
2263
|
+
);
|
2264
|
+
}
|
2180
2265
|
if (type === "str" || !type) {
|
2181
2266
|
const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
|
2182
2267
|
let data;
|
@@ -2298,6 +2383,13 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2298
2383
|
const meta = this.schema.meta || this.parentMeta;
|
2299
2384
|
const metaEndian = meta?.endian;
|
2300
2385
|
const endian = typeEndian || (typeof metaEndian === "string" ? metaEndian : "le");
|
2386
|
+
if (type.startsWith("b") && type.length > 1) {
|
2387
|
+
const bits = parseInt(type.substring(1), 10);
|
2388
|
+
if (!isNaN(bits) && bits >= 1 && bits <= 64) {
|
2389
|
+
const value = endian === "be" ? stream.readBitsIntBe(bits) : stream.readBitsIntLe(bits);
|
2390
|
+
return bits <= 32 ? Number(value) : value;
|
2391
|
+
}
|
2392
|
+
}
|
2301
2393
|
if (isIntegerType(type)) {
|
2302
2394
|
return this.readInteger(base, endian, stream);
|
2303
2395
|
}
|
@@ -2393,8 +2485,21 @@ var TypeInterpreter = class _TypeInterpreter {
|
|
2393
2485
|
return value;
|
2394
2486
|
}
|
2395
2487
|
if (typeof value === "string") {
|
2488
|
+
if (!value.includes("_") && !value.includes(".")) {
|
2489
|
+
const cached = this.expressionCache.get(value);
|
2490
|
+
if (cached !== void 0) {
|
2491
|
+
return cached;
|
2492
|
+
}
|
2493
|
+
}
|
2396
2494
|
try {
|
2397
|
-
|
2495
|
+
const result = evaluateExpression(value, context);
|
2496
|
+
if (!value.includes("_") && !value.includes(".")) {
|
2497
|
+
if (this.expressionCache.size >= this.MAX_CACHE_SIZE) {
|
2498
|
+
this.expressionCache.clear();
|
2499
|
+
}
|
2500
|
+
this.expressionCache.set(value, result);
|
2501
|
+
}
|
2502
|
+
return result;
|
2398
2503
|
} catch (error) {
|
2399
2504
|
throw new ParseError(
|
2400
2505
|
`Failed to evaluate expression "${value}": ${error instanceof Error ? error.message : String(error)}`
|
@@ -2534,7 +2639,7 @@ export {
|
|
2534
2639
|
* @module kaitai-struct-ts
|
2535
2640
|
* @author Fabiano Pinto
|
2536
2641
|
* @license MIT
|
2537
|
-
* @version 0.
|
2642
|
+
* @version 0.6.0
|
2538
2643
|
*
|
2539
2644
|
* @description
|
2540
2645
|
* A runtime interpreter for Kaitai Struct binary format definitions in TypeScript.
|