@futpib/parser 1.0.1 → 1.0.3

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 (425) hide show
  1. package/.github/copilot-instructions.md +149 -0
  2. package/.github/workflows/copilot-setup-steps.yml +18 -0
  3. package/.github/workflows/main.yml +29 -8
  4. package/.yarn/releases/yarn-4.9.4.cjs +942 -0
  5. package/.yarnrc.yml +1 -1
  6. package/build/allSettledStream.js +32 -14
  7. package/build/allSettledStream.test.js +32 -0
  8. package/build/androidPackage.d.ts +39 -0
  9. package/build/androidPackageParser.d.ts +17 -0
  10. package/build/androidPackageParser.js +185 -0
  11. package/build/androidPackageParser.test.js +22 -0
  12. package/build/androidPackageUnparser.d.ts +4 -0
  13. package/build/androidPackageUnparser.js +94 -0
  14. package/build/androidPackageUnparser.test.js +26 -0
  15. package/build/arbitrarilySlicedAsyncInterable.d.ts +3 -1
  16. package/build/arbitrarilySlicedAsyncInterable.js +3 -3
  17. package/build/arbitrarilySlicedAsyncInterator.js +2 -1
  18. package/build/arbitraryDalvikBytecode.d.ts +4 -0
  19. package/build/arbitraryDalvikBytecode.js +640 -0
  20. package/build/arbitraryDalvikExecutable.d.ts +3 -0
  21. package/build/arbitraryDalvikExecutable.js +282 -0
  22. package/build/arbitraryDosDateTime.js +1 -0
  23. package/build/arbitraryZipStream.js +1 -1
  24. package/build/arrayParser.js +2 -2
  25. package/build/arrayParser.test.js +3 -3
  26. package/build/arrayUnparser.d.ts +1 -1
  27. package/build/backsmali.d.ts +3 -0
  28. package/build/backsmali.js +50 -0
  29. package/build/bsonParser.js +6 -2
  30. package/build/customInvariant.d.ts +2 -1
  31. package/build/customInvariant.js +4 -6
  32. package/build/dalvikBytecodeParser/formatParsers.d.ts +171 -0
  33. package/build/dalvikBytecodeParser/formatParsers.js +304 -0
  34. package/build/dalvikBytecodeParser/formatSizes.d.ts +34 -0
  35. package/build/dalvikBytecodeParser/formatSizes.js +34 -0
  36. package/build/dalvikBytecodeParser/operationFormats.d.ts +225 -0
  37. package/build/dalvikBytecodeParser/operationFormats.js +225 -0
  38. package/build/dalvikBytecodeParser.d.ts +1207 -0
  39. package/build/dalvikBytecodeParser.js +1289 -0
  40. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +152 -0
  41. package/build/dalvikBytecodeUnparser/formatUnparsers.js +225 -0
  42. package/build/dalvikBytecodeUnparser.d.ts +3 -0
  43. package/build/dalvikBytecodeUnparser.js +642 -0
  44. package/build/dalvikBytecodeUnparser.test.js +25 -0
  45. package/build/dalvikExecutable.d.ts +215 -0
  46. package/build/dalvikExecutable.js +56 -0
  47. package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +4 -0
  48. package/build/dalvikExecutableParser/stringSyntaxParser.js +76 -0
  49. package/build/dalvikExecutableParser/typeParsers.d.ts +11 -0
  50. package/build/dalvikExecutableParser/typeParsers.js +39 -0
  51. package/build/dalvikExecutableParser/typedNumbers.d.ts +106 -0
  52. package/build/dalvikExecutableParser/typedNumbers.js +18 -0
  53. package/build/dalvikExecutableParser.d.ts +5 -0
  54. package/build/dalvikExecutableParser.js +1757 -0
  55. package/build/dalvikExecutableParser.test.js +72 -0
  56. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +275 -0
  57. package/build/dalvikExecutableUnparser/annotationUnparsers.d.ts +14 -0
  58. package/build/dalvikExecutableUnparser/annotationUnparsers.js +97 -0
  59. package/build/dalvikExecutableUnparser/poolBuilders.d.ts +49 -0
  60. package/build/dalvikExecutableUnparser/poolBuilders.js +140 -0
  61. package/build/dalvikExecutableUnparser/poolScanners.d.ts +4 -0
  62. package/build/dalvikExecutableUnparser/poolScanners.js +220 -0
  63. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +25 -0
  64. package/build/dalvikExecutableUnparser/sectionUnparsers.js +581 -0
  65. package/build/dalvikExecutableUnparser/utils.d.ts +10 -0
  66. package/build/dalvikExecutableUnparser/utils.js +108 -0
  67. package/build/dalvikExecutableUnparser.d.ts +4 -0
  68. package/build/dalvikExecutableUnparser.js +406 -0
  69. package/build/dalvikExecutableUnparser.test.js +31 -0
  70. package/build/debugLogInputParser.d.ts +4 -0
  71. package/build/debugLogInputParser.js +16 -0
  72. package/build/debugLogParser.js +14 -3
  73. package/build/disjunctionParser.d.ts +2 -1
  74. package/build/disjunctionParser.js +6 -4
  75. package/build/elementTerminatedArrayParser.d.ts +3 -0
  76. package/build/elementTerminatedArrayParser.js +18 -0
  77. package/build/elementTerminatedArrayParser.test.js +52 -0
  78. package/build/elementTerminatedSequenceArrayParser.d.ts +3 -0
  79. package/build/elementTerminatedSequenceArrayParser.js +32 -0
  80. package/build/elementTerminatedSequenceArrayParser.test.js +34 -0
  81. package/build/elementTerminatedSequenceParser.d.ts +3 -0
  82. package/build/elementTerminatedSequenceParser.js +27 -0
  83. package/build/elementTerminatedSequenceParser.test.js +34 -0
  84. package/build/endOfInputParser.d.ts +1 -1
  85. package/build/exactElementParser.js +10 -5
  86. package/build/exactElementSwitchParser.d.ts +3 -0
  87. package/build/exactElementSwitchParser.js +22 -0
  88. package/build/exactSequenceParser.d.ts +2 -1
  89. package/build/exactSequenceParser.js +12 -2
  90. package/build/fetchCid.d.ts +1 -0
  91. package/build/fetchCid.js +103 -0
  92. package/build/fetchCid.test.js +16 -0
  93. package/build/fixedLengthSequenceParser.d.ts +1 -0
  94. package/build/fixedLengthSequenceParser.js +18 -1
  95. package/build/fixedLengthSequenceParser.test.js +41 -0
  96. package/build/hasExecutable.d.ts +1 -0
  97. package/build/hasExecutable.js +8 -0
  98. package/build/highResolutionTimer.d.ts +16 -0
  99. package/build/highResolutionTimer.js +42 -0
  100. package/build/inputReader.d.ts +11 -0
  101. package/build/inputReader.js +37 -0
  102. package/build/inputReader.test.js +161 -8
  103. package/build/inputReaderState.d.ts +10 -0
  104. package/build/inputReaderState.js +16 -0
  105. package/build/inspect.d.ts +1 -0
  106. package/build/inspect.js +7 -0
  107. package/build/javaKeyStoreParser.test.js +8 -8
  108. package/build/jsonParser.d.ts +2 -0
  109. package/build/jsonParser.js +19 -22
  110. package/build/lazyMessageError.d.ts +48 -0
  111. package/build/lazyMessageError.js +53 -0
  112. package/build/lazyMessageError.test.d.ts +1 -0
  113. package/build/lazyMessageError.test.js +15 -0
  114. package/build/leb128Parser.d.ts +7 -0
  115. package/build/leb128Parser.js +82 -0
  116. package/build/leb128Parser.test.d.ts +1 -0
  117. package/build/leb128Parser.test.js +107 -0
  118. package/build/lookaheadParser.d.ts +2 -0
  119. package/build/lookaheadParser.js +14 -0
  120. package/build/negativeLookaheadParser.js +22 -16
  121. package/build/negativeLookaheadParser.test.d.ts +1 -0
  122. package/build/negativeLookaheadParser.test.js +30 -0
  123. package/build/noStackCaptureOverheadError.d.ts +4 -0
  124. package/build/noStackCaptureOverheadError.js +9 -0
  125. package/build/noStackCaptureOverheadError.test.d.ts +1 -0
  126. package/build/noStackCaptureOverheadError.test.js +15 -0
  127. package/build/nonEmptyArrayParser.d.ts +2 -0
  128. package/build/nonEmptyArrayParser.js +32 -0
  129. package/build/nonEmptyArrayParser.test.d.ts +1 -0
  130. package/build/nonEmptyArrayParser.test.js +17 -0
  131. package/build/optionalParser.js +2 -2
  132. package/build/parser.d.ts +11 -1
  133. package/build/parser.js +82 -32
  134. package/build/parser.test.js +141 -25
  135. package/build/parserAccessorParser.js +9 -1
  136. package/build/parserConsumedSequenceParser.d.ts +1 -1
  137. package/build/parserConsumedSequenceParser.js +21 -16
  138. package/build/parserContext.d.ts +22 -6
  139. package/build/parserContext.js +113 -57
  140. package/build/parserContext.test.js +33 -2
  141. package/build/parserCreatorCompose.d.ts +1 -0
  142. package/build/parserCreatorCompose.js +8 -2
  143. package/build/parserError.d.ts +605 -40
  144. package/build/parserError.js +98 -53
  145. package/build/parserImplementationInvariant.d.ts +1 -1
  146. package/build/parserImplementationInvariant.js +2 -2
  147. package/build/parserInputCompanion.d.ts +15 -0
  148. package/build/parserInputCompanion.js +38 -0
  149. package/build/promiseCompose.d.ts +1 -1
  150. package/build/promiseCompose.js +11 -1
  151. package/build/promiseSettled.d.ts +1 -0
  152. package/build/promiseSettled.js +4 -0
  153. package/build/separatedArrayParser.d.ts +2 -0
  154. package/build/separatedArrayParser.js +39 -0
  155. package/build/separatedArrayParser.test.d.ts +1 -0
  156. package/build/separatedArrayParser.test.js +21 -0
  157. package/build/separatedNonEmptyArrayParser.d.ts +2 -0
  158. package/build/separatedNonEmptyArrayParser.js +40 -0
  159. package/build/separatedNonEmptyArrayParser.test.d.ts +1 -0
  160. package/build/separatedNonEmptyArrayParser.test.js +66 -0
  161. package/build/sequenceBuffer.d.ts +10 -0
  162. package/build/sequenceBuffer.js +54 -2
  163. package/build/sequenceBuffer.test.js +57 -0
  164. package/build/sequenceTerminatedSequenceParser.d.ts +5 -0
  165. package/build/sequenceTerminatedSequenceParser.js +32 -0
  166. package/build/sequenceTerminatedSequenceParser.test.d.ts +1 -0
  167. package/build/sequenceTerminatedSequenceParser.test.js +37 -0
  168. package/build/sequenceUnparser.d.ts +1 -1
  169. package/build/skipParser.d.ts +1 -1
  170. package/build/skipParser.js +4 -2
  171. package/build/skipToParser.d.ts +2 -0
  172. package/build/skipToParser.js +11 -0
  173. package/build/sliceBoundedParser.d.ts +1 -1
  174. package/build/sliceBoundedParser.js +7 -2
  175. package/build/sliceBoundedParser.test.js +30 -1
  176. package/build/smali.d.ts +1 -0
  177. package/build/smali.js +21 -0
  178. package/build/smaliParser.d.ts +68 -0
  179. package/build/smaliParser.js +2081 -0
  180. package/build/smaliParser.test.d.ts +1 -0
  181. package/build/smaliParser.test.js +410 -0
  182. package/build/stringFromAsyncIterable.d.ts +1 -0
  183. package/build/stringFromAsyncIterable.js +7 -0
  184. package/build/terminatedArrayParser.d.ts +3 -1
  185. package/build/terminatedArrayParser.js +79 -2
  186. package/build/terminatedArrayParser.test.d.ts +1 -0
  187. package/build/terminatedArrayParser.test.js +131 -0
  188. package/build/toAsyncIterable.d.ts +1 -0
  189. package/build/toAsyncIterable.js +7 -0
  190. package/build/toAsyncIterator.d.ts +1 -0
  191. package/build/toAsyncIterator.js +33 -0
  192. package/build/tupleParser.d.ts +4 -0
  193. package/build/tupleParser.js +1 -5
  194. package/build/unionParser.d.ts +2 -1
  195. package/build/unionParser.js +29 -14
  196. package/build/unionParser.test.d.ts +1 -0
  197. package/build/unionParser.test.js +60 -0
  198. package/build/unparser.d.ts +3 -3
  199. package/build/unparser.js +6 -4
  200. package/build/unparser.test.js +7 -19
  201. package/build/unparserContext.d.ts +2 -2
  202. package/build/unparserContext.js +2 -3
  203. package/build/unparserError.d.ts +2 -1
  204. package/build/unparserError.js +2 -1
  205. package/build/unparserImplementationInvariant.d.ts +1 -1
  206. package/build/unparserOutputCompanion.d.ts +1 -1
  207. package/build/unparserOutputCompanion.js +1 -1
  208. package/build/zipParser.d.ts +7 -2
  209. package/build/zipParser.js +36 -12
  210. package/build/zipUnparser.d.ts +7 -4
  211. package/build/zipUnparser.js +64 -45
  212. package/build/zipUnparser.test.js +15 -15
  213. package/package.json +33 -24
  214. package/src/allSettledStream.test.ts +40 -0
  215. package/src/allSettledStream.ts +47 -15
  216. package/src/androidPackage.ts +48 -0
  217. package/src/androidPackageParser.test.ts +27 -0
  218. package/src/{apkParser.test.ts.md → androidPackageParser.test.ts.md} +4 -4
  219. package/src/androidPackageParser.test.ts.snap +0 -0
  220. package/src/androidPackageParser.ts +398 -0
  221. package/src/androidPackageUnparser.test.ts +34 -0
  222. package/src/androidPackageUnparser.ts +126 -0
  223. package/src/arbitrarilySlicedAsyncInterable.ts +7 -2
  224. package/src/arbitrarilySlicedAsyncInterator.ts +4 -4
  225. package/src/arbitraryDalvikBytecode.ts +992 -0
  226. package/src/arbitraryDalvikExecutable.ts +434 -0
  227. package/src/arbitraryDosDateTime.ts +1 -0
  228. package/src/arbitraryZipStream.ts +1 -1
  229. package/src/arrayParser.test.ts +3 -3
  230. package/src/arrayParser.ts +2 -2
  231. package/src/arrayUnparser.ts +2 -2
  232. package/src/backsmali.ts +74 -0
  233. package/src/bsonParser.test.ts +12 -14
  234. package/src/bsonParser.ts +13 -2
  235. package/src/customInvariant.ts +8 -12
  236. package/src/dalvikBytecodeParser/formatParsers.ts +780 -0
  237. package/src/dalvikBytecodeParser/formatSizes.ts +35 -0
  238. package/src/dalvikBytecodeParser/operationFormats.ts +226 -0
  239. package/src/dalvikBytecodeParser.ts +2873 -0
  240. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +442 -0
  241. package/src/dalvikBytecodeUnparser.test.ts +44 -0
  242. package/src/dalvikBytecodeUnparser.ts +758 -0
  243. package/src/dalvikExecutable.ts +282 -0
  244. package/src/dalvikExecutableParser/stringSyntaxParser.ts +145 -0
  245. package/src/dalvikExecutableParser/typeParsers.ts +74 -0
  246. package/src/dalvikExecutableParser/typedNumbers.ts +57 -0
  247. package/src/dalvikExecutableParser.test.ts +89 -0
  248. package/src/dalvikExecutableParser.test.ts.md +634 -0
  249. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  250. package/src/dalvikExecutableParser.ts +3245 -0
  251. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +363 -0
  252. package/src/dalvikExecutableUnparser/annotationUnparsers.ts +135 -0
  253. package/src/dalvikExecutableUnparser/poolBuilders.ts +189 -0
  254. package/src/dalvikExecutableUnparser/poolScanners.ts +297 -0
  255. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +683 -0
  256. package/src/dalvikExecutableUnparser/utils.ts +149 -0
  257. package/src/dalvikExecutableUnparser.test.ts +57 -0
  258. package/src/dalvikExecutableUnparser.ts +581 -0
  259. package/src/debugLogInputParser.ts +28 -0
  260. package/src/debugLogParser.ts +19 -3
  261. package/src/disjunctionParser.ts +12 -7
  262. package/src/elementTerminatedArrayParser.test.ts +99 -0
  263. package/src/elementTerminatedArrayParser.ts +31 -0
  264. package/src/elementTerminatedSequenceArrayParser.test.ts +52 -0
  265. package/src/elementTerminatedSequenceArrayParser.ts +52 -0
  266. package/src/elementTerminatedSequenceParser.test.ts +52 -0
  267. package/src/elementTerminatedSequenceParser.ts +43 -0
  268. package/src/endOfInputParser.ts +1 -1
  269. package/src/exactElementParser.ts +17 -11
  270. package/src/exactElementSwitchParser.ts +41 -0
  271. package/src/exactSequenceParser.ts +23 -2
  272. package/src/fetchCid.test.ts +20 -0
  273. package/src/fetchCid.ts +121 -0
  274. package/src/fixedLengthSequenceParser.test.ts +75 -0
  275. package/src/fixedLengthSequenceParser.ts +28 -1
  276. package/src/hasExecutable.ts +11 -0
  277. package/src/highResolutionTimer.ts +49 -0
  278. package/src/inputReader.test.ts +204 -8
  279. package/src/inputReader.ts +76 -3
  280. package/src/inputReaderState.ts +33 -0
  281. package/src/inspect.ts +9 -0
  282. package/src/javaKeyStoreParser.test.ts +12 -15
  283. package/src/javaKeyStoreParser.ts +2 -6
  284. package/src/jsonParser.test.ts +2 -4
  285. package/src/jsonParser.ts +46 -62
  286. package/src/lazyMessageError.test.ts +21 -0
  287. package/src/lazyMessageError.ts +88 -0
  288. package/src/leb128Parser.test.ts +173 -0
  289. package/src/leb128Parser.ts +125 -0
  290. package/src/lookaheadParser.ts +19 -0
  291. package/src/negativeLookaheadParser.test.ts +49 -0
  292. package/src/negativeLookaheadParser.ts +27 -15
  293. package/src/noStackCaptureOverheadError.test.ts +17 -0
  294. package/src/noStackCaptureOverheadError.ts +12 -0
  295. package/src/nonEmptyArrayParser.test.ts +21 -0
  296. package/src/nonEmptyArrayParser.ts +44 -0
  297. package/src/optionalParser.ts +3 -2
  298. package/src/parser.test.ts +203 -31
  299. package/src/parser.test.ts.md +34 -27
  300. package/src/parser.test.ts.snap +0 -0
  301. package/src/parser.ts +172 -45
  302. package/src/parserAccessorParser.ts +12 -2
  303. package/src/parserConsumedSequenceParser.ts +26 -17
  304. package/src/parserContext.test.ts +37 -2
  305. package/src/parserContext.ts +185 -79
  306. package/src/parserCreatorCompose.ts +20 -2
  307. package/src/parserError.ts +144 -61
  308. package/src/parserImplementationInvariant.ts +3 -3
  309. package/src/parserInputCompanion.ts +55 -0
  310. package/src/promiseCompose.ts +17 -3
  311. package/src/promiseSettled.ts +6 -0
  312. package/src/separatedArrayParser.test.ts +34 -0
  313. package/src/separatedArrayParser.ts +55 -0
  314. package/src/separatedNonEmptyArrayParser.test.ts +117 -0
  315. package/src/separatedNonEmptyArrayParser.ts +61 -0
  316. package/src/sequenceBuffer.test.ts +70 -0
  317. package/src/sequenceBuffer.ts +88 -2
  318. package/src/sequenceTerminatedSequenceParser.test.ts +58 -0
  319. package/src/sequenceTerminatedSequenceParser.ts +62 -0
  320. package/src/sequenceUnparser.ts +2 -2
  321. package/src/skipParser.ts +7 -5
  322. package/src/skipToParser.ts +16 -0
  323. package/src/sliceBoundedParser.test.ts +35 -1
  324. package/src/sliceBoundedParser.ts +19 -1
  325. package/src/smali.ts +29 -0
  326. package/src/smaliParser.test.ts +443 -0
  327. package/src/smaliParser.test.ts.md +3907 -0
  328. package/src/smaliParser.test.ts.snap +0 -0
  329. package/src/smaliParser.ts +3348 -0
  330. package/src/stringFromAsyncIterable.ts +9 -0
  331. package/src/terminatedArrayParser.test.ts +258 -0
  332. package/src/terminatedArrayParser.ts +109 -6
  333. package/src/toAsyncIterable.ts +7 -0
  334. package/src/toAsyncIterator.ts +48 -0
  335. package/src/tupleParser.ts +8 -5
  336. package/src/uint8Array.ts +2 -3
  337. package/src/unionParser.test.ts +78 -0
  338. package/src/unionParser.ts +47 -21
  339. package/src/unparser.test.ts +18 -34
  340. package/src/unparser.ts +13 -9
  341. package/src/unparserContext.ts +9 -13
  342. package/src/unparserError.ts +2 -1
  343. package/src/unparserImplementationInvariant.ts +1 -1
  344. package/src/unparserOutputCompanion.ts +1 -1
  345. package/src/zip.ts +2 -6
  346. package/src/zipParser.ts +71 -20
  347. package/src/zipUnparser.test.ts +19 -19
  348. package/src/zipUnparser.ts +139 -90
  349. package/tsconfig.json +7 -1
  350. package/xo.config.ts +15 -0
  351. package/.yarn/releases/yarn-4.5.3.cjs +0 -934
  352. package/build/apk.d.ts +0 -39
  353. package/build/apkParser.d.ts +0 -16
  354. package/build/apkParser.js +0 -164
  355. package/build/apkParser.test.js +0 -22
  356. package/build/apkUnparser.d.ts +0 -4
  357. package/build/apkUnparser.js +0 -90
  358. package/build/apkUnparser.test.js +0 -26
  359. package/build/arbitraryDosDate.d.ts +0 -2
  360. package/build/arbitraryDosDate.js +0 -8
  361. package/build/arbitraryZipEntry.d.ts +0 -3
  362. package/build/arbitraryZipEntry.js +0 -26
  363. package/build/createDisjunctionParser.d.ts +0 -2
  364. package/build/createDisjunctionParser.js +0 -47
  365. package/build/createExactParser.d.ts +0 -2
  366. package/build/createExactParser.js +0 -12
  367. package/build/createSequentialUnionParser.d.ts +0 -2
  368. package/build/createSequentialUnionParser.js +0 -69
  369. package/build/fixedLengthChunkParser.d.ts +0 -2
  370. package/build/fixedLengthChunkParser.js +0 -12
  371. package/build/fixedLengthParser.d.ts +0 -2
  372. package/build/fixedLengthParser.js +0 -12
  373. package/build/inputChunkBuffer.d.ts +0 -15
  374. package/build/inputChunkBuffer.js +0 -40
  375. package/build/inputChunkBuffer.test.js +0 -34
  376. package/build/inputCompanion.d.ts +0 -18
  377. package/build/inputCompanion.js +0 -28
  378. package/build/invariantDefined.d.ts +0 -1
  379. package/build/invariantDefined.js +0 -5
  380. package/build/invariantIdentity.d.ts +0 -3
  381. package/build/invariantIdentity.js +0 -5
  382. package/build/javaKeystoreParser.d.ts +0 -2
  383. package/build/javaKeystoreParser.js +0 -7
  384. package/build/jsonParser2.d.ts +0 -3
  385. package/build/jsonParser2.js +0 -52
  386. package/build/jsonParser2.test.js +0 -22
  387. package/build/negativeLookahead.d.ts +0 -2
  388. package/build/negativeLookahead.js +0 -18
  389. package/build/parserCompose.d.ts +0 -3
  390. package/build/parserCompose.js +0 -7
  391. package/build/parserImplementationInvariantInvariant.d.ts +0 -3
  392. package/build/parserImplementationInvariantInvariant.js +0 -15
  393. package/build/parserInvariant.d.ts +0 -4
  394. package/build/parserInvariant.js +0 -11
  395. package/build/promiseFish.d.ts +0 -1
  396. package/build/promiseFish.js +0 -3
  397. package/build/sequenceParser.d.ts +0 -3
  398. package/build/sequenceParser.js +0 -10
  399. package/build/terminatedSequenceParser.d.ts +0 -2
  400. package/build/terminatedSequenceParser.js +0 -24
  401. package/build/unparserInputCompanion.d.ts +0 -15
  402. package/build/unparserInputCompanion.js +0 -13
  403. package/build/zipEntry.d.ts +0 -28
  404. package/build/zipFile.d.ts +0 -32
  405. package/build/zipFileEntry.d.ts +0 -6
  406. package/src/apk.ts +0 -48
  407. package/src/apkParser.test.ts +0 -30
  408. package/src/apkParser.test.ts.snap +0 -0
  409. package/src/apkParser.ts +0 -392
  410. package/src/apkUnparser.test.ts +0 -37
  411. package/src/apkUnparser.ts +0 -120
  412. package/src/invariantDefined.ts +0 -6
  413. package/src/invariantIdentity.ts +0 -8
  414. /package/build/{apk.js → androidPackage.js} +0 -0
  415. /package/build/{apkParser.test.d.ts → androidPackageParser.test.d.ts} +0 -0
  416. /package/build/{apkUnparser.test.d.ts → androidPackageUnparser.test.d.ts} +0 -0
  417. /package/build/{arbitraryDosPermissions.d.ts → dalvikBytecodeUnparser.test.d.ts} +0 -0
  418. /package/build/{arbitraryDosPermissions.js → dalvikExecutableParser.test.d.ts} +0 -0
  419. /package/build/{inputChunkBuffer.test.d.ts → dalvikExecutableParserAgainstSmaliParser.test.d.ts} +0 -0
  420. /package/build/{jsonParser2.test.d.ts → dalvikExecutableUnparser.test.d.ts} +0 -0
  421. /package/build/{parserParsingInvariant.d.ts → elementTerminatedArrayParser.test.d.ts} +0 -0
  422. /package/build/{parserParsingInvariant.js → elementTerminatedSequenceArrayParser.test.d.ts} +0 -0
  423. /package/build/{zipEntry.js → elementTerminatedSequenceParser.test.d.ts} +0 -0
  424. /package/build/{zipFile.js → fetchCid.test.d.ts} +0 -0
  425. /package/build/{zipFileEntry.js → fixedLengthSequenceParser.test.d.ts} +0 -0
@@ -0,0 +1,3245 @@
1
+ import invariant from 'invariant';
2
+ import { MUtf8Decoder } from 'mutf-8';
3
+ import { type Iso } from 'monocle-ts';
4
+ import { createExactElementParser } from './exactElementParser.js';
5
+ import { createExactSequenceParser } from './exactSequenceParser.js';
6
+ import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
7
+ import { cloneParser, setParserName, type Parser } from './parser.js';
8
+ import { parserCreatorCompose } from './parserCreatorCompose.js';
9
+ import { promiseCompose } from './promiseCompose.js';
10
+ import { createQuantifierParser } from './quantifierParser.js';
11
+ import { createTupleParser } from './tupleParser.js';
12
+ import { createParserAccessorParser } from './parserAccessorParser.js';
13
+ import { createSkipToParser } from './skipToParser.js';
14
+ import { createLookaheadParser } from './lookaheadParser.js';
15
+ import {
16
+ getIsoTypedNumberArray,
17
+ type IndexIntoFieldIds,
18
+ type IndexIntoMethodIds,
19
+ type IndexIntoPrototypeIds,
20
+ type IndexIntoStringIds,
21
+ type IndexIntoTypeIds,
22
+ isoIndexIntoFieldIds,
23
+ isoIndexIntoMethodIds,
24
+ isoIndexIntoPrototypeIds,
25
+ isoIndexIntoStringIds,
26
+ isoIndexIntoTypeIds,
27
+ isoOffsetFromEncodedCatchHandlerListToEncodedCatchHandler,
28
+ isoOffsetToAnnotationItem,
29
+ isoOffsetToAnnotationsDirectoryItem,
30
+ isoOffsetToAnnotationSetItem,
31
+ isoOffsetToAnnotationSetRefListItem,
32
+ isoOffsetToClassDataItem,
33
+ isoOffsetToCodeItem,
34
+ isoOffsetToDebugInfoItem,
35
+ isoOffsetToEncodedArrayItem,
36
+ isoOffsetToStringDataItem,
37
+ isoOffsetToTypeList,
38
+ type OffsetFromEncodedCatchHandlerListToEncodedCatchHandler,
39
+ type OffsetToAnnotationItem,
40
+ type OffsetToAnnotationsDirectoryItem,
41
+ type OffsetToAnnotationSetItem,
42
+ type OffsetToAnnotationSetRefListItem,
43
+ type OffsetToClassDataItem,
44
+ type OffsetToCodeItem,
45
+ type OffsetToDebugInfoItem,
46
+ type OffsetToEncodedArrayItem,
47
+ type OffsetToStringDataItem,
48
+ type OffsetToTypeList,
49
+ type TypedNumberArray,
50
+ } from './dalvikExecutableParser/typedNumbers.js';
51
+ import { sleb128NumberParser, uleb128NumberParser } from './leb128Parser.js';
52
+ import { createDisjunctionParser } from './disjunctionParser.js';
53
+ import { createElementTerminatedSequenceParser } from './elementTerminatedSequenceParser.js';
54
+ import { createElementTerminatedArrayParserUnsafe } from './elementTerminatedArrayParser.js';
55
+ import {
56
+ createDalvikBytecodeParser, type DalvikBytecode, type DalvikBytecodeOperation, type DalvikBytecodeOperationResolvers, resolveDalvikBytecodeOperation,
57
+ } from './dalvikBytecodeParser.js';
58
+ import {
59
+ byteParser, ubyteParser, uintParser, uleb128p1NumberParser, ushortParser,
60
+ } from './dalvikExecutableParser/typeParsers.js';
61
+ import {
62
+ type DalvikExecutable,
63
+ type DalvikExecutableAccessFlags,
64
+ type DalvikExecutableAnnotation,
65
+ type DalvikExecutableClassAnnotations,
66
+ type DalvikExecutableClassData,
67
+ type DalvikExecutableClassFieldAnnotation,
68
+ type DalvikExecutableClassMethodAnnotation,
69
+ type DalvikExecutableClassParameterAnnotation,
70
+ type DalvikExecutableCode,
71
+ type DalvikExecutableDebugInfo,
72
+ type DalvikExecutableEncodedValue,
73
+ } from './dalvikExecutable.js';
74
+
75
+ // https://source.android.com/docs/core/runtime/dex-format
76
+
77
+ const createByteAlignParser = (byteAlignment: number): Parser<void, Uint8Array> => async parserContext => {
78
+ const toSkip = (byteAlignment - (parserContext.position % byteAlignment)) % byteAlignment;
79
+
80
+ parserContext.skip(toSkip);
81
+ };
82
+
83
+ const byteAlign4Parser: Parser<void, Uint8Array> = createByteAlignParser(4);
84
+
85
+ const dalvikExecutableHeaderVersionParser: Parser<number, Uint8Array> = promiseCompose(
86
+ createTupleParser([
87
+ createExactSequenceParser<Uint8Array>(Buffer.from('dex\n', 'utf8')),
88
+ createFixedLengthSequenceParser(3),
89
+ createExactElementParser(0),
90
+ ]),
91
+ ([ _magic1, versionUint8Array, _magic2 ]) => {
92
+ const versionBuffer = Buffer.from(versionUint8Array);
93
+ const versionString = versionBuffer.toString('utf8');
94
+ const version = Number.parseInt(versionString, 10);
95
+ return version;
96
+ },
97
+ );
98
+
99
+ type SizeOffset = {
100
+ size: number;
101
+ offset: number;
102
+ };
103
+
104
+ const sizeOffsetParser: Parser<SizeOffset, Uint8Array> = promiseCompose(
105
+ createTupleParser([
106
+ uintParser,
107
+ uintParser,
108
+ ]),
109
+ ([ size, offset ]) => ({ size, offset }),
110
+ );
111
+
112
+ type DalvikExecutableHeaderItem = {
113
+ version: number;
114
+ checksum: number;
115
+ sha1Hash: Uint8Array;
116
+ fileSize: number;
117
+ headerSize: number;
118
+ endianTag: number;
119
+ link: SizeOffset;
120
+ mapOffset: number;
121
+ stringIds: SizeOffset;
122
+ typeIds: SizeOffset;
123
+ prototypeIds: SizeOffset;
124
+ fieldIds: SizeOffset;
125
+ methodIds: SizeOffset;
126
+ classDefinitions: SizeOffset;
127
+ data: SizeOffset;
128
+ };
129
+
130
+ const dalvikExecutableHeaderItemParser: Parser<DalvikExecutableHeaderItem, Uint8Array> = promiseCompose(
131
+ createTupleParser([
132
+ dalvikExecutableHeaderVersionParser,
133
+ uintParser,
134
+ createFixedLengthSequenceParser(20),
135
+ uintParser,
136
+ uintParser,
137
+ uintParser,
138
+ sizeOffsetParser,
139
+ uintParser,
140
+ sizeOffsetParser,
141
+ sizeOffsetParser,
142
+ sizeOffsetParser,
143
+ sizeOffsetParser,
144
+ sizeOffsetParser,
145
+ sizeOffsetParser,
146
+ sizeOffsetParser,
147
+ ]),
148
+ ([
149
+ version,
150
+ checksum,
151
+ sha1Hash,
152
+ fileSize,
153
+ headerSize,
154
+ endianTag,
155
+ link,
156
+ mapOffset,
157
+ stringIds,
158
+ typeIds,
159
+ prototypeIds,
160
+ fieldIds,
161
+ methodIds,
162
+ classDefinitions,
163
+ data,
164
+ ]) => ({
165
+ version,
166
+ checksum,
167
+ sha1Hash,
168
+ fileSize,
169
+ headerSize,
170
+ endianTag,
171
+ link,
172
+ mapOffset,
173
+ stringIds,
174
+ typeIds,
175
+ prototypeIds,
176
+ fieldIds,
177
+ methodIds,
178
+ classDefinitions,
179
+ data,
180
+ }),
181
+ );
182
+
183
+ type DalvikExecutableStringIdItem = OffsetToStringDataItem;
184
+
185
+ const dalvikExecutableStringIdItemParser: Parser<DalvikExecutableStringIdItem, Uint8Array> = promiseCompose(
186
+ cloneParser(uintParser),
187
+ offset => isoOffsetToStringDataItem.wrap(offset),
188
+ );
189
+
190
+ type DalvikExecutableStringIdItems = TypedNumberArray<IndexIntoStringIds, DalvikExecutableStringIdItem>;
191
+
192
+ const isoDalvikExecutableStringIdItems = getIsoTypedNumberArray<IndexIntoStringIds, DalvikExecutableStringIdItem>();
193
+
194
+ const createSkipToThenStringIdItemsParser = ({ size, offset }: SizeOffset): Parser<DalvikExecutableStringIdItems, Uint8Array> => (
195
+ size === 0
196
+ ? (() => isoDalvikExecutableStringIdItems.wrap([]))
197
+ : promiseCompose(
198
+ createTupleParser([
199
+ createSkipToParser(offset),
200
+ createQuantifierParser(
201
+ dalvikExecutableStringIdItemParser,
202
+ size,
203
+ ),
204
+ ]),
205
+ ([ _, stringIds ]) => isoDalvikExecutableStringIdItems.wrap(stringIds),
206
+ )
207
+ );
208
+
209
+ type DalvikExecutableTypeIdItem = IndexIntoStringIds;
210
+
211
+ const dalvikExecutableTypeIdItemParser: Parser<DalvikExecutableTypeIdItem, Uint8Array> = promiseCompose(
212
+ cloneParser(uintParser),
213
+ index => isoIndexIntoStringIds.wrap(index),
214
+ );
215
+
216
+ type DalvikExecutableTypeIdItems = TypedNumberArray<IndexIntoTypeIds, DalvikExecutableTypeIdItem>;
217
+
218
+ const isoDalvikExecutableTypeIdItems = getIsoTypedNumberArray<IndexIntoTypeIds, DalvikExecutableTypeIdItem>();
219
+
220
+ const createSkipToThenTypeIdItemsParser = ({ size, offset }: SizeOffset): Parser<DalvikExecutableTypeIdItems, Uint8Array> => (
221
+ size === 0
222
+ ? (() => isoDalvikExecutableTypeIdItems.wrap([]))
223
+ : promiseCompose(
224
+ createTupleParser([
225
+ createSkipToParser(offset),
226
+ createQuantifierParser(
227
+ dalvikExecutableTypeIdItemParser,
228
+ size,
229
+ ),
230
+ ]),
231
+ ([ _, typeIds ]) => isoDalvikExecutableTypeIdItems.wrap(typeIds),
232
+ )
233
+ );
234
+
235
+ type DalvikExecutablePrototypeIdItem = {
236
+ shortyIndex: IndexIntoStringIds;
237
+ returnTypeIndex: IndexIntoTypeIds;
238
+ parametersOffset: OffsetToTypeList;
239
+ };
240
+
241
+ const prototypeIdItemParser: Parser<DalvikExecutablePrototypeIdItem, Uint8Array> = promiseCompose(
242
+ createTupleParser([
243
+ byteAlign4Parser,
244
+ uintParser,
245
+ uintParser,
246
+ uintParser,
247
+ ]),
248
+ ([ _, shortyIndex, returnTypeIndex, parametersOffset ]): DalvikExecutablePrototypeIdItem => ({
249
+ shortyIndex: isoIndexIntoStringIds.wrap(shortyIndex),
250
+ returnTypeIndex: isoIndexIntoTypeIds.wrap(returnTypeIndex),
251
+ parametersOffset: isoOffsetToTypeList.wrap(parametersOffset),
252
+ }),
253
+ );
254
+
255
+ type DalvikExecutablePrototypeIdItems = TypedNumberArray<IndexIntoPrototypeIds, DalvikExecutablePrototypeIdItem>;
256
+
257
+ const isoDalvikExecutablePrototypeIdItems = getIsoTypedNumberArray<IndexIntoPrototypeIds, DalvikExecutablePrototypeIdItem>();
258
+
259
+ const createSkipToThenPrototypeIdItemsParser = ({ size, offset }: SizeOffset): Parser<DalvikExecutablePrototypeIdItems, Uint8Array> => (
260
+ size === 0
261
+ ? (() => isoDalvikExecutablePrototypeIdItems.wrap([]))
262
+ : promiseCompose(
263
+ createTupleParser([
264
+ createSkipToParser(offset),
265
+ createQuantifierParser(
266
+ prototypeIdItemParser,
267
+ size,
268
+ ),
269
+ ]),
270
+ ([ _, prototypeIds ]) => isoDalvikExecutablePrototypeIdItems.wrap(prototypeIds),
271
+ )
272
+ );
273
+
274
+ const createSkipToThenItemByOffsetParser = <Offset, Item>({
275
+ sizeOffset: { size, offset },
276
+ itemParser,
277
+ byteAlign4,
278
+ isoOffset,
279
+ parserName,
280
+ }: {
281
+ sizeOffset: SizeOffset;
282
+ itemParser: Parser<Item, Uint8Array>;
283
+ byteAlign4: boolean;
284
+ isoOffset: Iso<Offset, number>;
285
+ parserName: string;
286
+ }): Parser<Map<Offset, Item>, Uint8Array> => {
287
+ const skipToThenItemByOffsetParser: Parser<Map<Offset, Item>, Uint8Array> = async parserContext => {
288
+ const itemByOffset = new Map<Offset, Item>();
289
+
290
+ if (size === 0) {
291
+ return itemByOffset;
292
+ }
293
+
294
+ await createSkipToParser(offset)(parserContext);
295
+
296
+ for (let i = 0; i < size; i++) {
297
+ if (byteAlign4) {
298
+ await byteAlign4Parser(parserContext);
299
+ }
300
+
301
+ const offset = parserContext.position;
302
+
303
+ const item = await itemParser(parserContext);
304
+
305
+ itemByOffset.set(isoOffset.wrap(offset), item);
306
+ }
307
+
308
+ return itemByOffset;
309
+ };
310
+
311
+ setParserName(skipToThenItemByOffsetParser, parserName);
312
+
313
+ return skipToThenItemByOffsetParser;
314
+ };
315
+
316
+ type DalvikExecutableFieldIdItem = {
317
+ classIndex: IndexIntoTypeIds;
318
+ typeIndex: IndexIntoTypeIds;
319
+ nameIndex: IndexIntoStringIds;
320
+ };
321
+
322
+ const dalvikExecutableFieldIdItemParser: Parser<DalvikExecutableFieldIdItem, Uint8Array> = promiseCompose(
323
+ createTupleParser([
324
+ ushortParser,
325
+ ushortParser,
326
+ uintParser,
327
+ ]),
328
+ ([ classIndex, typeIndex, nameIndex ]): DalvikExecutableFieldIdItem => ({
329
+ classIndex: isoIndexIntoTypeIds.wrap(classIndex),
330
+ typeIndex: isoIndexIntoTypeIds.wrap(typeIndex),
331
+ nameIndex: isoIndexIntoStringIds.wrap(nameIndex),
332
+ }),
333
+ );
334
+
335
+ type DalvikExecutableFieldIdItems = TypedNumberArray<IndexIntoFieldIds, DalvikExecutableFieldIdItem>;
336
+
337
+ const isoDalvikExecutableFieldIdItems = getIsoTypedNumberArray<IndexIntoFieldIds, DalvikExecutableFieldIdItem>();
338
+
339
+ const createSkipToThenFieldIdItemsParser = ({ size, offset }: SizeOffset): Parser<DalvikExecutableFieldIdItems, Uint8Array> => (
340
+ size === 0
341
+ ? (() => isoDalvikExecutableFieldIdItems.wrap([]))
342
+ : promiseCompose(
343
+ createTupleParser([
344
+ createSkipToParser(offset),
345
+ createQuantifierParser(
346
+ dalvikExecutableFieldIdItemParser,
347
+ size,
348
+ ),
349
+ ]),
350
+ ([ _, fieldIds ]) => isoDalvikExecutableFieldIdItems.wrap(fieldIds),
351
+ )
352
+ );
353
+
354
+ type DalvikExecutableMethodIdItem = {
355
+ classIndex: IndexIntoTypeIds;
356
+ prototypeIndex: IndexIntoPrototypeIds;
357
+ nameIndex: IndexIntoStringIds;
358
+ };
359
+
360
+ const dalvikExecutableMethodIdItemParser: Parser<DalvikExecutableMethodIdItem, Uint8Array> = promiseCompose(
361
+ createTupleParser([
362
+ ushortParser,
363
+ ushortParser,
364
+ uintParser,
365
+ ]),
366
+ ([ classIndex, prototypeIndex, nameIndex ]): DalvikExecutableMethodIdItem => ({
367
+ classIndex: isoIndexIntoTypeIds.wrap(classIndex),
368
+ prototypeIndex: isoIndexIntoPrototypeIds.wrap(prototypeIndex),
369
+ nameIndex: isoIndexIntoStringIds.wrap(nameIndex),
370
+ }),
371
+ );
372
+
373
+ type DalvikExecutableMethodIdItems = TypedNumberArray<IndexIntoMethodIds, DalvikExecutableMethodIdItem>;
374
+
375
+ const isoDalvikExecutableMethodIdItems = getIsoTypedNumberArray<IndexIntoMethodIds, DalvikExecutableMethodIdItem>();
376
+
377
+ const createSkipToThenMethodIdItemsParser = ({ size, offset }: SizeOffset): Parser<DalvikExecutableMethodIdItems, Uint8Array> => (
378
+ size === 0
379
+ ? (() => isoDalvikExecutableMethodIdItems.wrap([]))
380
+ : promiseCompose(
381
+ createTupleParser([
382
+ createSkipToParser(offset),
383
+ createQuantifierParser(
384
+ dalvikExecutableMethodIdItemParser,
385
+ size,
386
+ ),
387
+ ]),
388
+ ([ _, methodIds ]) => isoDalvikExecutableMethodIdItems.wrap(methodIds),
389
+ )
390
+ );
391
+
392
+ const parseAccessFlagsCommon = (flags: number): DalvikExecutableAccessFlags => ({
393
+ public: Boolean(flags & 0b0000_0001),
394
+ private: Boolean(flags & 0b0000_0010),
395
+ protected: Boolean(flags & 0b0000_0100),
396
+ static: Boolean(flags & 0b0000_1000),
397
+ final: Boolean(flags & 0b0001_0000),
398
+ synchronized: Boolean(flags & 0b0010_0000),
399
+ volatile: false,
400
+ bridge: false,
401
+ transient: Boolean(flags & 0b1000_0000),
402
+ varargs: Boolean(flags & 0b1000_0000),
403
+ native: Boolean(flags & 0b0000_0001_0000_0000),
404
+ interface: Boolean(flags & 0b0000_0010_0000_0000),
405
+ abstract: Boolean(flags & 0b0000_0100_0000_0000),
406
+ strict: Boolean(flags & 0b0000_1000_0000_0000),
407
+ synthetic: Boolean(flags & 0b0001_0000_0000_0000),
408
+ annotation: Boolean(flags & 0b0010_0000_0000_0000),
409
+ enum: Boolean(flags & 0b0100_0000_0000_0000),
410
+ constructor: Boolean(flags & 0b0000_0001_0000_0000_0000_0000),
411
+ declaredSynchronized: Boolean(flags & 0b0000_0010_0000_0000_0000_0000),
412
+ });
413
+
414
+ const parseAccessFlags = (flags: number): DalvikExecutableAccessFlags => parseAccessFlagsCommon(flags);
415
+
416
+ const parseFieldAccessFlags = (flags: number): DalvikExecutableAccessFlags => ({
417
+ ...parseAccessFlagsCommon(flags),
418
+ volatile: Boolean(flags & 0b0100_0000),
419
+ varargs: false, // Varargs is only for methods, not fields
420
+ bridge: false,
421
+ });
422
+
423
+ const parseMethodAccessFlags = (flags: number): DalvikExecutableAccessFlags => ({
424
+ ...parseAccessFlagsCommon(flags),
425
+ volatile: false,
426
+ transient: false, // Transient is only for fields, not methods
427
+ bridge: Boolean(flags & 0b0100_0000),
428
+ });
429
+
430
+ const uintAccessFlagsParser: Parser<DalvikExecutableAccessFlags, Uint8Array> = promiseCompose(
431
+ uintParser,
432
+ parseAccessFlags,
433
+ );
434
+
435
+ const uleb128AccessFlagsParser: Parser<DalvikExecutableAccessFlags, Uint8Array> = promiseCompose(
436
+ uleb128NumberParser,
437
+ parseAccessFlags,
438
+ );
439
+
440
+ const uleb128FieldAccessFlagsParser: Parser<DalvikExecutableAccessFlags, Uint8Array> = promiseCompose(
441
+ uleb128NumberParser,
442
+ parseFieldAccessFlags,
443
+ );
444
+
445
+ const uleb128MethodAccessFlagsParser: Parser<DalvikExecutableAccessFlags, Uint8Array> = promiseCompose(
446
+ uleb128NumberParser,
447
+ parseMethodAccessFlags,
448
+ );
449
+
450
+ type DalvikExecutableClassDefinitionItem = {
451
+ classIndex: IndexIntoTypeIds;
452
+ accessFlags: DalvikExecutableAccessFlags;
453
+ superclassIndex: IndexIntoTypeIds;
454
+ interfacesOffset: OffsetToTypeList;
455
+ sourceFileIndex: undefined | IndexIntoStringIds;
456
+ annotationsOffset: OffsetToAnnotationsDirectoryItem;
457
+ classDataOffset: OffsetToClassDataItem;
458
+ staticValuesOffset: OffsetToEncodedArrayItem;
459
+ };
460
+
461
+ const DEX_CLASS_DEFINITION_ITEM_SOURCE_FILE_NO_INDEX = 0xFF_FF_FF_FF;
462
+
463
+ const createSkipToThenClassDefinitionItemsParser = ({ size, offset }: SizeOffset): Parser<DalvikExecutableClassDefinitionItem[], Uint8Array> => (
464
+ size === 0
465
+ ? (() => [])
466
+ : promiseCompose(
467
+ createTupleParser([
468
+ createSkipToParser(offset),
469
+ createQuantifierParser(
470
+ promiseCompose(
471
+ createTupleParser([
472
+ uintParser,
473
+ uintAccessFlagsParser,
474
+ uintParser,
475
+ uintParser,
476
+ uintParser,
477
+ uintParser,
478
+ uintParser,
479
+ uintParser,
480
+ ]),
481
+ ([
482
+ classIndex,
483
+ accessFlags,
484
+ superclassIndex,
485
+ interfacesOffset,
486
+ sourceFileIndex,
487
+ annotationsOffset,
488
+ classDataOffset,
489
+ staticValuesOffset,
490
+ ]): DalvikExecutableClassDefinitionItem => ({
491
+ classIndex: isoIndexIntoTypeIds.wrap(classIndex),
492
+ accessFlags,
493
+ superclassIndex: isoIndexIntoTypeIds.wrap(superclassIndex),
494
+ interfacesOffset: isoOffsetToTypeList.wrap(interfacesOffset),
495
+ sourceFileIndex: (
496
+ sourceFileIndex === DEX_CLASS_DEFINITION_ITEM_SOURCE_FILE_NO_INDEX
497
+ ? undefined
498
+ : isoIndexIntoStringIds.wrap(sourceFileIndex)
499
+ ),
500
+ annotationsOffset: isoOffsetToAnnotationsDirectoryItem.wrap(annotationsOffset),
501
+ classDataOffset: isoOffsetToClassDataItem.wrap(classDataOffset),
502
+ staticValuesOffset: isoOffsetToEncodedArrayItem.wrap(staticValuesOffset),
503
+ }),
504
+ ),
505
+ size,
506
+ ),
507
+ ]),
508
+ ([ _, classDefinitions ]) => classDefinitions,
509
+ )
510
+ );
511
+
512
+ const createRawDataParser = ({ size, offset }: SizeOffset): Parser<undefined | Uint8Array, Uint8Array> => (
513
+ size === 0
514
+ ? (() => undefined)
515
+ : promiseCompose(
516
+ createTupleParser([
517
+ createSkipToParser(offset),
518
+ createFixedLengthSequenceParser(size),
519
+ ]),
520
+ ([ _, data ]) => data,
521
+ )
522
+ );
523
+
524
+ type DalvikExecutableStringDataItem = {
525
+ utf16Size: number;
526
+ data: Uint8Array;
527
+ };
528
+
529
+ const stringDataItemParser: Parser<DalvikExecutableStringDataItem, Uint8Array> = promiseCompose(
530
+ createTupleParser([
531
+ uleb128NumberParser,
532
+ createElementTerminatedSequenceParser(0),
533
+ ]),
534
+ ([ utf16Size, data ]) => ({
535
+ utf16Size,
536
+ data: new Uint8Array(data),
537
+ }),
538
+ );
539
+
540
+ type DalvikExecutableStringDataItemString = string;
541
+
542
+ const stringDataItemStringParser: Parser<DalvikExecutableStringDataItemString, Uint8Array> = promiseCompose(
543
+ stringDataItemParser,
544
+ ({ utf16Size, data }) => {
545
+ const mutf8Decoder = new MUtf8Decoder();
546
+ const string = mutf8Decoder.decode(data);
547
+ invariant(string.length === utf16Size, 'String length mismatch. Expected: %s, actual: %s', utf16Size, string.length);
548
+ return string;
549
+ },
550
+ );
551
+
552
+ type DalvikExecutableStringDataItemStringByOffset = Map<OffsetToStringDataItem, DalvikExecutableStringDataItemString>;
553
+
554
+ const createSkipToThenStringsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableStringDataItemStringByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
555
+ sizeOffset,
556
+ itemParser: stringDataItemStringParser,
557
+ byteAlign4: false,
558
+ isoOffset: isoOffsetToStringDataItem,
559
+ parserName: 'skipToThenStringsParser',
560
+ });
561
+
562
+ type DalvikExecutableTypeItem = IndexIntoTypeIds;
563
+
564
+ const dalvikExecutableTypeItemParser: Parser<DalvikExecutableTypeItem, Uint8Array> = promiseCompose(
565
+ cloneParser(ushortParser),
566
+ index => isoIndexIntoTypeIds.wrap(index),
567
+ );
568
+
569
+ type DalvikExecutableTypeList = TypedNumberArray<IndexIntoTypeIds, DalvikExecutableTypeItem>;
570
+
571
+ const isoDalvikExecutableTypeList = getIsoTypedNumberArray<IndexIntoTypeIds, DalvikExecutableTypeItem>();
572
+
573
+ const dalvikExecutableTypeListParser: Parser<DalvikExecutableTypeList, Uint8Array> = parserCreatorCompose(
574
+ () => createTupleParser([
575
+ byteAlign4Parser,
576
+ uintParser,
577
+ ]),
578
+ ([ _, size ]) => promiseCompose(
579
+ createQuantifierParser(
580
+ dalvikExecutableTypeItemParser,
581
+ size,
582
+ ),
583
+ typeItems => isoDalvikExecutableTypeList.wrap(typeItems),
584
+ ),
585
+ )();
586
+
587
+ type DalvikExecutableTypeListByOffset = Map<OffsetToTypeList, DalvikExecutableTypeList>;
588
+
589
+ const createSkipToThenTypeListByOffsetParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableTypeListByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
590
+ sizeOffset,
591
+ itemParser: dalvikExecutableTypeListParser,
592
+ byteAlign4: true,
593
+ isoOffset: isoOffsetToTypeList,
594
+ parserName: 'skipToThenTypeListByOffsetParser',
595
+ });
596
+
597
+ type DalvikExecutableFieldAnnotation = {
598
+ fieldIndex: IndexIntoFieldIds;
599
+ annotationsOffset: OffsetToAnnotationSetItem;
600
+ };
601
+
602
+ const fieldAnnotationParser: Parser<DalvikExecutableFieldAnnotation, Uint8Array> = promiseCompose(
603
+ createTupleParser([
604
+ uintParser,
605
+ uintParser,
606
+ ]),
607
+ ([
608
+ fieldIndex,
609
+ annotationsOffset,
610
+ ]) => ({
611
+ fieldIndex: isoIndexIntoFieldIds.wrap(fieldIndex),
612
+ annotationsOffset: isoOffsetToAnnotationSetItem.wrap(annotationsOffset),
613
+ }),
614
+ );
615
+
616
+ const createFieldAnnotationsParser = (fieldsSize: number): Parser<DalvikExecutableFieldAnnotation[], Uint8Array> => createQuantifierParser(
617
+ fieldAnnotationParser,
618
+ fieldsSize,
619
+ );
620
+
621
+ type DalvikExecutableMethodAnnotation = {
622
+ methodIndex: IndexIntoMethodIds;
623
+ annotationsOffset: OffsetToAnnotationSetItem;
624
+ };
625
+
626
+ const methodAnnotationParser: Parser<DalvikExecutableMethodAnnotation, Uint8Array> = promiseCompose(
627
+ createTupleParser([
628
+ uintParser,
629
+ uintParser,
630
+ ]),
631
+ ([
632
+ methodIndex,
633
+ annotationsOffset,
634
+ ]) => ({
635
+ methodIndex: isoIndexIntoMethodIds.wrap(methodIndex),
636
+ annotationsOffset: isoOffsetToAnnotationSetItem.wrap(annotationsOffset),
637
+ }),
638
+ );
639
+
640
+ const createMethodAnnotationsParser = (methodsSize: number): Parser<DalvikExecutableMethodAnnotation[], Uint8Array> => createQuantifierParser(
641
+ methodAnnotationParser,
642
+ methodsSize,
643
+ );
644
+
645
+ type DalvikExecutableParameterAnnotation = {
646
+ methodIndex: IndexIntoMethodIds;
647
+ annotationsOffset: OffsetToAnnotationSetRefListItem;
648
+ };
649
+
650
+ const parameterAnnotationParser: Parser<DalvikExecutableParameterAnnotation, Uint8Array> = promiseCompose(
651
+ createTupleParser([
652
+ uintParser,
653
+ uintParser,
654
+ ]),
655
+ ([
656
+ methodIndex,
657
+ annotationsOffset,
658
+ ]) => ({
659
+ methodIndex: isoIndexIntoMethodIds.wrap(methodIndex),
660
+ annotationsOffset: isoOffsetToAnnotationSetRefListItem.wrap(annotationsOffset),
661
+ }),
662
+ );
663
+
664
+ const createParameterAnnotationsParser = (parametersSize: number): Parser<DalvikExecutableParameterAnnotation[], Uint8Array> => createQuantifierParser(
665
+ parameterAnnotationParser,
666
+ parametersSize,
667
+ );
668
+
669
+ type DalvikExecutableAnnotationsDirectoryItem = {
670
+ classAnnotationsOffset: OffsetToAnnotationSetItem;
671
+ fieldAnnotations: DalvikExecutableFieldAnnotation[];
672
+ methodAnnotations: DalvikExecutableMethodAnnotation[];
673
+ parameterAnnotations: DalvikExecutableParameterAnnotation[];
674
+ };
675
+
676
+ const annotationsDirectoryItemParser: Parser<DalvikExecutableAnnotationsDirectoryItem, Uint8Array> = parserCreatorCompose(
677
+ () => createTupleParser([
678
+ byteAlign4Parser,
679
+ uintParser,
680
+ uintParser,
681
+ uintParser,
682
+ uintParser,
683
+ ]),
684
+ ([
685
+ _,
686
+ classAnnotationsOffset,
687
+ fieldsSize,
688
+ annotatedMethodsSize,
689
+ annotatedParametersSize,
690
+ ]) => promiseCompose(
691
+ createTupleParser([
692
+ () => isoOffsetToAnnotationSetItem.wrap(classAnnotationsOffset),
693
+ createFieldAnnotationsParser(fieldsSize),
694
+ createMethodAnnotationsParser(annotatedMethodsSize),
695
+ createParameterAnnotationsParser(annotatedParametersSize),
696
+ ]),
697
+ ([
698
+ classAnnotationsOffset,
699
+ fieldAnnotations,
700
+ methodAnnotations,
701
+ parameterAnnotations,
702
+ ]) => ({
703
+ classAnnotationsOffset,
704
+ fieldAnnotations,
705
+ methodAnnotations,
706
+ parameterAnnotations,
707
+ }),
708
+ ),
709
+ )();
710
+
711
+ type DalvikExecutableAnnotationsDirectoryItemByOffset = Map<OffsetToAnnotationsDirectoryItem, DalvikExecutableAnnotationsDirectoryItem>;
712
+
713
+ const createSkipToThenAnnotationsDirectoryItemsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableAnnotationsDirectoryItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
714
+ sizeOffset,
715
+ itemParser: annotationsDirectoryItemParser,
716
+ byteAlign4: true,
717
+ isoOffset: isoOffsetToAnnotationsDirectoryItem,
718
+ parserName: 'skipToThenAnnotationsDirectoryItemsParser',
719
+ });
720
+
721
+ type DalvikExecutableEncodedFieldDiff = {
722
+ fieldIndexDiff: number;
723
+ accessFlags: DalvikExecutableAccessFlags;
724
+ };
725
+
726
+ const encodedFieldParser: Parser<DalvikExecutableEncodedFieldDiff, Uint8Array> = promiseCompose(
727
+ createTupleParser([
728
+ uleb128NumberParser,
729
+ uleb128FieldAccessFlagsParser,
730
+ ]),
731
+ ([ fieldIndexDiff, accessFlags ]) => ({ fieldIndexDiff, accessFlags }),
732
+ );
733
+
734
+ type DalvikExecutableEncodedField = {
735
+ fieldIndex: IndexIntoFieldIds;
736
+ accessFlags: DalvikExecutableAccessFlags;
737
+ };
738
+
739
+ const createEncodedFieldsParser = (fieldsSize: number): Parser<DalvikExecutableEncodedField[], Uint8Array> => promiseCompose(
740
+ createQuantifierParser(
741
+ encodedFieldParser,
742
+ fieldsSize,
743
+ ),
744
+ encodedFields => {
745
+ let previousFieldIndex = 0;
746
+ return encodedFields.map(({ fieldIndexDiff, accessFlags }) => {
747
+ previousFieldIndex += fieldIndexDiff;
748
+ return {
749
+ fieldIndex: isoIndexIntoFieldIds.wrap(previousFieldIndex),
750
+ accessFlags,
751
+ };
752
+ });
753
+ },
754
+ );
755
+
756
+ type DalvikExecutableEncodedMethodDiff = {
757
+ methodIndexDiff: number;
758
+ accessFlags: DalvikExecutableAccessFlags;
759
+ codeOffset: OffsetToCodeItem;
760
+ };
761
+
762
+ const encodedMethodParser: Parser<DalvikExecutableEncodedMethodDiff, Uint8Array> = promiseCompose(
763
+ createTupleParser([
764
+ uleb128NumberParser,
765
+ uleb128MethodAccessFlagsParser,
766
+ uleb128NumberParser,
767
+ ]),
768
+ ([
769
+ methodIndexDiff,
770
+ accessFlags,
771
+ codeOffset,
772
+ ]) => ({
773
+ methodIndexDiff,
774
+ accessFlags,
775
+ codeOffset: isoOffsetToCodeItem.wrap(codeOffset),
776
+ }),
777
+ );
778
+
779
+ type DalvikExecutableEncodedMethod = {
780
+ methodIndex: IndexIntoMethodIds;
781
+ accessFlags: DalvikExecutableAccessFlags;
782
+ codeOffset: OffsetToCodeItem;
783
+ };
784
+
785
+ const createEncodedMethodsParser = (methodsSize: number): Parser<DalvikExecutableEncodedMethod[], Uint8Array> => promiseCompose(
786
+ createQuantifierParser(
787
+ encodedMethodParser,
788
+ methodsSize,
789
+ ),
790
+ encodedMethods => {
791
+ let previousMethodIndex = 0;
792
+ return encodedMethods.map(({ methodIndexDiff, accessFlags, codeOffset }) => {
793
+ previousMethodIndex += methodIndexDiff;
794
+ return {
795
+ methodIndex: isoIndexIntoMethodIds.wrap(previousMethodIndex),
796
+ accessFlags,
797
+ codeOffset,
798
+ };
799
+ });
800
+ },
801
+ );
802
+
803
+ type DalvikExecutableClassDataItem = {
804
+ staticFields: DalvikExecutableEncodedField[];
805
+ instanceFields: DalvikExecutableEncodedField[];
806
+ directMethods: DalvikExecutableEncodedMethod[];
807
+ virtualMethods: DalvikExecutableEncodedMethod[];
808
+ };
809
+
810
+ const classDataItemParser: Parser<DalvikExecutableClassDataItem, Uint8Array> = parserCreatorCompose(
811
+ () => createTupleParser([
812
+ uleb128NumberParser,
813
+ uleb128NumberParser,
814
+ uleb128NumberParser,
815
+ uleb128NumberParser,
816
+ ]),
817
+ ([
818
+ staticFieldsSize,
819
+ instanceFieldsSize,
820
+ directMethodsSize,
821
+ virtualMethodsSize,
822
+ ]) => promiseCompose(
823
+ createTupleParser([
824
+ createEncodedFieldsParser(staticFieldsSize),
825
+ createEncodedFieldsParser(instanceFieldsSize),
826
+ createEncodedMethodsParser(directMethodsSize),
827
+ createEncodedMethodsParser(virtualMethodsSize),
828
+ ]),
829
+ ([
830
+ staticFields,
831
+ instanceFields,
832
+ directMethods,
833
+ virtualMethods,
834
+ ]) => ({
835
+ staticFields,
836
+ instanceFields,
837
+ directMethods,
838
+ virtualMethods,
839
+ }),
840
+ ),
841
+ )();
842
+
843
+ type DalvikExecutableClassDataItemByOffset = Map<OffsetToClassDataItem, DalvikExecutableClassDataItem>;
844
+
845
+ const createSkipToThenClassDataItemsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableClassDataItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
846
+ sizeOffset,
847
+ itemParser: classDataItemParser,
848
+ byteAlign4: false,
849
+ isoOffset: isoOffsetToClassDataItem,
850
+ parserName: 'skipToThenClassDataItemsParser',
851
+ });
852
+
853
+ // Internal type for encoded values with type tags during parsing
854
+ type DalvikExecutableTaggedEncodedValue =
855
+ | { type: 'byte'; value: number }
856
+ | { type: 'short'; value: number }
857
+ | { type: 'char'; value: number }
858
+ | { type: 'int'; value: number }
859
+ | { type: 'long'; value: bigint }
860
+ | { type: 'float'; value: number }
861
+ | { type: 'double'; value: number }
862
+ | { type: 'methodType'; value: IndexIntoPrototypeIds }
863
+ | { type: 'methodHandle'; value: number }
864
+ | { type: 'string'; value: IndexIntoStringIds }
865
+ | { type: 'type'; value: IndexIntoTypeIds }
866
+ | { type: 'field'; value: IndexIntoFieldIds }
867
+ | { type: 'method'; value: IndexIntoMethodIds }
868
+ | { type: 'enum'; value: IndexIntoFieldIds }
869
+ | { type: 'array'; value: DalvikExecutableTaggedEncodedValue[] }
870
+ | { type: 'annotation'; value: DalvikExecutableEncodedAnnotation }
871
+ // eslint-disable-next-line @typescript-eslint/no-restricted-types
872
+ | { type: 'null'; value: null }
873
+ | { type: 'boolean'; value: boolean };
874
+
875
+ const createByteWith5LeastSignificantBitsEqualParser = (leastSignificant5: number): Parser<number, Uint8Array> => {
876
+ const byteWith5LeastSignificantBitsEqualParser: Parser<number, Uint8Array> = async parserContext => {
877
+ const byte = await parserContext.read(0);
878
+ parserContext.invariant(
879
+ (byte & 0b0001_1111) === leastSignificant5,
880
+ 'Expected byte with 5 least significant bits equal to %s, but got %s',
881
+ leastSignificant5.toString(2).padStart(8, '0'),
882
+ byte.toString(2).padStart(8, '0'),
883
+ );
884
+ return byte;
885
+ };
886
+
887
+ setParserName(byteWith5LeastSignificantBitsEqualParser, `createByteWith5LeastSignificantBitsEqualParser(${leastSignificant5.toString(2).padStart(5, '0')})`);
888
+
889
+ return byteWith5LeastSignificantBitsEqualParser;
890
+ };
891
+
892
+ const createEncodedValueArgParser = (valueType: number): Parser<number, Uint8Array> => promiseCompose(
893
+ createByteWith5LeastSignificantBitsEqualParser(valueType),
894
+ byte => byte >> 5,
895
+ );
896
+
897
+ const encodedValueByteParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = promiseCompose(
898
+ createTupleParser([
899
+ createExactElementParser(0),
900
+ byteParser,
901
+ ]),
902
+ ([ _, value ]) => ({ type: 'byte' as const, value }),
903
+ );
904
+
905
+ setParserName(encodedValueByteParser, 'encodedValueByteParser');
906
+
907
+ const encodedValueShortParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
908
+ () => createEncodedValueArgParser(0x02),
909
+ sizeSubOne => {
910
+ const size = sizeSubOne + 1;
911
+
912
+ if (size === 1) {
913
+ return promiseCompose(
914
+ createFixedLengthSequenceParser(size),
915
+ uint8Array => {
916
+ const buffer = Buffer.from(uint8Array);
917
+ return { type: 'short' as const, value: buffer.readInt8(0) };
918
+ },
919
+ );
920
+ }
921
+
922
+ invariant(size === 2, '(encodedValueShortParser) Unexpected size: %s', size);
923
+
924
+ return promiseCompose(
925
+ createFixedLengthSequenceParser(size),
926
+ uint8Array => {
927
+ const buffer = Buffer.from(uint8Array);
928
+ return { type: 'short' as const, value: buffer.readInt16LE(0) };
929
+ },
930
+ );
931
+ },
932
+ )();
933
+
934
+ setParserName(encodedValueShortParser, 'encodedValueShortParser');
935
+
936
+ const encodedValueCharParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
937
+ () => createEncodedValueArgParser(0x03),
938
+ sizeSubOne => {
939
+ const size = sizeSubOne + 1;
940
+
941
+ if (size == 1) {
942
+ return promiseCompose(
943
+ createFixedLengthSequenceParser(size),
944
+ uint8Array => {
945
+ const buffer = Buffer.from([ ...uint8Array, 0 ]);
946
+ return { type: 'char' as const, value: buffer.readUInt16LE(0) };
947
+ },
948
+ );
949
+ }
950
+
951
+ invariant(size === 2, '(encodedValueCharParser) Unexpected size: %s', size);
952
+
953
+ return promiseCompose(
954
+ createFixedLengthSequenceParser(size),
955
+ uint8Array => {
956
+ const buffer = Buffer.from(uint8Array);
957
+ return { type: 'char' as const, value: buffer.readUInt16LE(0) };
958
+ },
959
+ );
960
+ },
961
+ )();
962
+
963
+ setParserName(encodedValueCharParser, 'encodedValueCharParser');
964
+
965
+ const encodedValueIntParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
966
+ () => createEncodedValueArgParser(0x04),
967
+ sizeSubOne => {
968
+ const size = sizeSubOne + 1;
969
+
970
+ if (size === 1) {
971
+ return promiseCompose(
972
+ createFixedLengthSequenceParser(size),
973
+ uint8Array => {
974
+ const buffer = Buffer.from(uint8Array);
975
+ return { type: 'int' as const, value: buffer.readInt8(0) };
976
+ },
977
+ );
978
+ }
979
+
980
+ if (size === 2) {
981
+ return promiseCompose(
982
+ createFixedLengthSequenceParser(size),
983
+ uint8Array => {
984
+ const buffer = Buffer.from(uint8Array);
985
+ return { type: 'int' as const, value: buffer.readInt16LE(0) };
986
+ },
987
+ );
988
+ }
989
+
990
+ if (size === 3) {
991
+ return promiseCompose(
992
+ createFixedLengthSequenceParser(size),
993
+ uint8Array => {
994
+ const lastByte = uint8Array[uint8Array.length - 1];
995
+ const signBit = (lastByte & 0b1000_0000) >> 7;
996
+ const extensionByte = signBit === 1 ? 0xFF : 0x00;
997
+
998
+ const buffer = Buffer.from([ ...uint8Array, extensionByte ]);
999
+ return { type: 'int' as const, value: buffer.readInt32LE(0) };
1000
+ },
1001
+ );
1002
+ }
1003
+
1004
+ invariant(size === 4, '(encodedValueIntParser) Unexpected size: %s', size);
1005
+
1006
+ return promiseCompose(
1007
+ createFixedLengthSequenceParser(size),
1008
+ uint8Array => {
1009
+ const buffer = Buffer.from(uint8Array);
1010
+ return { type: 'int' as const, value: buffer.readInt32LE(0) };
1011
+ },
1012
+ );
1013
+ },
1014
+ )();
1015
+
1016
+ setParserName(encodedValueIntParser, 'encodedValueIntParser');
1017
+
1018
+ const encodedValueLongParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1019
+ () => createEncodedValueArgParser(0x06),
1020
+ sizeSubOne => {
1021
+ const size = sizeSubOne + 1;
1022
+
1023
+ if (size === 1) {
1024
+ return promiseCompose(
1025
+ createFixedLengthSequenceParser(size),
1026
+ uint8Array => {
1027
+ const buffer = Buffer.from(uint8Array);
1028
+ return { type: 'long' as const, value: BigInt(buffer.readInt8(0)) };
1029
+ },
1030
+ );
1031
+ }
1032
+
1033
+ if (size === 2) {
1034
+ return promiseCompose(
1035
+ createFixedLengthSequenceParser(size),
1036
+ uint8Array => {
1037
+ const buffer = Buffer.from(uint8Array);
1038
+ return { type: 'long' as const, value: BigInt(buffer.readInt16LE(0)) };
1039
+ },
1040
+ );
1041
+ }
1042
+
1043
+ if (size === 3) {
1044
+ return promiseCompose(
1045
+ createFixedLengthSequenceParser(size),
1046
+ uint8Array => {
1047
+ const lastByte = uint8Array[size - 1];
1048
+ const firstBit = (lastByte & 0b1000_0000) >> 7;
1049
+ const extensionByte = firstBit === 1 ? 0xFF : 0x00;
1050
+
1051
+ const buffer = Buffer.from([ ...uint8Array, extensionByte ]);
1052
+ return { type: 'long' as const, value: BigInt(buffer.readInt32LE(0)) };
1053
+ },
1054
+ );
1055
+ }
1056
+
1057
+ if (size === 4) {
1058
+ return promiseCompose(
1059
+ createFixedLengthSequenceParser(size),
1060
+ uint8Array => {
1061
+ const buffer = Buffer.from(uint8Array);
1062
+ return { type: 'long' as const, value: BigInt(buffer.readInt32LE(0)) };
1063
+ },
1064
+ );
1065
+ }
1066
+
1067
+ if (size === 5) {
1068
+ return promiseCompose(
1069
+ createFixedLengthSequenceParser(size),
1070
+ uint8Array => {
1071
+ const lastByte = uint8Array[size - 1];
1072
+ const firstBit = (lastByte & 0b1000_0000) >> 7;
1073
+ const extensionByte = firstBit === 1 ? 0xFF : 0x00;
1074
+
1075
+ const buffer = Buffer.from([ ...uint8Array, extensionByte, extensionByte, extensionByte ]);
1076
+ return { type: 'long' as const, value: BigInt(buffer.readBigInt64LE(0)) };
1077
+ },
1078
+ );
1079
+ }
1080
+
1081
+ if (size === 6) {
1082
+ return promiseCompose(
1083
+ createFixedLengthSequenceParser(size),
1084
+ uint8Array => {
1085
+ const lastByte = uint8Array[size - 1];
1086
+ const firstBit = (lastByte & 0b1000_0000) >> 7;
1087
+ const extensionByte = firstBit === 1 ? 0xFF : 0x00;
1088
+
1089
+ const buffer = Buffer.from([ ...uint8Array, extensionByte, extensionByte ]);
1090
+ return { type: 'long' as const, value: BigInt(buffer.readBigInt64LE(0)) };
1091
+ },
1092
+ );
1093
+ }
1094
+
1095
+ if (size === 7) {
1096
+ return promiseCompose(
1097
+ createFixedLengthSequenceParser(size),
1098
+ uint8Array => {
1099
+ const lastByte = uint8Array[size - 1];
1100
+ const firstBit = (lastByte & 0b1000_0000) >> 7;
1101
+ const extensionByte = firstBit === 1 ? 0xFF : 0x00;
1102
+
1103
+ const buffer = Buffer.from([ ...uint8Array, extensionByte ]);
1104
+ return { type: 'long' as const, value: BigInt(buffer.readBigInt64LE(0)) };
1105
+ },
1106
+ );
1107
+ }
1108
+
1109
+ invariant(size === 8, '(encodedValueLongParser) Unexpected size: %s', size);
1110
+
1111
+ return promiseCompose(
1112
+ createFixedLengthSequenceParser(size),
1113
+ uint8Array => {
1114
+ const buffer = Buffer.from(uint8Array);
1115
+ return { type: 'long' as const, value: buffer.readBigInt64LE(0) };
1116
+ },
1117
+ );
1118
+ },
1119
+ )();
1120
+
1121
+ setParserName(encodedValueLongParser, 'encodedValueLongParser');
1122
+
1123
+ const encodedValueFloatParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1124
+ () => createEncodedValueArgParser(0x10),
1125
+ sizeSubOne => {
1126
+ const size = sizeSubOne + 1;
1127
+
1128
+ if (size === 1) {
1129
+ return promiseCompose(
1130
+ createFixedLengthSequenceParser(size),
1131
+ uint8Array => {
1132
+ const buffer = Buffer.from([ 0, 0, 0, ...uint8Array ]);
1133
+ return { type: 'float' as const, value: buffer.readFloatLE(0) };
1134
+ },
1135
+ );
1136
+ }
1137
+
1138
+ if (size === 2) {
1139
+ return promiseCompose(
1140
+ createFixedLengthSequenceParser(size),
1141
+ uint8Array => {
1142
+ const buffer = Buffer.from([ 0, 0, ...uint8Array ]);
1143
+ return { type: 'float' as const, value: buffer.readFloatLE(0) };
1144
+ },
1145
+ );
1146
+ }
1147
+
1148
+ if (size === 3) {
1149
+ return promiseCompose(
1150
+ createFixedLengthSequenceParser(size),
1151
+ uint8Array => {
1152
+ const buffer = Buffer.from([ 0, ...uint8Array ]);
1153
+ return { type: 'float' as const, value: buffer.readFloatLE(0) };
1154
+ },
1155
+ );
1156
+ }
1157
+
1158
+ invariant(size === 4, '(encodedValueFloatParser) Unexpected size: %s', size);
1159
+
1160
+ return promiseCompose(
1161
+ createFixedLengthSequenceParser(size),
1162
+ uint8Array => {
1163
+ const buffer = Buffer.from(uint8Array);
1164
+ return { type: 'float' as const, value: buffer.readFloatLE(0) };
1165
+ },
1166
+ );
1167
+ },
1168
+ )();
1169
+
1170
+ setParserName(encodedValueFloatParser, 'encodedValueFloatParser');
1171
+
1172
+ const encodedValueDoubleParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1173
+ () => createEncodedValueArgParser(0x11),
1174
+ sizeSubOne => {
1175
+ const size = sizeSubOne + 1;
1176
+
1177
+ if (size === 1) {
1178
+ return promiseCompose(
1179
+ createFixedLengthSequenceParser(size),
1180
+ uint8Array => {
1181
+ const buffer = Buffer.from([ 0, 0, 0, 0, 0, 0, 0, ...uint8Array ]);
1182
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1183
+ },
1184
+ );
1185
+ }
1186
+
1187
+ if (size === 2) {
1188
+ return promiseCompose(
1189
+ createFixedLengthSequenceParser(size),
1190
+ uint8Array => {
1191
+ const buffer = Buffer.from([ 0, 0, 0, 0, 0, 0, ...uint8Array ]);
1192
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1193
+ },
1194
+ );
1195
+ }
1196
+
1197
+ if (size === 3) {
1198
+ return promiseCompose(
1199
+ createFixedLengthSequenceParser(size),
1200
+ uint8Array => {
1201
+ const buffer = Buffer.from([ 0, 0, 0, 0, 0, ...uint8Array ]);
1202
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1203
+ },
1204
+ );
1205
+ }
1206
+
1207
+ if (size === 4) {
1208
+ return promiseCompose(
1209
+ createFixedLengthSequenceParser(size),
1210
+ uint8Array => {
1211
+ const buffer = Buffer.from([ 0, 0, 0, 0, ...uint8Array ]);
1212
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1213
+ },
1214
+ );
1215
+ }
1216
+
1217
+ if (size === 5) {
1218
+ return promiseCompose(
1219
+ createFixedLengthSequenceParser(size),
1220
+ uint8Array => {
1221
+ const buffer = Buffer.from([ 0, 0, 0, ...uint8Array ]);
1222
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1223
+ },
1224
+ );
1225
+ }
1226
+
1227
+ if (size === 6) {
1228
+ return promiseCompose(
1229
+ createFixedLengthSequenceParser(size),
1230
+ uint8Array => {
1231
+ const buffer = Buffer.from([ 0, 0, ...uint8Array ]);
1232
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1233
+ },
1234
+ );
1235
+ }
1236
+
1237
+ if (size === 7) {
1238
+ return promiseCompose(
1239
+ createFixedLengthSequenceParser(size),
1240
+ uint8Array => {
1241
+ const buffer = Buffer.from([ 0, ...uint8Array ]);
1242
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1243
+ },
1244
+ );
1245
+ }
1246
+
1247
+ invariant(size === 8, '(encodedValueDoubleParser) Unexpected size: %s', size);
1248
+
1249
+ return promiseCompose(
1250
+ createFixedLengthSequenceParser(size),
1251
+ uint8Array => {
1252
+ const buffer = Buffer.from(uint8Array);
1253
+ return { type: 'double' as const, value: buffer.readDoubleLE(0) };
1254
+ },
1255
+ );
1256
+ },
1257
+ )();
1258
+
1259
+ setParserName(encodedValueDoubleParser, 'encodedValueDoubleParser');
1260
+
1261
+ const encodedValueMethodTypeParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1262
+ () => createEncodedValueArgParser(0x15),
1263
+ sizeSubOne => {
1264
+ const size = sizeSubOne + 1;
1265
+
1266
+ if (size === 1) {
1267
+ return promiseCompose(
1268
+ createFixedLengthSequenceParser(size),
1269
+ uint8Array => {
1270
+ const buffer = Buffer.from(uint8Array);
1271
+ return { type: 'methodType' as const, value: isoIndexIntoPrototypeIds.wrap(buffer.readUint8(0)) };
1272
+ },
1273
+ );
1274
+ }
1275
+
1276
+ if (size === 2) {
1277
+ return promiseCompose(
1278
+ createFixedLengthSequenceParser(size),
1279
+ uint8Array => {
1280
+ const buffer = Buffer.from(uint8Array);
1281
+ return { type: 'methodType' as const, value: isoIndexIntoPrototypeIds.wrap(buffer.readUInt16LE(0)) };
1282
+ },
1283
+ );
1284
+ }
1285
+
1286
+ invariant(size === 4, '(encodedValueMethodTypeParser) Unexpected size: %s', size);
1287
+
1288
+ return promiseCompose(
1289
+ createFixedLengthSequenceParser(size),
1290
+ uint8Array => {
1291
+ const buffer = Buffer.from(uint8Array);
1292
+ return { type: 'methodType' as const, value: isoIndexIntoPrototypeIds.wrap(buffer.readUInt32LE(0)) };
1293
+ },
1294
+ );
1295
+ },
1296
+ )();
1297
+
1298
+ setParserName(encodedValueMethodTypeParser, 'encodedValueMethodTypeParser');
1299
+
1300
+ const encodedValueMethodHandleParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1301
+ () => createEncodedValueArgParser(0x16),
1302
+ sizeSubOne => {
1303
+ const size = sizeSubOne + 1;
1304
+
1305
+ if (size === 1) {
1306
+ return promiseCompose(
1307
+ createFixedLengthSequenceParser(size),
1308
+ uint8Array => {
1309
+ const buffer = Buffer.from(uint8Array);
1310
+ return { type: 'methodHandle' as const, value: buffer.readUInt8(0) };
1311
+ },
1312
+ );
1313
+ }
1314
+
1315
+ if (size === 2) {
1316
+ return promiseCompose(
1317
+ createFixedLengthSequenceParser(size),
1318
+ uint8Array => {
1319
+ const buffer = Buffer.from(uint8Array);
1320
+ return { type: 'methodHandle' as const, value: buffer.readUInt16LE(0) };
1321
+ },
1322
+ );
1323
+ }
1324
+
1325
+ invariant(size === 4, '(encodedValueMethodHandleParser) Unexpected size: %s', size);
1326
+
1327
+ return promiseCompose(
1328
+ createFixedLengthSequenceParser(size),
1329
+ uint8Array => {
1330
+ const buffer = Buffer.from(uint8Array);
1331
+ return { type: 'methodHandle' as const, value: buffer.readUInt32LE(0) };
1332
+ },
1333
+ );
1334
+ },
1335
+ )();
1336
+
1337
+ setParserName(encodedValueMethodHandleParser, 'encodedValueMethodHandleParser');
1338
+
1339
+ const encodedValueStringParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1340
+ () => createEncodedValueArgParser(0x17),
1341
+ sizeSubOne => {
1342
+ const size = sizeSubOne + 1;
1343
+
1344
+ if (size === 1) {
1345
+ return promiseCompose(
1346
+ createFixedLengthSequenceParser(size),
1347
+ uint8Array => {
1348
+ const buffer = Buffer.from(uint8Array);
1349
+ return { type: 'string' as const, value: isoIndexIntoStringIds.wrap(buffer.readUInt8(0)) };
1350
+ },
1351
+ );
1352
+ }
1353
+
1354
+ if (size === 2) {
1355
+ return promiseCompose(
1356
+ createFixedLengthSequenceParser(size),
1357
+ uint8Array => {
1358
+ const buffer = Buffer.from(uint8Array);
1359
+ return { type: 'string' as const, value: isoIndexIntoStringIds.wrap(buffer.readUInt16LE(0)) };
1360
+ },
1361
+ );
1362
+ }
1363
+
1364
+ invariant(size === 4, '(encodedValueStringParser) Unexpected size: %s', size);
1365
+
1366
+ return promiseCompose(
1367
+ createFixedLengthSequenceParser(size),
1368
+ uint8Array => {
1369
+ const buffer = Buffer.from(uint8Array);
1370
+ return { type: 'string' as const, value: isoIndexIntoStringIds.wrap(buffer.readUInt32LE(0)) };
1371
+ },
1372
+ );
1373
+ },
1374
+ )();
1375
+
1376
+ setParserName(encodedValueStringParser, 'encodedValueStringParser');
1377
+
1378
+ const encodedValueTypeParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1379
+ () => createEncodedValueArgParser(0x18),
1380
+ sizeSubOne => {
1381
+ const size = sizeSubOne + 1;
1382
+
1383
+ if (size === 1) {
1384
+ return promiseCompose(
1385
+ createFixedLengthSequenceParser(size),
1386
+ uint8Array => {
1387
+ const buffer = Buffer.from(uint8Array);
1388
+ return { type: 'type' as const, value: isoIndexIntoTypeIds.wrap(buffer.readUInt8(0)) };
1389
+ },
1390
+ );
1391
+ }
1392
+
1393
+ if (size === 2) {
1394
+ return promiseCompose(
1395
+ createFixedLengthSequenceParser(size),
1396
+ uint8Array => {
1397
+ const buffer = Buffer.from(uint8Array);
1398
+ return { type: 'type' as const, value: isoIndexIntoTypeIds.wrap(buffer.readUInt16LE(0)) };
1399
+ },
1400
+ );
1401
+ }
1402
+
1403
+ invariant(size === 4, '(encodedValueTypeParser) Unexpected size: %s', size);
1404
+
1405
+ return promiseCompose(
1406
+ createFixedLengthSequenceParser(size),
1407
+ uint8Array => {
1408
+ const buffer = Buffer.from(uint8Array);
1409
+ return { type: 'type' as const, value: isoIndexIntoTypeIds.wrap(buffer.readUInt32LE(0)) };
1410
+ },
1411
+ );
1412
+ },
1413
+ )();
1414
+
1415
+ setParserName(encodedValueTypeParser, 'encodedValueTypeParser');
1416
+
1417
+ const encodedValueFieldParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1418
+ () => createEncodedValueArgParser(0x19),
1419
+ sizeSubOne => {
1420
+ const size = sizeSubOne + 1;
1421
+
1422
+ if (size === 1) {
1423
+ return promiseCompose(
1424
+ createFixedLengthSequenceParser(size),
1425
+ uint8Array => {
1426
+ const buffer = Buffer.from(uint8Array);
1427
+ return { type: 'field' as const, value: isoIndexIntoFieldIds.wrap(buffer.readUInt8(0)) };
1428
+ },
1429
+ );
1430
+ }
1431
+
1432
+ if (size === 2) {
1433
+ return promiseCompose(
1434
+ createFixedLengthSequenceParser(size),
1435
+ uint8Array => {
1436
+ const buffer = Buffer.from(uint8Array);
1437
+ return { type: 'field' as const, value: isoIndexIntoFieldIds.wrap(buffer.readUInt16LE(0)) };
1438
+ },
1439
+ );
1440
+ }
1441
+
1442
+ invariant(size === 4, '(encodedValueFieldParser) Unexpected size: %s', size);
1443
+
1444
+ return promiseCompose(
1445
+ createFixedLengthSequenceParser(size),
1446
+ uint8Array => {
1447
+ const buffer = Buffer.from(uint8Array);
1448
+ return { type: 'field' as const, value: isoIndexIntoFieldIds.wrap(buffer.readUInt32LE(0)) };
1449
+ },
1450
+ );
1451
+ },
1452
+ )();
1453
+
1454
+ setParserName(encodedValueFieldParser, 'encodedValueFieldParser');
1455
+
1456
+ const encodedValueMethodParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1457
+ () => createEncodedValueArgParser(0x1A),
1458
+ sizeSubOne => {
1459
+ const size = sizeSubOne + 1;
1460
+
1461
+ if (size === 1) {
1462
+ return promiseCompose(
1463
+ createFixedLengthSequenceParser(size),
1464
+ uint8Array => {
1465
+ const buffer = Buffer.from(uint8Array);
1466
+ return { type: 'method' as const, value: isoIndexIntoMethodIds.wrap(buffer.readUInt8(0)) };
1467
+ },
1468
+ );
1469
+ }
1470
+
1471
+ if (size === 2) {
1472
+ return promiseCompose(
1473
+ createFixedLengthSequenceParser(size),
1474
+ uint8Array => {
1475
+ const buffer = Buffer.from(uint8Array);
1476
+ return { type: 'method' as const, value: isoIndexIntoMethodIds.wrap(buffer.readUInt16LE(0)) };
1477
+ },
1478
+ );
1479
+ }
1480
+
1481
+ invariant(size === 4, '(encodedValueMethodParser) Unexpected size: %s', size);
1482
+
1483
+ return promiseCompose(
1484
+ createFixedLengthSequenceParser(size),
1485
+ uint8Array => {
1486
+ const buffer = Buffer.from(uint8Array);
1487
+ return { type: 'method' as const, value: isoIndexIntoMethodIds.wrap(buffer.readUInt32LE(0)) };
1488
+ },
1489
+ );
1490
+ },
1491
+ )();
1492
+
1493
+ setParserName(encodedValueMethodParser, 'encodedValueMethodParser');
1494
+
1495
+ const encodedValueEnumParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1496
+ () => createEncodedValueArgParser(0x1B),
1497
+ sizeSubOne => {
1498
+ const size = sizeSubOne + 1;
1499
+
1500
+ if (size === 1) {
1501
+ return promiseCompose(
1502
+ createFixedLengthSequenceParser(size),
1503
+ uint8Array => {
1504
+ const buffer = Buffer.from(uint8Array);
1505
+ return { type: 'enum' as const, value: isoIndexIntoFieldIds.wrap(buffer.readUInt8(0)) };
1506
+ },
1507
+ );
1508
+ }
1509
+
1510
+ if (size === 2) {
1511
+ return promiseCompose(
1512
+ createFixedLengthSequenceParser(size),
1513
+ uint8Array => {
1514
+ const buffer = Buffer.from(uint8Array);
1515
+ return { type: 'enum' as const, value: isoIndexIntoFieldIds.wrap(buffer.readUInt16LE(0)) };
1516
+ },
1517
+ );
1518
+ }
1519
+
1520
+ invariant(size === 4, '(encodedValueEnumParser) Unexpected size: %s', size);
1521
+
1522
+ return promiseCompose(
1523
+ createFixedLengthSequenceParser(size),
1524
+ uint8Array => {
1525
+ const buffer = Buffer.from(uint8Array);
1526
+ return { type: 'enum' as const, value: isoIndexIntoFieldIds.wrap(buffer.readUInt32LE(0)) };
1527
+ },
1528
+ );
1529
+ },
1530
+ )();
1531
+
1532
+ setParserName(encodedValueEnumParser, 'encodedValueEnumParser');
1533
+
1534
+ type DalvikExecutableEncodedArray = DalvikExecutableTaggedEncodedValue[];
1535
+
1536
+ const encodedArrayParser: Parser<DalvikExecutableTaggedEncodedValue[], Uint8Array> = parserCreatorCompose(
1537
+ () => uleb128NumberParser,
1538
+ size => createQuantifierParser(
1539
+ encodedValueParser,
1540
+ size,
1541
+ ),
1542
+ )();
1543
+
1544
+ setParserName(encodedArrayParser, 'encodedArrayParser');
1545
+
1546
+ const encodedValueArrayParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = promiseCompose(
1547
+ createTupleParser([
1548
+ parserCreatorCompose(
1549
+ () => createEncodedValueArgParser(0x1C),
1550
+ valueArg => parserContext => {
1551
+ parserContext.invariant(valueArg === 0, '(encodedValueArrayParser) valueArg: %s', valueArg);
1552
+ },
1553
+ )(),
1554
+ encodedArrayParser,
1555
+ ]),
1556
+ ([ _, array ]) => ({ type: 'array' as const, value: array }),
1557
+ );
1558
+
1559
+ setParserName(encodedValueArrayParser, 'encodedValueArrayParser');
1560
+
1561
+ type DalvikExecutableAnnotationElement = {
1562
+ nameIndex: IndexIntoStringIds;
1563
+ value: DalvikExecutableTaggedEncodedValue;
1564
+ };
1565
+
1566
+ type DalvikExecutableEncodedAnnotation = {
1567
+ typeIndex: IndexIntoTypeIds;
1568
+ elements: DalvikExecutableAnnotationElement[];
1569
+ };
1570
+
1571
+ const annotationElementParser: Parser<DalvikExecutableAnnotationElement, Uint8Array> = promiseCompose(
1572
+ createTupleParser([
1573
+ uleb128NumberParser,
1574
+ createParserAccessorParser(() => encodedValueParser),
1575
+ ]),
1576
+ ([
1577
+ nameIndex,
1578
+ value,
1579
+ ]) => ({
1580
+ nameIndex: isoIndexIntoStringIds.wrap(nameIndex),
1581
+ value,
1582
+ }),
1583
+ );
1584
+
1585
+ setParserName(annotationElementParser, 'annotationElementParser');
1586
+
1587
+ const encodedAnnotationParser: Parser<DalvikExecutableEncodedAnnotation, Uint8Array> = promiseCompose(
1588
+ parserCreatorCompose(
1589
+ () => createTupleParser([
1590
+ uleb128NumberParser,
1591
+ uleb128NumberParser,
1592
+ ]),
1593
+ ([
1594
+ typeIndex,
1595
+ size,
1596
+ ]) => createTupleParser([
1597
+ () => typeIndex,
1598
+ createQuantifierParser(
1599
+ annotationElementParser,
1600
+ size,
1601
+ ),
1602
+ ]),
1603
+ )(),
1604
+ ([
1605
+ typeIndex,
1606
+ elements,
1607
+ ]) => ({
1608
+ typeIndex: isoIndexIntoTypeIds.wrap(typeIndex),
1609
+ elements,
1610
+ }),
1611
+ );
1612
+
1613
+ setParserName(encodedAnnotationParser, 'encodedAnnotationParser');
1614
+
1615
+ const encodedValueAnnotationParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = promiseCompose(
1616
+ createTupleParser([
1617
+ parserCreatorCompose(
1618
+ () => createEncodedValueArgParser(0x1D),
1619
+ valueArg => parserContext => {
1620
+ parserContext.invariant(valueArg === 0, '(encodedValueAnnotationParser) valueArg: %s', valueArg);
1621
+ },
1622
+ )(),
1623
+ encodedAnnotationParser,
1624
+ ]),
1625
+ ([ _, annotation ]) => ({ type: 'annotation' as const, value: annotation }),
1626
+ );
1627
+
1628
+ setParserName(encodedValueAnnotationParser, 'encodedValueAnnotationParser');
1629
+
1630
+ const encodedValueNullParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = parserCreatorCompose(
1631
+ () => createEncodedValueArgParser(0x1E),
1632
+ valueArg => parserContext => {
1633
+ parserContext.invariant(valueArg === 0, '(encodedValueNullParser) valueArg: %s', valueArg);
1634
+ return ({ type: 'null' as const, value: null });
1635
+ },
1636
+ )();
1637
+
1638
+ setParserName(encodedValueNullParser, 'encodedValueNullParser');
1639
+
1640
+ const encodedValueBooleanParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = promiseCompose(
1641
+ createEncodedValueArgParser(0x1F),
1642
+ valueArg => ({ type: 'boolean' as const, value: Boolean(valueArg) }),
1643
+ );
1644
+
1645
+ setParserName(encodedValueBooleanParser, 'encodedValueBooleanParser');
1646
+
1647
+ const encodedValueParser: Parser<DalvikExecutableTaggedEncodedValue, Uint8Array> = createDisjunctionParser([
1648
+ encodedValueByteParser,
1649
+ encodedValueShortParser,
1650
+ encodedValueCharParser,
1651
+ encodedValueIntParser,
1652
+ encodedValueLongParser,
1653
+ encodedValueFloatParser,
1654
+ encodedValueDoubleParser,
1655
+ encodedValueMethodTypeParser,
1656
+ encodedValueMethodHandleParser,
1657
+ encodedValueStringParser,
1658
+ encodedValueTypeParser,
1659
+ encodedValueFieldParser,
1660
+ encodedValueMethodParser,
1661
+ encodedValueEnumParser,
1662
+ encodedValueArrayParser,
1663
+ encodedValueAnnotationParser,
1664
+ encodedValueNullParser,
1665
+ encodedValueBooleanParser,
1666
+ ]);
1667
+
1668
+ setParserName(encodedValueParser, 'encodedValueParser');
1669
+
1670
+ type DalvikExecutableTryItem = {
1671
+ startAddress: number;
1672
+ instructionCount: number;
1673
+ handlerOffset: OffsetFromEncodedCatchHandlerListToEncodedCatchHandler;
1674
+ };
1675
+
1676
+ const tryItemParser: Parser<DalvikExecutableTryItem, Uint8Array> = promiseCompose(
1677
+ createTupleParser([
1678
+ uintParser,
1679
+ ushortParser,
1680
+ ushortParser,
1681
+ ]),
1682
+ ([
1683
+ startAddress,
1684
+ instructionCount,
1685
+ handlerOffset,
1686
+ ]) => ({
1687
+ startAddress,
1688
+ instructionCount,
1689
+ handlerOffset: isoOffsetFromEncodedCatchHandlerListToEncodedCatchHandler.wrap(handlerOffset),
1690
+ }),
1691
+ );
1692
+
1693
+ setParserName(tryItemParser, 'tryItemParser');
1694
+
1695
+ type DalvikExecutableEncodedTypeAddressPair_ = {
1696
+ typeIndex: IndexIntoTypeIds;
1697
+ address: number;
1698
+ };
1699
+
1700
+ const encodedTypeAddressPairParser: Parser<DalvikExecutableEncodedTypeAddressPair_, Uint8Array> = promiseCompose(
1701
+ createTupleParser([
1702
+ uleb128NumberParser,
1703
+ uleb128NumberParser,
1704
+ ]),
1705
+ ([
1706
+ typeIndex,
1707
+ address,
1708
+ ]) => ({
1709
+ typeIndex: isoIndexIntoTypeIds.wrap(typeIndex),
1710
+ address,
1711
+ }),
1712
+ );
1713
+
1714
+ type DalvikExecutableEncodedCatchHandler_ = {
1715
+ handlers: DalvikExecutableEncodedTypeAddressPair_[];
1716
+ catchAllAddress: undefined | number;
1717
+ };
1718
+
1719
+ const encodedCatchHandlerParser: Parser<DalvikExecutableEncodedCatchHandler_, Uint8Array> = parserCreatorCompose(
1720
+ () => sleb128NumberParser,
1721
+ size => promiseCompose(
1722
+ createTupleParser([
1723
+ createQuantifierParser(
1724
+ encodedTypeAddressPairParser,
1725
+ Math.abs(size),
1726
+ ),
1727
+ size <= 0 ? uleb128NumberParser : () => undefined,
1728
+ ]),
1729
+ ([
1730
+ handlers,
1731
+ catchAllAddress,
1732
+ ]) => ({
1733
+ size,
1734
+ handlers,
1735
+ catchAllAddress,
1736
+ }),
1737
+ ),
1738
+ )();
1739
+
1740
+ setParserName(encodedCatchHandlerParser, 'encodedCatchHandlerParser');
1741
+
1742
+ type DalvikExecutableEncodedCatchHandlerByRelativeOffset = Map<OffsetFromEncodedCatchHandlerListToEncodedCatchHandler, DalvikExecutableEncodedCatchHandler_>;
1743
+
1744
+ const encodedCatchHandlerListParser: Parser<DalvikExecutableEncodedCatchHandlerByRelativeOffset, Uint8Array> = async parserContext => {
1745
+ const listOffset = parserContext.position;
1746
+ const handlers: DalvikExecutableEncodedCatchHandlerByRelativeOffset = new Map();
1747
+
1748
+ const size = await uleb128NumberParser(parserContext);
1749
+
1750
+ for (let i = 0; i < size; i += 1) {
1751
+ const handlerRelativeOffset = isoOffsetFromEncodedCatchHandlerListToEncodedCatchHandler.wrap(parserContext.position - listOffset);
1752
+ const handler = await encodedCatchHandlerParser(parserContext);
1753
+
1754
+ handlers.set(handlerRelativeOffset, handler);
1755
+ }
1756
+
1757
+ return handlers;
1758
+ };
1759
+
1760
+ setParserName(encodedCatchHandlerListParser, 'encodedCatchHandlerListParser');
1761
+
1762
+ type DalvikExecutableCodeItem<Instructions> = {
1763
+ registersSize: number;
1764
+ insSize: number;
1765
+ outsSize: number;
1766
+ debugInfoOffset: OffsetToDebugInfoItem;
1767
+ instructions: Instructions;
1768
+ tryItems: DalvikExecutableTryItem[];
1769
+ handlers: DalvikExecutableEncodedCatchHandlerByRelativeOffset;
1770
+ };
1771
+
1772
+ type CreateInstructionsParser<Instructions> = (size: number) => Parser<Instructions, Uint8Array>;
1773
+
1774
+ const createDalvikExecutableCodeItemParser = <Instructions>({
1775
+ createInstructionsParser,
1776
+ }: {
1777
+ createInstructionsParser: CreateInstructionsParser<Instructions>;
1778
+ }): Parser<DalvikExecutableCodeItem<Instructions>, Uint8Array> => {
1779
+ const dalvikExecutableCodeItemParser = parserCreatorCompose(
1780
+ () => createTupleParser([
1781
+ byteAlign4Parser,
1782
+ ushortParser,
1783
+ ushortParser,
1784
+ ushortParser,
1785
+ ushortParser,
1786
+ uintParser,
1787
+ uintParser,
1788
+ ]),
1789
+ ([
1790
+ _,
1791
+ registersSize,
1792
+ insSize,
1793
+ outsSize,
1794
+ triesSize,
1795
+ debugInfoOffset,
1796
+ instructionsSize,
1797
+ ]) => promiseCompose(
1798
+ createTupleParser([
1799
+ createInstructionsParser(instructionsSize * 2),
1800
+ (
1801
+ (
1802
+ triesSize !== 0
1803
+ && instructionsSize % 2 === 1
1804
+ )
1805
+ ? byteAlign4Parser
1806
+ : () => undefined
1807
+ ),
1808
+ (
1809
+ triesSize === 0
1810
+ ? () => []
1811
+ : createQuantifierParser(
1812
+ tryItemParser,
1813
+ triesSize,
1814
+ )
1815
+ ),
1816
+ (
1817
+ triesSize === 0
1818
+ ? () => new Map()
1819
+ : encodedCatchHandlerListParser
1820
+ ),
1821
+ ]),
1822
+ ([
1823
+ instructions,
1824
+ _padding,
1825
+ tryItems,
1826
+ handlers,
1827
+ ]) => ({
1828
+ registersSize,
1829
+ insSize,
1830
+ outsSize,
1831
+ triesSize,
1832
+ debugInfoOffset: isoOffsetToDebugInfoItem.wrap(debugInfoOffset),
1833
+ instructions,
1834
+ tryItems,
1835
+ handlers,
1836
+ }),
1837
+ ),
1838
+ )();
1839
+
1840
+ setParserName(dalvikExecutableCodeItemParser, 'dalvikExecutableCodeItemParser');
1841
+
1842
+ return dalvikExecutableCodeItemParser;
1843
+ };
1844
+
1845
+ type DalvikExecutableCodeItemByOffset<Instructions> = Map<OffsetToCodeItem, DalvikExecutableCodeItem<Instructions>>;
1846
+
1847
+ const createSkipToThenCodeItemsParser = <Instructions>({
1848
+ sizeOffset,
1849
+ createInstructionsParser,
1850
+ }: {
1851
+ sizeOffset: SizeOffset;
1852
+ createInstructionsParser: CreateInstructionsParser<Instructions>;
1853
+ }): Parser<DalvikExecutableCodeItemByOffset<Instructions>, Uint8Array> => createSkipToThenItemByOffsetParser({
1854
+ sizeOffset,
1855
+ itemParser: createDalvikExecutableCodeItemParser({
1856
+ createInstructionsParser,
1857
+ }),
1858
+ byteAlign4: true,
1859
+ isoOffset: isoOffsetToCodeItem,
1860
+ parserName: 'skipToThenCodeItemsParser',
1861
+ });
1862
+
1863
+ type DalvikExecutableDebugByteCodeValueItem =
1864
+ | {
1865
+ type: 'advancePc';
1866
+ addressDiff: number;
1867
+ }
1868
+ | {
1869
+ type: 'advanceLine';
1870
+ lineDiff: number;
1871
+ }
1872
+ | {
1873
+ type: 'startLocal';
1874
+ registerNum: number;
1875
+ nameIndex: undefined | IndexIntoStringIds;
1876
+ typeIndex: undefined | IndexIntoTypeIds;
1877
+ }
1878
+ | {
1879
+ type: 'startLocalExtended';
1880
+ registerNum: number;
1881
+ nameIndex: undefined | IndexIntoStringIds;
1882
+ typeIndex: undefined | IndexIntoTypeIds;
1883
+ signatureIndex: undefined | IndexIntoStringIds;
1884
+ }
1885
+ | {
1886
+ type: 'endLocal';
1887
+ registerNum: number;
1888
+ }
1889
+ | {
1890
+ type: 'restartLocal';
1891
+ registerNum: number;
1892
+ }
1893
+ | {
1894
+ type: 'setPrologueEnd';
1895
+ }
1896
+ | {
1897
+ type: 'setEpilogueBegin';
1898
+ }
1899
+ | {
1900
+ type: 'setFile';
1901
+ nameIndex: undefined | IndexIntoStringIds;
1902
+ }
1903
+ | {
1904
+ type: 'special';
1905
+ value: number;
1906
+ }
1907
+ ;
1908
+
1909
+ const dalvikExecutableDebugByteCodeValueParser: Parser<DalvikExecutableDebugByteCodeValueItem, Uint8Array> = parserCreatorCompose(
1910
+ () => ubyteParser,
1911
+ (value): Parser<DalvikExecutableDebugByteCodeValueItem, Uint8Array> => {
1912
+ switch (value) {
1913
+ case 0x01: { return promiseCompose(
1914
+ uleb128NumberParser,
1915
+ addressDiff => ({ type: 'advancePc', addressDiff }),
1916
+ );
1917
+ }
1918
+
1919
+ case 0x02: { return promiseCompose(
1920
+ sleb128NumberParser,
1921
+ lineDiff => ({ type: 'advanceLine', lineDiff }),
1922
+ );
1923
+ }
1924
+
1925
+ case 0x03: { return promiseCompose(
1926
+ createTupleParser([
1927
+ uleb128NumberParser,
1928
+ uleb128p1NumberParser,
1929
+ uleb128p1NumberParser,
1930
+ ]),
1931
+ ([ registerNumber, nameIndex, typeIndex ]) => ({
1932
+ type: 'startLocal',
1933
+ registerNum: registerNumber,
1934
+ nameIndex: nameIndex === -1 ? undefined : isoIndexIntoStringIds.wrap(nameIndex),
1935
+ typeIndex: typeIndex === -1 ? undefined : isoIndexIntoTypeIds.wrap(typeIndex),
1936
+ }),
1937
+ );
1938
+ }
1939
+
1940
+ case 0x04: { return promiseCompose(
1941
+ createTupleParser([
1942
+ uleb128NumberParser,
1943
+ uleb128p1NumberParser,
1944
+ uleb128p1NumberParser,
1945
+ uleb128p1NumberParser,
1946
+ ]),
1947
+ ([ registerNumber, nameIndex, typeIndex, signatureIndex ]) => ({
1948
+ type: 'startLocalExtended',
1949
+ registerNum: registerNumber,
1950
+ nameIndex: nameIndex === -1 ? undefined : isoIndexIntoStringIds.wrap(nameIndex),
1951
+ typeIndex: typeIndex === -1 ? undefined : isoIndexIntoTypeIds.wrap(typeIndex),
1952
+ signatureIndex: signatureIndex === -1 ? undefined : isoIndexIntoStringIds.wrap(signatureIndex),
1953
+ }),
1954
+ );
1955
+ }
1956
+
1957
+ case 0x05: { return promiseCompose(
1958
+ uleb128NumberParser,
1959
+ registerNumber => ({ type: 'endLocal', registerNum: registerNumber }),
1960
+ );
1961
+ }
1962
+
1963
+ case 0x06: { return promiseCompose(
1964
+ uleb128NumberParser,
1965
+ registerNumber => ({ type: 'restartLocal', registerNum: registerNumber }),
1966
+ );
1967
+ }
1968
+
1969
+ case 0x07: { return () => ({ type: 'setPrologueEnd' });
1970
+ }
1971
+
1972
+ case 0x08: { return () => ({ type: 'setEpilogueBegin' });
1973
+ }
1974
+
1975
+ case 0x09: { return promiseCompose(
1976
+ uleb128p1NumberParser,
1977
+ nameIndex => ({ type: 'setFile', nameIndex: nameIndex === -1 ? undefined : isoIndexIntoStringIds.wrap(nameIndex) }),
1978
+ );
1979
+ }
1980
+
1981
+ default: { return parserContext => {
1982
+ parserContext.invariant(value >= 0x0A, 'Unexpected special value: %s', value);
1983
+ return { type: 'special', value };
1984
+ };
1985
+ }
1986
+ }
1987
+ },
1988
+ )();
1989
+
1990
+ setParserName(dalvikExecutableDebugByteCodeValueParser, 'dalvikExecutableDebugByteCodeValueParser');
1991
+
1992
+ type DalvikExecutableDebugByteCodeItem = DalvikExecutableDebugByteCodeValueItem[];
1993
+
1994
+ const debugByteCodeParser: Parser<DalvikExecutableDebugByteCodeItem, Uint8Array> = createElementTerminatedArrayParserUnsafe(
1995
+ dalvikExecutableDebugByteCodeValueParser,
1996
+ 0,
1997
+ );
1998
+
1999
+ setParserName(debugByteCodeParser, 'debugByteCodeParser');
2000
+
2001
+ type DalvikExecutableDebugInfoItem = {
2002
+ lineStart: number;
2003
+ parameterNames: Array<undefined | IndexIntoStringIds>;
2004
+ bytecode: DalvikExecutableDebugByteCodeItem;
2005
+ };
2006
+
2007
+ const DEX_DEBUG_INFO_ITEM_PARAMETER_NAME_NO_INDEX = -1;
2008
+
2009
+ const debugInfoItemParser: Parser<DalvikExecutableDebugInfoItem, Uint8Array> = parserCreatorCompose(
2010
+ () => createTupleParser([
2011
+ uleb128NumberParser,
2012
+ uleb128NumberParser,
2013
+ ]),
2014
+ ([
2015
+ lineStart,
2016
+ parametersSize,
2017
+ ]) => promiseCompose(
2018
+ createTupleParser([
2019
+ createQuantifierParser(
2020
+ uleb128p1NumberParser,
2021
+ parametersSize,
2022
+ ),
2023
+ debugByteCodeParser,
2024
+ ]),
2025
+ ([ parameterNames, bytecode ]) => ({
2026
+ lineStart,
2027
+ parameterNames: parameterNames.map(parameterName => parameterName === DEX_DEBUG_INFO_ITEM_PARAMETER_NAME_NO_INDEX ? undefined : isoIndexIntoStringIds.wrap(parameterName)),
2028
+ bytecode,
2029
+ }),
2030
+ ),
2031
+ )();
2032
+
2033
+ setParserName(debugInfoItemParser, 'debugInfoItemParser');
2034
+
2035
+ type DalvikExecutableDebugInfoItemByOffset = Map<OffsetToDebugInfoItem, DalvikExecutableDebugInfoItem>;
2036
+
2037
+ const createSkipToThenDebugInfoItemsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableDebugInfoItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
2038
+ sizeOffset,
2039
+ itemParser: debugInfoItemParser,
2040
+ byteAlign4: false,
2041
+ isoOffset: isoOffsetToDebugInfoItem,
2042
+ parserName: 'skipToThenDebugInfoItemsParser',
2043
+ });
2044
+
2045
+ type DalvikExecutableAnnotationItemVisibility =
2046
+ | 'build'
2047
+ | 'runtime'
2048
+ | 'system'
2049
+ ;
2050
+
2051
+ const dalvikExecutableAnnotationItemVisibilityParser: Parser<DalvikExecutableAnnotationItemVisibility, Uint8Array> = promiseCompose(
2052
+ ubyteParser,
2053
+ visibility => {
2054
+ switch (visibility) {
2055
+ case 0x00: { return 'build';
2056
+ }
2057
+
2058
+ case 0x01: { return 'runtime';
2059
+ }
2060
+
2061
+ case 0x02: { return 'system';
2062
+ }
2063
+
2064
+ default: { invariant(false, 'Unexpected visibility: %s', visibility);
2065
+ }
2066
+ }
2067
+ },
2068
+ );
2069
+
2070
+ setParserName(dalvikExecutableAnnotationItemVisibilityParser, 'dalvikExecutableAnnotationItemVisibilityParser');
2071
+
2072
+ type DalvikExecutableAnnotationItem = {
2073
+ visibility: DalvikExecutableAnnotationItemVisibility;
2074
+ encodedAnnotation: DalvikExecutableEncodedAnnotation;
2075
+ };
2076
+
2077
+ const dalvikExecutableAnnotationItemParser: Parser<DalvikExecutableAnnotationItem, Uint8Array> = promiseCompose(
2078
+ createTupleParser([
2079
+ dalvikExecutableAnnotationItemVisibilityParser,
2080
+ encodedAnnotationParser,
2081
+ ]),
2082
+ ([ visibility, encodedAnnotation ]) => ({ visibility, encodedAnnotation }),
2083
+ );
2084
+
2085
+ setParserName(dalvikExecutableAnnotationItemParser, 'dalvikExecutableAnnotationItemParser');
2086
+
2087
+ type DalvikExecutableAnnotationItemByOffset = Map<OffsetToAnnotationItem, DalvikExecutableAnnotationItem>;
2088
+
2089
+ const createSkipToThenAnnotationItemsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableAnnotationItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
2090
+ sizeOffset,
2091
+ itemParser: dalvikExecutableAnnotationItemParser,
2092
+ byteAlign4: false,
2093
+ isoOffset: isoOffsetToAnnotationItem,
2094
+ parserName: 'skipToThenAnnotationItemsParser',
2095
+ });
2096
+
2097
+ type DalvikExecutableHeaderAndMap = {
2098
+ headerItem: DalvikExecutableHeaderItem;
2099
+ mapList: DalvikExecutableMapList;
2100
+ };
2101
+
2102
+ const dalvikExecutableHeaderAndMapParser: Parser<DalvikExecutableHeaderAndMap, Uint8Array> = parserCreatorCompose(
2103
+ () => dalvikExecutableHeaderItemParser,
2104
+ headerItem => promiseCompose(
2105
+ createLookaheadParser(createDalvikExecutableMapListParser(headerItem.mapOffset)),
2106
+ mapList => ({ headerItem, mapList }),
2107
+ ),
2108
+ )();
2109
+
2110
+ type DalvikExecutableAnnotationOffsetItem = {
2111
+ annotationOffset: OffsetToAnnotationItem;
2112
+ };
2113
+
2114
+ const dalvikExecutableAnnotationOffsetItemParser: Parser<DalvikExecutableAnnotationOffsetItem, Uint8Array> = promiseCompose(
2115
+ uintParser,
2116
+ annotationOffset => ({
2117
+ annotationOffset: isoOffsetToAnnotationItem.wrap(annotationOffset),
2118
+ }),
2119
+ );
2120
+
2121
+ type DalvikExecutableAnnotationSetItem = {
2122
+ entries: DalvikExecutableAnnotationOffsetItem[];
2123
+ };
2124
+
2125
+ const dalvikExecutableAnnotationSetItemParser: Parser<DalvikExecutableAnnotationSetItem, Uint8Array> = parserCreatorCompose(
2126
+ () => createTupleParser([
2127
+ byteAlign4Parser,
2128
+ uintParser,
2129
+ ]),
2130
+ ([ _, size ]) => promiseCompose(
2131
+ createQuantifierParser(
2132
+ dalvikExecutableAnnotationOffsetItemParser,
2133
+ size,
2134
+ ),
2135
+ entries => ({ entries }),
2136
+ ),
2137
+ )();
2138
+
2139
+ type DalvikExecutableAnnotationSetItemByOffset = Map<OffsetToAnnotationSetItem, DalvikExecutableAnnotationSetItem>;
2140
+
2141
+ const createSkipToThenAnnotationSetItemsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableAnnotationSetItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
2142
+ sizeOffset,
2143
+ itemParser: dalvikExecutableAnnotationSetItemParser,
2144
+ byteAlign4: true,
2145
+ isoOffset: isoOffsetToAnnotationSetItem,
2146
+ parserName: 'skipToThenAnnotationSetItemsParser',
2147
+ });
2148
+
2149
+ type DalvikExecutableAnnotationSetRefItem = OffsetToAnnotationSetItem;
2150
+
2151
+ const dalvikExecutableAnnotationSetRefItemParser: Parser<DalvikExecutableAnnotationSetRefItem, Uint8Array> = promiseCompose(
2152
+ uintParser,
2153
+ annotationsOffset => isoOffsetToAnnotationSetItem.wrap(annotationsOffset),
2154
+ );
2155
+
2156
+ type DalvikExecutableAnnotationSetRefList = {
2157
+ list: DalvikExecutableAnnotationSetRefItem[];
2158
+ };
2159
+
2160
+ const dalvikExecutableAnnotationSetRefListParser: Parser<DalvikExecutableAnnotationSetRefList, Uint8Array> = parserCreatorCompose(
2161
+ () => createTupleParser([
2162
+ byteAlign4Parser,
2163
+ uintParser,
2164
+ ]),
2165
+ ([ _, size ]) => promiseCompose(
2166
+ createQuantifierParser(
2167
+ dalvikExecutableAnnotationSetRefItemParser,
2168
+ size,
2169
+ ),
2170
+ list => ({ list }),
2171
+ ),
2172
+ )();
2173
+
2174
+ type DalvikExecutableAnnotationSetRefListItemByOffset = Map<OffsetToAnnotationSetRefListItem, DalvikExecutableAnnotationSetRefList>;
2175
+
2176
+ const createSkipToThenAnnotationSetRefListsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableAnnotationSetRefListItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
2177
+ sizeOffset,
2178
+ itemParser: dalvikExecutableAnnotationSetRefListParser,
2179
+ byteAlign4: true,
2180
+ isoOffset: isoOffsetToAnnotationSetRefListItem,
2181
+ parserName: 'skipToThenAnnotationSetRefListsParser',
2182
+ });
2183
+
2184
+ type DalvikExecutableMapItemType =
2185
+ | 'headerItem'
2186
+ | 'stringIdItem'
2187
+ | 'typeIdItem'
2188
+ | 'prototypeIdItem'
2189
+ | 'fieldIdItem'
2190
+ | 'methodIdItem'
2191
+ | 'classDefinitionItem'
2192
+ | 'callSiteIdItem'
2193
+ | 'methodHandleItem'
2194
+ | 'mapList'
2195
+ | 'typeList'
2196
+ | 'annotationSetRefList'
2197
+ | 'annotationSetItem'
2198
+ | 'classDataItem'
2199
+ | 'codeItem'
2200
+ | 'stringDataItem'
2201
+ | 'debugInfoItem'
2202
+ | 'annotationItem'
2203
+ | 'encodedArrayItem'
2204
+ | 'annotationsDirectoryItem'
2205
+ | 'hiddenApiClassDataItem'
2206
+ ;
2207
+
2208
+ const dalvikExecutableMapItemTypeParser: Parser<DalvikExecutableMapItemType, Uint8Array> = promiseCompose(
2209
+ ushortParser,
2210
+ type => {
2211
+ switch (type) {
2212
+ case 0x00_00: { return 'headerItem';
2213
+ }
2214
+
2215
+ case 0x00_01: { return 'stringIdItem';
2216
+ }
2217
+
2218
+ case 0x00_02: { return 'typeIdItem';
2219
+ }
2220
+
2221
+ case 0x00_03: { return 'prototypeIdItem';
2222
+ }
2223
+
2224
+ case 0x00_04: { return 'fieldIdItem';
2225
+ }
2226
+
2227
+ case 0x00_05: { return 'methodIdItem';
2228
+ }
2229
+
2230
+ case 0x00_06: { return 'classDefinitionItem';
2231
+ }
2232
+
2233
+ case 0x00_07: { return 'callSiteIdItem';
2234
+ }
2235
+
2236
+ case 0x00_08: { return 'methodHandleItem';
2237
+ }
2238
+
2239
+ case 0x10_00: { return 'mapList';
2240
+ }
2241
+
2242
+ case 0x10_01: { return 'typeList';
2243
+ }
2244
+
2245
+ case 0x10_02: { return 'annotationSetRefList';
2246
+ }
2247
+
2248
+ case 0x10_03: { return 'annotationSetItem';
2249
+ }
2250
+
2251
+ case 0x20_00: { return 'classDataItem';
2252
+ }
2253
+
2254
+ case 0x20_01: { return 'codeItem';
2255
+ }
2256
+
2257
+ case 0x20_02: { return 'stringDataItem';
2258
+ }
2259
+
2260
+ case 0x20_03: { return 'debugInfoItem';
2261
+ }
2262
+
2263
+ case 0x20_04: { return 'annotationItem';
2264
+ }
2265
+
2266
+ case 0x20_05: { return 'encodedArrayItem';
2267
+ }
2268
+
2269
+ case 0x20_06: { return 'annotationsDirectoryItem';
2270
+ }
2271
+
2272
+ case 0xF0_00: { return 'hiddenApiClassDataItem';
2273
+ }
2274
+
2275
+ default: { invariant(false, 'Unexpected map item type: %s', type);
2276
+ }
2277
+ }
2278
+ },
2279
+ );
2280
+
2281
+ type DalvikExecutableMapItem = {
2282
+ type: DalvikExecutableMapItemType;
2283
+ size: number;
2284
+ offset: number;
2285
+ };
2286
+
2287
+ const dalvikExecutableMapItemParser: Parser<DalvikExecutableMapItem, Uint8Array> = promiseCompose(
2288
+ createTupleParser([
2289
+ dalvikExecutableMapItemTypeParser,
2290
+ ushortParser,
2291
+ uintParser,
2292
+ uintParser,
2293
+ ]),
2294
+ ([ type, _unused, size, offset ]) => ({ type, size, offset }),
2295
+ );
2296
+
2297
+ type DalvikExecutableMapList = DalvikExecutableMapItem[];
2298
+
2299
+ const dalvikExecutableMapListParser: Parser<DalvikExecutableMapList, Uint8Array> = parserCreatorCompose(
2300
+ () => uintParser,
2301
+ size => createQuantifierParser(
2302
+ dalvikExecutableMapItemParser,
2303
+ size,
2304
+ ),
2305
+ )();
2306
+
2307
+ setParserName(dalvikExecutableMapListParser, 'dalvikExecutableMapListParser');
2308
+
2309
+ const createDalvikExecutableMapListParser = (mapOffset: number): Parser<DalvikExecutableMapList, Uint8Array> => {
2310
+ const dalvikExecutableMapParser = promiseCompose(
2311
+ createTupleParser([
2312
+ createSkipToParser(mapOffset),
2313
+ dalvikExecutableMapListParser,
2314
+ ]),
2315
+ ([ _, map ]) => map,
2316
+ );
2317
+
2318
+ setParserName(dalvikExecutableMapParser, 'dalvikExecutableMapParser');
2319
+
2320
+ return dalvikExecutableMapParser;
2321
+ };
2322
+
2323
+ type DalvikExecutableEncodedArrayItem = DalvikExecutableEncodedArray;
2324
+
2325
+ type DalvikExecutableEncodedArrayItemByOffset = Map<OffsetToEncodedArrayItem, DalvikExecutableEncodedArrayItem>;
2326
+
2327
+ const createSkipToThenEncodedArrayItemsParser = (sizeOffset: SizeOffset): Parser<DalvikExecutableEncodedArrayItemByOffset, Uint8Array> => createSkipToThenItemByOffsetParser({
2328
+ sizeOffset,
2329
+ itemParser: encodedArrayParser,
2330
+ byteAlign4: false,
2331
+ isoOffset: isoOffsetToEncodedArrayItem,
2332
+ parserName: 'skipToThenEncodedArrayItemsParser',
2333
+ });
2334
+
2335
+ type DalvikExecutableCallSiteIdItem = unknown; // TODO
2336
+
2337
+ type DalvikExecutableMethodHandleItem = unknown; // TODO
2338
+
2339
+ type DalvikExecutableHiddenApiClassDataItem = unknown; // TODO
2340
+
2341
+ type DalvikExecutableData<Instructions> = {
2342
+ headerItem: DalvikExecutableHeaderItem;
2343
+ stringIdItems: DalvikExecutableStringIdItems;
2344
+ typeIdItems: DalvikExecutableTypeIdItems;
2345
+ prototypeIdItems: DalvikExecutablePrototypeIdItems;
2346
+ fieldIdItems: DalvikExecutableFieldIdItems;
2347
+ methodIdItems: DalvikExecutableMethodIdItems;
2348
+ classDefinitionItems: DalvikExecutableClassDefinitionItem[];
2349
+ callSiteIdItems: DalvikExecutableCallSiteIdItem[];
2350
+ methodHandleItems: DalvikExecutableMethodHandleItem[];
2351
+ mapList: DalvikExecutableMapList;
2352
+ typeListByOffset: DalvikExecutableTypeListByOffset;
2353
+ annotationSetRefListItemByOffset: DalvikExecutableAnnotationSetRefListItemByOffset;
2354
+ annotationSetItemByOffset: DalvikExecutableAnnotationSetItemByOffset;
2355
+ classDataItemByOffset: DalvikExecutableClassDataItemByOffset;
2356
+ codeItemByOffset: DalvikExecutableCodeItemByOffset<Instructions>;
2357
+ stringDataItemStringByOffset: DalvikExecutableStringDataItemStringByOffset;
2358
+ debugInfoItemByOffset: DalvikExecutableDebugInfoItemByOffset;
2359
+ annotationItemByOffset: DalvikExecutableAnnotationItemByOffset;
2360
+ encodedArrayItemByOffset: DalvikExecutableEncodedArrayItemByOffset;
2361
+ annotationsDirectoryItemByOffset: DalvikExecutableAnnotationsDirectoryItemByOffset;
2362
+ hiddenApiClassDataItems: DalvikExecutableHiddenApiClassDataItem[];
2363
+ link: undefined | Uint8Array;
2364
+ };
2365
+
2366
+ const createDalvikExecutableDataParser = <Instructions>({
2367
+ headerItem,
2368
+ mapList,
2369
+ createInstructionsParser,
2370
+ }: DalvikExecutableHeaderAndMap & {
2371
+ createInstructionsParser: CreateInstructionsParser<Instructions>;
2372
+ }): Parser<DalvikExecutableData<Instructions>, Uint8Array> => {
2373
+ const dalvikExecutableDataParser: Parser<DalvikExecutableData<Instructions>, Uint8Array> = async parserContext => {
2374
+ let stringIdItems: DalvikExecutableStringIdItems = isoDalvikExecutableStringIdItems.wrap([]);
2375
+ let typeIdItems: DalvikExecutableTypeIdItems = isoDalvikExecutableTypeIdItems.wrap([]);
2376
+ let prototypeIdItems: DalvikExecutablePrototypeIdItems = isoDalvikExecutablePrototypeIdItems.wrap([]);
2377
+ let fieldIdItems: DalvikExecutableFieldIdItems = isoDalvikExecutableFieldIdItems.wrap([]);
2378
+ let methodIdItems: DalvikExecutableMethodIdItems = isoDalvikExecutableMethodIdItems.wrap([]);
2379
+ let classDefinitionItems: DalvikExecutableClassDefinitionItem[] = [];
2380
+ const callSiteIdItems: DalvikExecutableCallSiteIdItem[] = [];
2381
+ const methodHandleItems: DalvikExecutableMethodHandleItem[] = [];
2382
+ let typeListByOffset: DalvikExecutableTypeListByOffset = new Map();
2383
+ let annotationSetRefListItemByOffset: DalvikExecutableAnnotationSetRefListItemByOffset = new Map();
2384
+ let annotationSetItemByOffset: DalvikExecutableAnnotationSetItemByOffset = new Map();
2385
+ let classDataItemByOffset: DalvikExecutableClassDataItemByOffset = new Map();
2386
+ let codeItemByOffset: DalvikExecutableCodeItemByOffset<Instructions> = new Map();
2387
+ let stringDataItemStringByOffset: DalvikExecutableStringDataItemStringByOffset = new Map();
2388
+ let debugInfoItemByOffset: DalvikExecutableDebugInfoItemByOffset = new Map();
2389
+ let annotationItemByOffset: DalvikExecutableAnnotationItemByOffset = new Map();
2390
+ let encodedArrayItemByOffset: DalvikExecutableEncodedArrayItemByOffset = new Map();
2391
+ let annotationsDirectoryItemByOffset: DalvikExecutableAnnotationsDirectoryItemByOffset = new Map();
2392
+ const hiddenApiClassDataItems: DalvikExecutableHiddenApiClassDataItem[] = [];
2393
+
2394
+ // Track if link has been parsed
2395
+ let link: undefined | Uint8Array = undefined;
2396
+ let linkParsed = false;
2397
+
2398
+ for (const dexMapItem of mapList) {
2399
+ // Parse link data before any map item that comes after it in the file
2400
+ // Link data is not included in the map items, but is referenced in the header
2401
+ if (!linkParsed && headerItem.link.size > 0 && headerItem.link.offset < dexMapItem.offset) {
2402
+ link = await createRawDataParser(headerItem.link)(parserContext);
2403
+ linkParsed = true;
2404
+ }
2405
+ if (dexMapItem.type === 'headerItem') {
2406
+ continue;
2407
+ }
2408
+
2409
+ if (dexMapItem.type === 'stringIdItem') {
2410
+ stringIdItems = await createSkipToThenStringIdItemsParser(dexMapItem)(parserContext);
2411
+ continue;
2412
+ }
2413
+
2414
+ if (dexMapItem.type === 'typeIdItem') {
2415
+ typeIdItems = await createSkipToThenTypeIdItemsParser(dexMapItem)(parserContext);
2416
+ continue;
2417
+ }
2418
+
2419
+ if (dexMapItem.type === 'prototypeIdItem') {
2420
+ prototypeIdItems = await createSkipToThenPrototypeIdItemsParser(dexMapItem)(parserContext);
2421
+ continue;
2422
+ }
2423
+
2424
+ if (dexMapItem.type === 'fieldIdItem') {
2425
+ fieldIdItems = await createSkipToThenFieldIdItemsParser(dexMapItem)(parserContext);
2426
+ continue;
2427
+ }
2428
+
2429
+ if (dexMapItem.type === 'methodIdItem') {
2430
+ methodIdItems = await createSkipToThenMethodIdItemsParser(dexMapItem)(parserContext);
2431
+ continue;
2432
+ }
2433
+
2434
+ if (dexMapItem.type === 'classDefinitionItem') {
2435
+ classDefinitionItems = await createSkipToThenClassDefinitionItemsParser(dexMapItem)(parserContext);
2436
+ continue;
2437
+ }
2438
+
2439
+ if (dexMapItem.type === 'callSiteIdItem') {
2440
+ // TODO
2441
+ }
2442
+
2443
+ if (dexMapItem.type === 'methodHandleItem') {
2444
+ // TODO
2445
+ }
2446
+
2447
+ if (dexMapItem.type === 'mapList') {
2448
+ // Re-parse the map itself to consume it from the input
2449
+ await createDalvikExecutableMapListParser(dexMapItem.offset)(parserContext);
2450
+ continue;
2451
+ }
2452
+
2453
+ if (dexMapItem.type === 'typeList') {
2454
+ typeListByOffset = await createSkipToThenTypeListByOffsetParser(dexMapItem)(parserContext);
2455
+ continue;
2456
+ }
2457
+
2458
+ if (dexMapItem.type === 'annotationSetRefList') {
2459
+ annotationSetRefListItemByOffset = await createSkipToThenAnnotationSetRefListsParser(dexMapItem)(parserContext);
2460
+ continue;
2461
+ }
2462
+
2463
+ if (dexMapItem.type === 'annotationSetItem') {
2464
+ annotationSetItemByOffset = await createSkipToThenAnnotationSetItemsParser(dexMapItem)(parserContext);
2465
+ continue;
2466
+ }
2467
+
2468
+ if (dexMapItem.type === 'classDataItem') {
2469
+ classDataItemByOffset = await createSkipToThenClassDataItemsParser(dexMapItem)(parserContext);
2470
+ continue;
2471
+ }
2472
+
2473
+ if (dexMapItem.type === 'codeItem') {
2474
+ codeItemByOffset = await createSkipToThenCodeItemsParser({
2475
+ sizeOffset: dexMapItem,
2476
+ createInstructionsParser,
2477
+ })(parserContext);
2478
+ continue;
2479
+ }
2480
+
2481
+ if (dexMapItem.type === 'stringDataItem') {
2482
+ stringDataItemStringByOffset = await createSkipToThenStringsParser(dexMapItem)(parserContext);
2483
+ continue;
2484
+ }
2485
+
2486
+ if (dexMapItem.type === 'debugInfoItem') {
2487
+ debugInfoItemByOffset = await createSkipToThenDebugInfoItemsParser(dexMapItem)(parserContext);
2488
+ continue;
2489
+ }
2490
+
2491
+ if (dexMapItem.type === 'annotationItem') {
2492
+ annotationItemByOffset = await createSkipToThenAnnotationItemsParser(dexMapItem)(parserContext);
2493
+ continue;
2494
+ }
2495
+
2496
+ if (dexMapItem.type === 'encodedArrayItem') {
2497
+ encodedArrayItemByOffset = await createSkipToThenEncodedArrayItemsParser(dexMapItem)(parserContext);
2498
+ continue;
2499
+ }
2500
+
2501
+ if (dexMapItem.type === 'annotationsDirectoryItem') {
2502
+ annotationsDirectoryItemByOffset = await createSkipToThenAnnotationsDirectoryItemsParser(dexMapItem)(parserContext);
2503
+ continue;
2504
+ }
2505
+
2506
+ if (dexMapItem.type === 'hiddenApiClassDataItem') {
2507
+ // TODO
2508
+ }
2509
+
2510
+ invariant(false, 'Unexpected map item type: %s', dexMapItem.type);
2511
+ }
2512
+
2513
+ // Parse link data after the loop if it hasn't been parsed yet
2514
+ // This handles the case where link comes after all map items
2515
+ if (!linkParsed && headerItem.link.size > 0) {
2516
+ link = await createRawDataParser(headerItem.link)(parserContext);
2517
+ }
2518
+
2519
+ return {
2520
+ headerItem,
2521
+ stringIdItems,
2522
+ typeIdItems,
2523
+ prototypeIdItems,
2524
+ fieldIdItems,
2525
+ methodIdItems,
2526
+ classDefinitionItems,
2527
+ callSiteIdItems,
2528
+ methodHandleItems,
2529
+ mapList,
2530
+ typeListByOffset,
2531
+ annotationSetRefListItemByOffset,
2532
+ annotationSetItemByOffset,
2533
+ classDataItemByOffset,
2534
+ codeItemByOffset,
2535
+ stringDataItemStringByOffset,
2536
+ debugInfoItemByOffset,
2537
+ annotationItemByOffset,
2538
+ encodedArrayItemByOffset,
2539
+ annotationsDirectoryItemByOffset,
2540
+ hiddenApiClassDataItems,
2541
+ link,
2542
+ };
2543
+ };
2544
+
2545
+ setParserName(dalvikExecutableDataParser, 'dalvikExecutableDataParser');
2546
+
2547
+ return dalvikExecutableDataParser;
2548
+ };
2549
+
2550
+ const createDalvikExecutableParser = <Instructions>({
2551
+ createInstructionsParser,
2552
+ }: {
2553
+ createInstructionsParser: CreateInstructionsParser<Instructions>;
2554
+ }): Parser<DalvikExecutable<Instructions>, Uint8Array> => parserCreatorCompose(
2555
+ () => dalvikExecutableHeaderAndMapParser,
2556
+ ({
2557
+ headerItem,
2558
+ mapList,
2559
+ }) => promiseCompose(
2560
+ createDalvikExecutableDataParser({
2561
+ headerItem,
2562
+ mapList,
2563
+ createInstructionsParser,
2564
+ }),
2565
+ async ({
2566
+ headerItem: _headerItem,
2567
+ stringIdItems,
2568
+ typeIdItems,
2569
+ prototypeIdItems,
2570
+ fieldIdItems,
2571
+ methodIdItems,
2572
+ classDefinitionItems,
2573
+ // CallSiteIdItems,
2574
+ // methodHandleItems,
2575
+ mapList: _mapList,
2576
+ typeListByOffset,
2577
+ annotationSetRefListItemByOffset,
2578
+ annotationSetItemByOffset,
2579
+ classDataItemByOffset,
2580
+ codeItemByOffset,
2581
+ stringDataItemStringByOffset,
2582
+ debugInfoItemByOffset,
2583
+ annotationItemByOffset,
2584
+ encodedArrayItemByOffset,
2585
+ annotationsDirectoryItemByOffset,
2586
+ // HiddenApiClassDataItems,
2587
+ link,
2588
+ }) => {
2589
+ const strings = stringIdItems.map(stringId => {
2590
+ const stringOffset = stringId;
2591
+ const string = stringDataItemStringByOffset.get(stringOffset);
2592
+ invariant(string !== undefined, 'String must be there. String offset: %s', stringOffset);
2593
+
2594
+ return string;
2595
+ });
2596
+
2597
+ const types = typeIdItems.map(typeId => {
2598
+ const type = strings.at(typeId);
2599
+ invariant(type, 'Type string must be there. Type id: %s', typeId);
2600
+
2601
+ return type;
2602
+ });
2603
+
2604
+ const resolvedTypeListByOffset = new Map<OffsetToTypeList, string[]>([
2605
+ [ isoOffsetToTypeList.wrap(0), [] ],
2606
+ ]);
2607
+
2608
+ for (const [ offset, typeIndexes ] of typeListByOffset) {
2609
+ const typeNames = isoDalvikExecutableTypeList.unwrap(typeIndexes).map(typeIndex => {
2610
+ const type = types.at(typeIndex);
2611
+ invariant(type, 'Type must be there. Type id: %s', typeIndex);
2612
+
2613
+ return type;
2614
+ });
2615
+
2616
+ resolvedTypeListByOffset.set(offset, typeNames);
2617
+ }
2618
+
2619
+ const prototypes = prototypeIdItems.map(prototypeId => {
2620
+ const shorty = strings.at(prototypeId.shortyIndex);
2621
+ invariant(shorty, 'Shorty must be there. Shorty id: %s', prototypeId.shortyIndex);
2622
+
2623
+ const returnType = types.at(prototypeId.returnTypeIndex);
2624
+ invariant(returnType, 'Return type must be there. Return type id: %s', prototypeId.returnTypeIndex);
2625
+
2626
+ const parameters = resolvedTypeListByOffset.get(prototypeId.parametersOffset);
2627
+ invariant(parameters !== undefined, 'Parameters must be there. Parameters offset: %s', prototypeId.parametersOffset);
2628
+
2629
+ return { shorty, returnType, parameters };
2630
+ });
2631
+
2632
+ const fields = fieldIdItems.map(fieldId => {
2633
+ const class_ = types.at(fieldId.classIndex);
2634
+ invariant(class_, 'Class must be there. Class id: %s', fieldId.classIndex);
2635
+
2636
+ const type = types.at(fieldId.typeIndex);
2637
+ invariant(type, 'Type must be there. Type id: %s', fieldId.typeIndex);
2638
+
2639
+ const name = strings.at(fieldId.nameIndex);
2640
+ invariant(name, 'Name string must be there. String offset: %s', fieldId.nameIndex);
2641
+
2642
+ return { class: class_, type, name };
2643
+ });
2644
+
2645
+ const methods = methodIdItems.map(methodId => {
2646
+ const class_ = types.at(methodId.classIndex);
2647
+ invariant(class_, 'Class must be there. Class id: %s', methodId.classIndex);
2648
+
2649
+ const prototype = prototypes.at(methodId.prototypeIndex);
2650
+ invariant(prototype, 'Prototype must be there. Prototype id: %s', methodId.prototypeIndex);
2651
+
2652
+ const name = strings.at(methodId.nameIndex);
2653
+ invariant(name, 'Name string must be there. String offset: %s', methodId.nameIndex);
2654
+
2655
+ return { class: class_, prototype, name };
2656
+ });
2657
+
2658
+ const debugInfoByOffset = new Map<OffsetToDebugInfoItem, undefined | DalvikExecutableDebugInfo>([
2659
+ [ isoOffsetToDebugInfoItem.wrap(0), undefined ],
2660
+ ]);
2661
+
2662
+ for (const [ offset, debugInfoItem ] of debugInfoItemByOffset) {
2663
+ debugInfoByOffset.set(offset, {
2664
+ lineStart: debugInfoItem.lineStart,
2665
+ parameterNames: debugInfoItem.parameterNames.map(index => {
2666
+ if (index === undefined) {
2667
+ return undefined;
2668
+ }
2669
+
2670
+ const string = strings.at(index);
2671
+ invariant(string !== undefined, 'String must be there. String id: %s', index);
2672
+
2673
+ return string;
2674
+ }),
2675
+ bytecode: debugInfoItem.bytecode.map(value => {
2676
+ switch (value.type) {
2677
+ case 'startLocal': { return {
2678
+ type: 'startLocal',
2679
+ registerNum: value.registerNum,
2680
+ name: value.nameIndex === undefined ? undefined : strings.at(value.nameIndex),
2681
+ type_: value.typeIndex === undefined ? undefined : types.at(value.typeIndex),
2682
+ };
2683
+ }
2684
+
2685
+ case 'startLocalExtended': { return {
2686
+ type: 'startLocalExtended',
2687
+ registerNum: value.registerNum,
2688
+ name: value.nameIndex === undefined ? undefined : strings.at(value.nameIndex),
2689
+ type_: value.typeIndex === undefined ? undefined : types.at(value.typeIndex),
2690
+ signature: value.signatureIndex === undefined ? undefined : strings.at(value.signatureIndex),
2691
+ };
2692
+ }
2693
+
2694
+ case 'setFile': { return { type: 'setFile', name: value.nameIndex === undefined ? undefined : strings.at(value.nameIndex) };
2695
+ }
2696
+
2697
+ default: { return value;
2698
+ }
2699
+ }
2700
+ }),
2701
+ });
2702
+ }
2703
+
2704
+ const codeByOffset = new Map<OffsetToCodeItem, undefined | DalvikExecutableCode<Instructions>>([
2705
+ [ isoOffsetToCodeItem.wrap(0), undefined ],
2706
+ ]);
2707
+
2708
+ for (const [ offset, codeItem ] of codeItemByOffset) {
2709
+ const debugInfo = debugInfoByOffset.get(codeItem.debugInfoOffset);
2710
+
2711
+ codeByOffset.set(offset, {
2712
+ registersSize: codeItem.registersSize,
2713
+ insSize: codeItem.insSize,
2714
+ outsSize: codeItem.outsSize,
2715
+ debugInfo,
2716
+ instructions: codeItem.instructions,
2717
+ tries: codeItem.tryItems.map(tryItem => {
2718
+ const handler_ = codeItem.handlers.get(tryItem.handlerOffset);
2719
+ invariant(handler_, 'Handler must be there. Handler offset: %s', tryItem.handlerOffset);
2720
+
2721
+ const handler = {
2722
+ handlers: handler_.handlers.map(encodedHandler => {
2723
+ const type = types.at(encodedHandler.typeIndex);
2724
+ invariant(type, 'Type must be there. Type id: %s', encodedHandler.typeIndex);
2725
+
2726
+ return {
2727
+ type,
2728
+ address: encodedHandler.address,
2729
+ };
2730
+ }),
2731
+ catchAllAddress: handler_.catchAllAddress,
2732
+ };
2733
+
2734
+ return {
2735
+ startAddress: tryItem.startAddress,
2736
+ instructionCount: tryItem.instructionCount,
2737
+ handler,
2738
+ };
2739
+ }),
2740
+ });
2741
+ }
2742
+
2743
+ const classDataByOffset = new Map<OffsetToClassDataItem, undefined | DalvikExecutableClassData<Instructions>>([
2744
+ [ isoOffsetToClassDataItem.wrap(0), undefined ],
2745
+ ]);
2746
+
2747
+ const resolvers: DalvikBytecodeOperationResolvers = {
2748
+ resolveIndexIntoStringIds(indexIntoStringIds) {
2749
+ const string = strings.at(indexIntoStringIds);
2750
+ invariant(string !== undefined, 'String must be there. String id: %s', indexIntoStringIds);
2751
+
2752
+ return string;
2753
+ },
2754
+
2755
+ resolveIndexIntoTypeIds(indexIntoTypeIds) {
2756
+ const type = types.at(indexIntoTypeIds);
2757
+ invariant(type !== undefined, 'Type must be there. Type id: %s', indexIntoTypeIds);
2758
+
2759
+ return type;
2760
+ },
2761
+
2762
+ resolveIndexIntoMethodIds(indexIntoMethodIds) {
2763
+ const method = methods.at(indexIntoMethodIds);
2764
+ invariant(method !== undefined, 'Method must be there. Method id: %s', indexIntoMethodIds);
2765
+
2766
+ return method;
2767
+ },
2768
+
2769
+ resolveIndexIntoFieldIds(indexIntoFieldIds) {
2770
+ const field = fields.at(indexIntoFieldIds);
2771
+ invariant(field !== undefined, 'Field must be there. Field id: %s', indexIntoFieldIds);
2772
+
2773
+ return field;
2774
+ },
2775
+ };
2776
+
2777
+ function resolveCode(code: undefined | DalvikExecutableCode<Instructions>): undefined | DalvikExecutableCode<Instructions> {
2778
+ if (!code) {
2779
+ return code;
2780
+ }
2781
+
2782
+ const { instructions, ...rest } = code;
2783
+
2784
+ if (!Array.isArray(instructions)) {
2785
+ return code;
2786
+ }
2787
+
2788
+ return {
2789
+ ...rest,
2790
+ instructions: instructions.map((instruction: DalvikBytecodeOperation) => resolveDalvikBytecodeOperation(instruction, resolvers)) as Instructions,
2791
+ };
2792
+ }
2793
+
2794
+ for (const [ offset, classDataItem ] of classDataItemByOffset) {
2795
+ classDataByOffset.set(offset, {
2796
+ staticFields: classDataItem.staticFields.map(encodedField => {
2797
+ const field = fields.at(encodedField.fieldIndex);
2798
+ invariant(field, 'Field must be there. Field id: %s', encodedField.fieldIndex);
2799
+
2800
+ return {
2801
+ field,
2802
+ accessFlags: encodedField.accessFlags,
2803
+ };
2804
+ }),
2805
+
2806
+ instanceFields: classDataItem.instanceFields.map(encodedField => {
2807
+ const field = fields.at(encodedField.fieldIndex);
2808
+ invariant(field, 'Field must be there. Field id: %s', encodedField.fieldIndex);
2809
+
2810
+ return {
2811
+ field,
2812
+ accessFlags: encodedField.accessFlags,
2813
+ };
2814
+ }),
2815
+
2816
+ directMethods: classDataItem.directMethods.map(method => {
2817
+ const method_ = methods.at(method.methodIndex);
2818
+ invariant(method_, 'Method must be there. Method id: %s', method.methodIndex);
2819
+
2820
+ const code = codeByOffset.get(method.codeOffset);
2821
+ invariant(!method.codeOffset || code, 'Code must be there. Code offset: %s', method.codeOffset);
2822
+
2823
+ return {
2824
+ method: method_,
2825
+ accessFlags: method.accessFlags,
2826
+ code: resolveCode(code),
2827
+ };
2828
+ }),
2829
+
2830
+ virtualMethods: classDataItem.virtualMethods.map(method => {
2831
+ const method_ = methods.at(method.methodIndex);
2832
+ invariant(method_, 'Method must be there. Method id: %s', method.methodIndex);
2833
+
2834
+ const code = codeByOffset.get(method.codeOffset);
2835
+ invariant(!method.codeOffset || code, 'Code must be there. Code offset: %s', method.codeOffset);
2836
+
2837
+ return {
2838
+ method: method_,
2839
+ accessFlags: method.accessFlags,
2840
+ code: resolveCode(code),
2841
+ };
2842
+ }),
2843
+ });
2844
+ }
2845
+
2846
+ // Resolve TaggedEncodedValue to DalvikExecutableEncodedValue for static values
2847
+ // Resolves internal index types to actual values while preserving type tags
2848
+ function resolveTaggedEncodedValueForStaticValues(taggedValue: DalvikExecutableTaggedEncodedValue): DalvikExecutableEncodedValue {
2849
+ const { type, value } = taggedValue;
2850
+
2851
+ // For primitive types, keep the type tag and value
2852
+ if (
2853
+ type === 'byte'
2854
+ || type === 'short'
2855
+ || type === 'char'
2856
+ || type === 'int'
2857
+ || type === 'float'
2858
+ || type === 'double'
2859
+ || type === 'long'
2860
+ || type === 'boolean'
2861
+ || type === 'null'
2862
+ || type === 'methodHandle'
2863
+ ) {
2864
+ return { type, value } as DalvikExecutableEncodedValue;
2865
+ }
2866
+
2867
+ // For types that reference the pool, resolve the index to the actual value
2868
+ if (type === 'methodType') {
2869
+ const prototype = prototypes.at(value);
2870
+ invariant(prototype, 'Prototype must be there. Prototype id: %s', isoIndexIntoPrototypeIds.unwrap(value));
2871
+ return { type, value: prototype };
2872
+ }
2873
+
2874
+ if (type === 'string') {
2875
+ const string = strings.at(value);
2876
+ invariant(string !== undefined, 'String must be there. String id: %s', isoIndexIntoStringIds.unwrap(value));
2877
+ return { type, value: string };
2878
+ }
2879
+
2880
+ if (type === 'type') {
2881
+ const typeString = types.at(value);
2882
+ invariant(typeString !== undefined, 'Type must be there. Type id: %s', isoIndexIntoTypeIds.unwrap(value));
2883
+ return { type, value: typeString };
2884
+ }
2885
+
2886
+ if (type === 'field' || type === 'enum') {
2887
+ const field = fields.at(value);
2888
+ invariant(field, 'Field must be there. Field id: %s', isoIndexIntoFieldIds.unwrap(value));
2889
+ return { type, value: field };
2890
+ }
2891
+
2892
+ if (type === 'method') {
2893
+ const method = methods.at(value);
2894
+ invariant(method, 'Method must be there. Method id: %s', isoIndexIntoMethodIds.unwrap(value));
2895
+ return { type, value: method };
2896
+ }
2897
+
2898
+ if (type === 'array') {
2899
+ return { type, value: value.map(resolveTaggedEncodedValueForStaticValues) };
2900
+ }
2901
+
2902
+ if (type === 'annotation') {
2903
+ // Resolve the encoded annotation
2904
+ const annotationType = types.at(value.typeIndex);
2905
+ invariant(annotationType, 'Type must be there. Type id: %s', isoIndexIntoTypeIds.unwrap(value.typeIndex));
2906
+
2907
+ const resolvedElements = value.elements.map(element => {
2908
+ const name = strings.at(element.nameIndex);
2909
+ invariant(name, 'Name string must be there. String offset: %s', element.nameIndex);
2910
+
2911
+ return {
2912
+ name,
2913
+ value: resolveTaggedEncodedValueForAnnotations(element.value),
2914
+ };
2915
+ });
2916
+
2917
+ const annotation: DalvikExecutableAnnotation = {
2918
+ visibility: 'build', // Default visibility for embedded annotations
2919
+ type: annotationType,
2920
+ elements: resolvedElements,
2921
+ };
2922
+
2923
+ return { type, value: annotation };
2924
+ }
2925
+
2926
+ // This should never happen
2927
+ throw new Error(`Unknown encoded value type: ${type}`);
2928
+ }
2929
+
2930
+ // Resolve TaggedEncodedValue to DalvikExecutableEncodedValue for annotation elements
2931
+ // Resolves internal index types to actual values while preserving type tags
2932
+ function resolveTaggedEncodedValueForAnnotations(taggedValue: DalvikExecutableTaggedEncodedValue): DalvikExecutableEncodedValue {
2933
+ const { type, value } = taggedValue;
2934
+
2935
+ // For primitive types, keep the type tag and value
2936
+ if (
2937
+ type === 'byte'
2938
+ || type === 'short'
2939
+ || type === 'char'
2940
+ || type === 'int'
2941
+ || type === 'float'
2942
+ || type === 'double'
2943
+ || type === 'long'
2944
+ || type === 'boolean'
2945
+ || type === 'null'
2946
+ || type === 'methodHandle'
2947
+ ) {
2948
+ return { type, value } as DalvikExecutableEncodedValue;
2949
+ }
2950
+
2951
+ // For types that reference the pool, resolve the index to the actual value
2952
+ if (type === 'methodType') {
2953
+ const prototype = prototypes.at(value);
2954
+ invariant(prototype, 'Prototype must be there. Prototype id: %s', isoIndexIntoPrototypeIds.unwrap(value));
2955
+ return { type, value: prototype };
2956
+ }
2957
+
2958
+ if (type === 'string') {
2959
+ const string = strings.at(value);
2960
+ invariant(string !== undefined, 'String must be there. String id: %s', isoIndexIntoStringIds.unwrap(value));
2961
+ return { type, value: string };
2962
+ }
2963
+
2964
+ if (type === 'type') {
2965
+ const typeString = types.at(value);
2966
+ invariant(typeString !== undefined, 'Type must be there. Type id: %s', isoIndexIntoTypeIds.unwrap(value));
2967
+ return { type, value: typeString };
2968
+ }
2969
+
2970
+ if (type === 'field' || type === 'enum') {
2971
+ const field = fields.at(value);
2972
+ invariant(field, 'Field must be there. Field id: %s', isoIndexIntoFieldIds.unwrap(value));
2973
+ return { type, value: field };
2974
+ }
2975
+
2976
+ if (type === 'method') {
2977
+ const method = methods.at(value);
2978
+ invariant(method, 'Method must be there. Method id: %s', isoIndexIntoMethodIds.unwrap(value));
2979
+ return { type, value: method };
2980
+ }
2981
+
2982
+ // For arrays, recursively resolve elements
2983
+ if (type === 'array') {
2984
+ return { type, value: value.map(resolveTaggedEncodedValueForAnnotations) };
2985
+ }
2986
+
2987
+ // For annotations
2988
+ if (type === 'annotation') {
2989
+ // Resolve the encoded annotation (subannotation)
2990
+ const annotationType = types.at(value.typeIndex);
2991
+ invariant(annotationType, 'Type must be there. Type id: %s', isoIndexIntoTypeIds.unwrap(value.typeIndex));
2992
+
2993
+ const resolvedElements = value.elements.map(element => {
2994
+ const name = strings.at(element.nameIndex);
2995
+ invariant(name, 'Name string must be there. String offset: %s', element.nameIndex);
2996
+
2997
+ return {
2998
+ name,
2999
+ value: resolveTaggedEncodedValueForAnnotations(element.value),
3000
+ };
3001
+ });
3002
+
3003
+ const annotation: DalvikExecutableAnnotation = {
3004
+ visibility: 'build', // Default visibility for embedded annotations
3005
+ type: annotationType,
3006
+ elements: resolvedElements,
3007
+ };
3008
+
3009
+ return { type, value: annotation };
3010
+ }
3011
+
3012
+ // This should never happen
3013
+ throw new Error(`Unknown encoded value type: ${type}`);
3014
+ }
3015
+
3016
+ function resolveAnnotationOffsetItem({ annotationOffset }: DalvikExecutableAnnotationOffsetItem): DalvikExecutableAnnotation {
3017
+ const annotationItem = annotationItemByOffset.get(annotationOffset);
3018
+ invariant(annotationItem, 'Annotation must be there. Annotation offset: %s', annotationOffset);
3019
+
3020
+ const type = types.at(annotationItem.encodedAnnotation.typeIndex);
3021
+ invariant(type, 'Type must be there. Type id: %s', annotationItem.encodedAnnotation.typeIndex);
3022
+
3023
+ const elements = annotationItem.encodedAnnotation.elements.map(element => {
3024
+ const name = strings.at(element.nameIndex);
3025
+ invariant(name, 'Name string must be there. String offset: %s', element.nameIndex);
3026
+
3027
+ return {
3028
+ name,
3029
+ value: resolveTaggedEncodedValueForAnnotations(element.value),
3030
+ };
3031
+ });
3032
+
3033
+ return {
3034
+ visibility: annotationItem.visibility,
3035
+ type,
3036
+ elements,
3037
+ };
3038
+ }
3039
+
3040
+ function resolveAnnotationSetItem(annotationSetItem: undefined | DalvikExecutableAnnotationSetItem): undefined | DalvikExecutableAnnotation[] {
3041
+ if (!annotationSetItem) {
3042
+ return undefined;
3043
+ }
3044
+
3045
+ const annotationSet = annotationSetItem.entries.map(resolveAnnotationOffsetItem);
3046
+
3047
+ if (!annotationSet.length) {
3048
+ return [];
3049
+ }
3050
+
3051
+ return annotationSet;
3052
+ }
3053
+
3054
+ const classDefinitions = classDefinitionItems.map(classDefinitionItem => {
3055
+ const class_ = types.at(classDefinitionItem.classIndex);
3056
+ invariant(class_, 'Class must be there. Class id: %s', classDefinitionItem.classIndex);
3057
+
3058
+ const superclass = types.at(classDefinitionItem.superclassIndex);
3059
+ invariant(superclass, 'Superclass must be there. Superclass id: %s', classDefinitionItem.superclassIndex);
3060
+
3061
+ const interfaces = resolvedTypeListByOffset.get(classDefinitionItem.interfacesOffset);
3062
+ invariant(interfaces !== undefined, 'Interfaces must be there. Interfaces offset: %s', classDefinitionItem.interfacesOffset);
3063
+
3064
+ const sourceFile = classDefinitionItem.sourceFileIndex === undefined ? undefined : strings.at(classDefinitionItem.sourceFileIndex);
3065
+
3066
+ const annotationsDirectoryItem = annotationsDirectoryItemByOffset.get(classDefinitionItem.annotationsOffset);
3067
+ invariant(
3068
+ isoOffsetToAnnotationsDirectoryItem.unwrap(classDefinitionItem.annotationsOffset) === 0 || annotationsDirectoryItem,
3069
+ 'Annotations directory item must be there. Annotations offset: %s',
3070
+ classDefinitionItem.annotationsOffset,
3071
+ );
3072
+
3073
+ const annotations: undefined | DalvikExecutableClassAnnotations = (() => {
3074
+ if (!annotationsDirectoryItem) {
3075
+ return undefined;
3076
+ }
3077
+
3078
+ const classAnnotationSetItem = annotationSetItemByOffset.get(annotationsDirectoryItem.classAnnotationsOffset);
3079
+ invariant(
3080
+ isoOffsetToAnnotationSetItem.unwrap(annotationsDirectoryItem.classAnnotationsOffset) === 0 || classAnnotationSetItem,
3081
+ 'Class annotations must be there. Class annotations offset: %s',
3082
+ annotationsDirectoryItem.classAnnotationsOffset,
3083
+ );
3084
+
3085
+ const classAnnotations = (
3086
+ classAnnotationSetItem
3087
+ ? resolveAnnotationSetItem(classAnnotationSetItem)
3088
+ : undefined
3089
+ ) ?? [];
3090
+
3091
+ const fieldAnnotations: DalvikExecutableClassFieldAnnotation[] = annotationsDirectoryItem.fieldAnnotations.flatMap(fieldAnnotation => {
3092
+ const field = fields.at(fieldAnnotation.fieldIndex);
3093
+ invariant(field, 'Field must be there. Field id: %s', fieldAnnotation.fieldIndex);
3094
+
3095
+ const annotationSetItem = annotationSetItemByOffset.get(fieldAnnotation.annotationsOffset);
3096
+ invariant(
3097
+ isoOffsetToAnnotationSetItem.unwrap(fieldAnnotation.annotationsOffset) === 0 || annotationSetItem,
3098
+ 'Annotations must be there. Annotations offset: %s',
3099
+ fieldAnnotation.annotationsOffset,
3100
+ );
3101
+
3102
+ const annotations = resolveAnnotationSetItem(annotationSetItem);
3103
+
3104
+ // Skip fields with no annotations (undefined or empty array)
3105
+ if (!annotations || annotations.length === 0) {
3106
+ return [];
3107
+ }
3108
+
3109
+ return [{
3110
+ field,
3111
+ annotations,
3112
+ }];
3113
+ });
3114
+
3115
+ const methodAnnotations: DalvikExecutableClassMethodAnnotation[] = annotationsDirectoryItem.methodAnnotations.flatMap(methodAnnotation => {
3116
+ const method = methods.at(methodAnnotation.methodIndex);
3117
+ invariant(method, 'Method must be there. Method id: %s', methodAnnotation.methodIndex);
3118
+
3119
+ const annotationSetItem = annotationSetItemByOffset.get(methodAnnotation.annotationsOffset);
3120
+ invariant(
3121
+ isoOffsetToAnnotationSetItem.unwrap(methodAnnotation.annotationsOffset) === 0 || annotationSetItem,
3122
+ 'Annotations must be there. Annotations offset: %s',
3123
+ methodAnnotation.annotationsOffset,
3124
+ );
3125
+
3126
+ const annotations = resolveAnnotationSetItem(annotationSetItem) ?? [];
3127
+
3128
+ // Skip methods with no annotations
3129
+ if (annotations.length === 0) {
3130
+ return [];
3131
+ }
3132
+
3133
+ return [{
3134
+ method,
3135
+ annotations,
3136
+ }];
3137
+ });
3138
+
3139
+ const parameterAnnotations: DalvikExecutableClassParameterAnnotation[] = annotationsDirectoryItem.parameterAnnotations.flatMap(parameterAnnotation => {
3140
+ const method = methods.at(parameterAnnotation.methodIndex);
3141
+ invariant(method, 'Method must be there. Method id: %s', parameterAnnotation.methodIndex);
3142
+
3143
+ const annotationSetRefList = annotationSetRefListItemByOffset.get(parameterAnnotation.annotationsOffset);
3144
+ invariant(
3145
+ isoOffsetToAnnotationSetRefListItem.unwrap(parameterAnnotation.annotationsOffset) === 0 || annotationSetRefList,
3146
+ 'Annotations must be there. Annotations offset: %s',
3147
+ parameterAnnotation.annotationsOffset,
3148
+ );
3149
+
3150
+ const annotations: DalvikExecutableClassParameterAnnotation['annotations'] = annotationSetRefList?.list.map(annotationSetRefItem => {
3151
+ const annotationSetItem = annotationSetItemByOffset.get(annotationSetRefItem);
3152
+ invariant(
3153
+ isoOffsetToAnnotationSetItem.unwrap(annotationSetRefItem) === 0 || annotationSetItem,
3154
+ 'Annotations must be there. Annotations offset: %s',
3155
+ annotationSetRefItem,
3156
+ );
3157
+
3158
+ const annotationSet = resolveAnnotationSetItem(annotationSetItem);
3159
+
3160
+ return annotationSet ?? [];
3161
+ }) ?? [];
3162
+
3163
+ return { method, annotations };
3164
+ });
3165
+
3166
+ return {
3167
+ classAnnotations,
3168
+ fieldAnnotations,
3169
+ methodAnnotations,
3170
+ parameterAnnotations,
3171
+ };
3172
+ })();
3173
+
3174
+ const classData = classDataByOffset.get(classDefinitionItem.classDataOffset);
3175
+
3176
+ const staticValuesTagged = isoOffsetToEncodedArrayItem.unwrap(classDefinitionItem.staticValuesOffset) === 0 ? [] : encodedArrayItemByOffset.get(classDefinitionItem.staticValuesOffset);
3177
+ invariant(staticValuesTagged, 'Static values must be there. Static values offset: %s', classDefinitionItem.staticValuesOffset);
3178
+
3179
+ const staticValues = staticValuesTagged.map(resolveTaggedEncodedValueForStaticValues);
3180
+
3181
+ const allMembers = [
3182
+ ...classData?.staticFields ?? [],
3183
+ ...classData?.instanceFields ?? [],
3184
+ ...classData?.directMethods ?? [],
3185
+ // ...classData?.virtualMethods ?? [], // TODO?
3186
+ ];
3187
+
3188
+ const allMembersAreSynthetic = (
3189
+ allMembers.every(member => member.accessFlags.synthetic)
3190
+ && allMembers.length > 0
3191
+ );
3192
+
3193
+ const accessFlags = {
3194
+ ...classDefinitionItem.accessFlags,
3195
+ // Use the synthetic flag from the class definition, or compute it from members if not set
3196
+ synthetic: classDefinitionItem.accessFlags.synthetic || allMembersAreSynthetic,
3197
+ };
3198
+
3199
+ return {
3200
+ class: class_,
3201
+ accessFlags,
3202
+ superclass,
3203
+ interfaces,
3204
+ sourceFile,
3205
+ annotations,
3206
+ classData,
3207
+ staticValues,
3208
+ };
3209
+ });
3210
+
3211
+ // Sort parameter annotations in each class by method index in classData
3212
+ for (const classDef of classDefinitions) {
3213
+ if (classDef.annotations?.parameterAnnotations && classDef.classData) {
3214
+ const allMethods = [...(classDef.classData.directMethods ?? []), ...(classDef.classData.virtualMethods ?? [])];
3215
+ classDef.annotations.parameterAnnotations.sort((a, b) => {
3216
+ const indexA = allMethods.findIndex(m =>
3217
+ m.method.name === a.method.name &&
3218
+ m.method.prototype.shorty === a.method.prototype.shorty
3219
+ );
3220
+ const indexB = allMethods.findIndex(m =>
3221
+ m.method.name === b.method.name &&
3222
+ m.method.prototype.shorty === b.method.prototype.shorty
3223
+ );
3224
+ return indexA - indexB;
3225
+ });
3226
+ }
3227
+ }
3228
+
3229
+ return {
3230
+ classDefinitions,
3231
+ link,
3232
+ };
3233
+ },
3234
+ ),
3235
+ )();
3236
+
3237
+ export const dalvikExecutableParser: Parser<DalvikExecutable<DalvikBytecode>, Uint8Array> = createDalvikExecutableParser({
3238
+ createInstructionsParser: createDalvikBytecodeParser,
3239
+ });
3240
+
3241
+ setParserName(dalvikExecutableParser, 'dalvikExecutableParser');
3242
+
3243
+ export const dalvikExecutableWithRawInstructionsParser: Parser<DalvikExecutable<Uint8Array>, Uint8Array> = createDalvikExecutableParser<Uint8Array>({
3244
+ createInstructionsParser: createFixedLengthSequenceParser,
3245
+ });