@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,434 @@
|
|
|
1
|
+
import * as fc from 'fast-check';
|
|
2
|
+
import {
|
|
3
|
+
type DalvikExecutable,
|
|
4
|
+
type DalvikExecutableClassDefinition,
|
|
5
|
+
type DalvikExecutableAccessFlags,
|
|
6
|
+
type DalvikExecutableClassData,
|
|
7
|
+
type DalvikExecutableField,
|
|
8
|
+
type DalvikExecutableFieldWithAccess,
|
|
9
|
+
type DalvikExecutableMethod,
|
|
10
|
+
type DalvikExecutableMethodWithAccess,
|
|
11
|
+
type DalvikExecutablePrototype,
|
|
12
|
+
type DalvikExecutableCode,
|
|
13
|
+
type DalvikExecutableDebugInfo,
|
|
14
|
+
type DalvikExecutableAnnotation,
|
|
15
|
+
type DalvikExecutableClassAnnotations,
|
|
16
|
+
type DalvikExecutableClassFieldAnnotation,
|
|
17
|
+
type DalvikExecutableClassMethodAnnotation,
|
|
18
|
+
type DalvikExecutableClassParameterAnnotation,
|
|
19
|
+
type DalvikExecutableEncodedValue,
|
|
20
|
+
} from './dalvikExecutable.js';
|
|
21
|
+
|
|
22
|
+
// Local type definitions for non-exported types
|
|
23
|
+
|
|
24
|
+
type DalvikExecutableAnnotationItemVisibility = 'build' | 'runtime' | 'system';
|
|
25
|
+
|
|
26
|
+
type DalvikExecutableAnnotationElement = {
|
|
27
|
+
name: string;
|
|
28
|
+
value: DalvikExecutableEncodedValue;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type DalvikExecutableDebugByteCodeValue =
|
|
32
|
+
| { type: 'advancePc'; addressDiff: number }
|
|
33
|
+
| { type: 'advanceLine'; lineDiff: number }
|
|
34
|
+
| { type: 'startLocal'; registerNum: number; name: undefined | string; type_: undefined | string }
|
|
35
|
+
| { type: 'startLocalExtended'; registerNum: number; name: undefined | string; type_: undefined | string; signature: undefined | string }
|
|
36
|
+
| { type: 'endLocal'; registerNum: number }
|
|
37
|
+
| { type: 'restartLocal'; registerNum: number }
|
|
38
|
+
| { type: 'setPrologueEnd' }
|
|
39
|
+
| { type: 'setEpilogueBegin' }
|
|
40
|
+
| { type: 'setFile'; name: undefined | string }
|
|
41
|
+
| { type: 'special'; value: number };
|
|
42
|
+
|
|
43
|
+
// String generators for valid Dalvik identifiers and type descriptors
|
|
44
|
+
|
|
45
|
+
const arbitraryJavaIdentifier = fc.stringMatching(/^[a-zA-Z_][a-zA-Z0-9_]*$/);
|
|
46
|
+
|
|
47
|
+
const arbitraryPrimitiveType = fc.oneof(
|
|
48
|
+
fc.constant('V'), // void
|
|
49
|
+
fc.constant('Z'), // boolean
|
|
50
|
+
fc.constant('B'), // byte
|
|
51
|
+
fc.constant('S'), // short
|
|
52
|
+
fc.constant('C'), // char
|
|
53
|
+
fc.constant('I'), // int
|
|
54
|
+
fc.constant('J'), // long
|
|
55
|
+
fc.constant('F'), // float
|
|
56
|
+
fc.constant('D'), // double
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const arbitraryDalvikClassName: fc.Arbitrary<string> = fc.tuple(
|
|
60
|
+
fc.array(arbitraryJavaIdentifier, { minLength: 1, maxLength: 3 }),
|
|
61
|
+
arbitraryJavaIdentifier,
|
|
62
|
+
).map(([packages, className]) => `L${packages.join('/')}/${className};`);
|
|
63
|
+
|
|
64
|
+
const arbitraryDalvikTypeName: fc.Arbitrary<string> = fc.oneof(
|
|
65
|
+
arbitraryPrimitiveType,
|
|
66
|
+
arbitraryDalvikClassName,
|
|
67
|
+
arbitraryPrimitiveType.map(p => `[${p}`), // array of primitive
|
|
68
|
+
arbitraryDalvikClassName.map(c => `[${c}`), // array of object
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const arbitraryDalvikMethodName = fc.oneof(
|
|
72
|
+
arbitraryJavaIdentifier,
|
|
73
|
+
fc.constant('<init>'),
|
|
74
|
+
fc.constant('<clinit>'),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const arbitraryDalvikFieldName = arbitraryJavaIdentifier;
|
|
78
|
+
|
|
79
|
+
// Access flags generator - common flags for all contexts
|
|
80
|
+
const arbitraryDalvikExecutableAccessFlagsCommon: fc.Arbitrary<DalvikExecutableAccessFlags> = fc.record({
|
|
81
|
+
public: fc.boolean(),
|
|
82
|
+
private: fc.boolean(),
|
|
83
|
+
protected: fc.boolean(),
|
|
84
|
+
static: fc.boolean(),
|
|
85
|
+
final: fc.boolean(),
|
|
86
|
+
synchronized: fc.boolean(),
|
|
87
|
+
volatile: fc.constant(false),
|
|
88
|
+
bridge: fc.constant(false),
|
|
89
|
+
transient: fc.constant(false),
|
|
90
|
+
varargs: fc.constant(false),
|
|
91
|
+
native: fc.boolean(),
|
|
92
|
+
interface: fc.boolean(),
|
|
93
|
+
abstract: fc.boolean(),
|
|
94
|
+
strict: fc.boolean(),
|
|
95
|
+
synthetic: fc.boolean(),
|
|
96
|
+
annotation: fc.boolean(),
|
|
97
|
+
enum: fc.boolean(),
|
|
98
|
+
constructor: fc.boolean(),
|
|
99
|
+
declaredSynchronized: fc.boolean(),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Access flags for fields - volatile and transient are valid (0x40 and 0x80)
|
|
103
|
+
const arbitraryDalvikExecutableFieldAccessFlags: fc.Arbitrary<DalvikExecutableAccessFlags> = fc.record({
|
|
104
|
+
public: fc.boolean(),
|
|
105
|
+
private: fc.boolean(),
|
|
106
|
+
protected: fc.boolean(),
|
|
107
|
+
static: fc.boolean(),
|
|
108
|
+
final: fc.boolean(),
|
|
109
|
+
synchronized: fc.boolean(),
|
|
110
|
+
volatile: fc.boolean(),
|
|
111
|
+
bridge: fc.constant(false),
|
|
112
|
+
transient: fc.boolean(),
|
|
113
|
+
varargs: fc.constant(false),
|
|
114
|
+
native: fc.boolean(),
|
|
115
|
+
interface: fc.boolean(),
|
|
116
|
+
abstract: fc.boolean(),
|
|
117
|
+
strict: fc.boolean(),
|
|
118
|
+
synthetic: fc.boolean(),
|
|
119
|
+
annotation: fc.boolean(),
|
|
120
|
+
enum: fc.boolean(),
|
|
121
|
+
constructor: fc.boolean(),
|
|
122
|
+
declaredSynchronized: fc.boolean(),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Access flags for methods - bridge and varargs are valid (0x40 and 0x80)
|
|
126
|
+
const arbitraryDalvikExecutableMethodAccessFlags: fc.Arbitrary<DalvikExecutableAccessFlags> = fc.record({
|
|
127
|
+
public: fc.boolean(),
|
|
128
|
+
private: fc.boolean(),
|
|
129
|
+
protected: fc.boolean(),
|
|
130
|
+
static: fc.boolean(),
|
|
131
|
+
final: fc.boolean(),
|
|
132
|
+
synchronized: fc.boolean(),
|
|
133
|
+
volatile: fc.constant(false),
|
|
134
|
+
bridge: fc.boolean(),
|
|
135
|
+
transient: fc.constant(false),
|
|
136
|
+
varargs: fc.boolean(),
|
|
137
|
+
native: fc.boolean(),
|
|
138
|
+
interface: fc.boolean(),
|
|
139
|
+
abstract: fc.boolean(),
|
|
140
|
+
strict: fc.boolean(),
|
|
141
|
+
synthetic: fc.boolean(),
|
|
142
|
+
annotation: fc.boolean(),
|
|
143
|
+
enum: fc.boolean(),
|
|
144
|
+
constructor: fc.boolean(),
|
|
145
|
+
declaredSynchronized: fc.boolean(),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Generic access flags for class-level (uses common)
|
|
149
|
+
const arbitraryDalvikExecutableAccessFlags: fc.Arbitrary<DalvikExecutableAccessFlags> = arbitraryDalvikExecutableAccessFlagsCommon;
|
|
150
|
+
|
|
151
|
+
// Field generator
|
|
152
|
+
const arbitraryDalvikExecutableField: fc.Arbitrary<DalvikExecutableField> = fc.record({
|
|
153
|
+
class: arbitraryDalvikClassName,
|
|
154
|
+
type: arbitraryDalvikTypeName,
|
|
155
|
+
name: arbitraryDalvikFieldName,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const arbitraryDalvikExecutableFieldWithAccess: fc.Arbitrary<DalvikExecutableFieldWithAccess> = fc.record({
|
|
159
|
+
field: arbitraryDalvikExecutableField,
|
|
160
|
+
accessFlags: arbitraryDalvikExecutableFieldAccessFlags,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Prototype generator
|
|
164
|
+
const arbitraryShorty: fc.Arbitrary<string> = fc.tuple(
|
|
165
|
+
arbitraryPrimitiveType, // return type
|
|
166
|
+
fc.array(fc.oneof(fc.constant('L'), arbitraryPrimitiveType), { maxLength: 5 }), // parameters
|
|
167
|
+
).map(([returnType, params]) => returnType + params.join(''));
|
|
168
|
+
|
|
169
|
+
const arbitraryDalvikExecutablePrototype: fc.Arbitrary<DalvikExecutablePrototype> = arbitraryShorty.chain(shorty => {
|
|
170
|
+
const returnTypeChar = shorty[0];
|
|
171
|
+
const paramChars = shorty.slice(1).split('');
|
|
172
|
+
|
|
173
|
+
const returnType = returnTypeChar === 'L' ? arbitraryDalvikClassName : fc.constant(returnTypeChar);
|
|
174
|
+
const parameters = fc.tuple(
|
|
175
|
+
...paramChars.map(char => char === 'L' ? arbitraryDalvikClassName : fc.constant(char))
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return fc.record({
|
|
179
|
+
shorty: fc.constant(shorty),
|
|
180
|
+
returnType,
|
|
181
|
+
parameters,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Method generator
|
|
186
|
+
const arbitraryDalvikExecutableMethod: fc.Arbitrary<DalvikExecutableMethod> = fc.record({
|
|
187
|
+
class: arbitraryDalvikClassName,
|
|
188
|
+
prototype: arbitraryDalvikExecutablePrototype,
|
|
189
|
+
name: arbitraryDalvikMethodName,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Encoded value generator (recursive)
|
|
193
|
+
// DalvikExecutableEncodedValue is now a tagged union with type information
|
|
194
|
+
const arbitraryDalvikExecutableEncodedValue: fc.Arbitrary<DalvikExecutableEncodedValue> = fc.letrec(tie => ({
|
|
195
|
+
value: fc.oneof(
|
|
196
|
+
fc.record({ type: fc.constant('byte' as const), value: fc.integer({ min: -128, max: 127 }) }),
|
|
197
|
+
fc.record({ type: fc.constant('short' as const), value: fc.integer({ min: -32768, max: 32767 }) }),
|
|
198
|
+
fc.record({ type: fc.constant('char' as const), value: fc.integer({ min: 0, max: 65535 }) }),
|
|
199
|
+
fc.record({ type: fc.constant('int' as const), value: fc.integer({ min: -2147483648, max: 2147483647 }) }),
|
|
200
|
+
fc.record({ type: fc.constant('long' as const), value: fc.bigInt({ min: -9223372036854775808n, max: 9223372036854775807n }) }),
|
|
201
|
+
fc.record({ type: fc.constant('float' as const), value: fc.float() }),
|
|
202
|
+
fc.record({ type: fc.constant('double' as const), value: fc.double() }),
|
|
203
|
+
fc.record({ type: fc.constant('methodType' as const), value: arbitraryDalvikExecutablePrototype }),
|
|
204
|
+
fc.record({ type: fc.constant('methodHandle' as const), value: fc.nat(255) }),
|
|
205
|
+
fc.record({ type: fc.constant('string' as const), value: fc.string() }),
|
|
206
|
+
fc.record({ type: fc.constant('type' as const), value: arbitraryDalvikClassName }),
|
|
207
|
+
fc.record({ type: fc.constant('field' as const), value: arbitraryDalvikExecutableField }),
|
|
208
|
+
fc.record({ type: fc.constant('method' as const), value: arbitraryDalvikExecutableMethod }),
|
|
209
|
+
fc.record({ type: fc.constant('enum' as const), value: arbitraryDalvikExecutableField }),
|
|
210
|
+
fc.record({ type: fc.constant('array' as const), value: fc.array(tie('value') as fc.Arbitrary<DalvikExecutableEncodedValue>, { maxLength: 3 }) }),
|
|
211
|
+
// Note: We skip 'annotation' type here to avoid deep recursion complexity
|
|
212
|
+
fc.record({ type: fc.constant('null' as const), value: fc.constant(null) }),
|
|
213
|
+
fc.record({ type: fc.constant('boolean' as const), value: fc.boolean() }),
|
|
214
|
+
),
|
|
215
|
+
})).value;
|
|
216
|
+
|
|
217
|
+
// Annotation generators
|
|
218
|
+
const arbitraryAnnotationVisibility: fc.Arbitrary<DalvikExecutableAnnotationItemVisibility> = fc.oneof(
|
|
219
|
+
fc.constant('build' as const),
|
|
220
|
+
fc.constant('runtime' as const),
|
|
221
|
+
fc.constant('system' as const),
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const arbitraryDalvikExecutableAnnotationElement: fc.Arbitrary<DalvikExecutableAnnotationElement> = fc.record({
|
|
225
|
+
name: arbitraryJavaIdentifier,
|
|
226
|
+
value: arbitraryDalvikExecutableEncodedValue,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const arbitraryDalvikExecutableAnnotation: fc.Arbitrary<DalvikExecutableAnnotation> = fc.record({
|
|
230
|
+
visibility: arbitraryAnnotationVisibility,
|
|
231
|
+
type: arbitraryDalvikClassName,
|
|
232
|
+
elements: fc.array(arbitraryDalvikExecutableAnnotationElement, { maxLength: 3 }),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Debug info generators
|
|
236
|
+
const arbitraryDalvikExecutableDebugByteCodeValue: fc.Arbitrary<DalvikExecutableDebugByteCodeValue> = fc.oneof(
|
|
237
|
+
fc.record({
|
|
238
|
+
type: fc.constant('advancePc' as const),
|
|
239
|
+
addressDiff: fc.nat({ max: 255 }),
|
|
240
|
+
}),
|
|
241
|
+
fc.record({
|
|
242
|
+
type: fc.constant('advanceLine' as const),
|
|
243
|
+
lineDiff: fc.integer({ min: -128, max: 127 }),
|
|
244
|
+
}),
|
|
245
|
+
fc.record({
|
|
246
|
+
type: fc.constant('startLocal' as const),
|
|
247
|
+
registerNum: fc.nat({ max: 255 }),
|
|
248
|
+
name: fc.option(arbitraryJavaIdentifier, { nil: undefined }),
|
|
249
|
+
type_: fc.option(arbitraryDalvikTypeName, { nil: undefined }),
|
|
250
|
+
}),
|
|
251
|
+
fc.record({
|
|
252
|
+
type: fc.constant('startLocalExtended' as const),
|
|
253
|
+
registerNum: fc.nat({ max: 255 }),
|
|
254
|
+
name: fc.option(arbitraryJavaIdentifier, { nil: undefined }),
|
|
255
|
+
type_: fc.option(arbitraryDalvikTypeName, { nil: undefined }),
|
|
256
|
+
signature: fc.option(fc.string(), { nil: undefined }),
|
|
257
|
+
}),
|
|
258
|
+
fc.record({
|
|
259
|
+
type: fc.constant('endLocal' as const),
|
|
260
|
+
registerNum: fc.nat({ max: 255 }),
|
|
261
|
+
}),
|
|
262
|
+
fc.record({
|
|
263
|
+
type: fc.constant('restartLocal' as const),
|
|
264
|
+
registerNum: fc.nat({ max: 255 }),
|
|
265
|
+
}),
|
|
266
|
+
fc.record({
|
|
267
|
+
type: fc.constant('setPrologueEnd' as const),
|
|
268
|
+
}),
|
|
269
|
+
fc.record({
|
|
270
|
+
type: fc.constant('setEpilogueBegin' as const),
|
|
271
|
+
}),
|
|
272
|
+
fc.record({
|
|
273
|
+
type: fc.constant('setFile' as const),
|
|
274
|
+
name: fc.option(fc.string(), { nil: undefined }),
|
|
275
|
+
}),
|
|
276
|
+
fc.record({
|
|
277
|
+
type: fc.constant('special' as const),
|
|
278
|
+
// Special opcodes must be >= 0x0A (values 0x00-0x09 are specific debug opcodes)
|
|
279
|
+
value: fc.integer({ min: 0x0A, max: 255 }),
|
|
280
|
+
}),
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const arbitraryDalvikExecutableDebugInfo: fc.Arbitrary<DalvikExecutableDebugInfo> = fc.record({
|
|
284
|
+
lineStart: fc.nat({ max: 65535 }),
|
|
285
|
+
parameterNames: fc.array(fc.option(arbitraryJavaIdentifier, { nil: undefined }), { maxLength: 5 }),
|
|
286
|
+
bytecode: fc.array(arbitraryDalvikExecutableDebugByteCodeValue, { maxLength: 10 }),
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Try-catch handler generators
|
|
290
|
+
interface DalvikExecutableTry {
|
|
291
|
+
startAddress: number;
|
|
292
|
+
instructionCount: number;
|
|
293
|
+
handler: DalvikExecutableEncodedCatchHandler;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
interface DalvikExecutableEncodedCatchHandler {
|
|
297
|
+
handlers: DalvikExecutableEncodedTypeAddressPair[];
|
|
298
|
+
catchAllAddress: undefined | number;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
interface DalvikExecutableEncodedTypeAddressPair {
|
|
302
|
+
type: string;
|
|
303
|
+
address: number;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const arbitraryDalvikExecutableEncodedTypeAddressPair: fc.Arbitrary<DalvikExecutableEncodedTypeAddressPair> = fc.record({
|
|
307
|
+
type: arbitraryDalvikClassName,
|
|
308
|
+
address: fc.nat({ max: 65535 }),
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const arbitraryDalvikExecutableEncodedCatchHandler: fc.Arbitrary<DalvikExecutableEncodedCatchHandler> = fc.record({
|
|
312
|
+
handlers: fc.array(arbitraryDalvikExecutableEncodedTypeAddressPair, { maxLength: 3 }),
|
|
313
|
+
catchAllAddress: fc.option(fc.nat({ max: 65535 }), { nil: undefined }),
|
|
314
|
+
}).filter(handler => {
|
|
315
|
+
// A handler must have at least one typed handler OR a catch-all address
|
|
316
|
+
return handler.handlers.length > 0 || handler.catchAllAddress !== undefined;
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const arbitraryDalvikExecutableTry: fc.Arbitrary<DalvikExecutableTry> = fc.record({
|
|
320
|
+
startAddress: fc.nat({ max: 65535 }),
|
|
321
|
+
instructionCount: fc.nat({ max: 255 }),
|
|
322
|
+
handler: arbitraryDalvikExecutableEncodedCatchHandler,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Generic factory function for DalvikExecutable
|
|
326
|
+
export const createArbitraryDalvikExecutable = <Instructions>(
|
|
327
|
+
arbitraryInstructions: fc.Arbitrary<Instructions>,
|
|
328
|
+
): fc.Arbitrary<DalvikExecutable<Instructions>> => {
|
|
329
|
+
// Code generator using provided instructions arbitrary
|
|
330
|
+
const arbitraryDalvikExecutableCode: fc.Arbitrary<DalvikExecutableCode<Instructions>> = fc.record({
|
|
331
|
+
registersSize: fc.nat({ max: 65535 }),
|
|
332
|
+
insSize: fc.nat({ max: 255 }),
|
|
333
|
+
outsSize: fc.nat({ max: 255 }),
|
|
334
|
+
debugInfo: fc.option(arbitraryDalvikExecutableDebugInfo, { nil: undefined }),
|
|
335
|
+
instructions: arbitraryInstructions,
|
|
336
|
+
tries: fc.array(arbitraryDalvikExecutableTry, { maxLength: 2 }),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Method with access and code
|
|
340
|
+
const arbitraryDalvikExecutableMethodWithAccess: fc.Arbitrary<DalvikExecutableMethodWithAccess<Instructions>> = fc.record({
|
|
341
|
+
method: arbitraryDalvikExecutableMethod,
|
|
342
|
+
accessFlags: arbitraryDalvikExecutableMethodAccessFlags,
|
|
343
|
+
code: fc.option(arbitraryDalvikExecutableCode, { nil: undefined }),
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Annotation collections
|
|
347
|
+
const arbitraryDalvikExecutableClassFieldAnnotation: fc.Arbitrary<DalvikExecutableClassFieldAnnotation> = fc.record({
|
|
348
|
+
field: arbitraryDalvikExecutableField,
|
|
349
|
+
annotations: fc.option(fc.array(arbitraryDalvikExecutableAnnotation, { maxLength: 2 }), { nil: undefined }),
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const arbitraryDalvikExecutableClassMethodAnnotation: fc.Arbitrary<DalvikExecutableClassMethodAnnotation> = fc.record({
|
|
353
|
+
method: arbitraryDalvikExecutableMethod,
|
|
354
|
+
annotations: fc.array(arbitraryDalvikExecutableAnnotation, { maxLength: 2 }),
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const arbitraryDalvikExecutableClassParameterAnnotation: fc.Arbitrary<DalvikExecutableClassParameterAnnotation> = fc.record({
|
|
358
|
+
method: arbitraryDalvikExecutableMethod,
|
|
359
|
+
annotations: fc.array(
|
|
360
|
+
fc.array(arbitraryDalvikExecutableAnnotation, { maxLength: 2 }),
|
|
361
|
+
{ maxLength: 3 }
|
|
362
|
+
),
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const arbitraryDalvikExecutableClassAnnotations: fc.Arbitrary<DalvikExecutableClassAnnotations> = fc.record({
|
|
366
|
+
classAnnotations: fc.array(arbitraryDalvikExecutableAnnotation, { maxLength: 2 }),
|
|
367
|
+
fieldAnnotations: fc.array(arbitraryDalvikExecutableClassFieldAnnotation, { maxLength: 2 }),
|
|
368
|
+
methodAnnotations: fc.array(arbitraryDalvikExecutableClassMethodAnnotation, { maxLength: 2 }),
|
|
369
|
+
parameterAnnotations: fc.array(arbitraryDalvikExecutableClassParameterAnnotation, { maxLength: 2 }),
|
|
370
|
+
}).map(annotations => ({
|
|
371
|
+
...annotations,
|
|
372
|
+
// Filter out field/method/parameter annotations with undefined or empty annotations array
|
|
373
|
+
// In DEX format, fields/methods/parameters with no annotations should not appear in the annotations directory at all
|
|
374
|
+
fieldAnnotations: annotations.fieldAnnotations.filter(fa => fa.annotations !== undefined && fa.annotations.length > 0),
|
|
375
|
+
methodAnnotations: annotations.methodAnnotations.filter(ma => ma.annotations.length > 0),
|
|
376
|
+
parameterAnnotations: annotations.parameterAnnotations.filter(pa => pa.annotations.length > 0 && pa.annotations.some(paramAnnots => paramAnnots.length > 0)),
|
|
377
|
+
}));
|
|
378
|
+
|
|
379
|
+
// Class data
|
|
380
|
+
const arbitraryDalvikExecutableClassData: fc.Arbitrary<DalvikExecutableClassData<Instructions>> = fc.record({
|
|
381
|
+
staticFields: fc.array(arbitraryDalvikExecutableFieldWithAccess, { maxLength: 3 }),
|
|
382
|
+
instanceFields: fc.array(arbitraryDalvikExecutableFieldWithAccess, { maxLength: 3 }),
|
|
383
|
+
directMethods: fc.array(arbitraryDalvikExecutableMethodWithAccess, { maxLength: 3 }),
|
|
384
|
+
virtualMethods: fc.array(arbitraryDalvikExecutableMethodWithAccess, { maxLength: 3 }),
|
|
385
|
+
}).filter(classData =>
|
|
386
|
+
// Filter out empty classData (all arrays empty) as it's semantically equivalent to undefined
|
|
387
|
+
classData.staticFields.length > 0 ||
|
|
388
|
+
classData.instanceFields.length > 0 ||
|
|
389
|
+
classData.directMethods.length > 0 ||
|
|
390
|
+
classData.virtualMethods.length > 0
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
// Class definition
|
|
394
|
+
const arbitraryDalvikExecutableClassDefinition: fc.Arbitrary<DalvikExecutableClassDefinition<Instructions>> = fc.record({
|
|
395
|
+
class: arbitraryDalvikClassName,
|
|
396
|
+
accessFlags: arbitraryDalvikExecutableAccessFlags,
|
|
397
|
+
superclass: arbitraryDalvikClassName,
|
|
398
|
+
interfaces: fc.array(arbitraryDalvikClassName, { maxLength: 3 }),
|
|
399
|
+
sourceFile: fc.option(fc.stringMatching(/^[a-zA-Z0-9_]+\.java$/), { nil: undefined }),
|
|
400
|
+
annotations: fc.option(arbitraryDalvikExecutableClassAnnotations, { nil: undefined }),
|
|
401
|
+
staticValues: fc.array(arbitraryDalvikExecutableEncodedValue, { maxLength: 3 }),
|
|
402
|
+
classData: fc.option(arbitraryDalvikExecutableClassData, { nil: undefined }),
|
|
403
|
+
}).map(classDef => {
|
|
404
|
+
// Match parser logic: if all members are synthetic, set class synthetic to true
|
|
405
|
+
const allMembers = [
|
|
406
|
+
...classDef.classData?.staticFields ?? [],
|
|
407
|
+
...classDef.classData?.instanceFields ?? [],
|
|
408
|
+
...classDef.classData?.directMethods ?? [],
|
|
409
|
+
// Note: virtualMethods are not included to match parser behavior
|
|
410
|
+
];
|
|
411
|
+
const allMembersAreSynthetic = (
|
|
412
|
+
allMembers.every(member => member.accessFlags.synthetic)
|
|
413
|
+
&& allMembers.length > 0
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
if (allMembersAreSynthetic) {
|
|
417
|
+
return {
|
|
418
|
+
...classDef,
|
|
419
|
+
accessFlags: {
|
|
420
|
+
...classDef.accessFlags,
|
|
421
|
+
synthetic: true,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return classDef;
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// Root DalvikExecutable
|
|
430
|
+
return fc.record({
|
|
431
|
+
classDefinitions: fc.array(arbitraryDalvikExecutableClassDefinition, { minLength: 1, maxLength: 3 }),
|
|
432
|
+
link: fc.option(fc.uint8Array({ minLength: 1, maxLength: 10 }), { nil: undefined }),
|
|
433
|
+
});
|
|
434
|
+
};
|
|
@@ -6,7 +6,7 @@ function addZipEntryToZip(zip: JSZip, zipEntry: ZipEntry) {
|
|
|
6
6
|
const options = {
|
|
7
7
|
comment: zipEntry.comment,
|
|
8
8
|
date: zipEntry.date,
|
|
9
|
-
//
|
|
9
|
+
// UnixPermissions: zipEntry.permissions.type === 'unix' ? zipEntry.permissions.unixPermissions : undefined,
|
|
10
10
|
// dosPermissions: zipEntry.permissions.type === 'dos' ? zipEntry.permissions.dosPermissions : undefined,
|
|
11
11
|
};
|
|
12
12
|
|
package/src/arrayParser.test.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
2
|
import { createArrayParser } from './arrayParser.js';
|
|
3
|
-
import { type Parser,
|
|
3
|
+
import { type Parser, runParserWithRemainingInput } from './parser.js';
|
|
4
4
|
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
5
5
|
|
|
6
6
|
test('does not loop forever with a child parser that does not consume anything', async t => {
|
|
7
7
|
const parser: Parser<undefined[], string> = createArrayParser(async () => undefined);
|
|
8
|
-
const
|
|
8
|
+
const { output } = await runParserWithRemainingInput(parser, 'foo', stringParserInputCompanion);
|
|
9
9
|
|
|
10
|
-
t.deepEqual(
|
|
10
|
+
t.deepEqual(output, []);
|
|
11
11
|
});
|
package/src/arrayParser.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getParserName, type Parser, setParserName } from './parser.js';
|
|
2
|
-
import {
|
|
2
|
+
import { isParserParsingFailedError } from './parserError.js';
|
|
3
3
|
|
|
4
4
|
export const createArrayParser = <ElementOutput, Sequence>(
|
|
5
5
|
elementParser: Parser<ElementOutput, Sequence>,
|
|
@@ -19,7 +19,7 @@ export const createArrayParser = <ElementOutput, Sequence>(
|
|
|
19
19
|
elements.push(element);
|
|
20
20
|
elementParserContext.unlookahead();
|
|
21
21
|
} catch (error) {
|
|
22
|
-
if (error
|
|
22
|
+
if (isParserParsingFailedError(error)) {
|
|
23
23
|
return elements;
|
|
24
24
|
}
|
|
25
25
|
|
package/src/arrayUnparser.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Unparser } from
|
|
1
|
+
import { type Unparser } from './unparser.js';
|
|
2
2
|
|
|
3
3
|
export const createArrayUnparser = <ElementInput, Sequence>(
|
|
4
4
|
elementUnparser: Unparser<ElementInput, Sequence>,
|
|
@@ -10,4 +10,4 @@ export const createArrayUnparser = <ElementInput, Sequence>(
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
return arrayUnparser;
|
|
13
|
-
}
|
|
13
|
+
};
|
package/src/backsmali.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execa } from 'execa';
|
|
4
|
+
import { temporaryDirectory, temporaryFile } from 'tempy';
|
|
5
|
+
import { smaliClass } from './smali.js';
|
|
6
|
+
|
|
7
|
+
export async function baksmaliClass(
|
|
8
|
+
dexStream: Uint8Array | AsyncIterable<Uint8Array>,
|
|
9
|
+
smaliFilePath: string,
|
|
10
|
+
): Promise<string> {
|
|
11
|
+
const inputFilePath = temporaryFile();
|
|
12
|
+
const outputDirectoryPath = temporaryDirectory();
|
|
13
|
+
|
|
14
|
+
await fs.writeFile(inputFilePath, dexStream);
|
|
15
|
+
|
|
16
|
+
await execa('baksmali', [
|
|
17
|
+
'disassemble',
|
|
18
|
+
'--classes',
|
|
19
|
+
'L' + smaliFilePath + ';',
|
|
20
|
+
'--output',
|
|
21
|
+
outputDirectoryPath,
|
|
22
|
+
inputFilePath,
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
await fs.unlink(inputFilePath);
|
|
26
|
+
|
|
27
|
+
const smaliFilePath_ = path.join(outputDirectoryPath, smaliFilePath + '.smali');
|
|
28
|
+
|
|
29
|
+
const smali = await fs.readFile(smaliFilePath_, 'utf8');
|
|
30
|
+
|
|
31
|
+
await fs.rm(outputDirectoryPath, {
|
|
32
|
+
recursive: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return smali;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function backsmaliSmaliIsolateClass(
|
|
39
|
+
dexStream: Uint8Array | AsyncIterable<Uint8Array>,
|
|
40
|
+
smaliFilePath: string,
|
|
41
|
+
): Promise<Uint8Array> {
|
|
42
|
+
const smali = await baksmaliClass(dexStream, smaliFilePath);
|
|
43
|
+
return smaliClass(smali);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function baksmaliListClasses(dexStream: Uint8Array | AsyncIterable<Uint8Array>): Promise<string[]> {
|
|
47
|
+
const inputFilePath = temporaryFile();
|
|
48
|
+
|
|
49
|
+
await fs.writeFile(inputFilePath, dexStream);
|
|
50
|
+
|
|
51
|
+
const result = await execa('baksmali', [
|
|
52
|
+
'list',
|
|
53
|
+
'classes',
|
|
54
|
+
inputFilePath,
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
await fs.unlink(inputFilePath);
|
|
58
|
+
|
|
59
|
+
if (result.stderr) {
|
|
60
|
+
throw new Error(`baksmali error: ${result.stderr}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const classes = result.stdout
|
|
64
|
+
.split('\n')
|
|
65
|
+
.filter(line => line.trim())
|
|
66
|
+
.map(line => line.trim())
|
|
67
|
+
.map(class_ => (
|
|
68
|
+
class_
|
|
69
|
+
.replace(/^L/, '')
|
|
70
|
+
.replace(/;$/, '')
|
|
71
|
+
));
|
|
72
|
+
|
|
73
|
+
return classes;
|
|
74
|
+
}
|
package/src/bsonParser.test.ts
CHANGED
|
@@ -8,21 +8,19 @@ import { uint8ArrayParserInputCompanion } from './parserInputCompanion.js';
|
|
|
8
8
|
testProp(
|
|
9
9
|
'bson',
|
|
10
10
|
[
|
|
11
|
-
arbitrarilySlicedAsyncIterator(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.
|
|
15
|
-
|
|
16
|
-
const jsonValue = JSON.parse(jsonString);
|
|
11
|
+
arbitrarilySlicedAsyncIterator(fc
|
|
12
|
+
.json()
|
|
13
|
+
.filter(jsonString => {
|
|
14
|
+
// BSON.serialize does not support non-object top-level values
|
|
15
|
+
const jsonValue = JSON.parse(jsonString);
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
),
|
|
17
|
+
return (
|
|
18
|
+
jsonValue !== null
|
|
19
|
+
&& typeof jsonValue === 'object'
|
|
20
|
+
&& !Array.isArray(jsonValue)
|
|
21
|
+
);
|
|
22
|
+
})
|
|
23
|
+
.map(jsonString => BSON.serialize(JSON.parse(jsonString)))),
|
|
26
24
|
],
|
|
27
25
|
async (t, [ bsonUint8Array, bsonUint8ArrayChunkIterator ]) => {
|
|
28
26
|
const expected = BSON.deserialize(bsonUint8Array);
|
package/src/bsonParser.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type JsonObject, type JsonValue } from 'type-fest';
|
|
2
2
|
import { getParserName, setParserName, type Parser } from './parser.js';
|
|
3
|
-
import { invariantDefined } from './invariantDefined.js';
|
|
4
3
|
import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
|
|
5
4
|
import { promiseCompose } from './promiseCompose.js';
|
|
6
5
|
import { createTupleParser } from './tupleParser.js';
|
|
@@ -34,9 +33,17 @@ const cstringParser: Parser<string, Uint8Array> = promiseCompose(
|
|
|
34
33
|
);
|
|
35
34
|
|
|
36
35
|
const doubleParser: Parser<number, Uint8Array> = promiseCompose(buffer8Parser, buffer => buffer.readDoubleLE(0));
|
|
36
|
+
|
|
37
|
+
setParserName(doubleParser, 'doubleParser');
|
|
38
|
+
|
|
37
39
|
const int32Parser: Parser<number, Uint8Array> = promiseCompose(buffer4Parser, buffer => buffer.readInt32LE(0));
|
|
40
|
+
|
|
41
|
+
setParserName(int32Parser, 'int32Parser');
|
|
42
|
+
|
|
38
43
|
const uint32Parser: Parser<number, Uint8Array> = promiseCompose(buffer4Parser, buffer => buffer.readUInt32LE(0));
|
|
39
44
|
|
|
45
|
+
setParserName(uint32Parser, 'uint32Parser');
|
|
46
|
+
|
|
40
47
|
const createFixedLengthStringParser = (length: number): Parser<string, Uint8Array> => promiseCompose(
|
|
41
48
|
createFixedLengthBufferParser(length),
|
|
42
49
|
buffer => buffer.toString('utf8'),
|
|
@@ -56,6 +63,8 @@ const bsonStringParser: Parser<string, Uint8Array> = async parserContext => {
|
|
|
56
63
|
return createFixedLengthNullTerminatedStringParser(stringSize - 1)(parserContext);
|
|
57
64
|
};
|
|
58
65
|
|
|
66
|
+
setParserName(bsonStringParser, 'bsonStringParser');
|
|
67
|
+
|
|
59
68
|
const bsonArrayParser = promiseCompose(
|
|
60
69
|
createTupleParser([
|
|
61
70
|
createSkipParser(4),
|
|
@@ -64,8 +73,10 @@ const bsonArrayParser = promiseCompose(
|
|
|
64
73
|
([ _, elements ]) => elements.map(([ _, value ]) => value),
|
|
65
74
|
);
|
|
66
75
|
|
|
76
|
+
setParserName(bsonArrayParser, 'bsonArrayParser');
|
|
77
|
+
|
|
67
78
|
const bsonBooleanParser: Parser<boolean, Uint8Array> = async parserContext => {
|
|
68
|
-
const booleanValue =
|
|
79
|
+
const booleanValue = await parserContext.read(0);
|
|
69
80
|
|
|
70
81
|
return booleanValue === 1;
|
|
71
82
|
};
|