@k67/kaitai-struct-ts 0.3.0 → 0.5.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/dist/index.mjs CHANGED
@@ -1815,9 +1815,7 @@ var Evaluator = class {
1815
1815
  evaluateEnumAccess(enumName, valueName, context) {
1816
1816
  const value = context.getEnumValue(enumName, valueName);
1817
1817
  if (value === void 0) {
1818
- throw new ParseError(
1819
- `Enum value "${enumName}::${valueName}" not found`
1820
- );
1818
+ throw new ParseError(`Enum value "${enumName}::${valueName}" not found`);
1821
1819
  }
1822
1820
  return value;
1823
1821
  }
@@ -1926,12 +1924,21 @@ var TypeInterpreter = class _TypeInterpreter {
1926
1924
  *
1927
1925
  * @param stream - Binary stream to parse
1928
1926
  * @param parent - Parent object (for nested types)
1927
+ * @param typeArgs - Arguments for parametric types
1929
1928
  * @returns Parsed object
1930
1929
  */
1931
- parse(stream, parent) {
1930
+ parse(stream, parent, typeArgs) {
1932
1931
  const result = {};
1933
1932
  const context = new Context(stream, result, parent, this.schema.enums);
1934
1933
  context.current = result;
1934
+ if (typeArgs && this.schema.params) {
1935
+ for (let i = 0; i < this.schema.params.length && i < typeArgs.length; i++) {
1936
+ const param = this.schema.params[i];
1937
+ const argValue = typeArgs[i];
1938
+ const evaluatedArg = typeof argValue === "string" ? this.evaluateValue(argValue, context) : argValue;
1939
+ context.set(param.id, evaluatedArg);
1940
+ }
1941
+ }
1935
1942
  if (this.schema.seq) {
1936
1943
  for (const attr of this.schema.seq) {
1937
1944
  const value = this.parseAttribute(attr, context);
@@ -1940,8 +1947,83 @@ var TypeInterpreter = class _TypeInterpreter {
1940
1947
  }
1941
1948
  }
1942
1949
  }
1950
+ if (this.schema.instances) {
1951
+ this.setupInstances(result, stream, context);
1952
+ }
1943
1953
  return result;
1944
1954
  }
1955
+ /**
1956
+ * Set up lazy-evaluated instance getters.
1957
+ * Instances are computed on first access and cached.
1958
+ *
1959
+ * @param result - Result object to add getters to
1960
+ * @param stream - Stream for parsing
1961
+ * @param context - Execution context
1962
+ * @private
1963
+ */
1964
+ setupInstances(result, stream, context) {
1965
+ if (!this.schema.instances) return;
1966
+ for (const [name, instance] of Object.entries(this.schema.instances)) {
1967
+ let cached = void 0;
1968
+ let evaluated = false;
1969
+ Object.defineProperty(result, name, {
1970
+ get: () => {
1971
+ if (!evaluated) {
1972
+ cached = this.parseInstance(
1973
+ instance,
1974
+ stream,
1975
+ context
1976
+ );
1977
+ evaluated = true;
1978
+ }
1979
+ return cached;
1980
+ },
1981
+ enumerable: true,
1982
+ configurable: true
1983
+ });
1984
+ }
1985
+ }
1986
+ /**
1987
+ * Parse an instance (lazy-evaluated field).
1988
+ *
1989
+ * @param instance - Instance specification
1990
+ * @param stream - Stream to read from
1991
+ * @param context - Execution context
1992
+ * @returns Parsed or calculated value
1993
+ * @private
1994
+ */
1995
+ parseInstance(instance, stream, context) {
1996
+ if ("value" in instance) {
1997
+ return this.evaluateValue(
1998
+ instance.value,
1999
+ context
2000
+ );
2001
+ }
2002
+ const savedPos = stream.pos;
2003
+ try {
2004
+ if (instance.pos !== void 0) {
2005
+ const pos = this.evaluateValue(
2006
+ instance.pos,
2007
+ context
2008
+ );
2009
+ if (typeof pos === "number") {
2010
+ stream.seek(pos);
2011
+ } else if (typeof pos === "bigint") {
2012
+ stream.seek(Number(pos));
2013
+ } else {
2014
+ throw new ParseError(
2015
+ `pos must evaluate to a number, got ${typeof pos}`
2016
+ );
2017
+ }
2018
+ }
2019
+ const value = this.parseAttribute(instance, context);
2020
+ return value;
2021
+ } finally {
2022
+ if (instance.pos !== void 0) {
2023
+ stream.seek(savedPos);
2024
+ }
2025
+ }
2026
+ }
1945
2027
  /**
1946
2028
  * Parse a single attribute according to its specification.
1947
2029
  *
@@ -2097,14 +2179,27 @@ var TypeInterpreter = class _TypeInterpreter {
2097
2179
  }
2098
2180
  if (type === "str" || !type) {
2099
2181
  const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
2182
+ let data;
2100
2183
  if (type === "str") {
2101
- return stream.readStr(size, encoding);
2184
+ data = stream.readBytes(size);
2185
+ if (attr.process) {
2186
+ data = this.applyProcessing(data, attr.process);
2187
+ }
2188
+ return new TextDecoder(encoding).decode(data);
2102
2189
  } else {
2103
- return stream.readBytes(size);
2190
+ data = stream.readBytes(size);
2191
+ if (attr.process) {
2192
+ data = this.applyProcessing(data, attr.process);
2193
+ }
2194
+ return data;
2104
2195
  }
2105
2196
  } else {
2106
- const substream = stream.substream(size);
2107
- return this.parseType(type, substream, context);
2197
+ let data = stream.readBytes(size);
2198
+ if (attr.process) {
2199
+ data = this.applyProcessing(data, attr.process);
2200
+ }
2201
+ const substream = new KaitaiStream(data);
2202
+ return this.parseType(type, substream, context, attr["type-args"]);
2108
2203
  }
2109
2204
  }
2110
2205
  if (attr["size-eos"]) {
@@ -2119,7 +2214,7 @@ var TypeInterpreter = class _TypeInterpreter {
2119
2214
  if (!type) {
2120
2215
  throw new ParseError("Attribute must have either type, size, or contents");
2121
2216
  }
2122
- return this.parseType(type, stream, context);
2217
+ return this.parseType(type, stream, context, attr["type-args"]);
2123
2218
  }
2124
2219
  /**
2125
2220
  * Parse a value of a specific type.
@@ -2127,12 +2222,17 @@ var TypeInterpreter = class _TypeInterpreter {
2127
2222
  * @param type - Type name or switch specification
2128
2223
  * @param stream - Stream to read from
2129
2224
  * @param context - Execution context
2225
+ * @param typeArgs - Arguments for parametric types
2130
2226
  * @returns Parsed value
2131
2227
  * @private
2132
2228
  */
2133
- parseType(type, stream, context) {
2229
+ parseType(type, stream, context, typeArgs) {
2134
2230
  if (typeof type === "object") {
2135
- throw new NotImplementedError("Switch types");
2231
+ return this.parseSwitchType(
2232
+ type,
2233
+ stream,
2234
+ context
2235
+ );
2136
2236
  }
2137
2237
  if (isBuiltinType(type)) {
2138
2238
  return this.parseBuiltinType(type, stream, context);
@@ -2143,11 +2243,46 @@ var TypeInterpreter = class _TypeInterpreter {
2143
2243
  if (this.schema.enums && !typeSchema.enums) {
2144
2244
  typeSchema.enums = this.schema.enums;
2145
2245
  }
2246
+ if (this.schema.types && !typeSchema.types) {
2247
+ typeSchema.types = this.schema.types;
2248
+ }
2146
2249
  const interpreter = new _TypeInterpreter(typeSchema, meta);
2147
- return interpreter.parse(stream, context.current);
2250
+ return interpreter.parse(stream, context.current, typeArgs);
2148
2251
  }
2149
2252
  throw new ParseError(`Unknown type: ${type}`);
2150
2253
  }
2254
+ /**
2255
+ * Parse a switch type (type selection based on expression).
2256
+ *
2257
+ * @param switchType - Switch type specification
2258
+ * @param stream - Stream to read from
2259
+ * @param context - Execution context
2260
+ * @returns Parsed value
2261
+ * @private
2262
+ */
2263
+ parseSwitchType(switchType, stream, context) {
2264
+ const switchOn = switchType["switch-on"];
2265
+ const cases = switchType["cases"];
2266
+ const defaultType = switchType["default"];
2267
+ if (!switchOn || typeof switchOn !== "string") {
2268
+ throw new ParseError("switch-on expression is required for switch types");
2269
+ }
2270
+ if (!cases) {
2271
+ throw new ParseError("cases are required for switch types");
2272
+ }
2273
+ const switchValue = this.evaluateValue(switchOn, context);
2274
+ const switchKey = String(switchValue);
2275
+ let selectedType = cases[switchKey];
2276
+ if (selectedType === void 0 && defaultType) {
2277
+ selectedType = defaultType;
2278
+ }
2279
+ if (selectedType === void 0) {
2280
+ throw new ParseError(
2281
+ `No matching case for switch value "${switchKey}" and no default type specified`
2282
+ );
2283
+ }
2284
+ return this.parseType(selectedType, stream, context);
2285
+ }
2151
2286
  /**
2152
2287
  * Parse a built-in type.
2153
2288
  *
@@ -2225,11 +2360,27 @@ var TypeInterpreter = class _TypeInterpreter {
2225
2360
  }
2226
2361
  }
2227
2362
  /**
2228
- * Evaluate an expression or return a literal value.
2229
- * If the value is a string, it's treated as an expression.
2230
- * If it's a number or boolean, it's returned as-is.
2363
+ * Apply processing transformation to data.
2364
+ * Supports basic transformations like zlib decompression.
2365
+ *
2366
+ * @param data - Data to process
2367
+ * @param process - Processing specification
2368
+ * @returns Processed data
2369
+ * @private
2370
+ */
2371
+ applyProcessing(data, process) {
2372
+ const processType = typeof process === "string" ? process : process.algorithm;
2373
+ if (processType) {
2374
+ throw new NotImplementedError(
2375
+ `Processing type "${processType}" is not yet implemented. Supported in future versions with zlib, encryption, etc.`
2376
+ );
2377
+ }
2378
+ return data;
2379
+ }
2380
+ /**
2381
+ * Evaluate a value that can be an expression or literal.
2231
2382
  *
2232
- * @param value - Expression string or literal value
2383
+ * @param value - Value to evaluate (expression string, number, or boolean)
2233
2384
  * @param context - Execution context
2234
2385
  * @returns Evaluated result
2235
2386
  * @private