@k67/kaitai-struct-ts 0.9.0 → 0.10.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.js CHANGED
@@ -42,30 +42,68 @@ module.exports = __toCommonJS(index_exports);
42
42
 
43
43
  // src/utils/errors.ts
44
44
  var KaitaiError = class _KaitaiError extends Error {
45
- constructor(message, position) {
46
- super(message);
45
+ constructor(message, position, context) {
46
+ super(_KaitaiError.formatMessage(message, position, context));
47
47
  this.position = position;
48
+ this.context = context;
48
49
  this.name = "KaitaiError";
49
50
  Object.setPrototypeOf(this, _KaitaiError.prototype);
50
51
  }
52
+ /**
53
+ * Format error message with position and context.
54
+ * @private
55
+ */
56
+ static formatMessage(message, position, context) {
57
+ let formatted = message;
58
+ if (position !== void 0) {
59
+ formatted += ` (at byte offset 0x${position.toString(16).toUpperCase()})`;
60
+ }
61
+ if (context && context.length > 0) {
62
+ const hexContext = _KaitaiError.formatHexContext(context, position);
63
+ formatted += `
64
+ ${hexContext}`;
65
+ }
66
+ return formatted;
67
+ }
68
+ /**
69
+ * Format hex dump context around error position.
70
+ * @private
71
+ */
72
+ static formatHexContext(data, position) {
73
+ const contextSize = 16;
74
+ const start = Math.max(0, (position ?? 0) - contextSize);
75
+ const end = Math.min(data.length, (position ?? 0) + contextSize);
76
+ const chunk = data.slice(start, end);
77
+ const lines = ["Context:"];
78
+ let offset = start;
79
+ for (let i = 0; i < chunk.length; i += 16) {
80
+ const lineBytes = chunk.slice(i, i + 16);
81
+ const hex = Array.from(lineBytes).map((b) => b.toString(16).padStart(2, "0")).join(" ");
82
+ const ascii = Array.from(lineBytes).map((b) => b >= 32 && b <= 126 ? String.fromCharCode(b) : ".").join("");
83
+ const offsetStr = ` ${(offset + i).toString(16).padStart(8, "0")}`;
84
+ const marker = position !== void 0 && position >= offset + i && position < offset + i + lineBytes.length ? " <--" : "";
85
+ lines.push(`${offsetStr}: ${hex.padEnd(48, " ")} | ${ascii}${marker}`);
86
+ }
87
+ return lines.join("\n");
88
+ }
51
89
  };
52
90
  var ValidationError = class _ValidationError extends KaitaiError {
53
- constructor(message, position) {
54
- super(message, position);
91
+ constructor(message, position, context) {
92
+ super(message, position, context);
55
93
  this.name = "ValidationError";
56
94
  Object.setPrototypeOf(this, _ValidationError.prototype);
57
95
  }
58
96
  };
59
97
  var ParseError = class _ParseError extends KaitaiError {
60
- constructor(message, position) {
61
- super(message, position);
98
+ constructor(message, position, context) {
99
+ super(message, position, context);
62
100
  this.name = "ParseError";
63
101
  Object.setPrototypeOf(this, _ParseError.prototype);
64
102
  }
65
103
  };
66
104
  var EOFError = class _EOFError extends KaitaiError {
67
- constructor(message = "Unexpected end of stream", position) {
68
- super(message, position);
105
+ constructor(message = "Unexpected end of stream", position, context) {
106
+ super(message, position, context);
69
107
  this.name = "EOFError";
70
108
  Object.setPrototypeOf(this, _EOFError.prototype);
71
109
  }
@@ -1857,15 +1895,15 @@ var Evaluator = class {
1857
1895
  return !this.equals(leftVal, rightVal);
1858
1896
  // Bitwise
1859
1897
  case "<<":
1860
- return this.toInt(leftVal) << this.toInt(rightVal);
1898
+ return this.bitwiseOp(leftVal, rightVal, (a, b) => a << b);
1861
1899
  case ">>":
1862
- return this.toInt(leftVal) >> this.toInt(rightVal);
1900
+ return this.bitwiseOp(leftVal, rightVal, (a, b) => a >> b);
1863
1901
  case "&":
1864
- return this.toInt(leftVal) & this.toInt(rightVal);
1902
+ return this.bitwiseOp(leftVal, rightVal, (a, b) => a & b);
1865
1903
  case "|":
1866
- return this.toInt(leftVal) | this.toInt(rightVal);
1904
+ return this.bitwiseOp(leftVal, rightVal, (a, b) => a | b);
1867
1905
  case "^":
1868
- return this.toInt(leftVal) ^ this.toInt(rightVal);
1906
+ return this.bitwiseOp(leftVal, rightVal, (a, b) => a ^ b);
1869
1907
  // Logical
1870
1908
  case "and":
1871
1909
  return this.toBoolean(leftVal) && this.toBoolean(rightVal);
@@ -1909,6 +1947,16 @@ var Evaluator = class {
1909
1947
  `Cannot access property ${property} of null/undefined`
1910
1948
  );
1911
1949
  }
1950
+ if (property === "to_i") {
1951
+ if (typeof obj === "number") return Math.floor(obj);
1952
+ if (typeof obj === "bigint") return Number(obj);
1953
+ if (typeof obj === "string") return parseInt(obj, 10);
1954
+ if (typeof obj === "boolean") return obj ? 1 : 0;
1955
+ return this.toInt(obj);
1956
+ }
1957
+ if (property === "to_s") {
1958
+ return String(obj);
1959
+ }
1912
1960
  if (typeof obj === "object") {
1913
1961
  return obj[property];
1914
1962
  }
@@ -1935,8 +1983,9 @@ var Evaluator = class {
1935
1983
  * Evaluate method call (object.method()).
1936
1984
  * @private
1937
1985
  */
1938
- evaluateMethodCall(object, method, _args, context) {
1986
+ evaluateMethodCall(object, method, args, context) {
1939
1987
  const obj = this.evaluate(object, context);
1988
+ const evalArgs = args.map((arg) => this.evaluate(arg, context));
1940
1989
  if (method === "length" || method === "size") {
1941
1990
  if (Array.isArray(obj)) return obj.length;
1942
1991
  if (obj instanceof Uint8Array) return obj.length;
@@ -1944,13 +1993,182 @@ var Evaluator = class {
1944
1993
  throw new ParseError(`Object does not have a ${method} property`);
1945
1994
  }
1946
1995
  if (method === "to_i") {
1996
+ const base = evalArgs.length > 0 ? this.toInt(evalArgs[0]) : 10;
1997
+ if (typeof obj === "string") {
1998
+ return parseInt(obj, base);
1999
+ }
1947
2000
  return this.toInt(obj);
1948
2001
  }
1949
2002
  if (method === "to_s") {
1950
2003
  return String(obj);
1951
2004
  }
2005
+ if (typeof obj === "string") {
2006
+ return this.evaluateStringMethod(obj, method, evalArgs);
2007
+ }
2008
+ if (Array.isArray(obj) || obj instanceof Uint8Array) {
2009
+ return this.evaluateArrayMethod(obj, method, evalArgs);
2010
+ }
1952
2011
  throw new ParseError(`Unknown method: ${method}`);
1953
2012
  }
2013
+ /**
2014
+ * Evaluate string methods.
2015
+ * @private
2016
+ */
2017
+ evaluateStringMethod(str, method, args) {
2018
+ switch (method) {
2019
+ case "substring": {
2020
+ const start = args.length > 0 ? this.toInt(args[0]) : 0;
2021
+ const end = args.length > 1 ? this.toInt(args[1]) : void 0;
2022
+ return str.substring(start, end);
2023
+ }
2024
+ case "substr": {
2025
+ const start = args.length > 0 ? this.toInt(args[0]) : 0;
2026
+ const length = args.length > 1 ? this.toInt(args[1]) : void 0;
2027
+ return str.substr(start, length);
2028
+ }
2029
+ case "reverse":
2030
+ return str.split("").reverse().join("");
2031
+ case "to_i": {
2032
+ const base = args.length > 0 ? this.toInt(args[0]) : 10;
2033
+ return parseInt(str, base);
2034
+ }
2035
+ case "length":
2036
+ case "size":
2037
+ return str.length;
2038
+ // Ruby-style string methods used in Kaitai
2039
+ case "upcase":
2040
+ case "to_upper":
2041
+ return str.toUpperCase();
2042
+ case "downcase":
2043
+ case "to_lower":
2044
+ return str.toLowerCase();
2045
+ case "capitalize":
2046
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
2047
+ case "strip":
2048
+ case "trim":
2049
+ return str.trim();
2050
+ case "lstrip":
2051
+ case "trim_start":
2052
+ return str.trimStart();
2053
+ case "rstrip":
2054
+ case "trim_end":
2055
+ return str.trimEnd();
2056
+ case "starts_with":
2057
+ case "startsWith": {
2058
+ if (args.length === 0) {
2059
+ throw new ParseError("starts_with requires 1 argument");
2060
+ }
2061
+ return str.startsWith(String(args[0]));
2062
+ }
2063
+ case "ends_with":
2064
+ case "endsWith": {
2065
+ if (args.length === 0) {
2066
+ throw new ParseError("ends_with requires 1 argument");
2067
+ }
2068
+ return str.endsWith(String(args[0]));
2069
+ }
2070
+ case "includes":
2071
+ case "contains": {
2072
+ if (args.length === 0) {
2073
+ throw new ParseError("includes requires 1 argument");
2074
+ }
2075
+ return str.includes(String(args[0]));
2076
+ }
2077
+ case "index_of":
2078
+ case "indexOf": {
2079
+ if (args.length === 0) {
2080
+ throw new ParseError("index_of requires 1 argument");
2081
+ }
2082
+ return str.indexOf(String(args[0]));
2083
+ }
2084
+ case "split": {
2085
+ if (args.length === 0) {
2086
+ throw new ParseError("split requires 1 argument");
2087
+ }
2088
+ return str.split(String(args[0]));
2089
+ }
2090
+ case "replace": {
2091
+ if (args.length < 2) {
2092
+ throw new ParseError("replace requires 2 arguments");
2093
+ }
2094
+ return str.replace(String(args[0]), String(args[1]));
2095
+ }
2096
+ case "replace_all":
2097
+ case "replaceAll": {
2098
+ if (args.length < 2) {
2099
+ throw new ParseError("replace_all requires 2 arguments");
2100
+ }
2101
+ const search = String(args[0]);
2102
+ const replace = String(args[1]);
2103
+ return str.split(search).join(replace);
2104
+ }
2105
+ case "pad_left":
2106
+ case "padStart": {
2107
+ if (args.length === 0) {
2108
+ throw new ParseError("pad_left requires at least 1 argument");
2109
+ }
2110
+ const length = this.toInt(args[0]);
2111
+ const fillString = args.length > 1 ? String(args[1]) : " ";
2112
+ return str.padStart(length, fillString);
2113
+ }
2114
+ case "pad_right":
2115
+ case "padEnd": {
2116
+ if (args.length === 0) {
2117
+ throw new ParseError("pad_right requires at least 1 argument");
2118
+ }
2119
+ const length = this.toInt(args[0]);
2120
+ const fillString = args.length > 1 ? String(args[1]) : " ";
2121
+ return str.padEnd(length, fillString);
2122
+ }
2123
+ default:
2124
+ throw new ParseError(`Unknown string method: ${method}`);
2125
+ }
2126
+ }
2127
+ /**
2128
+ * Evaluate array methods.
2129
+ * @private
2130
+ */
2131
+ evaluateArrayMethod(arr, method, args) {
2132
+ const array = Array.isArray(arr) ? arr : Array.from(arr);
2133
+ switch (method) {
2134
+ case "length":
2135
+ case "size":
2136
+ return array.length;
2137
+ case "first":
2138
+ return array[0];
2139
+ case "last":
2140
+ return array[array.length - 1];
2141
+ case "min":
2142
+ return Math.min(...array.map((v) => this.toNumber(v)));
2143
+ case "max":
2144
+ return Math.max(...array.map((v) => this.toNumber(v)));
2145
+ case "reverse":
2146
+ return [...array].reverse();
2147
+ case "sort":
2148
+ return [...array].sort((a, b) => this.compare(a, b));
2149
+ case "includes":
2150
+ case "contains": {
2151
+ if (args.length === 0) {
2152
+ throw new ParseError("includes requires 1 argument");
2153
+ }
2154
+ return array.some((item) => this.equals(item, args[0]));
2155
+ }
2156
+ case "index_of":
2157
+ case "indexOf": {
2158
+ if (args.length === 0) {
2159
+ throw new ParseError("index_of requires 1 argument");
2160
+ }
2161
+ return array.findIndex((item) => this.equals(item, args[0]));
2162
+ }
2163
+ case "slice": {
2164
+ const start = args.length > 0 ? this.toInt(args[0]) : 0;
2165
+ const end = args.length > 1 ? this.toInt(args[1]) : void 0;
2166
+ return array.slice(start, end);
2167
+ }
2168
+ default:
2169
+ throw new ParseError(`Unknown array method: ${method}`);
2170
+ }
2171
+ }
1954
2172
  /**
1955
2173
  * Evaluate enum access (EnumName::value).
1956
2174
  * @private
@@ -1980,6 +2198,38 @@ var Evaluator = class {
1980
2198
  const result = a % b;
1981
2199
  return result < 0 ? result + b : result;
1982
2200
  }
2201
+ /**
2202
+ * Helper: Bitwise operation with BigInt support.
2203
+ * JavaScript bitwise operators work on 32-bit integers, but Kaitai
2204
+ * may use 64-bit values. For values that fit in 32 bits, use native ops.
2205
+ * For larger values, convert to BigInt (with limitations).
2206
+ * @private
2207
+ */
2208
+ bitwiseOp(left, right, op) {
2209
+ if (typeof left === "bigint" || typeof right === "bigint") {
2210
+ const leftBig = typeof left === "bigint" ? left : BigInt(left);
2211
+ const rightBig = typeof right === "bigint" ? right : BigInt(right);
2212
+ if (op.toString().includes("<<")) {
2213
+ return leftBig << BigInt(Number(rightBig));
2214
+ }
2215
+ if (op.toString().includes(">>")) {
2216
+ return leftBig >> BigInt(Number(rightBig));
2217
+ }
2218
+ if (op.toString().includes("&")) {
2219
+ return leftBig & rightBig;
2220
+ }
2221
+ if (op.toString().includes("|")) {
2222
+ return leftBig | rightBig;
2223
+ }
2224
+ if (op.toString().includes("^")) {
2225
+ return leftBig ^ rightBig;
2226
+ }
2227
+ }
2228
+ if (left === void 0 || left === null || right === void 0 || right === null) {
2229
+ throw new ParseError("Cannot perform bitwise operation on null/undefined");
2230
+ }
2231
+ return op(this.toInt(left), this.toInt(right));
2232
+ }
1983
2233
  /**
1984
2234
  * Helper: Compare two values.
1985
2235
  * @private
@@ -2067,6 +2317,112 @@ function evaluateExpression(expression, context) {
2067
2317
  return evaluator.evaluate(ast, context);
2068
2318
  }
2069
2319
 
2320
+ // src/utils/process.ts
2321
+ var import_pako = require("pako");
2322
+ function applyProcess(data, process) {
2323
+ const spec = typeof process === "string" ? { algorithm: process } : process;
2324
+ const algorithm = spec.algorithm;
2325
+ if (!algorithm) {
2326
+ throw new ParseError("Process specification missing algorithm");
2327
+ }
2328
+ switch (algorithm) {
2329
+ case "zlib":
2330
+ return processZlib(data);
2331
+ case "xor":
2332
+ return processXor(data, spec.key);
2333
+ case "rol":
2334
+ return processRol(data, spec.amount, spec.group);
2335
+ case "ror":
2336
+ return processRor(data, spec.amount, spec.group);
2337
+ case "bswap2":
2338
+ return processByteswap(data, 2);
2339
+ case "bswap4":
2340
+ return processByteswap(data, 4);
2341
+ case "bswap8":
2342
+ return processByteswap(data, 8);
2343
+ case "bswap16":
2344
+ return processByteswap(data, 16);
2345
+ default:
2346
+ throw new ParseError(
2347
+ `Unknown process algorithm: ${algorithm}. Supported: zlib, xor, rol, ror, bswap2, bswap4, bswap8, bswap16`
2348
+ );
2349
+ }
2350
+ }
2351
+ function processZlib(data) {
2352
+ try {
2353
+ return (0, import_pako.inflate)(data);
2354
+ } catch (error) {
2355
+ throw new ParseError(
2356
+ `Zlib decompression failed: ${error instanceof Error ? error.message : String(error)}`
2357
+ );
2358
+ }
2359
+ }
2360
+ function processXor(data, key) {
2361
+ if (key === void 0) {
2362
+ throw new ParseError("XOR process requires a key parameter");
2363
+ }
2364
+ const result = new Uint8Array(data.length);
2365
+ const keyBytes = Array.isArray(key) ? key : [key];
2366
+ if (keyBytes.length === 0) {
2367
+ throw new ParseError("XOR key cannot be empty");
2368
+ }
2369
+ for (let i = 0; i < data.length; i++) {
2370
+ result[i] = data[i] ^ keyBytes[i % keyBytes.length];
2371
+ }
2372
+ return result;
2373
+ }
2374
+ function processRol(data, amount, group) {
2375
+ const bits = amount ?? 1;
2376
+ const groupSize = group ?? 1;
2377
+ if (bits < 0 || bits > 7) {
2378
+ throw new ParseError("ROL amount must be between 0 and 7");
2379
+ }
2380
+ if (groupSize !== 1) {
2381
+ throw new ParseError("ROL with group size > 1 not yet supported");
2382
+ }
2383
+ const result = new Uint8Array(data.length);
2384
+ for (let i = 0; i < data.length; i++) {
2385
+ const byte = data[i];
2386
+ result[i] = (byte << bits | byte >> 8 - bits) & 255;
2387
+ }
2388
+ return result;
2389
+ }
2390
+ function processRor(data, amount, group) {
2391
+ const bits = amount ?? 1;
2392
+ const groupSize = group ?? 1;
2393
+ if (bits < 0 || bits > 7) {
2394
+ throw new ParseError("ROR amount must be between 0 and 7");
2395
+ }
2396
+ if (groupSize !== 1) {
2397
+ throw new ParseError("ROR with group size > 1 not yet supported");
2398
+ }
2399
+ const result = new Uint8Array(data.length);
2400
+ for (let i = 0; i < data.length; i++) {
2401
+ const byte = data[i];
2402
+ result[i] = (byte >> bits | byte << 8 - bits) & 255;
2403
+ }
2404
+ return result;
2405
+ }
2406
+ function processByteswap(data, groupSize) {
2407
+ if (![2, 4, 8, 16].includes(groupSize)) {
2408
+ throw new ParseError(
2409
+ `Invalid byteswap group size: ${groupSize}. Must be 2, 4, 8, or 16`
2410
+ );
2411
+ }
2412
+ if (data.length % groupSize !== 0) {
2413
+ throw new ParseError(
2414
+ `Data length ${data.length} is not aligned to group size ${groupSize}`
2415
+ );
2416
+ }
2417
+ const result = new Uint8Array(data.length);
2418
+ for (let i = 0; i < data.length; i += groupSize) {
2419
+ for (let j = 0; j < groupSize; j++) {
2420
+ result[i + j] = data[i + groupSize - 1 - j];
2421
+ }
2422
+ }
2423
+ return result;
2424
+ }
2425
+
2070
2426
  // src/interpreter/TypeInterpreter.ts
2071
2427
  var TypeInterpreter = class _TypeInterpreter {
2072
2428
  /**
@@ -2103,13 +2459,20 @@ var TypeInterpreter = class _TypeInterpreter {
2103
2459
  * @param stream - Binary stream to parse
2104
2460
  * @param parent - Parent object (for nested types)
2105
2461
  * @param typeArgs - Arguments for parametric types
2462
+ * @param root - Root object of the parse tree (for nested types)
2106
2463
  * @returns Parsed object
2107
2464
  */
2108
- parse(stream, parent, typeArgs) {
2465
+ parse(stream, parent, typeArgs, root) {
2109
2466
  const result = {};
2110
- const context = new Context(stream, result, parent, this.schema.enums);
2467
+ const actualRoot = root || result;
2468
+ const context = new Context(stream, actualRoot, parent, this.schema.enums);
2111
2469
  context.current = result;
2470
+ const startPos = stream.pos;
2112
2471
  result["_io"] = stream;
2472
+ if (root) {
2473
+ ;
2474
+ result["_root"] = root;
2475
+ }
2113
2476
  if (typeArgs && this.schema.params) {
2114
2477
  for (let i = 0; i < this.schema.params.length && i < typeArgs.length; i++) {
2115
2478
  const param = this.schema.params[i];
@@ -2118,6 +2481,9 @@ var TypeInterpreter = class _TypeInterpreter {
2118
2481
  context.set(param.id, evaluatedArg);
2119
2482
  }
2120
2483
  }
2484
+ if (this.schema.instances) {
2485
+ this.setupInstances(result, stream, context);
2486
+ }
2121
2487
  if (this.schema.seq) {
2122
2488
  for (const attr of this.schema.seq) {
2123
2489
  const value = this.parseAttribute(attr, context);
@@ -2126,9 +2492,8 @@ var TypeInterpreter = class _TypeInterpreter {
2126
2492
  }
2127
2493
  }
2128
2494
  }
2129
- if (this.schema.instances) {
2130
- this.setupInstances(result, stream, context);
2131
- }
2495
+ const endPos = stream.pos;
2496
+ result["_sizeof"] = endPos - startPos;
2132
2497
  return result;
2133
2498
  }
2134
2499
  /**
@@ -2433,11 +2798,13 @@ var TypeInterpreter = class _TypeInterpreter {
2433
2798
  context
2434
2799
  );
2435
2800
  }
2436
- if (isBuiltinType(type)) {
2437
- return this.parseBuiltinType(type, stream, context);
2801
+ const { typeName, args } = this.parseParameterizedType(type, context);
2802
+ const effectiveArgs = args.length > 0 ? args : typeArgs;
2803
+ if (isBuiltinType(typeName)) {
2804
+ return this.parseBuiltinType(typeName, stream, context);
2438
2805
  }
2439
- if (this.schema.types && type in this.schema.types) {
2440
- const typeSchema = this.schema.types[type];
2806
+ if (this.schema.types && typeName in this.schema.types) {
2807
+ const typeSchema = this.schema.types[typeName];
2441
2808
  const meta = this.schema.meta || this.parentMeta;
2442
2809
  if (this.schema.enums && !typeSchema.enums) {
2443
2810
  typeSchema.enums = this.schema.enums;
@@ -2446,9 +2813,100 @@ var TypeInterpreter = class _TypeInterpreter {
2446
2813
  typeSchema.types = this.schema.types;
2447
2814
  }
2448
2815
  const interpreter = new _TypeInterpreter(typeSchema, meta);
2449
- return interpreter.parse(stream, context.current, typeArgs);
2816
+ return interpreter.parse(
2817
+ stream,
2818
+ context.current,
2819
+ effectiveArgs,
2820
+ context.root
2821
+ );
2822
+ }
2823
+ throw new ParseError(`Unknown type: ${typeName}`);
2824
+ }
2825
+ /**
2826
+ * Parse parameterized type syntax and extract type name and arguments.
2827
+ * Supports: type_name(arg1, arg2, ...) or just type_name
2828
+ *
2829
+ * @param typeSpec - Type specification string
2830
+ * @param context - Execution context for evaluating argument expressions
2831
+ * @returns Object with typeName and evaluated args
2832
+ * @private
2833
+ */
2834
+ parseParameterizedType(typeSpec, context) {
2835
+ const match = typeSpec.match(/^([a-z_][a-z0-9_]*)\((.*)\)$/i);
2836
+ if (!match) {
2837
+ return { typeName: typeSpec, args: [] };
2838
+ }
2839
+ const typeName = match[1];
2840
+ const argsString = match[2].trim();
2841
+ if (!argsString) {
2842
+ return { typeName, args: [] };
2843
+ }
2844
+ const args = [];
2845
+ let current = "";
2846
+ let inString = false;
2847
+ let stringChar = "";
2848
+ let parenDepth = 0;
2849
+ for (let i = 0; i < argsString.length; i++) {
2850
+ const char = argsString[i];
2851
+ if (inString) {
2852
+ current += char;
2853
+ if (char === stringChar && argsString[i - 1] !== "\\") {
2854
+ inString = false;
2855
+ }
2856
+ } else if (char === '"' || char === "'") {
2857
+ inString = true;
2858
+ stringChar = char;
2859
+ current += char;
2860
+ } else if (char === "(") {
2861
+ parenDepth++;
2862
+ current += char;
2863
+ } else if (char === ")") {
2864
+ parenDepth--;
2865
+ current += char;
2866
+ } else if (char === "," && parenDepth === 0) {
2867
+ args.push(this.parseArgument(current.trim(), context));
2868
+ current = "";
2869
+ } else {
2870
+ current += char;
2871
+ }
2872
+ }
2873
+ if (current.trim()) {
2874
+ args.push(this.parseArgument(current.trim(), context));
2875
+ }
2876
+ return { typeName, args };
2877
+ }
2878
+ /**
2879
+ * Parse and evaluate a single type argument.
2880
+ *
2881
+ * @param arg - Argument string
2882
+ * @param context - Execution context
2883
+ * @returns Evaluated argument value
2884
+ * @private
2885
+ */
2886
+ parseArgument(arg, context) {
2887
+ if (arg === "true") return true;
2888
+ if (arg === "false") return false;
2889
+ if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
2890
+ return arg.slice(1, -1);
2891
+ }
2892
+ if (/^-?\d+$/.test(arg)) {
2893
+ return parseInt(arg, 10);
2894
+ }
2895
+ if (/^-?\d+\.\d+$/.test(arg)) {
2896
+ return parseFloat(arg);
2897
+ }
2898
+ if (/^0x[0-9a-f]+$/i.test(arg)) {
2899
+ return parseInt(arg, 16);
2900
+ }
2901
+ try {
2902
+ const result = this.evaluateValue(arg, context);
2903
+ if (typeof result === "string" || typeof result === "number" || typeof result === "boolean") {
2904
+ return result;
2905
+ }
2906
+ return Number(result);
2907
+ } catch {
2908
+ return arg;
2450
2909
  }
2451
- throw new ParseError(`Unknown type: ${type}`);
2452
2910
  }
2453
2911
  /**
2454
2912
  * Parse a switch type (type selection based on expression).
@@ -2491,12 +2949,21 @@ var TypeInterpreter = class _TypeInterpreter {
2491
2949
  * @returns Parsed value
2492
2950
  * @private
2493
2951
  */
2494
- parseBuiltinType(type, stream, _context) {
2952
+ parseBuiltinType(type, stream, context) {
2495
2953
  const base = getBaseType(type);
2496
2954
  const typeEndian = getTypeEndianness(type);
2497
2955
  const meta = this.schema.meta || this.parentMeta;
2498
2956
  const metaEndian = meta?.endian;
2499
- const endian = typeEndian || (typeof metaEndian === "string" ? metaEndian : "le");
2957
+ let endian;
2958
+ if (typeEndian) {
2959
+ endian = typeEndian;
2960
+ } else if (typeof metaEndian === "string") {
2961
+ endian = metaEndian;
2962
+ } else if (metaEndian && typeof metaEndian === "object") {
2963
+ endian = this.evaluateEndianExpression(metaEndian, context);
2964
+ } else {
2965
+ endian = "le";
2966
+ }
2500
2967
  if (isIntegerType(type)) {
2501
2968
  return this.readInteger(base, endian, stream);
2502
2969
  }
@@ -2573,7 +3040,7 @@ var TypeInterpreter = class _TypeInterpreter {
2573
3040
  }
2574
3041
  /**
2575
3042
  * Apply processing transformation to data.
2576
- * Supports basic transformations like zlib decompression.
3043
+ * Delegates to the process utility module.
2577
3044
  *
2578
3045
  * @param data - Data to process
2579
3046
  * @param process - Processing specification
@@ -2581,13 +3048,35 @@ var TypeInterpreter = class _TypeInterpreter {
2581
3048
  * @private
2582
3049
  */
2583
3050
  applyProcessing(data, process) {
2584
- const processType = typeof process === "string" ? process : process.algorithm;
2585
- if (processType) {
2586
- throw new NotImplementedError(
2587
- `Processing type "${processType}" is not yet implemented. Supported in future versions with zlib, encryption, etc.`
2588
- );
3051
+ return applyProcess(data, process);
3052
+ }
3053
+ /**
3054
+ * Evaluate expression-based endianness (switch-on).
3055
+ *
3056
+ * @param endianExpr - Endianness expression with switch-on and cases
3057
+ * @param context - Execution context
3058
+ * @returns Resolved endianness ('le' or 'be')
3059
+ * @private
3060
+ */
3061
+ evaluateEndianExpression(endianExpr, context) {
3062
+ const switchOn = endianExpr["switch-on"];
3063
+ const cases = endianExpr.cases;
3064
+ if (!switchOn || typeof switchOn !== "string") {
3065
+ throw new ParseError('Endian expression missing "switch-on" field');
3066
+ }
3067
+ if (!cases || typeof cases !== "object") {
3068
+ throw new ParseError('Endian expression missing "cases" field');
3069
+ }
3070
+ const switchValue = this.evaluateValue(switchOn, context);
3071
+ const key = String(switchValue);
3072
+ if (key in cases) {
3073
+ const endian = cases[key];
3074
+ if (endian !== "le" && endian !== "be") {
3075
+ throw new ParseError(`Invalid endianness value: ${endian}`);
3076
+ }
3077
+ return endian;
2589
3078
  }
2590
- return data;
3079
+ return "le";
2591
3080
  }
2592
3081
  /**
2593
3082
  * Evaluate a value that can be an expression or literal.
@@ -2730,6 +3219,12 @@ function parse(ksyYaml, buffer, options = {}) {
2730
3219
  * @author Fabiano Pinto
2731
3220
  * @license MIT
2732
3221
  */
3222
+ /**
3223
+ * @fileoverview Data processing utilities for Kaitai Struct
3224
+ * @module utils/process
3225
+ * @author Fabiano Pinto
3226
+ * @license MIT
3227
+ */
2733
3228
  /**
2734
3229
  * @fileoverview Type interpreter for executing Kaitai Struct schemas
2735
3230
  * @module interpreter/TypeInterpreter