@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.
- package/.github/copilot-instructions.md +149 -0
- package/.github/workflows/copilot-setup-steps.yml +18 -0
- package/.github/workflows/main.yml +29 -8
- package/.yarn/releases/yarn-4.9.4.cjs +942 -0
- package/.yarnrc.yml +1 -1
- package/build/allSettledStream.js +32 -14
- package/build/allSettledStream.test.js +32 -0
- package/build/androidPackage.d.ts +39 -0
- package/build/androidPackageParser.d.ts +17 -0
- package/build/androidPackageParser.js +185 -0
- package/build/androidPackageParser.test.js +22 -0
- package/build/androidPackageUnparser.d.ts +4 -0
- package/build/androidPackageUnparser.js +94 -0
- package/build/androidPackageUnparser.test.js +26 -0
- package/build/arbitrarilySlicedAsyncInterable.d.ts +3 -1
- package/build/arbitrarilySlicedAsyncInterable.js +3 -3
- package/build/arbitrarilySlicedAsyncInterator.js +2 -1
- package/build/arbitraryDalvikBytecode.d.ts +4 -0
- package/build/arbitraryDalvikBytecode.js +640 -0
- package/build/arbitraryDalvikExecutable.d.ts +3 -0
- package/build/arbitraryDalvikExecutable.js +282 -0
- package/build/arbitraryDosDateTime.js +1 -0
- package/build/arbitraryZipStream.js +1 -1
- package/build/arrayParser.js +2 -2
- package/build/arrayParser.test.js +3 -3
- package/build/arrayUnparser.d.ts +1 -1
- package/build/backsmali.d.ts +3 -0
- package/build/backsmali.js +50 -0
- package/build/bsonParser.js +6 -2
- package/build/customInvariant.d.ts +2 -1
- package/build/customInvariant.js +4 -6
- package/build/dalvikBytecodeParser/formatParsers.d.ts +171 -0
- package/build/dalvikBytecodeParser/formatParsers.js +304 -0
- package/build/dalvikBytecodeParser/formatSizes.d.ts +34 -0
- package/build/dalvikBytecodeParser/formatSizes.js +34 -0
- package/build/dalvikBytecodeParser/operationFormats.d.ts +225 -0
- package/build/dalvikBytecodeParser/operationFormats.js +225 -0
- package/build/dalvikBytecodeParser.d.ts +1207 -0
- package/build/dalvikBytecodeParser.js +1289 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +152 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.js +225 -0
- package/build/dalvikBytecodeUnparser.d.ts +3 -0
- package/build/dalvikBytecodeUnparser.js +642 -0
- package/build/dalvikBytecodeUnparser.test.js +25 -0
- package/build/dalvikExecutable.d.ts +215 -0
- package/build/dalvikExecutable.js +56 -0
- package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +4 -0
- package/build/dalvikExecutableParser/stringSyntaxParser.js +76 -0
- package/build/dalvikExecutableParser/typeParsers.d.ts +11 -0
- package/build/dalvikExecutableParser/typeParsers.js +39 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +106 -0
- package/build/dalvikExecutableParser/typedNumbers.js +18 -0
- package/build/dalvikExecutableParser.d.ts +5 -0
- package/build/dalvikExecutableParser.js +1757 -0
- package/build/dalvikExecutableParser.test.js +72 -0
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +275 -0
- package/build/dalvikExecutableUnparser/annotationUnparsers.d.ts +14 -0
- package/build/dalvikExecutableUnparser/annotationUnparsers.js +97 -0
- package/build/dalvikExecutableUnparser/poolBuilders.d.ts +49 -0
- package/build/dalvikExecutableUnparser/poolBuilders.js +140 -0
- package/build/dalvikExecutableUnparser/poolScanners.d.ts +4 -0
- package/build/dalvikExecutableUnparser/poolScanners.js +220 -0
- package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +25 -0
- package/build/dalvikExecutableUnparser/sectionUnparsers.js +581 -0
- package/build/dalvikExecutableUnparser/utils.d.ts +10 -0
- package/build/dalvikExecutableUnparser/utils.js +108 -0
- package/build/dalvikExecutableUnparser.d.ts +4 -0
- package/build/dalvikExecutableUnparser.js +406 -0
- package/build/dalvikExecutableUnparser.test.js +31 -0
- package/build/debugLogInputParser.d.ts +4 -0
- package/build/debugLogInputParser.js +16 -0
- package/build/debugLogParser.js +14 -3
- package/build/disjunctionParser.d.ts +2 -1
- package/build/disjunctionParser.js +6 -4
- package/build/elementTerminatedArrayParser.d.ts +3 -0
- package/build/elementTerminatedArrayParser.js +18 -0
- package/build/elementTerminatedArrayParser.test.js +52 -0
- package/build/elementTerminatedSequenceArrayParser.d.ts +3 -0
- package/build/elementTerminatedSequenceArrayParser.js +32 -0
- package/build/elementTerminatedSequenceArrayParser.test.js +34 -0
- package/build/elementTerminatedSequenceParser.d.ts +3 -0
- package/build/elementTerminatedSequenceParser.js +27 -0
- package/build/elementTerminatedSequenceParser.test.js +34 -0
- package/build/endOfInputParser.d.ts +1 -1
- package/build/exactElementParser.js +10 -5
- package/build/exactElementSwitchParser.d.ts +3 -0
- package/build/exactElementSwitchParser.js +22 -0
- package/build/exactSequenceParser.d.ts +2 -1
- package/build/exactSequenceParser.js +12 -2
- package/build/fetchCid.d.ts +1 -0
- package/build/fetchCid.js +103 -0
- package/build/fetchCid.test.js +16 -0
- package/build/fixedLengthSequenceParser.d.ts +1 -0
- package/build/fixedLengthSequenceParser.js +18 -1
- package/build/fixedLengthSequenceParser.test.js +41 -0
- package/build/hasExecutable.d.ts +1 -0
- package/build/hasExecutable.js +8 -0
- package/build/highResolutionTimer.d.ts +16 -0
- package/build/highResolutionTimer.js +42 -0
- package/build/inputReader.d.ts +11 -0
- package/build/inputReader.js +37 -0
- package/build/inputReader.test.js +161 -8
- package/build/inputReaderState.d.ts +10 -0
- package/build/inputReaderState.js +16 -0
- package/build/inspect.d.ts +1 -0
- package/build/inspect.js +7 -0
- package/build/javaKeyStoreParser.test.js +8 -8
- package/build/jsonParser.d.ts +2 -0
- package/build/jsonParser.js +19 -22
- package/build/lazyMessageError.d.ts +48 -0
- package/build/lazyMessageError.js +53 -0
- package/build/lazyMessageError.test.d.ts +1 -0
- package/build/lazyMessageError.test.js +15 -0
- package/build/leb128Parser.d.ts +7 -0
- package/build/leb128Parser.js +82 -0
- package/build/leb128Parser.test.d.ts +1 -0
- package/build/leb128Parser.test.js +107 -0
- package/build/lookaheadParser.d.ts +2 -0
- package/build/lookaheadParser.js +14 -0
- package/build/negativeLookaheadParser.js +22 -16
- package/build/negativeLookaheadParser.test.d.ts +1 -0
- package/build/negativeLookaheadParser.test.js +30 -0
- package/build/noStackCaptureOverheadError.d.ts +4 -0
- package/build/noStackCaptureOverheadError.js +9 -0
- package/build/noStackCaptureOverheadError.test.d.ts +1 -0
- package/build/noStackCaptureOverheadError.test.js +15 -0
- package/build/nonEmptyArrayParser.d.ts +2 -0
- package/build/nonEmptyArrayParser.js +32 -0
- package/build/nonEmptyArrayParser.test.d.ts +1 -0
- package/build/nonEmptyArrayParser.test.js +17 -0
- package/build/optionalParser.js +2 -2
- package/build/parser.d.ts +11 -1
- package/build/parser.js +82 -32
- package/build/parser.test.js +141 -25
- package/build/parserAccessorParser.js +9 -1
- package/build/parserConsumedSequenceParser.d.ts +1 -1
- package/build/parserConsumedSequenceParser.js +21 -16
- package/build/parserContext.d.ts +22 -6
- package/build/parserContext.js +113 -57
- package/build/parserContext.test.js +33 -2
- package/build/parserCreatorCompose.d.ts +1 -0
- package/build/parserCreatorCompose.js +8 -2
- package/build/parserError.d.ts +605 -40
- package/build/parserError.js +98 -53
- package/build/parserImplementationInvariant.d.ts +1 -1
- package/build/parserImplementationInvariant.js +2 -2
- package/build/parserInputCompanion.d.ts +15 -0
- package/build/parserInputCompanion.js +38 -0
- package/build/promiseCompose.d.ts +1 -1
- package/build/promiseCompose.js +11 -1
- package/build/promiseSettled.d.ts +1 -0
- package/build/promiseSettled.js +4 -0
- package/build/separatedArrayParser.d.ts +2 -0
- package/build/separatedArrayParser.js +39 -0
- package/build/separatedArrayParser.test.d.ts +1 -0
- package/build/separatedArrayParser.test.js +21 -0
- package/build/separatedNonEmptyArrayParser.d.ts +2 -0
- package/build/separatedNonEmptyArrayParser.js +40 -0
- package/build/separatedNonEmptyArrayParser.test.d.ts +1 -0
- package/build/separatedNonEmptyArrayParser.test.js +66 -0
- package/build/sequenceBuffer.d.ts +10 -0
- package/build/sequenceBuffer.js +54 -2
- package/build/sequenceBuffer.test.js +57 -0
- package/build/sequenceTerminatedSequenceParser.d.ts +5 -0
- package/build/sequenceTerminatedSequenceParser.js +32 -0
- package/build/sequenceTerminatedSequenceParser.test.d.ts +1 -0
- package/build/sequenceTerminatedSequenceParser.test.js +37 -0
- package/build/sequenceUnparser.d.ts +1 -1
- package/build/skipParser.d.ts +1 -1
- package/build/skipParser.js +4 -2
- package/build/skipToParser.d.ts +2 -0
- package/build/skipToParser.js +11 -0
- package/build/sliceBoundedParser.d.ts +1 -1
- package/build/sliceBoundedParser.js +7 -2
- package/build/sliceBoundedParser.test.js +30 -1
- package/build/smali.d.ts +1 -0
- package/build/smali.js +21 -0
- package/build/smaliParser.d.ts +68 -0
- package/build/smaliParser.js +2081 -0
- package/build/smaliParser.test.d.ts +1 -0
- package/build/smaliParser.test.js +410 -0
- package/build/stringFromAsyncIterable.d.ts +1 -0
- package/build/stringFromAsyncIterable.js +7 -0
- package/build/terminatedArrayParser.d.ts +3 -1
- package/build/terminatedArrayParser.js +79 -2
- package/build/terminatedArrayParser.test.d.ts +1 -0
- package/build/terminatedArrayParser.test.js +131 -0
- package/build/toAsyncIterable.d.ts +1 -0
- package/build/toAsyncIterable.js +7 -0
- package/build/toAsyncIterator.d.ts +1 -0
- package/build/toAsyncIterator.js +33 -0
- package/build/tupleParser.d.ts +4 -0
- package/build/tupleParser.js +1 -5
- package/build/unionParser.d.ts +2 -1
- package/build/unionParser.js +29 -14
- package/build/unionParser.test.d.ts +1 -0
- package/build/unionParser.test.js +60 -0
- package/build/unparser.d.ts +3 -3
- package/build/unparser.js +6 -4
- package/build/unparser.test.js +7 -19
- package/build/unparserContext.d.ts +2 -2
- package/build/unparserContext.js +2 -3
- package/build/unparserError.d.ts +2 -1
- package/build/unparserError.js +2 -1
- package/build/unparserImplementationInvariant.d.ts +1 -1
- package/build/unparserOutputCompanion.d.ts +1 -1
- package/build/unparserOutputCompanion.js +1 -1
- package/build/zipParser.d.ts +7 -2
- package/build/zipParser.js +36 -12
- package/build/zipUnparser.d.ts +7 -4
- package/build/zipUnparser.js +64 -45
- package/build/zipUnparser.test.js +15 -15
- package/package.json +33 -24
- package/src/allSettledStream.test.ts +40 -0
- package/src/allSettledStream.ts +47 -15
- package/src/androidPackage.ts +48 -0
- package/src/androidPackageParser.test.ts +27 -0
- package/src/{apkParser.test.ts.md → androidPackageParser.test.ts.md} +4 -4
- package/src/androidPackageParser.test.ts.snap +0 -0
- package/src/androidPackageParser.ts +398 -0
- package/src/androidPackageUnparser.test.ts +34 -0
- package/src/androidPackageUnparser.ts +126 -0
- package/src/arbitrarilySlicedAsyncInterable.ts +7 -2
- package/src/arbitrarilySlicedAsyncInterator.ts +4 -4
- package/src/arbitraryDalvikBytecode.ts +992 -0
- package/src/arbitraryDalvikExecutable.ts +434 -0
- package/src/arbitraryDosDateTime.ts +1 -0
- package/src/arbitraryZipStream.ts +1 -1
- package/src/arrayParser.test.ts +3 -3
- package/src/arrayParser.ts +2 -2
- package/src/arrayUnparser.ts +2 -2
- package/src/backsmali.ts +74 -0
- package/src/bsonParser.test.ts +12 -14
- package/src/bsonParser.ts +13 -2
- package/src/customInvariant.ts +8 -12
- package/src/dalvikBytecodeParser/formatParsers.ts +780 -0
- package/src/dalvikBytecodeParser/formatSizes.ts +35 -0
- package/src/dalvikBytecodeParser/operationFormats.ts +226 -0
- package/src/dalvikBytecodeParser.ts +2873 -0
- package/src/dalvikBytecodeUnparser/formatUnparsers.ts +442 -0
- package/src/dalvikBytecodeUnparser.test.ts +44 -0
- package/src/dalvikBytecodeUnparser.ts +758 -0
- package/src/dalvikExecutable.ts +282 -0
- package/src/dalvikExecutableParser/stringSyntaxParser.ts +145 -0
- package/src/dalvikExecutableParser/typeParsers.ts +74 -0
- package/src/dalvikExecutableParser/typedNumbers.ts +57 -0
- package/src/dalvikExecutableParser.test.ts +89 -0
- package/src/dalvikExecutableParser.test.ts.md +634 -0
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +3245 -0
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +363 -0
- package/src/dalvikExecutableUnparser/annotationUnparsers.ts +135 -0
- package/src/dalvikExecutableUnparser/poolBuilders.ts +189 -0
- package/src/dalvikExecutableUnparser/poolScanners.ts +297 -0
- package/src/dalvikExecutableUnparser/sectionUnparsers.ts +683 -0
- package/src/dalvikExecutableUnparser/utils.ts +149 -0
- package/src/dalvikExecutableUnparser.test.ts +57 -0
- package/src/dalvikExecutableUnparser.ts +581 -0
- package/src/debugLogInputParser.ts +28 -0
- package/src/debugLogParser.ts +19 -3
- package/src/disjunctionParser.ts +12 -7
- package/src/elementTerminatedArrayParser.test.ts +99 -0
- package/src/elementTerminatedArrayParser.ts +31 -0
- package/src/elementTerminatedSequenceArrayParser.test.ts +52 -0
- package/src/elementTerminatedSequenceArrayParser.ts +52 -0
- package/src/elementTerminatedSequenceParser.test.ts +52 -0
- package/src/elementTerminatedSequenceParser.ts +43 -0
- package/src/endOfInputParser.ts +1 -1
- package/src/exactElementParser.ts +17 -11
- package/src/exactElementSwitchParser.ts +41 -0
- package/src/exactSequenceParser.ts +23 -2
- package/src/fetchCid.test.ts +20 -0
- package/src/fetchCid.ts +121 -0
- package/src/fixedLengthSequenceParser.test.ts +75 -0
- package/src/fixedLengthSequenceParser.ts +28 -1
- package/src/hasExecutable.ts +11 -0
- package/src/highResolutionTimer.ts +49 -0
- package/src/inputReader.test.ts +204 -8
- package/src/inputReader.ts +76 -3
- package/src/inputReaderState.ts +33 -0
- package/src/inspect.ts +9 -0
- package/src/javaKeyStoreParser.test.ts +12 -15
- package/src/javaKeyStoreParser.ts +2 -6
- package/src/jsonParser.test.ts +2 -4
- package/src/jsonParser.ts +46 -62
- package/src/lazyMessageError.test.ts +21 -0
- package/src/lazyMessageError.ts +88 -0
- package/src/leb128Parser.test.ts +173 -0
- package/src/leb128Parser.ts +125 -0
- package/src/lookaheadParser.ts +19 -0
- package/src/negativeLookaheadParser.test.ts +49 -0
- package/src/negativeLookaheadParser.ts +27 -15
- package/src/noStackCaptureOverheadError.test.ts +17 -0
- package/src/noStackCaptureOverheadError.ts +12 -0
- package/src/nonEmptyArrayParser.test.ts +21 -0
- package/src/nonEmptyArrayParser.ts +44 -0
- package/src/optionalParser.ts +3 -2
- package/src/parser.test.ts +203 -31
- package/src/parser.test.ts.md +34 -27
- package/src/parser.test.ts.snap +0 -0
- package/src/parser.ts +172 -45
- package/src/parserAccessorParser.ts +12 -2
- package/src/parserConsumedSequenceParser.ts +26 -17
- package/src/parserContext.test.ts +37 -2
- package/src/parserContext.ts +185 -79
- package/src/parserCreatorCompose.ts +20 -2
- package/src/parserError.ts +144 -61
- package/src/parserImplementationInvariant.ts +3 -3
- package/src/parserInputCompanion.ts +55 -0
- package/src/promiseCompose.ts +17 -3
- package/src/promiseSettled.ts +6 -0
- package/src/separatedArrayParser.test.ts +34 -0
- package/src/separatedArrayParser.ts +55 -0
- package/src/separatedNonEmptyArrayParser.test.ts +117 -0
- package/src/separatedNonEmptyArrayParser.ts +61 -0
- package/src/sequenceBuffer.test.ts +70 -0
- package/src/sequenceBuffer.ts +88 -2
- package/src/sequenceTerminatedSequenceParser.test.ts +58 -0
- package/src/sequenceTerminatedSequenceParser.ts +62 -0
- package/src/sequenceUnparser.ts +2 -2
- package/src/skipParser.ts +7 -5
- package/src/skipToParser.ts +16 -0
- package/src/sliceBoundedParser.test.ts +35 -1
- package/src/sliceBoundedParser.ts +19 -1
- package/src/smali.ts +29 -0
- package/src/smaliParser.test.ts +443 -0
- package/src/smaliParser.test.ts.md +3907 -0
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +3348 -0
- package/src/stringFromAsyncIterable.ts +9 -0
- package/src/terminatedArrayParser.test.ts +258 -0
- package/src/terminatedArrayParser.ts +109 -6
- package/src/toAsyncIterable.ts +7 -0
- package/src/toAsyncIterator.ts +48 -0
- package/src/tupleParser.ts +8 -5
- package/src/uint8Array.ts +2 -3
- package/src/unionParser.test.ts +78 -0
- package/src/unionParser.ts +47 -21
- package/src/unparser.test.ts +18 -34
- package/src/unparser.ts +13 -9
- package/src/unparserContext.ts +9 -13
- package/src/unparserError.ts +2 -1
- package/src/unparserImplementationInvariant.ts +1 -1
- package/src/unparserOutputCompanion.ts +1 -1
- package/src/zip.ts +2 -6
- package/src/zipParser.ts +71 -20
- package/src/zipUnparser.test.ts +19 -19
- package/src/zipUnparser.ts +139 -90
- package/tsconfig.json +7 -1
- package/xo.config.ts +15 -0
- package/.yarn/releases/yarn-4.5.3.cjs +0 -934
- package/build/apk.d.ts +0 -39
- package/build/apkParser.d.ts +0 -16
- package/build/apkParser.js +0 -164
- package/build/apkParser.test.js +0 -22
- package/build/apkUnparser.d.ts +0 -4
- package/build/apkUnparser.js +0 -90
- package/build/apkUnparser.test.js +0 -26
- package/build/arbitraryDosDate.d.ts +0 -2
- package/build/arbitraryDosDate.js +0 -8
- package/build/arbitraryZipEntry.d.ts +0 -3
- package/build/arbitraryZipEntry.js +0 -26
- package/build/createDisjunctionParser.d.ts +0 -2
- package/build/createDisjunctionParser.js +0 -47
- package/build/createExactParser.d.ts +0 -2
- package/build/createExactParser.js +0 -12
- package/build/createSequentialUnionParser.d.ts +0 -2
- package/build/createSequentialUnionParser.js +0 -69
- package/build/fixedLengthChunkParser.d.ts +0 -2
- package/build/fixedLengthChunkParser.js +0 -12
- package/build/fixedLengthParser.d.ts +0 -2
- package/build/fixedLengthParser.js +0 -12
- package/build/inputChunkBuffer.d.ts +0 -15
- package/build/inputChunkBuffer.js +0 -40
- package/build/inputChunkBuffer.test.js +0 -34
- package/build/inputCompanion.d.ts +0 -18
- package/build/inputCompanion.js +0 -28
- package/build/invariantDefined.d.ts +0 -1
- package/build/invariantDefined.js +0 -5
- package/build/invariantIdentity.d.ts +0 -3
- package/build/invariantIdentity.js +0 -5
- package/build/javaKeystoreParser.d.ts +0 -2
- package/build/javaKeystoreParser.js +0 -7
- package/build/jsonParser2.d.ts +0 -3
- package/build/jsonParser2.js +0 -52
- package/build/jsonParser2.test.js +0 -22
- package/build/negativeLookahead.d.ts +0 -2
- package/build/negativeLookahead.js +0 -18
- package/build/parserCompose.d.ts +0 -3
- package/build/parserCompose.js +0 -7
- package/build/parserImplementationInvariantInvariant.d.ts +0 -3
- package/build/parserImplementationInvariantInvariant.js +0 -15
- package/build/parserInvariant.d.ts +0 -4
- package/build/parserInvariant.js +0 -11
- package/build/promiseFish.d.ts +0 -1
- package/build/promiseFish.js +0 -3
- package/build/sequenceParser.d.ts +0 -3
- package/build/sequenceParser.js +0 -10
- package/build/terminatedSequenceParser.d.ts +0 -2
- package/build/terminatedSequenceParser.js +0 -24
- package/build/unparserInputCompanion.d.ts +0 -15
- package/build/unparserInputCompanion.js +0 -13
- package/build/zipEntry.d.ts +0 -28
- package/build/zipFile.d.ts +0 -32
- package/build/zipFileEntry.d.ts +0 -6
- package/src/apk.ts +0 -48
- package/src/apkParser.test.ts +0 -30
- package/src/apkParser.test.ts.snap +0 -0
- package/src/apkParser.ts +0 -392
- package/src/apkUnparser.test.ts +0 -37
- package/src/apkUnparser.ts +0 -120
- package/src/invariantDefined.ts +0 -6
- package/src/invariantIdentity.ts +0 -8
- /package/build/{apk.js → androidPackage.js} +0 -0
- /package/build/{apkParser.test.d.ts → androidPackageParser.test.d.ts} +0 -0
- /package/build/{apkUnparser.test.d.ts → androidPackageUnparser.test.d.ts} +0 -0
- /package/build/{arbitraryDosPermissions.d.ts → dalvikBytecodeUnparser.test.d.ts} +0 -0
- /package/build/{arbitraryDosPermissions.js → dalvikExecutableParser.test.d.ts} +0 -0
- /package/build/{inputChunkBuffer.test.d.ts → dalvikExecutableParserAgainstSmaliParser.test.d.ts} +0 -0
- /package/build/{jsonParser2.test.d.ts → dalvikExecutableUnparser.test.d.ts} +0 -0
- /package/build/{parserParsingInvariant.d.ts → elementTerminatedArrayParser.test.d.ts} +0 -0
- /package/build/{parserParsingInvariant.js → elementTerminatedSequenceArrayParser.test.d.ts} +0 -0
- /package/build/{zipEntry.js → elementTerminatedSequenceParser.test.d.ts} +0 -0
- /package/build/{zipFile.js → fetchCid.test.d.ts} +0 -0
- /package/build/{zipFileEntry.js → fixedLengthSequenceParser.test.d.ts} +0 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Unparser } from './unparser.js';
|
|
2
|
+
import { type DalvikExecutable } from './dalvikExecutable.js';
|
|
3
|
+
import { type DalvikBytecode } from './dalvikBytecodeParser.js';
|
|
4
|
+
export declare const dalvikExecutableUnparser: Unparser<DalvikExecutable<DalvikBytecode>, Uint8Array>;
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { uintUnparser, ushortUnparser } from './dalvikBytecodeUnparser/formatUnparsers.js';
|
|
2
|
+
import { createPoolBuilders } from './dalvikExecutableUnparser/poolBuilders.js';
|
|
3
|
+
import { scanForPoolReferences } from './dalvikExecutableUnparser/poolScanners.js';
|
|
4
|
+
import { createSectionUnparsers } from './dalvikExecutableUnparser/sectionUnparsers.js';
|
|
5
|
+
import { createAnnotationUnparsers } from './dalvikExecutableUnparser/annotationUnparsers.js';
|
|
6
|
+
import { alignmentUnparser } from './dalvikExecutableUnparser/utils.js';
|
|
7
|
+
async function* yieldAndCapture(gen) {
|
|
8
|
+
let value;
|
|
9
|
+
for await (value of gen) {
|
|
10
|
+
yield value;
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Helper function to write a pool size and reserve space for its offset.
|
|
16
|
+
* Returns a WriteLater for the offset.
|
|
17
|
+
*/
|
|
18
|
+
async function* writePoolHeader(size, unparserContext) {
|
|
19
|
+
yield* uintUnparser(size, unparserContext);
|
|
20
|
+
const offsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
21
|
+
return offsetWriteLater;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Helper function to conditionally write an offset placeholder.
|
|
25
|
+
* Returns WriteLater if condition is true, otherwise writes 0 and returns undefined.
|
|
26
|
+
*/
|
|
27
|
+
async function* writeConditionalOffset(condition, unparserContext) {
|
|
28
|
+
if (condition) {
|
|
29
|
+
const offsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
30
|
+
return offsetWriteLater;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
yield* uintUnparser(0, unparserContext);
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Helper class to track offset and count for a section of items.
|
|
39
|
+
* Records the offset of the first item and counts items as they are written.
|
|
40
|
+
*/
|
|
41
|
+
class SectionTracker {
|
|
42
|
+
_offset = 0;
|
|
43
|
+
_count = 0;
|
|
44
|
+
recordItem(position) {
|
|
45
|
+
if (this._count === 0) {
|
|
46
|
+
this._offset = position;
|
|
47
|
+
}
|
|
48
|
+
this._count++;
|
|
49
|
+
}
|
|
50
|
+
get offset() {
|
|
51
|
+
return this._offset;
|
|
52
|
+
}
|
|
53
|
+
get count() {
|
|
54
|
+
return this._count;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export const dalvikExecutableUnparser = async function* (input, unparserContext) {
|
|
58
|
+
const poolBuilders = createPoolBuilders();
|
|
59
|
+
scanForPoolReferences(input, poolBuilders);
|
|
60
|
+
const sectionUnparsers = createSectionUnparsers(poolBuilders);
|
|
61
|
+
const annotationUnparsers = createAnnotationUnparsers(sectionUnparsers.getStringIndex, sectionUnparsers.getTypeIndex, sectionUnparsers.getFieldIndex, sectionUnparsers.getMethodIndex, sectionUnparsers.encodedValueUnparser);
|
|
62
|
+
const { stringPool, typePool, protoPool, fieldPool, methodPool } = poolBuilders;
|
|
63
|
+
const magicBytes = new Uint8Array([0x64, 0x65, 0x78, 0x0A]);
|
|
64
|
+
yield magicBytes;
|
|
65
|
+
const versionBytes = new Uint8Array([0x30, 0x33, 0x35, 0x00]);
|
|
66
|
+
yield versionBytes;
|
|
67
|
+
const checksumWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
68
|
+
const sha1WriteLater = yield* yieldAndCapture(unparserContext.writeLater(20));
|
|
69
|
+
const fileSizeWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
70
|
+
yield* uintUnparser(0x70, unparserContext);
|
|
71
|
+
yield* uintUnparser(0x12345678, unparserContext);
|
|
72
|
+
const linkData = input.link;
|
|
73
|
+
const hasLink = !!(linkData && linkData.length > 0);
|
|
74
|
+
if (hasLink) {
|
|
75
|
+
yield* uintUnparser(linkData.length, unparserContext);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
yield* uintUnparser(0, unparserContext);
|
|
79
|
+
}
|
|
80
|
+
const linkOffsetWriteLater = yield* writeConditionalOffset(hasLink, unparserContext);
|
|
81
|
+
const mapOffsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
82
|
+
const stringIdsOffsetWriteLater = yield* writePoolHeader(stringPool.size(), unparserContext);
|
|
83
|
+
const typeIdsOffsetWriteLater = yield* writePoolHeader(typePool.size(), unparserContext);
|
|
84
|
+
const protoIdsOffsetWriteLater = yield* writePoolHeader(protoPool.size(), unparserContext);
|
|
85
|
+
const fieldIdsOffsetWriteLater = yield* writePoolHeader(fieldPool.size(), unparserContext);
|
|
86
|
+
const methodIdsOffsetWriteLater = yield* writePoolHeader(methodPool.size(), unparserContext);
|
|
87
|
+
const classDefsOffsetWriteLater = yield* writePoolHeader(input.classDefinitions.length, unparserContext);
|
|
88
|
+
const dataOffsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
89
|
+
const dataSizeWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
90
|
+
const stringIdsOffset = unparserContext.position;
|
|
91
|
+
yield* unparserContext.writeEarlier(stringIdsOffsetWriteLater, uintUnparser, stringIdsOffset);
|
|
92
|
+
const stringDataOffsetWriteLaters = [];
|
|
93
|
+
for (let i = 0; i < stringPool.size(); i++) {
|
|
94
|
+
const offsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
95
|
+
stringDataOffsetWriteLaters.push(offsetWriteLater);
|
|
96
|
+
}
|
|
97
|
+
const typeIdsOffset = unparserContext.position;
|
|
98
|
+
yield* unparserContext.writeEarlier(typeIdsOffsetWriteLater, uintUnparser, typeIdsOffset);
|
|
99
|
+
for (const type of typePool.getTypes()) {
|
|
100
|
+
const stringIndex = sectionUnparsers.getStringIndex(type);
|
|
101
|
+
yield* uintUnparser(stringIndex, unparserContext);
|
|
102
|
+
}
|
|
103
|
+
const protoIdsOffset = unparserContext.position;
|
|
104
|
+
yield* unparserContext.writeEarlier(protoIdsOffsetWriteLater, uintUnparser, protoIdsOffset);
|
|
105
|
+
const protoParameterListOffsetWriteLaters = [];
|
|
106
|
+
for (const proto of protoPool.getProtos()) {
|
|
107
|
+
const shortyIndex = sectionUnparsers.getStringIndex(proto.shorty);
|
|
108
|
+
const returnTypeIndex = sectionUnparsers.getTypeIndex(proto.returnType);
|
|
109
|
+
yield* uintUnparser(shortyIndex, unparserContext);
|
|
110
|
+
yield* uintUnparser(returnTypeIndex, unparserContext);
|
|
111
|
+
if (proto.parameters.length > 0) {
|
|
112
|
+
const offsetWriteLater = yield* yieldAndCapture(unparserContext.writeLater(4));
|
|
113
|
+
protoParameterListOffsetWriteLaters.push(offsetWriteLater);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
protoParameterListOffsetWriteLaters.push(null);
|
|
117
|
+
yield* uintUnparser(0, unparserContext);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const fieldIdsOffset = unparserContext.position;
|
|
121
|
+
yield* unparserContext.writeEarlier(fieldIdsOffsetWriteLater, uintUnparser, fieldIdsOffset);
|
|
122
|
+
for (const field of fieldPool.getFields()) {
|
|
123
|
+
yield* sectionUnparsers.fieldIdUnparser(field, unparserContext);
|
|
124
|
+
}
|
|
125
|
+
const methodIdsOffset = unparserContext.position;
|
|
126
|
+
yield* unparserContext.writeEarlier(methodIdsOffsetWriteLater, uintUnparser, methodIdsOffset);
|
|
127
|
+
for (const method of methodPool.getMethods()) {
|
|
128
|
+
yield* sectionUnparsers.methodIdUnparser(method, unparserContext);
|
|
129
|
+
}
|
|
130
|
+
const classDefsOffset = unparserContext.position;
|
|
131
|
+
yield* unparserContext.writeEarlier(classDefsOffsetWriteLater, uintUnparser, classDefsOffset);
|
|
132
|
+
const classDefItems = [];
|
|
133
|
+
for (const classDef of input.classDefinitions) {
|
|
134
|
+
const classTypeIndex = sectionUnparsers.getTypeIndex(classDef.class);
|
|
135
|
+
const accessFlags = sectionUnparsers.accessFlagsToNumber(classDef.accessFlags);
|
|
136
|
+
const superclassTypeIndex = sectionUnparsers.getTypeIndex(classDef.superclass);
|
|
137
|
+
yield* uintUnparser(classTypeIndex, unparserContext);
|
|
138
|
+
yield* uintUnparser(accessFlags, unparserContext);
|
|
139
|
+
yield* uintUnparser(superclassTypeIndex, unparserContext);
|
|
140
|
+
const interfacesOffsetWriteLater = yield* writeConditionalOffset(classDef.interfaces.length > 0, unparserContext);
|
|
141
|
+
const sourceFileIndex = classDef.sourceFile ? sectionUnparsers.getStringIndex(classDef.sourceFile) : 0xFFFFFFFF;
|
|
142
|
+
yield* uintUnparser(sourceFileIndex, unparserContext);
|
|
143
|
+
const annotationsOffsetWriteLater = yield* writeConditionalOffset(!!classDef.annotations, unparserContext);
|
|
144
|
+
const hasClassData = !!(classDef.classData && (classDef.classData.staticFields.length > 0 ||
|
|
145
|
+
classDef.classData.instanceFields.length > 0 ||
|
|
146
|
+
classDef.classData.directMethods.length > 0 ||
|
|
147
|
+
classDef.classData.virtualMethods.length > 0));
|
|
148
|
+
const classDataOffsetWriteLater = yield* writeConditionalOffset(hasClassData, unparserContext);
|
|
149
|
+
const staticValuesOffsetWriteLater = yield* writeConditionalOffset(classDef.staticValues.length > 0, unparserContext);
|
|
150
|
+
classDefItems.push({
|
|
151
|
+
interfacesOffsetWriteLater,
|
|
152
|
+
annotationsOffsetWriteLater,
|
|
153
|
+
classDataOffsetWriteLater,
|
|
154
|
+
staticValuesOffsetWriteLater,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const dataOffset = unparserContext.position;
|
|
158
|
+
yield* unparserContext.writeEarlier(dataOffsetWriteLater, uintUnparser, dataOffset);
|
|
159
|
+
for (let i = 0; i < stringPool.size(); i++) {
|
|
160
|
+
const stringDataOffset = unparserContext.position;
|
|
161
|
+
yield* unparserContext.writeEarlier(stringDataOffsetWriteLaters[i], uintUnparser, stringDataOffset);
|
|
162
|
+
yield* sectionUnparsers.stringDataUnparser(stringPool.getStrings()[i], unparserContext);
|
|
163
|
+
}
|
|
164
|
+
const typeListItemsTracker = new SectionTracker();
|
|
165
|
+
for (let i = 0; i < protoPool.size(); i++) {
|
|
166
|
+
const proto = protoPool.getProtos()[i];
|
|
167
|
+
if (proto.parameters.length > 0) {
|
|
168
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
169
|
+
typeListItemsTracker.recordItem(unparserContext.position);
|
|
170
|
+
const paramListOffset = unparserContext.position;
|
|
171
|
+
const writeLater = protoParameterListOffsetWriteLaters[i];
|
|
172
|
+
if (writeLater) {
|
|
173
|
+
yield* unparserContext.writeEarlier(writeLater, uintUnparser, paramListOffset);
|
|
174
|
+
}
|
|
175
|
+
yield* sectionUnparsers.typeListUnparser(proto.parameters, unparserContext);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Track classDataItem, codeItem, and debugInfoItem for later writing
|
|
179
|
+
// Collect data to write items grouped by type (required by DEX format)
|
|
180
|
+
const classDataToWrite = [];
|
|
181
|
+
const codeToWrite = [];
|
|
182
|
+
const debugInfoToWrite = [];
|
|
183
|
+
// First pass: collect type lists, encoded arrays, and classData/code/debugInfo to write
|
|
184
|
+
const encodedArrayItemsTracker = new SectionTracker();
|
|
185
|
+
const typeListsToWrite = [];
|
|
186
|
+
const encodedArraysToWrite = [];
|
|
187
|
+
for (let classIdx = 0; classIdx < input.classDefinitions.length; classIdx++) {
|
|
188
|
+
const classDef = input.classDefinitions[classIdx];
|
|
189
|
+
const classDefItem = classDefItems[classIdx];
|
|
190
|
+
if (classDef.interfaces.length > 0 && classDefItem.interfacesOffsetWriteLater) {
|
|
191
|
+
typeListsToWrite.push({
|
|
192
|
+
interfaces: classDef.interfaces,
|
|
193
|
+
offsetWriteLater: classDefItem.interfacesOffsetWriteLater,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
if (classDef.staticValues.length > 0 && classDefItem.staticValuesOffsetWriteLater) {
|
|
197
|
+
encodedArraysToWrite.push({
|
|
198
|
+
staticValues: classDef.staticValues,
|
|
199
|
+
offsetWriteLater: classDefItem.staticValuesOffsetWriteLater,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (classDef.classData && classDefItem.classDataOffsetWriteLater) {
|
|
203
|
+
classDataToWrite.push({ classDef, classDefItem, classIdx });
|
|
204
|
+
// Collect code items from this class
|
|
205
|
+
const allMethods = [...classDef.classData.directMethods, ...classDef.classData.virtualMethods];
|
|
206
|
+
for (const method of allMethods) {
|
|
207
|
+
if (method.code) {
|
|
208
|
+
codeToWrite.push({ code: method.code });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Second pass: write all type lists (interfaces)
|
|
214
|
+
for (const typeList of typeListsToWrite) {
|
|
215
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
216
|
+
typeListItemsTracker.recordItem(unparserContext.position);
|
|
217
|
+
const typeListOffset = unparserContext.position;
|
|
218
|
+
yield* unparserContext.writeEarlier(typeList.offsetWriteLater, uintUnparser, typeListOffset);
|
|
219
|
+
yield* sectionUnparsers.typeListUnparser(typeList.interfaces, unparserContext);
|
|
220
|
+
}
|
|
221
|
+
// Third pass: write all encoded arrays (static values)
|
|
222
|
+
for (const encodedArray of encodedArraysToWrite) {
|
|
223
|
+
encodedArrayItemsTracker.recordItem(unparserContext.position);
|
|
224
|
+
const encodedArrayOffset = unparserContext.position;
|
|
225
|
+
yield* unparserContext.writeEarlier(encodedArray.offsetWriteLater, uintUnparser, encodedArrayOffset);
|
|
226
|
+
yield* sectionUnparsers.encodedArrayUnparser(encodedArray.staticValues, unparserContext);
|
|
227
|
+
}
|
|
228
|
+
// Fourth pass: write all code items (grouped) and build offset map
|
|
229
|
+
const codeItemsTracker = new SectionTracker();
|
|
230
|
+
const codeOffsetMap = new Map();
|
|
231
|
+
for (const { code } of codeToWrite) {
|
|
232
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
233
|
+
codeItemsTracker.recordItem(unparserContext.position);
|
|
234
|
+
const codeOffset = unparserContext.position;
|
|
235
|
+
codeOffsetMap.set(code, codeOffset);
|
|
236
|
+
let debugInfoOffsetWriteLater;
|
|
237
|
+
yield* sectionUnparsers.codeItemUnparser(result => {
|
|
238
|
+
debugInfoOffsetWriteLater = result.debugInfoOffsetWriteLater;
|
|
239
|
+
})(code, unparserContext);
|
|
240
|
+
if (code.debugInfo && debugInfoOffsetWriteLater) {
|
|
241
|
+
debugInfoToWrite.push({ debugInfo: code.debugInfo, offsetWriteLater: debugInfoOffsetWriteLater });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Fifth pass: write all classData items (grouped) using the offset map
|
|
245
|
+
const classDataItemsTracker = new SectionTracker();
|
|
246
|
+
for (const { classDef, classDefItem } of classDataToWrite) {
|
|
247
|
+
classDataItemsTracker.recordItem(unparserContext.position);
|
|
248
|
+
const classDataOffset = unparserContext.position;
|
|
249
|
+
if (classDefItem.classDataOffsetWriteLater && classDef.classData) {
|
|
250
|
+
yield* unparserContext.writeEarlier(classDefItem.classDataOffsetWriteLater, uintUnparser, classDataOffset);
|
|
251
|
+
yield* sectionUnparsers.classDataUnparser(codeOffsetMap)(classDef.classData, unparserContext);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Sixth pass: write all debugInfo items (grouped)
|
|
255
|
+
const debugInfoItemsTracker = new SectionTracker();
|
|
256
|
+
for (const { debugInfo, offsetWriteLater } of debugInfoToWrite) {
|
|
257
|
+
debugInfoItemsTracker.recordItem(unparserContext.position);
|
|
258
|
+
const debugInfoOffset = unparserContext.position;
|
|
259
|
+
yield* unparserContext.writeEarlier(offsetWriteLater, uintUnparser, debugInfoOffset);
|
|
260
|
+
yield* sectionUnparsers.debugInfoUnparser(debugInfo, unparserContext);
|
|
261
|
+
}
|
|
262
|
+
// Seventh pass: write annotations
|
|
263
|
+
const annotationsDirectoryItemsTracker = new SectionTracker();
|
|
264
|
+
const annotationSetItemsTracker = new SectionTracker();
|
|
265
|
+
const annotationSetRefListItemsTracker = new SectionTracker();
|
|
266
|
+
const annotationItemsTracker = new SectionTracker();
|
|
267
|
+
const annotationSetsToWrite = [];
|
|
268
|
+
const annotationSetRefListsToWrite = [];
|
|
269
|
+
// First sub-pass: write annotation directories and ref lists, collect sets/items
|
|
270
|
+
for (let classIdx = 0; classIdx < input.classDefinitions.length; classIdx++) {
|
|
271
|
+
const classDef = input.classDefinitions[classIdx];
|
|
272
|
+
const classDefItem = classDefItems[classIdx];
|
|
273
|
+
if (classDef.annotations && classDefItem.annotationsOffsetWriteLater) {
|
|
274
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
275
|
+
annotationsDirectoryItemsTracker.recordItem(unparserContext.position);
|
|
276
|
+
const annotationsOffset = unparserContext.position;
|
|
277
|
+
yield* unparserContext.writeEarlier(classDefItem.annotationsOffsetWriteLater, uintUnparser, annotationsOffset);
|
|
278
|
+
const annotationOffsetWriteLaters = {};
|
|
279
|
+
yield* annotationUnparsers.annotationsDirectoryItemUnparser(annotationOffsetWriteLaters)(classDef.annotations, unparserContext);
|
|
280
|
+
if (classDef.annotations.classAnnotations.length > 0 && annotationOffsetWriteLaters.classAnnotationsOffsetWriteLater) {
|
|
281
|
+
annotationSetsToWrite.push({
|
|
282
|
+
annotations: classDef.annotations.classAnnotations,
|
|
283
|
+
setOffsetWriteLater: annotationOffsetWriteLaters.classAnnotationsOffsetWriteLater,
|
|
284
|
+
itemOffsetWriteLaters: [],
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
for (let i = 0; i < classDef.annotations.fieldAnnotations.length; i++) {
|
|
288
|
+
const fieldAnnotation = classDef.annotations.fieldAnnotations[i];
|
|
289
|
+
const fieldAnnotationsOffsetWriteLater = annotationOffsetWriteLaters.fieldAnnotationsOffsetWriteLaters?.[i];
|
|
290
|
+
if (fieldAnnotation.annotations && fieldAnnotation.annotations.length > 0 && fieldAnnotationsOffsetWriteLater) {
|
|
291
|
+
annotationSetsToWrite.push({
|
|
292
|
+
annotations: fieldAnnotation.annotations,
|
|
293
|
+
setOffsetWriteLater: fieldAnnotationsOffsetWriteLater,
|
|
294
|
+
itemOffsetWriteLaters: [],
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
for (let i = 0; i < classDef.annotations.methodAnnotations.length; i++) {
|
|
299
|
+
const methodAnnotation = classDef.annotations.methodAnnotations[i];
|
|
300
|
+
if (methodAnnotation.annotations.length > 0 && annotationOffsetWriteLaters.methodAnnotationsOffsetWriteLaters?.[i]) {
|
|
301
|
+
annotationSetsToWrite.push({
|
|
302
|
+
annotations: methodAnnotation.annotations,
|
|
303
|
+
setOffsetWriteLater: annotationOffsetWriteLaters.methodAnnotationsOffsetWriteLaters[i],
|
|
304
|
+
itemOffsetWriteLaters: [],
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
for (let i = 0; i < classDef.annotations.parameterAnnotations.length; i++) {
|
|
309
|
+
const paramAnnotation = classDef.annotations.parameterAnnotations[i];
|
|
310
|
+
if (annotationOffsetWriteLaters.parameterAnnotationsOffsetWriteLaters?.[i]) {
|
|
311
|
+
annotationSetRefListsToWrite.push({
|
|
312
|
+
parameterAnnotations: paramAnnotation.annotations,
|
|
313
|
+
refListOffsetWriteLater: annotationOffsetWriteLaters.parameterAnnotationsOffsetWriteLaters[i],
|
|
314
|
+
setOffsetWriteLaters: [],
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
// Second sub-pass: write all annotation set ref lists
|
|
321
|
+
for (const refList of annotationSetRefListsToWrite) {
|
|
322
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
323
|
+
annotationSetRefListItemsTracker.recordItem(unparserContext.position);
|
|
324
|
+
const refListOffset = unparserContext.position;
|
|
325
|
+
yield* unparserContext.writeEarlier(refList.refListOffsetWriteLater, uintUnparser, refListOffset);
|
|
326
|
+
yield* annotationUnparsers.annotationSetRefListUnparser(refList.setOffsetWriteLaters)(refList.parameterAnnotations, unparserContext);
|
|
327
|
+
// Collect annotation sets from this ref list
|
|
328
|
+
for (let j = 0; j < refList.parameterAnnotations.length; j++) {
|
|
329
|
+
const paramSet = refList.parameterAnnotations[j];
|
|
330
|
+
const annotationSetOffsetWriteLater = refList.setOffsetWriteLaters[j];
|
|
331
|
+
if (paramSet.length > 0 && annotationSetOffsetWriteLater) {
|
|
332
|
+
annotationSetsToWrite.push({
|
|
333
|
+
annotations: paramSet,
|
|
334
|
+
setOffsetWriteLater: annotationSetOffsetWriteLater,
|
|
335
|
+
itemOffsetWriteLaters: [],
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Third sub-pass: write all annotation sets
|
|
341
|
+
for (const annotationSet of annotationSetsToWrite) {
|
|
342
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
343
|
+
annotationSetItemsTracker.recordItem(unparserContext.position);
|
|
344
|
+
const setOffset = unparserContext.position;
|
|
345
|
+
yield* unparserContext.writeEarlier(annotationSet.setOffsetWriteLater, uintUnparser, setOffset);
|
|
346
|
+
yield* annotationUnparsers.annotationSetItemUnparser(annotationSet.itemOffsetWriteLaters)(annotationSet.annotations, unparserContext);
|
|
347
|
+
}
|
|
348
|
+
// Fourth sub-pass: write all annotation items
|
|
349
|
+
for (const annotationSet of annotationSetsToWrite) {
|
|
350
|
+
for (let i = 0; i < annotationSet.annotations.length; i++) {
|
|
351
|
+
annotationItemsTracker.recordItem(unparserContext.position);
|
|
352
|
+
const itemOffset = unparserContext.position;
|
|
353
|
+
yield* unparserContext.writeEarlier(annotationSet.itemOffsetWriteLaters[i], uintUnparser, itemOffset);
|
|
354
|
+
yield* annotationUnparsers.annotationItemUnparser(annotationSet.annotations[i], unparserContext);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (input.link && linkOffsetWriteLater) {
|
|
358
|
+
const linkOffset = unparserContext.position;
|
|
359
|
+
yield* unparserContext.writeEarlier(linkOffsetWriteLater, uintUnparser, linkOffset);
|
|
360
|
+
yield input.link;
|
|
361
|
+
}
|
|
362
|
+
yield* alignmentUnparser(4)(undefined, unparserContext);
|
|
363
|
+
const mapOffset = unparserContext.position;
|
|
364
|
+
yield* unparserContext.writeEarlier(mapOffsetWriteLater, uintUnparser, mapOffset);
|
|
365
|
+
// Build map items from section definitions
|
|
366
|
+
const sectionConfigs = [
|
|
367
|
+
{ type: 0x0000, size: 1, offset: 0 },
|
|
368
|
+
{ type: 0x0001, size: stringPool.size(), offset: stringIdsOffset },
|
|
369
|
+
{ type: 0x0002, size: typePool.size(), offset: typeIdsOffset },
|
|
370
|
+
{ type: 0x0003, size: protoPool.size(), offset: protoIdsOffset },
|
|
371
|
+
{ type: 0x0004, size: fieldPool.size(), offset: fieldIdsOffset },
|
|
372
|
+
{ type: 0x0005, size: methodPool.size(), offset: methodIdsOffset },
|
|
373
|
+
{ type: 0x0006, size: input.classDefinitions.length, offset: classDefsOffset },
|
|
374
|
+
{ type: 0x2002, size: stringPool.size(), offset: dataOffset },
|
|
375
|
+
{ type: 0x1001, size: typeListItemsTracker.count, offset: typeListItemsTracker.offset },
|
|
376
|
+
{ type: 0x1002, size: annotationSetRefListItemsTracker.count, offset: annotationSetRefListItemsTracker.offset },
|
|
377
|
+
{ type: 0x1003, size: annotationSetItemsTracker.count, offset: annotationSetItemsTracker.offset },
|
|
378
|
+
{ type: 0x2000, size: classDataItemsTracker.count, offset: classDataItemsTracker.offset },
|
|
379
|
+
{ type: 0x2001, size: codeItemsTracker.count, offset: codeItemsTracker.offset },
|
|
380
|
+
{ type: 0x2003, size: debugInfoItemsTracker.count, offset: debugInfoItemsTracker.offset },
|
|
381
|
+
{ type: 0x2004, size: annotationItemsTracker.count, offset: annotationItemsTracker.offset },
|
|
382
|
+
{ type: 0x2005, size: encodedArrayItemsTracker.count, offset: encodedArrayItemsTracker.offset },
|
|
383
|
+
{ type: 0x2006, size: annotationsDirectoryItemsTracker.count, offset: annotationsDirectoryItemsTracker.offset },
|
|
384
|
+
{ type: 0x1000, size: 1, offset: mapOffset },
|
|
385
|
+
];
|
|
386
|
+
// Filter out sections with zero size (except header and map which always exist)
|
|
387
|
+
const mapItems = sectionConfigs.filter(config => config.type === 0x0000 || config.type === 0x1000 || config.size > 0);
|
|
388
|
+
// Sort map items by offset (required by DEX format spec)
|
|
389
|
+
mapItems.sort((a, b) => a.offset - b.offset);
|
|
390
|
+
yield* uintUnparser(mapItems.length, unparserContext);
|
|
391
|
+
for (const mapItem of mapItems) {
|
|
392
|
+
yield* ushortUnparser(mapItem.type, unparserContext);
|
|
393
|
+
yield* ushortUnparser(0, unparserContext);
|
|
394
|
+
yield* uintUnparser(mapItem.size, unparserContext);
|
|
395
|
+
yield* uintUnparser(mapItem.offset, unparserContext);
|
|
396
|
+
}
|
|
397
|
+
const fileSize = unparserContext.position;
|
|
398
|
+
yield* unparserContext.writeEarlier(fileSizeWriteLater, uintUnparser, fileSize);
|
|
399
|
+
const dataSize = fileSize - dataOffset;
|
|
400
|
+
yield* unparserContext.writeEarlier(dataSizeWriteLater, uintUnparser, dataSize);
|
|
401
|
+
yield* unparserContext.writeEarlier(checksumWriteLater, uintUnparser, 0);
|
|
402
|
+
const zeroSha1 = new Uint8Array(20);
|
|
403
|
+
yield* unparserContext.writeEarlier(sha1WriteLater, async function* (hash) {
|
|
404
|
+
yield hash;
|
|
405
|
+
}, zeroSha1);
|
|
406
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { testProp } from '@fast-check/ava';
|
|
2
|
+
import * as fc from 'fast-check';
|
|
3
|
+
import { createArbitraryDalvikExecutable } from './arbitraryDalvikExecutable.js';
|
|
4
|
+
import { dalvikExecutableUnparser } from './dalvikExecutableUnparser.js';
|
|
5
|
+
import { dalvikExecutableParser } from './dalvikExecutableParser.js';
|
|
6
|
+
import { runParser } from './parser.js';
|
|
7
|
+
import { runUnparser } from './unparser.js';
|
|
8
|
+
import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
|
|
9
|
+
import { uint8ArrayUnparserOutputCompanion } from './unparserOutputCompanion.js';
|
|
10
|
+
import { uint8ArrayAsyncIterableToUint8Array } from './uint8Array.js';
|
|
11
|
+
const seed = process.env.SEED ? Number(process.env.SEED) : undefined;
|
|
12
|
+
// Use minimal bytecode for testing - simple nop and return-void instructions
|
|
13
|
+
const arbitraryMinimalBytecode = fc.array(fc.oneof(fc.constant({
|
|
14
|
+
operation: 'nop',
|
|
15
|
+
}), fc.constant({
|
|
16
|
+
operation: 'return-void',
|
|
17
|
+
})), { maxLength: 10 });
|
|
18
|
+
testProp('dalvikExecutableUnparser roundtrip', [createArbitraryDalvikExecutable(arbitraryMinimalBytecode)], async (t, dalvikExecutable) => {
|
|
19
|
+
// Unparse to bytes
|
|
20
|
+
const unparsedIterable = runUnparser(dalvikExecutableUnparser, dalvikExecutable, uint8ArrayUnparserOutputCompanion);
|
|
21
|
+
const bytes = await uint8ArrayAsyncIterableToUint8Array(unparsedIterable);
|
|
22
|
+
// Re-parse
|
|
23
|
+
const reparsed = await runParser(dalvikExecutableParser, bytes, uint8ArrayParserInputCompanion, {
|
|
24
|
+
errorStack: true,
|
|
25
|
+
});
|
|
26
|
+
// Assert equality
|
|
27
|
+
t.deepEqual(reparsed, dalvikExecutable);
|
|
28
|
+
}, {
|
|
29
|
+
verbose: true,
|
|
30
|
+
seed,
|
|
31
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const createDebugLogInputParser = ({ maxLookahead = 8, } = {}) => async (parserContext) => {
|
|
2
|
+
let lookahead = maxLookahead;
|
|
3
|
+
while (lookahead > 0) {
|
|
4
|
+
const sequence = await parserContext.peekSequence(0, lookahead);
|
|
5
|
+
if (!sequence) {
|
|
6
|
+
lookahead -= 1;
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
let prettySequence = sequence;
|
|
10
|
+
if (prettySequence instanceof Uint8Array) {
|
|
11
|
+
prettySequence = Buffer.from(prettySequence).toString('hex');
|
|
12
|
+
}
|
|
13
|
+
console.log('debugLogInput (position: %s): %s', parserContext.position, prettySequence);
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
};
|
package/build/debugLogParser.js
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import { getParserName, setParserName } from './parser.js';
|
|
2
2
|
export const createDebugLogParser = (childParser) => {
|
|
3
3
|
let idCounter = 0;
|
|
4
|
+
function getLogParserName() {
|
|
5
|
+
const childParserName = getParserName(childParser);
|
|
6
|
+
if (childParserName !== 'anonymous') {
|
|
7
|
+
return childParserName;
|
|
8
|
+
}
|
|
9
|
+
const debugLogParserName = getParserName(debugLogParser);
|
|
10
|
+
if (!debugLogParserName.startsWith('debugLog(')) {
|
|
11
|
+
return debugLogParserName;
|
|
12
|
+
}
|
|
13
|
+
return 'anonymousDebugLogChild';
|
|
14
|
+
}
|
|
4
15
|
const debugLogParser = async (parserContext) => {
|
|
5
16
|
const id = idCounter++;
|
|
6
17
|
const initialPosition = parserContext.position;
|
|
7
|
-
console.debug('%s %s: started (position: %s)',
|
|
18
|
+
console.debug('%s %s: started (position: %s)', getLogParserName(), id, initialPosition);
|
|
8
19
|
try {
|
|
9
20
|
const result = await childParser(parserContext);
|
|
10
|
-
console.debug('%s %s: finished (position: %s, consumed: %s): %o',
|
|
21
|
+
console.debug('%s %s: finished (position: %s, consumed: %s): %o', getLogParserName(), id, parserContext.position, parserContext.position - initialPosition, result);
|
|
11
22
|
return result;
|
|
12
23
|
}
|
|
13
24
|
catch (error) {
|
|
14
|
-
console.debug('%s %s: failed (position: %s, consumed: %s): %o',
|
|
25
|
+
console.debug('%s %s: failed (position: %s, consumed: %s): %o', getLogParserName(), id, parserContext.position, parserContext.position - initialPosition, error);
|
|
15
26
|
throw error;
|
|
16
27
|
}
|
|
17
28
|
};
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { type Parser } from './parser.js';
|
|
2
|
-
|
|
2
|
+
import { type DeriveSequenceElement } from './sequence.js';
|
|
3
|
+
export declare const createDisjunctionParser: <Output, Sequence, Element = DeriveSequenceElement<Sequence>>(childParsers: Array<Parser<unknown, Sequence, Element>>) => Parser<Output, Sequence, Element>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getParserName, setParserName } from './parser.js';
|
|
2
|
-
import {
|
|
2
|
+
import { isParserParsingFailedError } from './parserError.js';
|
|
3
3
|
import { parserImplementationInvariant } from './parserImplementationInvariant.js';
|
|
4
|
+
import { promiseSettled } from './promiseSettled.js';
|
|
4
5
|
export const createDisjunctionParser = (childParsers) => {
|
|
5
6
|
parserImplementationInvariant(childParsers.length > 0, 'Disjunction parser must have at least one child parser.');
|
|
6
7
|
const disjunctionParser = async (parserContext) => {
|
|
@@ -9,22 +10,23 @@ export const createDisjunctionParser = (childParsers) => {
|
|
|
9
10
|
const childParserContext = parserContext.lookahead({
|
|
10
11
|
debugName: getParserName(childParser, 'anonymousDisjunctionChild'),
|
|
11
12
|
});
|
|
12
|
-
const
|
|
13
|
+
const childParserResult = await promiseSettled(childParser(childParserContext));
|
|
13
14
|
if (childParserResult.status === 'fulfilled') {
|
|
14
15
|
const successfulParserOutput = childParserResult.value;
|
|
15
16
|
childParserContext.unlookahead();
|
|
16
17
|
childParserContext.dispose();
|
|
17
18
|
return successfulParserOutput;
|
|
18
19
|
}
|
|
20
|
+
childParserContext.dispose();
|
|
19
21
|
const error = childParserResult.reason;
|
|
20
|
-
if (error
|
|
22
|
+
if (isParserParsingFailedError(error)) {
|
|
21
23
|
parserParsingFailedErrors.push(error);
|
|
22
24
|
}
|
|
23
25
|
else {
|
|
24
26
|
throw error;
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
|
-
parserContext.invariantJoin(false, parserParsingFailedErrors, 'No disjunction child parser succeeded.');
|
|
29
|
+
return parserContext.invariantJoin(false, parserParsingFailedErrors, 'No disjunction child parser succeeded.');
|
|
28
30
|
};
|
|
29
31
|
const name = [
|
|
30
32
|
'(',
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type Parser } from './parser.js';
|
|
2
|
+
import { type DeriveSequenceElement } from './sequence.js';
|
|
3
|
+
export declare const createElementTerminatedArrayParserUnsafe: <ElementOutput, Sequence, Element = DeriveSequenceElement<Sequence>>(elementParser: Parser<ElementOutput, Sequence>, terminatorElement: Element) => Parser<ElementOutput[], Sequence>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getParserName, setParserName } from './parser.js';
|
|
2
|
+
export const createElementTerminatedArrayParserUnsafe = (elementParser, terminatorElement) => {
|
|
3
|
+
const elementTerminatedArrayParserUnsafe = async (parserContext) => {
|
|
4
|
+
const elements = [];
|
|
5
|
+
while (true) {
|
|
6
|
+
const inputElement = await parserContext.peek(0);
|
|
7
|
+
if (inputElement === terminatorElement) {
|
|
8
|
+
parserContext.skip(1);
|
|
9
|
+
break;
|
|
10
|
+
}
|
|
11
|
+
const element = await elementParser(parserContext);
|
|
12
|
+
elements.push(element);
|
|
13
|
+
}
|
|
14
|
+
return elements;
|
|
15
|
+
};
|
|
16
|
+
setParserName(elementTerminatedArrayParserUnsafe, `${getParserName(elementParser, 'anonymousElement')}*?${JSON.stringify(terminatorElement)}`);
|
|
17
|
+
return elementTerminatedArrayParserUnsafe;
|
|
18
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import * as fc from 'fast-check';
|
|
3
|
+
import { testProp } from '@fast-check/ava';
|
|
4
|
+
import { createTerminatedArrayParserNaive } from './terminatedArrayParser.js';
|
|
5
|
+
import { runParser } from './parser.js';
|
|
6
|
+
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
7
|
+
import { HighResolutionTotalTimer } from './highResolutionTimer.js';
|
|
8
|
+
import { createElementParser } from './elementParser.js';
|
|
9
|
+
import { createExactSequenceParser } from './exactSequenceParser.js';
|
|
10
|
+
import { createTupleParser } from './tupleParser.js';
|
|
11
|
+
import { createNegativeLookaheadParser } from './negativeLookaheadParser.js';
|
|
12
|
+
import { promiseCompose } from './promiseCompose.js';
|
|
13
|
+
import { createElementTerminatedArrayParserUnsafe } from './elementTerminatedArrayParser.js';
|
|
14
|
+
const naiveTotalTimer = new HighResolutionTotalTimer();
|
|
15
|
+
const elementTotalTimer = new HighResolutionTotalTimer();
|
|
16
|
+
testProp.serial('elementTerminatedArrayParserUnsafe', [
|
|
17
|
+
fc
|
|
18
|
+
.string({
|
|
19
|
+
minLength: 1,
|
|
20
|
+
})
|
|
21
|
+
.map(string => ({
|
|
22
|
+
string,
|
|
23
|
+
terminator: string.slice(-1),
|
|
24
|
+
}))
|
|
25
|
+
.filter(({ string, terminator }) => string.split(terminator).length === 2),
|
|
26
|
+
], async (t, { string, terminator }) => {
|
|
27
|
+
const terminatedArrayParserNaive = promiseCompose(createTerminatedArrayParserNaive(promiseCompose(createTupleParser([
|
|
28
|
+
createNegativeLookaheadParser(createExactSequenceParser(terminator)),
|
|
29
|
+
createElementParser(),
|
|
30
|
+
]), ([_, element]) => element), createExactSequenceParser(terminator)), ([characters]) => characters);
|
|
31
|
+
const elementTerminatedArrayParserUnsafe = createElementTerminatedArrayParserUnsafe(promiseCompose(createTupleParser([
|
|
32
|
+
createNegativeLookaheadParser(createExactSequenceParser(terminator)),
|
|
33
|
+
createElementParser(),
|
|
34
|
+
]), ([_, element]) => element), terminator);
|
|
35
|
+
const createTestWrapperParser = (innerParser) => async (parserContext) => {
|
|
36
|
+
const characters = await innerParser(parserContext);
|
|
37
|
+
return {
|
|
38
|
+
string: characters.join(''),
|
|
39
|
+
nextPeek: await parserContext.peek(0),
|
|
40
|
+
position: parserContext.position,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
const actualNaive = await naiveTotalTimer.measureAsync(async () => runParser(createTestWrapperParser(terminatedArrayParserNaive), string, stringParserInputCompanion));
|
|
44
|
+
t.is(actualNaive.string.length, string.split(terminator)[0].length);
|
|
45
|
+
const actual = await elementTotalTimer.measureAsync(async () => runParser(createTestWrapperParser(elementTerminatedArrayParserUnsafe), string, stringParserInputCompanion));
|
|
46
|
+
t.deepEqual(actual, actualNaive);
|
|
47
|
+
}, {
|
|
48
|
+
verbose: true,
|
|
49
|
+
});
|
|
50
|
+
test.serial('elementTerminatedArrayParserUnsafe performance', t => {
|
|
51
|
+
t.true(elementTotalTimer.time * 2n < naiveTotalTimer.time, `Naive: ${naiveTotalTimer.time / 1000000n}ms, Unsafe: ${elementTotalTimer.time / 1000000n}ms`);
|
|
52
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type Parser } from './parser.js';
|
|
2
|
+
import { type DeriveSequenceElement } from './sequence.js';
|
|
3
|
+
export declare const createElementTerminatedSequenceArrayParser: <Sequence, Element = DeriveSequenceElement<Sequence>>(terminatorElement: Element) => Parser<Sequence[], Sequence, Element>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { setParserName } from './parser.js';
|
|
2
|
+
export const createElementTerminatedSequenceArrayParser = (terminatorElement) => {
|
|
3
|
+
const elementTerminatedSequenceArrayParser = async (parserContext) => {
|
|
4
|
+
const sequences = [];
|
|
5
|
+
let start = 0;
|
|
6
|
+
let window = 1;
|
|
7
|
+
while (true) {
|
|
8
|
+
const sequence = await parserContext.peekSequence(start, start + window);
|
|
9
|
+
if (sequence === undefined) {
|
|
10
|
+
window = Math.floor(window / 2);
|
|
11
|
+
if (start === 0 && window === 0) {
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
parserContext.invariant(window > 0, 'Unexpected end of input without terminator');
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const terminatorIndex = parserContext.indexOf(sequence, terminatorElement);
|
|
18
|
+
if (terminatorIndex === -1) {
|
|
19
|
+
start += window;
|
|
20
|
+
window *= 2;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const sequence_ = await parserContext.readSequence(0, start + terminatorIndex);
|
|
24
|
+
parserContext.skip(1);
|
|
25
|
+
sequences.push(sequence_);
|
|
26
|
+
start = 0;
|
|
27
|
+
}
|
|
28
|
+
return sequences;
|
|
29
|
+
};
|
|
30
|
+
setParserName(elementTerminatedSequenceArrayParser, `(.*?${JSON.stringify(terminatorElement)})*`);
|
|
31
|
+
return elementTerminatedSequenceArrayParser;
|
|
32
|
+
};
|