@futpib/parser 1.0.3 → 1.0.6

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 (262) hide show
  1. package/.claude/settings.local.json +24 -0
  2. package/.github/workflows/main.yml +1 -0
  3. package/build/androidPackageParser.js +30 -32
  4. package/build/arbitraryDalvikBytecode.d.ts +3 -3
  5. package/build/arbitraryDalvikBytecode.js +33 -27
  6. package/build/arbitraryDalvikExecutable.js +55 -17
  7. package/build/arbitraryJava.d.ts +31 -0
  8. package/build/arbitraryJava.js +532 -0
  9. package/build/arbitraryJavaScript.d.ts +3 -0
  10. package/build/arbitraryJavaScript.js +263 -0
  11. package/build/arbitraryJavascript.d.ts +3 -0
  12. package/build/arbitraryJavascript.js +263 -0
  13. package/build/arbitraryZig.d.ts +3 -0
  14. package/build/arbitraryZig.js +240 -0
  15. package/build/arbitraryZipStream.d.ts +1 -1
  16. package/build/arrayParser.js +72 -13
  17. package/build/backsmali.d.ts +4 -3
  18. package/build/backsmali.js +26 -6
  19. package/build/bash.d.ts +89 -0
  20. package/build/bash.js +1 -0
  21. package/build/bashParser.d.ts +6 -0
  22. package/build/bashParser.js +335 -0
  23. package/build/bashParser.test.d.ts +1 -0
  24. package/build/bashParser.test.js +343 -0
  25. package/build/bashParserEdgeCases.test.d.ts +1 -0
  26. package/build/bashParserEdgeCases.test.js +117 -0
  27. package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
  28. package/build/dalvikBytecodeParser/addressConversion.js +334 -0
  29. package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
  30. package/build/dalvikBytecodeParser/formatParsers.js +13 -14
  31. package/build/dalvikBytecodeParser.d.ts +60 -31
  32. package/build/dalvikBytecodeParser.js +92 -35
  33. package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
  34. package/build/dalvikBytecodeParser.test-d.js +268 -0
  35. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
  36. package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
  37. package/build/dalvikBytecodeUnparser.d.ts +2 -2
  38. package/build/dalvikBytecodeUnparser.js +23 -23
  39. package/build/dalvikBytecodeUnparser.test.js +7 -7
  40. package/build/dalvikExecutable.d.ts +3 -3
  41. package/build/dalvikExecutable.test-d.d.ts +1 -0
  42. package/build/dalvikExecutable.test-d.js +59 -0
  43. package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
  44. package/build/dalvikExecutableParser/typedNumbers.js +3 -0
  45. package/build/dalvikExecutableParser.d.ts +2 -1
  46. package/build/dalvikExecutableParser.js +96 -77
  47. package/build/dalvikExecutableParser.test.js +24 -3
  48. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
  49. package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
  50. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
  51. package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
  52. package/build/dalvikExecutableUnparser.d.ts +2 -2
  53. package/build/dalvikExecutableUnparser.test.js +2 -1
  54. package/build/disjunctionParser.d.ts +5 -3
  55. package/build/disjunctionParser.js +79 -17
  56. package/build/disjunctionParser.test-d.d.ts +1 -0
  57. package/build/disjunctionParser.test-d.js +72 -0
  58. package/build/elementSwitchParser.d.ts +4 -0
  59. package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
  60. package/build/elementSwitchParser.test-d.d.ts +1 -0
  61. package/build/elementSwitchParser.test-d.js +44 -0
  62. package/build/exactSequenceParser.d.ts +4 -2
  63. package/build/exactSequenceParser.test-d.d.ts +1 -0
  64. package/build/exactSequenceParser.test-d.js +36 -0
  65. package/build/fetchCid.js +2 -66
  66. package/build/index.d.ts +25 -2
  67. package/build/index.js +23 -1
  68. package/build/index.test.js +16 -1
  69. package/build/inputReader.d.ts +10 -0
  70. package/build/inputReader.js +36 -0
  71. package/build/java.d.ts +502 -0
  72. package/build/java.js +2 -0
  73. package/build/javaKeyStoreParser.js +14 -17
  74. package/build/javaParser.d.ts +51 -0
  75. package/build/javaParser.js +1538 -0
  76. package/build/javaParser.test.d.ts +1 -0
  77. package/build/javaParser.test.js +1287 -0
  78. package/build/javaScript.d.ts +35 -0
  79. package/build/javaScript.js +1 -0
  80. package/build/javaScriptParser.d.ts +9 -0
  81. package/build/javaScriptParser.js +34 -0
  82. package/build/javaScriptUnparser.d.ts +3 -0
  83. package/build/javaScriptUnparser.js +4 -0
  84. package/build/javaScriptUnparser.test.d.ts +1 -0
  85. package/build/javaScriptUnparser.test.js +24 -0
  86. package/build/javaUnparser.d.ts +2 -0
  87. package/build/javaUnparser.js +519 -0
  88. package/build/javaUnparser.test.d.ts +1 -0
  89. package/build/javaUnparser.test.js +24 -0
  90. package/build/javascript.d.ts +35 -0
  91. package/build/javascript.js +1 -0
  92. package/build/javascriptParser.d.ts +9 -0
  93. package/build/javascriptParser.js +34 -0
  94. package/build/javascriptUnparser.d.ts +3 -0
  95. package/build/javascriptUnparser.js +4 -0
  96. package/build/javascriptUnparser.test.d.ts +1 -0
  97. package/build/javascriptUnparser.test.js +24 -0
  98. package/build/jsonParser.js +2 -12
  99. package/build/lazyMessageError.d.ts +3 -0
  100. package/build/lookaheadParser.js +60 -3
  101. package/build/negativeLookaheadParser.js +70 -11
  102. package/build/nonEmptyArrayParser.js +72 -13
  103. package/build/objectParser.d.ts +12 -0
  104. package/build/objectParser.js +31 -0
  105. package/build/objectParser.test-d.d.ts +1 -0
  106. package/build/objectParser.test-d.js +112 -0
  107. package/build/objectParser.test.d.ts +1 -0
  108. package/build/objectParser.test.js +55 -0
  109. package/build/optionalParser.js +69 -10
  110. package/build/parser.d.ts +4 -0
  111. package/build/parser.js +3 -1
  112. package/build/parser.test.js +114 -1
  113. package/build/parserConsumedSequenceParser.js +66 -7
  114. package/build/parserContext.d.ts +6 -0
  115. package/build/parserContext.js +20 -11
  116. package/build/parserError.d.ts +119 -27
  117. package/build/parserError.js +16 -8
  118. package/build/regexpParser.d.ts +2 -0
  119. package/build/regexpParser.js +101 -0
  120. package/build/regexpParser.test.d.ts +1 -0
  121. package/build/regexpParser.test.js +114 -0
  122. package/build/regularExpression.d.ts +63 -0
  123. package/build/regularExpression.js +1 -0
  124. package/build/regularExpressionParser.d.ts +3 -0
  125. package/build/regularExpressionParser.js +600 -0
  126. package/build/regularExpressionParser.test.d.ts +1 -0
  127. package/build/regularExpressionParser.test.js +89 -0
  128. package/build/separatedArrayParser.js +73 -14
  129. package/build/separatedNonEmptyArrayParser.js +73 -14
  130. package/build/sliceBoundedParser.js +62 -5
  131. package/build/smaliParser.d.ts +7 -7
  132. package/build/smaliParser.js +185 -268
  133. package/build/smaliParser.test.js +58 -0
  134. package/build/stringEscapes.d.ts +5 -0
  135. package/build/stringEscapes.js +244 -0
  136. package/build/symbolicExpression.d.ts +29 -0
  137. package/build/symbolicExpression.js +1 -0
  138. package/build/symbolicExpressionParser.d.ts +4 -0
  139. package/build/symbolicExpressionParser.js +123 -0
  140. package/build/symbolicExpressionParser.test.d.ts +1 -0
  141. package/build/symbolicExpressionParser.test.js +289 -0
  142. package/build/terminatedArrayParser.js +113 -38
  143. package/build/terminatedArrayParser.test.js +4 -2
  144. package/build/tupleParser.d.ts +7 -15
  145. package/build/tupleParser.js +1 -0
  146. package/build/unionParser.d.ts +5 -3
  147. package/build/unionParser.js +7 -2
  148. package/build/unionParser.test-d.d.ts +1 -0
  149. package/build/unionParser.test-d.js +72 -0
  150. package/build/unionParser.test.js +10 -11
  151. package/build/zig.d.ts +280 -0
  152. package/build/zig.js +2 -0
  153. package/build/zigParser.d.ts +3 -0
  154. package/build/zigParser.js +1119 -0
  155. package/build/zigParser.test.d.ts +1 -0
  156. package/build/zigParser.test.js +1590 -0
  157. package/build/zigUnparser.d.ts +2 -0
  158. package/build/zigUnparser.js +460 -0
  159. package/build/zigUnparser.test.d.ts +1 -0
  160. package/build/zigUnparser.test.js +24 -0
  161. package/build/zipParser.js +19 -32
  162. package/build/zipUnparser.js +19 -7
  163. package/build/zipUnparser.test.js +1 -1
  164. package/node_modules-@types/s-expression/index.d.ts +5 -0
  165. package/package.json +25 -6
  166. package/src/androidPackageParser.ts +33 -60
  167. package/src/arbitraryDalvikBytecode.ts +39 -31
  168. package/src/arbitraryDalvikExecutable.ts +65 -20
  169. package/src/arbitraryJava.ts +804 -0
  170. package/src/arbitraryJavaScript.ts +410 -0
  171. package/src/arbitraryZig.ts +380 -0
  172. package/src/arrayParser.ts +1 -3
  173. package/src/backsmali.ts +35 -4
  174. package/src/bash.ts +127 -0
  175. package/src/bashParser.test.ts +590 -0
  176. package/src/bashParser.ts +498 -0
  177. package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
  178. package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
  179. package/src/dalvikBytecodeParser.test-d.ts +310 -0
  180. package/src/dalvikBytecodeParser.ts +194 -69
  181. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
  182. package/src/dalvikBytecodeUnparser.test.ts +7 -7
  183. package/src/dalvikBytecodeUnparser.ts +31 -30
  184. package/src/dalvikExecutable.test-d.ts +132 -0
  185. package/src/dalvikExecutable.ts +3 -3
  186. package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
  187. package/src/dalvikExecutableParser.test.ts +37 -3
  188. package/src/dalvikExecutableParser.test.ts.md +163 -2
  189. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  190. package/src/dalvikExecutableParser.ts +121 -139
  191. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
  192. package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
  193. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
  194. package/src/dalvikExecutableUnparser.test.ts +3 -2
  195. package/src/dalvikExecutableUnparser.ts +4 -4
  196. package/src/disjunctionParser.test-d.ts +105 -0
  197. package/src/disjunctionParser.ts +18 -15
  198. package/src/elementSwitchParser.test-d.ts +74 -0
  199. package/src/elementSwitchParser.ts +51 -0
  200. package/src/exactSequenceParser.test-d.ts +43 -0
  201. package/src/exactSequenceParser.ts +13 -8
  202. package/src/fetchCid.ts +2 -76
  203. package/src/index.test.ts +22 -1
  204. package/src/index.ts +119 -2
  205. package/src/inputReader.ts +53 -0
  206. package/src/java.ts +708 -0
  207. package/src/javaKeyStoreParser.ts +18 -32
  208. package/src/javaParser.test.ts +1592 -0
  209. package/src/javaParser.ts +2640 -0
  210. package/src/javaScript.ts +36 -0
  211. package/src/javaScriptParser.ts +57 -0
  212. package/src/javaScriptUnparser.test.ts +37 -0
  213. package/src/javaScriptUnparser.ts +7 -0
  214. package/src/javaUnparser.test.ts +37 -0
  215. package/src/javaUnparser.ts +640 -0
  216. package/src/jsonParser.ts +6 -27
  217. package/src/lookaheadParser.ts +2 -6
  218. package/src/negativeLookaheadParser.ts +1 -3
  219. package/src/nonEmptyArrayParser.ts +1 -3
  220. package/src/objectParser.test-d.ts +152 -0
  221. package/src/objectParser.test.ts +71 -0
  222. package/src/objectParser.ts +69 -0
  223. package/src/optionalParser.ts +1 -3
  224. package/src/parser.test.ts +151 -4
  225. package/src/parser.ts +11 -1
  226. package/src/parserConsumedSequenceParser.ts +2 -4
  227. package/src/parserContext.ts +26 -11
  228. package/src/parserError.ts +17 -3
  229. package/src/regexpParser.test.ts +264 -0
  230. package/src/regexpParser.ts +126 -0
  231. package/src/regularExpression.ts +24 -0
  232. package/src/regularExpressionParser.test.ts +102 -0
  233. package/src/regularExpressionParser.ts +920 -0
  234. package/src/separatedArrayParser.ts +1 -3
  235. package/src/separatedNonEmptyArrayParser.ts +1 -3
  236. package/src/sliceBoundedParser.test.ts +2 -2
  237. package/src/sliceBoundedParser.ts +15 -19
  238. package/src/smaliParser.test.ts +64 -0
  239. package/src/smaliParser.test.ts.md +12 -12
  240. package/src/smaliParser.test.ts.snap +0 -0
  241. package/src/smaliParser.ts +246 -534
  242. package/src/stringEscapes.ts +253 -0
  243. package/src/symbolicExpression.ts +17 -0
  244. package/src/symbolicExpressionParser.test.ts +466 -0
  245. package/src/symbolicExpressionParser.ts +190 -0
  246. package/src/terminatedArrayParser.test.ts +9 -6
  247. package/src/terminatedArrayParser.ts +25 -29
  248. package/src/tupleParser.ts +21 -18
  249. package/src/unionParser.test-d.ts +105 -0
  250. package/src/unionParser.test.ts +18 -17
  251. package/src/unionParser.ts +28 -16
  252. package/src/zig.ts +411 -0
  253. package/src/zigParser.test.ts +1693 -0
  254. package/src/zigParser.ts +1745 -0
  255. package/src/zigUnparser.test.ts +37 -0
  256. package/src/zigUnparser.ts +615 -0
  257. package/src/zipParser.ts +20 -56
  258. package/src/zipUnparser.test.ts +1 -1
  259. package/src/zipUnparser.ts +22 -7
  260. package/tsconfig.json +2 -2
  261. package/build/exactElementSwitchParser.d.ts +0 -3
  262. package/src/exactElementSwitchParser.ts +0 -41
@@ -29,6 +29,24 @@ export type IndexIntoMethodIds = {} & Newtype<{
29
29
  export declare const isoIndexIntoMethodIds: import("monocle-ts").Iso<Newtype<{
30
30
  readonly IndexIntoMethodIds: unique symbol;
31
31
  }, number>, number>;
32
+ export type IndexIntoCallSiteIds = {} & Newtype<{
33
+ readonly IndexIntoCallSiteIds: unique symbol;
34
+ }, number>;
35
+ export declare const isoIndexIntoCallSiteIds: import("monocle-ts").Iso<Newtype<{
36
+ readonly IndexIntoCallSiteIds: unique symbol;
37
+ }, number>, number>;
38
+ export type CodeUnit = {} & Newtype<{
39
+ readonly CodeUnit: unique symbol;
40
+ }, number>;
41
+ export declare const isoCodeUnit: import("monocle-ts").Iso<Newtype<{
42
+ readonly CodeUnit: unique symbol;
43
+ }, number>, number>;
44
+ export type InstructionIndex = {} & Newtype<{
45
+ readonly InstructionIndex: unique symbol;
46
+ }, number>;
47
+ export declare const isoInstructionIndex: import("monocle-ts").Iso<Newtype<{
48
+ readonly InstructionIndex: unique symbol;
49
+ }, number>, number>;
32
50
  export type OffsetToStringDataItem = {} & Newtype<{
33
51
  readonly OffsetToStringDataItem: unique symbol;
34
52
  }, number>;
@@ -4,6 +4,9 @@ export const isoIndexIntoTypeIds = iso();
4
4
  export const isoIndexIntoPrototypeIds = iso();
5
5
  export const isoIndexIntoFieldIds = iso();
6
6
  export const isoIndexIntoMethodIds = iso();
7
+ export const isoIndexIntoCallSiteIds = iso();
8
+ export const isoCodeUnit = iso();
9
+ export const isoInstructionIndex = iso();
7
10
  export const isoOffsetToStringDataItem = iso();
8
11
  export const isoOffsetToTypeList = iso();
9
12
  export const isoOffsetToAnnotationsDirectoryItem = iso();
@@ -1,5 +1,6 @@
1
1
  import { type Parser } from './parser.js';
2
- import { type DalvikBytecode } from './dalvikBytecodeParser.js';
2
+ import { type DalvikBytecode } from './dalvikBytecodeParser/addressConversion.js';
3
3
  import { type DalvikExecutable } from './dalvikExecutable.js';
4
4
  export declare const dalvikExecutableParser: Parser<DalvikExecutable<DalvikBytecode>, Uint8Array>;
5
+ export { type DalvikBytecodeOperation, type DalvikBytecode } from './dalvikBytecodeParser/addressConversion.js';
5
6
  export declare const dalvikExecutableWithRawInstructionsParser: Parser<DalvikExecutable<Uint8Array>, Uint8Array>;
@@ -3,6 +3,7 @@ import { MUtf8Decoder } from 'mutf-8';
3
3
  import { createExactElementParser } from './exactElementParser.js';
4
4
  import { createExactSequenceParser } from './exactSequenceParser.js';
5
5
  import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
6
+ import { createObjectParser } from './objectParser.js';
6
7
  import { cloneParser, setParserName } from './parser.js';
7
8
  import { parserCreatorCompose } from './parserCreatorCompose.js';
8
9
  import { promiseCompose } from './promiseCompose.js';
@@ -16,8 +17,11 @@ import { sleb128NumberParser, uleb128NumberParser } from './leb128Parser.js';
16
17
  import { createDisjunctionParser } from './disjunctionParser.js';
17
18
  import { createElementTerminatedSequenceParser } from './elementTerminatedSequenceParser.js';
18
19
  import { createElementTerminatedArrayParserUnsafe } from './elementTerminatedArrayParser.js';
19
- import { createDalvikBytecodeParser, resolveDalvikBytecodeOperation, } from './dalvikBytecodeParser.js';
20
+ import { createRawDalvikBytecodeParser, resolveRawDalvikBytecodeOperationIndices, } from './dalvikBytecodeParser.js';
21
+ import { buildCodeUnitToIndexMap, codeUnitToInstructionIndex, convertBranchOffsetsToInstructionOffsets, unwrapBranchOffsets, } from './dalvikBytecodeParser/addressConversion.js';
22
+ import { isoCodeUnit, isoInstructionIndex } from './dalvikExecutableParser/typedNumbers.js';
20
23
  import { byteParser, ubyteParser, uintParser, uleb128p1NumberParser, ushortParser, } from './dalvikExecutableParser/typeParsers.js';
24
+ import { dalvikExecutableMethodEquals, } from './dalvikExecutable.js';
21
25
  // https://source.android.com/docs/core/runtime/dex-format
22
26
  const createByteAlignParser = (byteAlignment) => async (parserContext) => {
23
27
  const toSkip = (byteAlignment - (parserContext.position % byteAlignment)) % byteAlignment;
@@ -34,43 +38,27 @@ const dalvikExecutableHeaderVersionParser = promiseCompose(createTupleParser([
34
38
  const version = Number.parseInt(versionString, 10);
35
39
  return version;
36
40
  });
37
- const sizeOffsetParser = promiseCompose(createTupleParser([
38
- uintParser,
39
- uintParser,
40
- ]), ([size, offset]) => ({ size, offset }));
41
- const dalvikExecutableHeaderItemParser = promiseCompose(createTupleParser([
42
- dalvikExecutableHeaderVersionParser,
43
- uintParser,
44
- createFixedLengthSequenceParser(20),
45
- uintParser,
46
- uintParser,
47
- uintParser,
48
- sizeOffsetParser,
49
- uintParser,
50
- sizeOffsetParser,
51
- sizeOffsetParser,
52
- sizeOffsetParser,
53
- sizeOffsetParser,
54
- sizeOffsetParser,
55
- sizeOffsetParser,
56
- sizeOffsetParser,
57
- ]), ([version, checksum, sha1Hash, fileSize, headerSize, endianTag, link, mapOffset, stringIds, typeIds, prototypeIds, fieldIds, methodIds, classDefinitions, data,]) => ({
58
- version,
59
- checksum,
60
- sha1Hash,
61
- fileSize,
62
- headerSize,
63
- endianTag,
64
- link,
65
- mapOffset,
66
- stringIds,
67
- typeIds,
68
- prototypeIds,
69
- fieldIds,
70
- methodIds,
71
- classDefinitions,
72
- data,
73
- }));
41
+ const sizeOffsetParser = createObjectParser({
42
+ size: uintParser,
43
+ offset: uintParser,
44
+ });
45
+ const dalvikExecutableHeaderItemParser = createObjectParser({
46
+ version: dalvikExecutableHeaderVersionParser,
47
+ checksum: uintParser,
48
+ sha1Hash: createFixedLengthSequenceParser(20),
49
+ fileSize: uintParser,
50
+ headerSize: uintParser,
51
+ endianTag: uintParser,
52
+ link: sizeOffsetParser,
53
+ mapOffset: uintParser,
54
+ stringIds: sizeOffsetParser,
55
+ typeIds: sizeOffsetParser,
56
+ prototypeIds: sizeOffsetParser,
57
+ fieldIds: sizeOffsetParser,
58
+ methodIds: sizeOffsetParser,
59
+ classDefinitions: sizeOffsetParser,
60
+ data: sizeOffsetParser,
61
+ });
74
62
  const dalvikExecutableStringIdItemParser = promiseCompose(cloneParser(uintParser), offset => isoOffsetToStringDataItem.wrap(offset));
75
63
  const isoDalvikExecutableStringIdItems = getIsoTypedNumberArray();
76
64
  const createSkipToThenStringIdItemsParser = ({ size, offset }) => (size === 0
@@ -308,10 +296,10 @@ const createSkipToThenAnnotationsDirectoryItemsParser = (sizeOffset) => createSk
308
296
  isoOffset: isoOffsetToAnnotationsDirectoryItem,
309
297
  parserName: 'skipToThenAnnotationsDirectoryItemsParser',
310
298
  });
311
- const encodedFieldParser = promiseCompose(createTupleParser([
312
- uleb128NumberParser,
313
- uleb128FieldAccessFlagsParser,
314
- ]), ([fieldIndexDiff, accessFlags]) => ({ fieldIndexDiff, accessFlags }));
299
+ const encodedFieldParser = createObjectParser({
300
+ fieldIndexDiff: uleb128NumberParser,
301
+ accessFlags: uleb128FieldAccessFlagsParser,
302
+ });
315
303
  const createEncodedFieldsParser = (fieldsSize) => promiseCompose(createQuantifierParser(encodedFieldParser, fieldsSize), encodedFields => {
316
304
  let previousFieldIndex = 0;
317
305
  return encodedFields.map(({ fieldIndexDiff, accessFlags }) => {
@@ -375,10 +363,11 @@ const createByteWith5LeastSignificantBitsEqualParser = (leastSignificant5) => {
375
363
  return byteWith5LeastSignificantBitsEqualParser;
376
364
  };
377
365
  const createEncodedValueArgParser = (valueType) => promiseCompose(createByteWith5LeastSignificantBitsEqualParser(valueType), byte => byte >> 5);
378
- const encodedValueByteParser = promiseCompose(createTupleParser([
379
- createExactElementParser(0),
380
- byteParser,
381
- ]), ([_, value]) => ({ type: 'byte', value }));
366
+ const encodedValueByteParser = createObjectParser({
367
+ type: 'byte',
368
+ _tag: createExactElementParser(0),
369
+ value: byteParser,
370
+ });
382
371
  setParserName(encodedValueByteParser, 'encodedValueByteParser');
383
372
  const encodedValueShortParser = parserCreatorCompose(() => createEncodedValueArgParser(0x02), sizeSubOne => {
384
373
  const size = sizeSubOne + 1;
@@ -730,12 +719,13 @@ const encodedValueEnumParser = parserCreatorCompose(() => createEncodedValueArgP
730
719
  setParserName(encodedValueEnumParser, 'encodedValueEnumParser');
731
720
  const encodedArrayParser = parserCreatorCompose(() => uleb128NumberParser, size => createQuantifierParser(encodedValueParser, size))();
732
721
  setParserName(encodedArrayParser, 'encodedArrayParser');
733
- const encodedValueArrayParser = promiseCompose(createTupleParser([
734
- parserCreatorCompose(() => createEncodedValueArgParser(0x1C), valueArg => parserContext => {
722
+ const encodedValueArrayParser = createObjectParser({
723
+ type: 'array',
724
+ _tag: parserCreatorCompose(() => createEncodedValueArgParser(0x1C), valueArg => parserContext => {
735
725
  parserContext.invariant(valueArg === 0, '(encodedValueArrayParser) valueArg: %s', valueArg);
736
726
  })(),
737
- encodedArrayParser,
738
- ]), ([_, array]) => ({ type: 'array', value: array }));
727
+ value: encodedArrayParser,
728
+ });
739
729
  setParserName(encodedValueArrayParser, 'encodedValueArrayParser');
740
730
  const annotationElementParser = promiseCompose(createTupleParser([
741
731
  uleb128NumberParser,
@@ -756,12 +746,13 @@ const encodedAnnotationParser = promiseCompose(parserCreatorCompose(() => create
756
746
  elements,
757
747
  }));
758
748
  setParserName(encodedAnnotationParser, 'encodedAnnotationParser');
759
- const encodedValueAnnotationParser = promiseCompose(createTupleParser([
760
- parserCreatorCompose(() => createEncodedValueArgParser(0x1D), valueArg => parserContext => {
749
+ const encodedValueAnnotationParser = createObjectParser({
750
+ type: 'annotation',
751
+ _tag: parserCreatorCompose(() => createEncodedValueArgParser(0x1D), valueArg => parserContext => {
761
752
  parserContext.invariant(valueArg === 0, '(encodedValueAnnotationParser) valueArg: %s', valueArg);
762
753
  })(),
763
- encodedAnnotationParser,
764
- ]), ([_, annotation]) => ({ type: 'annotation', value: annotation }));
754
+ value: encodedAnnotationParser,
755
+ });
765
756
  setParserName(encodedValueAnnotationParser, 'encodedValueAnnotationParser');
766
757
  const encodedValueNullParser = parserCreatorCompose(() => createEncodedValueArgParser(0x1E), valueArg => parserContext => {
767
758
  parserContext.invariant(valueArg === 0, '(encodedValueNullParser) valueArg: %s', valueArg);
@@ -875,10 +866,16 @@ const createSkipToThenCodeItemsParser = ({ sizeOffset, createInstructionsParser,
875
866
  const dalvikExecutableDebugByteCodeValueParser = parserCreatorCompose(() => ubyteParser, (value) => {
876
867
  switch (value) {
877
868
  case 0x01: {
878
- return promiseCompose(uleb128NumberParser, addressDiff => ({ type: 'advancePc', addressDiff }));
869
+ return createObjectParser({
870
+ type: 'advancePc',
871
+ addressDiff: uleb128NumberParser,
872
+ });
879
873
  }
880
874
  case 0x02: {
881
- return promiseCompose(sleb128NumberParser, lineDiff => ({ type: 'advanceLine', lineDiff }));
875
+ return createObjectParser({
876
+ type: 'advanceLine',
877
+ lineDiff: sleb128NumberParser,
878
+ });
882
879
  }
883
880
  case 0x03: {
884
881
  return promiseCompose(createTupleParser([
@@ -969,10 +966,10 @@ const dalvikExecutableAnnotationItemVisibilityParser = promiseCompose(ubyteParse
969
966
  }
970
967
  });
971
968
  setParserName(dalvikExecutableAnnotationItemVisibilityParser, 'dalvikExecutableAnnotationItemVisibilityParser');
972
- const dalvikExecutableAnnotationItemParser = promiseCompose(createTupleParser([
973
- dalvikExecutableAnnotationItemVisibilityParser,
974
- encodedAnnotationParser,
975
- ]), ([visibility, encodedAnnotation]) => ({ visibility, encodedAnnotation }));
969
+ const dalvikExecutableAnnotationItemParser = createObjectParser({
970
+ visibility: dalvikExecutableAnnotationItemVisibilityParser,
971
+ encodedAnnotation: encodedAnnotationParser,
972
+ });
976
973
  setParserName(dalvikExecutableAnnotationItemParser, 'dalvikExecutableAnnotationItemParser');
977
974
  const createSkipToThenAnnotationItemsParser = (sizeOffset) => createSkipToThenItemByOffsetParser({
978
975
  sizeOffset,
@@ -1078,12 +1075,12 @@ const dalvikExecutableMapItemTypeParser = promiseCompose(ushortParser, type => {
1078
1075
  }
1079
1076
  }
1080
1077
  });
1081
- const dalvikExecutableMapItemParser = promiseCompose(createTupleParser([
1082
- dalvikExecutableMapItemTypeParser,
1083
- ushortParser,
1084
- uintParser,
1085
- uintParser,
1086
- ]), ([type, _unused, size, offset]) => ({ type, size, offset }));
1078
+ const dalvikExecutableMapItemParser = createObjectParser({
1079
+ type: dalvikExecutableMapItemTypeParser,
1080
+ _unused: ushortParser,
1081
+ size: uintParser,
1082
+ offset: uintParser,
1083
+ });
1087
1084
  const dalvikExecutableMapListParser = parserCreatorCompose(() => uintParser, size => createQuantifierParser(dalvikExecutableMapItemParser, size))();
1088
1085
  setParserName(dalvikExecutableMapListParser, 'dalvikExecutableMapListParser');
1089
1086
  const createDalvikExecutableMapListParser = (mapOffset) => {
@@ -1358,29 +1355,49 @@ link, }) => {
1358
1355
  ]);
1359
1356
  for (const [offset, codeItem] of codeItemByOffset) {
1360
1357
  const debugInfo = debugInfoByOffset.get(codeItem.debugInfoOffset);
1358
+ // Build code unit to instruction index mapping for address conversion
1359
+ const rawInstructions = codeItem.instructions;
1360
+ const codeUnitToIndexMap = Array.isArray(rawInstructions) ? buildCodeUnitToIndexMap(rawInstructions) : undefined;
1361
+ // Convert branch offsets from code units to instruction offsets
1362
+ // Tier 1 (CodeUnit) -> Tier 2 (InstructionIndex) -> Tier 3 (plain numbers)
1363
+ const convertedInstructions = (Array.isArray(rawInstructions) && codeUnitToIndexMap)
1364
+ ? unwrapBranchOffsets(convertBranchOffsetsToInstructionOffsets(rawInstructions))
1365
+ : codeItem.instructions;
1361
1366
  codeByOffset.set(offset, {
1362
1367
  registersSize: codeItem.registersSize,
1363
1368
  insSize: codeItem.insSize,
1364
1369
  outsSize: codeItem.outsSize,
1365
1370
  debugInfo,
1366
- instructions: codeItem.instructions,
1371
+ instructions: convertedInstructions,
1367
1372
  tries: codeItem.tryItems.map(tryItem => {
1368
1373
  const handler_ = codeItem.handlers.get(tryItem.handlerOffset);
1369
1374
  invariant(handler_, 'Handler must be there. Handler offset: %s', tryItem.handlerOffset);
1375
+ // Convert handler addresses from code units to instruction indices (unwrapped for Tier 3)
1370
1376
  const handler = {
1371
1377
  handlers: handler_.handlers.map(encodedHandler => {
1372
1378
  const type = types.at(encodedHandler.typeIndex);
1373
1379
  invariant(type, 'Type must be there. Type id: %s', encodedHandler.typeIndex);
1374
1380
  return {
1375
1381
  type,
1376
- address: encodedHandler.address,
1382
+ handlerInstructionIndex: codeUnitToIndexMap
1383
+ ? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(encodedHandler.address), codeUnitToIndexMap))
1384
+ : encodedHandler.address,
1377
1385
  };
1378
1386
  }),
1379
- catchAllAddress: handler_.catchAllAddress,
1387
+ catchAllInstructionIndex: (handler_.catchAllAddress !== undefined && codeUnitToIndexMap)
1388
+ ? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(handler_.catchAllAddress), codeUnitToIndexMap))
1389
+ : handler_.catchAllAddress,
1380
1390
  };
1391
+ // Convert try block addresses from code units to instruction indices (unwrapped for Tier 3)
1392
+ const startInstructionIndex = codeUnitToIndexMap
1393
+ ? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(tryItem.startAddress), codeUnitToIndexMap))
1394
+ : tryItem.startAddress;
1395
+ const endInstructionIndex = codeUnitToIndexMap
1396
+ ? isoInstructionIndex.unwrap(codeUnitToInstructionIndex(isoCodeUnit.wrap(tryItem.startAddress + tryItem.instructionCount), codeUnitToIndexMap))
1397
+ : tryItem.startAddress + tryItem.instructionCount;
1381
1398
  return {
1382
- startAddress: tryItem.startAddress,
1383
- instructionCount: tryItem.instructionCount,
1399
+ startInstructionIndex,
1400
+ instructionCount: endInstructionIndex - startInstructionIndex,
1384
1401
  handler,
1385
1402
  };
1386
1403
  }),
@@ -1421,7 +1438,7 @@ link, }) => {
1421
1438
  }
1422
1439
  return {
1423
1440
  ...rest,
1424
- instructions: instructions.map((instruction) => resolveDalvikBytecodeOperation(instruction, resolvers)),
1441
+ instructions: instructions.map((instruction) => resolveRawDalvikBytecodeOperationIndices(instruction, resolvers)),
1425
1442
  };
1426
1443
  }
1427
1444
  for (const [offset, classDataItem] of classDataItemByOffset) {
@@ -1735,10 +1752,8 @@ link, }) => {
1735
1752
  if (classDef.annotations?.parameterAnnotations && classDef.classData) {
1736
1753
  const allMethods = [...(classDef.classData.directMethods ?? []), ...(classDef.classData.virtualMethods ?? [])];
1737
1754
  classDef.annotations.parameterAnnotations.sort((a, b) => {
1738
- const indexA = allMethods.findIndex(m => m.method.name === a.method.name &&
1739
- m.method.prototype.shorty === a.method.prototype.shorty);
1740
- const indexB = allMethods.findIndex(m => m.method.name === b.method.name &&
1741
- m.method.prototype.shorty === b.method.prototype.shorty);
1755
+ const indexA = allMethods.findIndex(m => dalvikExecutableMethodEquals(m.method, a.method));
1756
+ const indexB = allMethods.findIndex(m => dalvikExecutableMethodEquals(m.method, b.method));
1742
1757
  return indexA - indexB;
1743
1758
  });
1744
1759
  }
@@ -1748,8 +1763,12 @@ link, }) => {
1748
1763
  link,
1749
1764
  };
1750
1765
  }))();
1766
+ // The factory creates a parser that outputs RawDalvikBytecode, but the parser internally transforms
1767
+ // instructions via unwrapBranchOffsets(convertBranchOffsetsToInstructionOffsets(...)) and
1768
+ // resolveRawDalvikBytecodeOperationIndices to produce DalvikBytecode with plain number indices.
1769
+ // The cast is required because TypeScript can't track this internal transformation.
1751
1770
  export const dalvikExecutableParser = createDalvikExecutableParser({
1752
- createInstructionsParser: createDalvikBytecodeParser,
1771
+ createInstructionsParser: createRawDalvikBytecodeParser,
1753
1772
  });
1754
1773
  setParserName(dalvikExecutableParser, 'dalvikExecutableParser');
1755
1774
  export const dalvikExecutableWithRawInstructionsParser = createDalvikExecutableParser({
@@ -54,8 +54,10 @@ const dexWithParsedInstructionsMacro = test.macro({
54
54
  if (typeof key !== 'string') {
55
55
  return;
56
56
  }
57
- t.false(key.endsWith('Offset') && key !== 'branchOffset', 'All offsets should be resolved: ' + path.join('.'));
58
- t.false(key.endsWith('Index'), 'All indexes should be resolved: ' + path.join('.'));
57
+ t.false(key.endsWith('Offset'), 'All offsets should be resolved: ' + path.join('.'));
58
+ // InstructionIndex fields are expected in Tier 3
59
+ const allowedIndexFields = ['targetInstructionIndex', 'targetInstructionIndices', 'startInstructionIndex', 'handlerInstructionIndex', 'catchAllInstructionIndex'];
60
+ t.false(key.endsWith('Index') && !allowedIndexFields.includes(key) && key !== 'targetInstructionIndices', 'All indexes should be resolved: ' + path.join('.'));
59
61
  });
60
62
  if (shouldSnapshot) {
61
63
  t.snapshot(actual);
@@ -66,7 +68,26 @@ const dexWithParsedInstructionsMacro = test.macro({
66
68
  }
67
69
  },
68
70
  });
69
- test.serial.only(dexWithParsedInstructionsMacro, 'bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4', true);
71
+ test.serial(dexWithParsedInstructionsMacro, 'bafkreibb4gsprc3fvmnyqx6obswvm7e7wngnfj64gz65ey72r7xgyzymt4', true);
70
72
  test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeiebe27ylo53trgitu6fqfbmba43c4ivxj3nt4kumsilkucpbdxtqq', false);
71
73
  test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeibbupm7uzhuq4pa674rb2amxsenbdaoijigmaf4onaodaql4mh7yy', false);
72
74
  test.serial.skip(dexWithParsedInstructionsMacro, 'bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda', false);
75
+ const methodMacro = test.macro({
76
+ title: (providedTitle, dexCid, className, methodName) => providedTitle ?? `method ${className}.${methodName} from ${dexCid}`,
77
+ async exec(t, dexCid, className, methodName) {
78
+ const dexStream = await fetchCid(dexCid);
79
+ const dex = await runParser(dalvikExecutableParser, dexStream, uint8ArrayParserInputCompanion, {
80
+ errorJoinMode: 'all',
81
+ });
82
+ const classDef = dex.classDefinitions.find(c => c.class === className);
83
+ t.truthy(classDef, `Class ${className} not found`);
84
+ const allMethods = [
85
+ ...(classDef.classData?.directMethods ?? []),
86
+ ...(classDef.classData?.virtualMethods ?? []),
87
+ ];
88
+ const method = allMethods.find(m => m.method.name === methodName);
89
+ t.truthy(method, `Method ${methodName} not found in ${className}`);
90
+ t.snapshot(method);
91
+ },
92
+ });
93
+ test.serial(methodMacro, 'bafkreifycfnx4xf3nlml4qavlyxr6bes66nxsow3iaqjghewfsozoj2h3q', 'Lpl/czak/minimal/MainActivity;', 'getPackedSwitchResult');
@@ -148,6 +148,9 @@ const parseAllClassesInDexAgainstSmaliMacro = test.macro({
148
148
  },
149
149
  });
150
150
  const testCasesByCid = {
151
+ bafkreifycfnx4xf3nlml4qavlyxr6bes66nxsow3iaqjghewfsozoj2h3q: [
152
+ { smaliFilePath: 'pl/czak/minimal/MainActivity', isolate: true },
153
+ ],
151
154
  bafybeicb3qajmwy6li7hche2nkucvytaxcyxhwhphmi73tgydjzmyoqoda: [
152
155
  { smaliFilePath: 'androidx/activity/ComponentActivity$1', isolate: true },
153
156
  { smaliFilePath: 'androidx/activity/R$id', isolate: true },
@@ -1,4 +1,4 @@
1
1
  import { type DalvikExecutable } from '../dalvikExecutable.js';
2
- import { type DalvikBytecode } from '../dalvikBytecodeParser.js';
2
+ import { type DalvikBytecodeOperation } from '../dalvikBytecodeParser/addressConversion.js';
3
3
  import { type PoolBuilders } from './poolBuilders.js';
4
- export declare function scanForPoolReferences(dalvikExecutable: DalvikExecutable<DalvikBytecode>, poolBuilders: PoolBuilders): void;
4
+ export declare function scanForPoolReferences(dalvikExecutable: DalvikExecutable<DalvikBytecodeOperation[]>, poolBuilders: PoolBuilders): void;
@@ -1,6 +1,6 @@
1
1
  import { type Unparser } from '../unparser.js';
2
2
  import { type DalvikExecutableAccessFlags, type DalvikExecutableClassData, type DalvikExecutableCode, type DalvikExecutableDebugInfo, type DalvikExecutableEncodedValue, type DalvikExecutableField, type DalvikExecutableMethod, type DalvikExecutablePrototype } from '../dalvikExecutable.js';
3
- import { type DalvikBytecode } from '../dalvikBytecodeParser.js';
3
+ import { type DalvikBytecodeOperation } from '../dalvikBytecodeParser/addressConversion.js';
4
4
  import { type PoolBuilders } from './poolBuilders.js';
5
5
  import { WriteLater } from '../unparserContext.js';
6
6
  export declare function createSectionUnparsers(poolBuilders: PoolBuilders): {
@@ -14,8 +14,8 @@ export declare function createSectionUnparsers(poolBuilders: PoolBuilders): {
14
14
  debugInfoUnparser: Unparser<DalvikExecutableDebugInfo, Uint8Array<ArrayBufferLike>>;
15
15
  codeItemUnparser: (callback?: (result: {
16
16
  debugInfoOffsetWriteLater?: WriteLater<Uint8Array, number>;
17
- }) => void) => Unparser<DalvikExecutableCode<DalvikBytecode>, Uint8Array>;
18
- classDataUnparser: (codeOffsetMap: Map<DalvikExecutableCode<DalvikBytecode>, number>) => Unparser<DalvikExecutableClassData<DalvikBytecode>, Uint8Array>;
17
+ }) => void) => Unparser<DalvikExecutableCode<DalvikBytecodeOperation[]>, Uint8Array>;
18
+ classDataUnparser: (codeOffsetMap: Map<DalvikExecutableCode<DalvikBytecodeOperation[]>, number>) => Unparser<DalvikExecutableClassData<DalvikBytecodeOperation[]>, Uint8Array>;
19
19
  accessFlagsToNumber: (accessFlags: DalvikExecutableAccessFlags) => number;
20
20
  getStringIndex: (str: string | undefined) => number;
21
21
  getTypeIndex: (typeDescriptor: string | undefined) => number;
@@ -5,7 +5,9 @@ async function* yieldAndCapture(gen) {
5
5
  }
6
6
  return value;
7
7
  }
8
- import { dalvikBytecodeUnparser } from '../dalvikBytecodeUnparser.js';
8
+ import { rawDalvikBytecodeUnparser } from '../dalvikBytecodeUnparser.js';
9
+ import { buildIndexToCodeUnitMapFromResolved, instructionIndexToCodeUnit, wrapBranchOffsets, convertInstructionOffsetsToBranchOffsets, } from '../dalvikBytecodeParser/addressConversion.js';
10
+ import { isoCodeUnit, isoInstructionIndex } from '../dalvikExecutableParser/typedNumbers.js';
9
11
  import { ubyteUnparser, ushortUnparser, uintUnparser } from '../dalvikBytecodeUnparser/formatUnparsers.js';
10
12
  import { encodeModifiedUtf8, sleb128Unparser, uleb128p1Unparser, uleb128Unparser } from './utils.js';
11
13
  export function createSectionUnparsers(poolBuilders) {
@@ -461,17 +463,26 @@ export function createSectionUnparsers(poolBuilders) {
461
463
  if (callback) {
462
464
  callback({ debugInfoOffsetWriteLater });
463
465
  }
464
- const instructionsSizeInShorts = await calculateInstructionsSize(input.instructions);
466
+ // Convert branch offsets from instruction offsets back to code units
467
+ // Tier 3 (plain numbers) -> Tier 2 (InstructionIndex) -> Tier 1 (CodeUnit)
468
+ const rawInstructions = convertInstructionOffsetsToBranchOffsets(wrapBranchOffsets(input.instructions));
469
+ const instructionsSizeInShorts = await calculateRawInstructionsSize(rawInstructions);
465
470
  yield* uintUnparser(instructionsSizeInShorts, unparserContext);
466
- yield* dalvikBytecodeUnparser(input.instructions, unparserContext);
471
+ yield* rawDalvikBytecodeUnparser(rawInstructions, unparserContext);
467
472
  if (input.tries.length > 0 && instructionsSizeInShorts % 2 !== 0) {
468
473
  yield* ushortUnparser(0, unparserContext);
469
474
  }
470
475
  if (input.tries.length > 0) {
476
+ // Build index to code unit mapping for address conversion
477
+ const indexToCodeUnitMap = buildIndexToCodeUnitMapFromResolved(input.instructions);
471
478
  const handlerOffsetWriteLaters = [];
472
479
  for (const tryBlock of input.tries) {
473
- yield* uintUnparser(tryBlock.startAddress, unparserContext);
474
- yield* ushortUnparser(tryBlock.instructionCount, unparserContext);
480
+ // Convert instruction indices back to code unit offsets
481
+ const startAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(tryBlock.startInstructionIndex), indexToCodeUnitMap));
482
+ const endAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(tryBlock.startInstructionIndex + tryBlock.instructionCount), indexToCodeUnitMap));
483
+ const instructionCountCodeUnits = endAddressCodeUnit - startAddressCodeUnit;
484
+ yield* uintUnparser(startAddressCodeUnit, unparserContext);
485
+ yield* ushortUnparser(instructionCountCodeUnits, unparserContext);
475
486
  const handlerOffsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(2));
476
487
  handlerOffsetWriteLaters.push(handlerOffsetWriteLater);
477
488
  }
@@ -482,7 +493,7 @@ export function createSectionUnparsers(poolBuilders) {
482
493
  const handler = tryBlock.handler;
483
494
  const handlerOffset = unparserContext.position - handlersStartOffset;
484
495
  yield* unparserContext.writeEarlier(handlerOffsetWriteLaters[i], ushortUnparser, handlerOffset);
485
- if (handler.catchAllAddress !== undefined) {
496
+ if (handler.catchAllInstructionIndex !== undefined) {
486
497
  yield* sleb128Unparser(-handler.handlers.length, unparserContext);
487
498
  }
488
499
  else {
@@ -491,23 +502,27 @@ export function createSectionUnparsers(poolBuilders) {
491
502
  for (const handlerItem of handler.handlers) {
492
503
  const typeIndex = getTypeIndex(handlerItem.type);
493
504
  yield* uleb128Unparser(typeIndex, unparserContext);
494
- yield* uleb128Unparser(handlerItem.address, unparserContext);
505
+ // Convert handler address from instruction index to code unit offset
506
+ const handlerAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(handlerItem.handlerInstructionIndex), indexToCodeUnitMap));
507
+ yield* uleb128Unparser(handlerAddressCodeUnit, unparserContext);
495
508
  }
496
- if (handler.catchAllAddress !== undefined) {
497
- yield* uleb128Unparser(handler.catchAllAddress, unparserContext);
509
+ if (handler.catchAllInstructionIndex !== undefined) {
510
+ // Convert catchAllInstructionIndex from instruction index to code unit offset
511
+ const catchAllAddressCodeUnit = isoCodeUnit.unwrap(instructionIndexToCodeUnit(isoInstructionIndex.wrap(handler.catchAllInstructionIndex), indexToCodeUnitMap));
512
+ yield* uleb128Unparser(catchAllAddressCodeUnit, unparserContext);
498
513
  }
499
514
  }
500
515
  }
501
516
  };
502
517
  };
503
- async function calculateInstructionsSize(instructions) {
518
+ async function calculateRawInstructionsSize(instructions) {
504
519
  let totalSize = 0;
505
520
  const mockContext = {
506
521
  position: 0,
507
522
  writeLater: () => { throw new Error('Not supported'); },
508
523
  writeEarlier: () => { throw new Error('Not supported'); },
509
524
  };
510
- for await (const chunk of dalvikBytecodeUnparser(instructions, mockContext)) {
525
+ for await (const chunk of rawDalvikBytecodeUnparser(instructions, mockContext)) {
511
526
  if (chunk instanceof Uint8Array) {
512
527
  totalSize += chunk.length;
513
528
  }
@@ -1,4 +1,4 @@
1
1
  import { type Unparser } from './unparser.js';
2
2
  import { type DalvikExecutable } from './dalvikExecutable.js';
3
- import { type DalvikBytecode } from './dalvikBytecodeParser.js';
4
- export declare const dalvikExecutableUnparser: Unparser<DalvikExecutable<DalvikBytecode>, Uint8Array>;
3
+ import { type DalvikBytecodeOperation } from './dalvikBytecodeParser/addressConversion.js';
4
+ export declare const dalvikExecutableUnparser: Unparser<DalvikExecutable<DalvikBytecodeOperation[]>, Uint8Array>;
@@ -10,6 +10,7 @@ import { uint8ArrayUnparserOutputCompanion } from './unparserOutputCompanion.js'
10
10
  import { uint8ArrayAsyncIterableToUint8Array } from './uint8Array.js';
11
11
  const seed = process.env.SEED ? Number(process.env.SEED) : undefined;
12
12
  // Use minimal bytecode for testing - simple nop and return-void instructions
13
+ // These operations have no branch offsets, so they work the same in all tiers
13
14
  const arbitraryMinimalBytecode = fc.array(fc.oneof(fc.constant({
14
15
  operation: 'nop',
15
16
  }), fc.constant({
@@ -19,7 +20,7 @@ testProp('dalvikExecutableUnparser roundtrip', [createArbitraryDalvikExecutable(
19
20
  // Unparse to bytes
20
21
  const unparsedIterable = runUnparser(dalvikExecutableUnparser, dalvikExecutable, uint8ArrayUnparserOutputCompanion);
21
22
  const bytes = await uint8ArrayAsyncIterableToUint8Array(unparsedIterable);
22
- // Re-parse
23
+ // Re-parse (parser now outputs Tier 3 directly)
23
24
  const reparsed = await runParser(dalvikExecutableParser, bytes, uint8ArrayParserInputCompanion, {
24
25
  errorStack: true,
25
26
  });
@@ -1,3 +1,5 @@
1
- import { type Parser } from './parser.js';
2
- import { type DeriveSequenceElement } from './sequence.js';
3
- export declare const createDisjunctionParser: <Output, Sequence, Element = DeriveSequenceElement<Sequence>>(childParsers: Array<Parser<unknown, Sequence, Element>>) => Parser<Output, Sequence, Element>;
1
+ import { type Parser, type ParserOutput, type ParserSequence } from './parser.js';
2
+ type DisjunctionParserOutput<Parsers extends readonly unknown[]> = ParserOutput<Parsers[number]>;
3
+ type InferSequenceFromParserArray<T extends readonly unknown[]> = ParserSequence<T[number]>;
4
+ export declare function createDisjunctionParser<const Parsers extends readonly Parser<any, any, any>[]>(childParsers: Parsers): Parser<DisjunctionParserOutput<Parsers>, InferSequenceFromParserArray<Parsers>>;
5
+ export {};