Compare commits
1334 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 13e934ce4d | |||
| 7b54c3ae70 | |||
| b82791706a | |||
| e51a7fe417 | |||
| cf96fdec59 | |||
| 3374f9b64a | |||
| 6b54cde89c | |||
| 59b560b553 | |||
| 8b08ac3806 | |||
| d9d4180581 | |||
| 33f93ddc8a | |||
| bcd0c949dc | |||
| fc0f1f9a1c | |||
| abd64007e2 | |||
| fb02e32a6a | |||
| f33a2e4768 | |||
| 3d8e5e5851 | |||
| 646ee2d963 | |||
| b6f27d8a1a | |||
| 97d04edb01 | |||
| 2486c981a8 | |||
| b7a8a2879e | |||
| 092e897104 | |||
| a0a9f7fd41 | |||
| 00f0f5547b | |||
| 00608f8e51 | |||
| d0351a88ba | |||
| bee476895c | |||
| 580f25faae | |||
| 1d1ca7d0c0 | |||
| dbf4527ce6 | |||
| ec726d6ca1 | |||
| be1c02455f | |||
| aee1e86398 | |||
| c0d721bea1 | |||
| e19a456642 | |||
| acd57930cc | |||
| 73348e5183 | |||
| 32c92dd9a8 | |||
| 8bbdbfc563 | |||
| fd6cb2451b | |||
| 47647bbb9a | |||
| e31d697cd9 | |||
| a796d15289 | |||
| f56eb271a1 | |||
| fbebcb9845 | |||
| 79c91634ad | |||
| f6e12d71a0 | |||
| 62835fbade | |||
| 07c66b5c3c | |||
| e3aa49aaa9 | |||
| 9981949a2b | |||
| ea6492e5ba | |||
| 03d4cb134f | |||
| 37b0b09f25 | |||
| 1e75544636 | |||
| d4ce969fb7 | |||
| 9a692d6be4 | |||
| d3a8a43c74 | |||
| 518da3d8b5 | |||
| 61f5386fe5 | |||
| 20cb9c6a3b | |||
| 4a6784dc68 | |||
| bb6db25c9d | |||
| d0c496858e | |||
| b0ab702f9e | |||
| 5846e6d22e | |||
| 4daad2fc79 | |||
| cca6ca25d1 | |||
| dfa6a83f7c | |||
| d1a3935c9e | |||
| b4f1021885 | |||
| a163e5a1de | |||
| 6eeb303d73 | |||
| 3209dbb7a4 | |||
| d84f0389ec | |||
| 5d720dd29c | |||
| c9d650d186 | |||
| ce60aa8635 | |||
| 4a9276e904 | |||
| b78d3aa2f7 | |||
| 4644d1d8ac | |||
| 7b8fc01319 | |||
| ff66f95a8a | |||
| 4ef1f3b12b | |||
| 8873038b57 | |||
| bf58f03405 | |||
| acf1c8187e | |||
| 7bd1b14728 | |||
| 61f04d6b07 | |||
| 5d5bf325fe | |||
| afdd2d8b39 | |||
| b18604071a | |||
| 801890f0a8 | |||
| 3d36c93beb | |||
| 54fbbd9524 | |||
| 306547d499 | |||
| a43b475be7 | |||
| bc4bb0dc41 | |||
| ea5916452d | |||
| 19f3cdf501 | |||
| 45d320a596 | |||
| 6860a8be7e | |||
| 94915db739 | |||
| 29d114402d | |||
| 6889670b11 | |||
| fe7d527fcc | |||
| 84e211b809 | |||
| f4849d67cf | |||
| 60a8d8b9fd | |||
| 1449354c54 | |||
| 0df474f35a | |||
| de629544a3 | |||
| 7a2dad8ef2 | |||
| a46e35c15c | |||
| 73966fda89 | |||
| fe0ab5ebf8 | |||
| 8345edf76b | |||
| ff0fbba720 | |||
| fe41d6ed3d | |||
| ff95b9e999 | |||
| 87844d2193 | |||
| 2ac0cc62e6 | |||
| 2924bb259c | |||
| 17695babf4 | |||
| 0d105a5095 | |||
| 7eab3c8534 | |||
| 47f2e516e5 | |||
| fdad829c49 | |||
| 2fa7f84251 | |||
| 828cad3287 | |||
| cc0cb6a3d3 | |||
| a67dfcb7e1 | |||
| baa93bad63 | |||
| 45df80f036 | |||
| 792e0d6f3a | |||
| fe9d3bcab7 | |||
| 1e1036c049 | |||
| 60dcdc7096 | |||
| c4c3d42d16 | |||
| 58c36de8c2 | |||
| b4ca566a19 | |||
| e644bad758 | |||
| dd86abcc5e | |||
| f0513a1a55 | |||
| be6cb573b1 | |||
| 5d064d3e50 | |||
| 15b6309e2c | |||
| 417bb7a7e9 | |||
| 4c74e8e300 | |||
| 57238de6ff | |||
| 313c4a121a | |||
| 39912398fc | |||
| 7544d1a113 | |||
| cfbe5ab672 | |||
| 2661b91a6f | |||
| 61578e8793 | |||
| cc6a893402 | |||
| 4d8a5d6671 | |||
| 982307b1ac | |||
| 37054dc84e | |||
| 343e2c531a | |||
| 6fa5d247f0 | |||
| 688dea0c50 | |||
| c0815b12bc | |||
| 233f8692b2 | |||
| e5be41b9cc | |||
| 3788e4ef3a | |||
| 32855f4511 | |||
| 3d5e225274 | |||
| 8a34d973ff | |||
| a43b3282ef | |||
| 249801880c | |||
| 742d30d770 | |||
| 267413332a | |||
| f9c94f27f1 | |||
| d2131d9640 | |||
| 548821c4df | |||
| 958ab245ae | |||
| 8f3cc3e8c1 | |||
| b872ffd1b9 | |||
| c5263f92fe | |||
| 1475e887c8 | |||
| c21cabcba7 | |||
| 063af8cd62 | |||
| 2d10537050 | |||
| 3814951408 | |||
| 964bd62d35 | |||
| 3ed2df828f | |||
| b26abdc851 | |||
| 90185fd947 | |||
| 681f8a98b5 | |||
| 0b225238fb | |||
| a7649dda7a | |||
| b5e3dcf70f | |||
| 7abbc81886 | |||
| 9c30aeacdb | |||
| 8f27de4d0e | |||
| 02b69d2d29 | |||
| e6fde48b69 | |||
| 109dea0857 | |||
| 1d34328dd3 | |||
| ef4f1d3ed4 | |||
| 23696d3971 | |||
| efa2f5d172 | |||
| 699ceb197e | |||
| 5c83c22501 | |||
| 7bb5c0a859 | |||
| 603863403f | |||
| 889a945cf1 | |||
| fd80e03809 | |||
| b5807082d9 | |||
| 5d1f0b8cae | |||
| 3f9aa34057 | |||
| e2c860f260 | |||
| 0938351d97 | |||
| 937dd20794 | |||
| ea5e87560a | |||
| 5fbbf2150e | |||
| 0e11bffe82 | |||
| ba9af5c288 | |||
| cca706c94f | |||
| 2df69bbfb4 | |||
| f5307636ef | |||
| 9a39b70a46 | |||
| e63808bc4b | |||
| 847225a6a9 | |||
| eee354a3ab | |||
| 1cc00a54f3 | |||
| ffdad1b652 | |||
| 9a8ec76989 | |||
| 0be5b2cea9 | |||
| c94201be4a | |||
| 1051dacb1e | |||
| a2bfe9bbe8 | |||
| 8c6ec3bccc | |||
| 015876b790 | |||
| 280f3870a9 | |||
| e9d770ae9e | |||
| 5f1bd1d9ba | |||
| 60fb458024 | |||
| 1b08779536 | |||
| c37e39a819 | |||
| 2d58fbd4b1 | |||
| ffbf800404 | |||
| 500aa8a68d | |||
| 58e8268126 | |||
| f9da6e00ed | |||
| 821cc668c7 | |||
| 287ba49008 | |||
| 115e563a2b | |||
| 1669200e62 | |||
| 6ab224ea0d | |||
| 61855a7ea1 | |||
| bda3119e86 | |||
| b26abed686 | |||
| c179beee95 | |||
| 04a454094b | |||
| 33bcbfec41 | |||
| ec645d80b1 | |||
| a8d889de3d | |||
| ec0bf701c8 | |||
| ad4dd116be | |||
| ef79f266c8 | |||
| 366225f9be | |||
| 730db0d24f | |||
| 05fb77e9bd | |||
| bbabfa0354 | |||
| 96bd9f0f17 | |||
| fd5b397b40 | |||
| f5e3a261b4 | |||
| 52a884608a | |||
| 74ddfde950 | |||
| 9aacb4f312 | |||
| 82e2104f3c | |||
| 09fa35f144 | |||
| f2a6a1e942 | |||
| b85900aa3d | |||
| 37a42d1418 | |||
| 07dde05337 | |||
| 8618214c7f | |||
| b80f32a36f | |||
| ce527ed753 | |||
| f2ea6415c9 | |||
| bc70f8eabb | |||
| be25cbf8c2 | |||
| f9c0cad146 | |||
| b356ff76e1 | |||
| ec9244a635 | |||
| a5bd64461d | |||
| 54bf79ccc5 | |||
| 6182332eef | |||
| 37b57096ec | |||
| 6aab8fabc9 | |||
| 665c1e57d2 | |||
| 6e8affcbdc | |||
| 41d6b0018e | |||
| dbadbb01fc | |||
| 0f52077c5c | |||
| ea861829c7 | |||
| c1de235289 | |||
| 8f969d4e89 | |||
| 0c1f830f94 | |||
| 43c082e4da | |||
| ecdc4e6757 | |||
| b865c9c687 | |||
| 6b4976c593 | |||
| 2807dc5090 | |||
| 463d2b90fa | |||
| bff00d101f | |||
| 1290ef63a2 | |||
| 49d2b34d84 | |||
| eecdfae73f | |||
| 8760b4ddde | |||
| 3599b248a4 | |||
| 2fdd496518 | |||
| 278e3c2d47 | |||
| 881a716b8e | |||
| a73c9e90fc | |||
| 56749b2afb | |||
| d7ec35791b | |||
| d51362ed50 | |||
| 5c0c1daa71 | |||
| 603ea3989a | |||
| 018ff98df7 | |||
| 5fbabdefca | |||
| 13607fc8b6 | |||
| 0c33d723c8 | |||
| 0143423dc9 | |||
| 21b1452485 | |||
| ecb8abb98e | |||
| a3a4fabd5a | |||
| edf6ce273c | |||
| 1bb956a8b0 | |||
| 276ee537e1 | |||
| 7e628ad1a1 | |||
| 0a40b53412 | |||
| 682f90de2f | |||
| 1a07ab8ab1 | |||
| d86449a8ea | |||
| 75d2e540aa | |||
| e73612b4d2 | |||
| a19aec9d9f | |||
| 61be1d8b0a | |||
| 4483533417 | |||
| fb703cd856 | |||
| c0ff7572ac | |||
| 8e7ffc8ddb | |||
| f994abee21 | |||
| 6f1dfb6848 | |||
| 306bc7abc3 | |||
| 8ed48183c7 | |||
| fdc3fe1a8d | |||
| 2805770510 | |||
| 03052baabe | |||
| 23e643c686 | |||
| faeae086d1 | |||
| 38e64fafbd | |||
| e723c245ee | |||
| 3e57dacfd3 | |||
| f5accc8464 | |||
| 238fe17df0 | |||
| 295befbaaa | |||
| 5f20033f18 | |||
| 5f376c6e21 | |||
| 68a99c5410 | |||
| 8db70ee7a5 | |||
| b6155afd32 | |||
| d5bf9f20a6 | |||
| 2d5c0fda4a | |||
| 5d56001826 | |||
| 2de91f9a3a | |||
| e06e6bd483 | |||
| 1e57e85382 | |||
| ca03406a3d | |||
| 2d28da9b0e | |||
| edb1717969 | |||
| 1b51234edc | |||
| e6d896d91e | |||
| a989fa7e64 | |||
| f7002c7fad | |||
| 41d986bdca | |||
| 192a8116f1 | |||
| 173d85bf84 | |||
| b310e92d7a | |||
| 4a92ee07cc | |||
| fdffe20c46 | |||
| 15d464d620 | |||
| 1bd4526e4c | |||
| 816308e3ca | |||
| cfd851a980 | |||
| d129be7e86 | |||
| 6433fcef72 | |||
| d120556772 | |||
| 19f40b8549 | |||
| 89acf73010 | |||
| b70276d896 | |||
| 76b370e249 | |||
| b73f2ef0b9 | |||
| 762c2d70bd | |||
| 4e81bdd76f | |||
| 4d87b447a6 | |||
| 8f0d0e4f4d | |||
| c39a696977 | |||
| b78a0257b4 | |||
| cdede7eca4 | |||
| 72180164d8 | |||
| 2dc0db230c | |||
| 24657f6b3c | |||
| e358476c71 | |||
| 45a637f33b | |||
| 76cf9596e2 | |||
| 95c07a4e76 | |||
| 2d1d5a419c | |||
| f45547e2c1 | |||
| 1f463c7152 | |||
| 2c92c6b0a6 | |||
| f83ee45ac8 | |||
| f695fafe74 | |||
| f6ab105ef7 | |||
| f81a2c4ebb | |||
| c602b3d967 | |||
| f213082da5 | |||
| 8d26fa2a89 | |||
| a06231d007 | |||
| 68b84ea786 | |||
| 868e99e0b5 | |||
| 95db98e574 | |||
| 63fc7e05b6 | |||
| 2c2bb64c09 | |||
| 0f5d07c6b1 | |||
| fbb6aa580e | |||
| d9692a4f5f | |||
| ef0c09ca5b | |||
| 752c61ae71 | |||
| 8f635076ea | |||
| 8d5130a329 | |||
| 09a5e0893b | |||
| de8c315a7a | |||
| 3abdd40498 | |||
| 5b7ebec7e3 | |||
| de603ef909 | |||
| a0a6779097 | |||
| ce9645864d | |||
| d076c4e73d | |||
| 3e4c6a9c51 | |||
| 74a2d7d5e7 | |||
| 219f9ebede | |||
| ba0e918fef | |||
| 9b75a4f199 | |||
| 2d65594383 | |||
| 36f439a82b | |||
| 0efc99e43e | |||
| c0c35f32a8 | |||
| 53e51c76a5 | |||
| 14265a7b70 | |||
| 4467f9118f | |||
| 240a903438 | |||
| afa331e8fc | |||
| 6620e650ef | |||
| 2aa7438346 | |||
| 26fb7f33fb | |||
| 6f4451364b | |||
| 1a642108ef | |||
| dddb7b2878 | |||
| 82cafe6e94 | |||
| b578479270 | |||
| 85b77cd3c0 | |||
| 38c3f8bf9a | |||
| f558203a9d | |||
| 347d6e2c2e | |||
| eb4d540b04 | |||
| 83b6ffbba9 | |||
| 50c5f0874f | |||
| a72e6aeafe | |||
| 683cd76cc5 | |||
| df313dbfec | |||
| 2e3579a8fd | |||
| 99c8ceae9a | |||
| fa67f4fef7 | |||
| e9a7ccd00c | |||
| 76e5824d99 | |||
| 3bf101d7ac | |||
| c28320e1b2 | |||
| ea5b66d463 | |||
| 8a67c39279 | |||
| 67054bda3d | |||
| ed4c5a3a17 | |||
| ae1b1ce99e | |||
| 5d3c96ead2 | |||
| 63ad7fb128 | |||
| ccdbb1d62c | |||
| 3474f0da04 | |||
| 0fd9a9df29 | |||
| e29011eb95 | |||
| f52d2814df | |||
| 6e507f0cdc | |||
| f825901849 | |||
| 5aaceee978 | |||
| f53dbbfebf | |||
| d29263ef57 | |||
| d8c8fb4e18 | |||
| 835f9fb5e0 | |||
| ecbcbbe8d4 | |||
| 37b1bff8f2 | |||
| 5e8f9b900f | |||
| ddefead764 | |||
| 54f83cee1c | |||
| 7f3bd8c668 | |||
| ea10f2af47 | |||
| 2d810a2864 | |||
| bac2386a1a | |||
| 06ec12ba17 | |||
| 7f713e5592 | |||
| ee2556ecb6 | |||
| e57787393e | |||
| b7634024d6 | |||
| 9417671606 | |||
| 2e652b4219 | |||
| 1d6ebed7e5 | |||
| 19cf22b9e3 | |||
| 75fbdd3ac4 | |||
| 13e317d927 | |||
| 7a309ca367 | |||
| a992c93198 | |||
| ee3a653c1b | |||
| e8e7028792 | |||
| 2403d32ae4 | |||
| 1c89c7290c | |||
| 1891f6fd7e | |||
| e933b41236 | |||
| 9f7432134c | |||
| 7d69e5aaab | |||
| 780b1a0d53 | |||
| ea37f3e9f7 | |||
| c6ed117df6 | |||
| cedcc29e01 | |||
| d5219e7f0c | |||
| 9a6dec0dbd | |||
| 17574ee554 | |||
| 926f4e497a | |||
| acbe94df27 | |||
| a2f018a00b | |||
| 98cc1b1022 | |||
| 745f46f81f | |||
| 6912ed40b4 | |||
| a89dbc1152 | |||
| 0c4d46ead5 | |||
| eae9bac938 | |||
| cb91c8c41c | |||
| cb1f3e9843 | |||
| d4927db52b | |||
| bc7300bd01 | |||
| 278d7fa3f9 | |||
| d9af91bc4d | |||
| 18fe9f305c | |||
| e5e64365fc | |||
| fdf170529f | |||
| 50283ab543 | |||
| 3fa3e5acec | |||
| 4230cd5b5a | |||
| 1ad6527de5 | |||
| 0421ad80c1 | |||
| 35e0201f06 | |||
| 118eea5e77 | |||
| 7f317be325 | |||
| e1aa9f6de4 | |||
| 058a5e3bb2 | |||
| 92b49ec2b5 | |||
| 583a04b092 | |||
| 444a04e2f7 | |||
| 157e702ffd | |||
| 77892f41ec | |||
| 6ba0e1dbf6 | |||
| 950fbbaa83 | |||
| 912c431511 | |||
| 5d6b82724a | |||
| 78c976ad4f | |||
| fbdfd135da | |||
| dd51783d9e | |||
| 158fc2fca3 | |||
| 24284a6f3a | |||
| 85c2c63aa3 | |||
| f354f7de63 | |||
| 540c0a8100 | |||
| 4d00fede56 | |||
| b1bc5c08ff | |||
| 305d4f4fe5 | |||
| 2d149e9a5d | |||
| 87b9ff3c35 | |||
| 1c36b3c74c | |||
| 068e4b8e3d | |||
| df38a6424f | |||
| 5d186e56a5 | |||
| 0fafcfa006 | |||
| e3fdbafd86 | |||
| 07c2b14479 | |||
| cdc844aaf3 | |||
| e1b7d361b9 | |||
| 12ef29bebc | |||
| 22ed241d50 | |||
| 28e5a3c5be | |||
| bb4d88cc68 | |||
| 4aaea2b93f | |||
| bc8d7c4fc3 | |||
| 5ea6c46778 | |||
| b28f8ba85b | |||
| 4db50fb749 | |||
| 1dd0c90a04 | |||
| 2bace2bde2 | |||
| 1a9cb832ab | |||
| 6844a46c93 | |||
| e9e45707da | |||
| b9d02ff4c4 | |||
| 29b64300bc | |||
| 777355e86e | |||
| 620a177ce8 | |||
| 683c2dfbeb | |||
| 266cbcc6f4 | |||
| 8a45602ae6 | |||
| 711419a797 | |||
| 603f3057eb | |||
| fa6fc1f871 | |||
| 49fa320989 | |||
| 2f301bf150 | |||
| b4892ce17f | |||
| 151c171616 | |||
| 79477a2de3 | |||
| 78aadda931 | |||
| b50706505f | |||
| 9114821fb1 | |||
| 1195582da8 | |||
| 258987b0ff | |||
| a6a734c70d | |||
| d6c23a2a9b | |||
| db028904d7 | |||
| 63a571306c | |||
| bc4db61e25 | |||
| c7e6e28830 | |||
| 1d7b6fdb2c | |||
| ce5d8eeff8 | |||
| 894e0e6132 | |||
| 127f0ecf3f | |||
| cf7767e702 | |||
| e0aedc7949 | |||
| bad78de74c | |||
| 12df8a169f | |||
| 15c9d33339 | |||
| 7e0fafbaf1 | |||
| 57b9c1dd7a | |||
| 8ba0c17259 | |||
| cd32151083 | |||
| 75b52d672e | |||
| 11d04508f7 | |||
| e641b773b5 | |||
| 6e5899c654 | |||
| c66ffaa7f9 | |||
| 5193c6a5d8 | |||
| e7212af547 | |||
| 3ca1357af4 | |||
| 90e95213e4 | |||
| ae2d4da585 | |||
| 691d5cd1e6 | |||
| 58a46c6417 | |||
| d3f6160e62 | |||
| 03e4afb12f | |||
| 6802f6028e | |||
| 5ca61cfe18 | |||
| 32d55b48f2 | |||
| ab4b6f9e54 | |||
| 9100ad1220 | |||
| 8b4f8fb572 | |||
| 87e0e5bf16 | |||
| e4c2d6cf6e | |||
| fb0bdb5112 | |||
| f4b3645435 | |||
| c27f2badf7 | |||
| 1a877d6535 | |||
| 5ada9331b6 | |||
| a0f4ccb7a4 | |||
| 5b5524a7dd | |||
| 3cc464c9c9 | |||
| 51555667cf | |||
| e01ea7010f | |||
| 77732c83c9 | |||
| a67fc83949 | |||
| 3d920725aa | |||
| 2f2fbea558 | |||
| e7a86a2960 | |||
| b282d97ffe | |||
| e4ca52a95f | |||
| d972d9ec74 | |||
| 0721a6b050 | |||
| 762ee6550e | |||
| 18070eb7a6 | |||
| 8486891728 | |||
| 4679172d4f | |||
| 92a6c333d8 | |||
| 358adbdd65 | |||
| 65f7c80222 | |||
| d2e6bb236e | |||
| eaeb114258 | |||
| 1533b7fe6e | |||
| a2cd8e1ead | |||
| 4edb512121 | |||
| 702b88228c | |||
| 14fd88b2f8 | |||
| 20657e8bb5 | |||
| 93d3194e3b | |||
| 39331d9120 | |||
| b4fa6644bc | |||
| 0b2e2ed034 | |||
| 81231206f3 | |||
| 49d0e76272 | |||
| 0809993b37 | |||
| 0c3afcc24c | |||
| d6c851eed4 | |||
| dcf4a7c4e3 | |||
| 9ba07b986b | |||
| e6b6b93cbb | |||
| fcd58ae76f | |||
| df380dea27 | |||
| 9d88592391 | |||
| c906c11b0f | |||
| 4fbc56cdb0 | |||
| 98c0416b20 | |||
| fa41874e30 | |||
| 2aa6c99c90 | |||
| 5f60c0f1bb | |||
| cb741db623 | |||
| 1df217c4a0 | |||
| 81f209ba9e | |||
| 34a31aa7df | |||
| 5099e02c9b | |||
| f364b39b29 | |||
| 4cd4746f9a | |||
| 6448f0e32b | |||
| e07332d49a | |||
| bd8a44c4c9 | |||
| 21e94d8d5c | |||
| 7b1c7b967a | |||
| e4b19ab560 | |||
| 49137c9751 | |||
| 0606c90f22 | |||
| 65ade379a6 | |||
| a06df187c9 | |||
| e784c7f7df | |||
| a717392379 | |||
| a71b3a71d8 | |||
| 3366bf3dec | |||
| a505534197 | |||
| 357706b070 | |||
| e02434d135 | |||
| 4586015fc0 | |||
| 1832f2aee3 | |||
| 1ec127c3cb | |||
| 7a3b7c55c9 | |||
| b66293a2f7 | |||
| abcaafa89a | |||
| cf25cc4faa | |||
| b57001d4a7 | |||
| 83decc2473 | |||
| 92faa569be | |||
| c5b731169d | |||
| f0a8ef81d3 | |||
| 994973ac01 | |||
| c9622c0771 | |||
| 8551c6c903 | |||
| 9a9ac4308e | |||
| e784cbdd09 | |||
| 2744c4bfb6 | |||
| e4f4c1b84a | |||
| e5fa818b5c | |||
| b22b554a69 | |||
| e9b8060889 | |||
| 1c2b2c072c | |||
| 3d451912ee | |||
| fe91d774fa | |||
| d8306cb1c0 | |||
| 909cf0a576 | |||
| 8fe1ee11e4 | |||
| d2bef108f5 | |||
| ba8ba504b1 | |||
| 481b5abf85 | |||
| c4e1d9445a | |||
| cb03532b76 | |||
| c93e9eea14 | |||
| 9a67b19973 | |||
| 95c75bed1e | |||
| b008568a5c | |||
| 94fb91cec6 | |||
| c54dd77f35 | |||
| 17fbc99f29 | |||
| 21dd17290b | |||
| dc73fc92be | |||
| 592215db66 | |||
| fb318e3bd9 | |||
| 5f3c8816a3 | |||
| 6016b902c7 | |||
| 5852da1e3d | |||
| 502fd069be | |||
| fad9e7b827 | |||
| 35116d0b1a | |||
| 3b781e41ad | |||
| a3e9744364 | |||
| 7030daeccd | |||
| e7151ad7b2 | |||
| ed2a3c8458 | |||
| 779f75cd52 | |||
| 54683e3198 | |||
| 09335395f5 | |||
| 57e3dd8f15 | |||
| a9bbadd602 | |||
| 2c570681f7 | |||
| 25166970cc | |||
| d3a0a56b8b | |||
| 3c2c198a0e | |||
| 4d4d67f0b4 | |||
| 97e8a34906 | |||
| 82f3b57e83 | |||
| af2f14f807 | |||
| fe248d7098 | |||
| 1a2e702b25 | |||
| 1da20b8e7d | |||
| 01f74ff706 | |||
| 89e95eb9ee | |||
| a61ebaaa00 | |||
| 7a5a2fcd84 | |||
| 8d5554f1b5 | |||
| 873aabb471 | |||
| 4bed9dc358 | |||
| e229874195 | |||
| 473b6e31e9 | |||
| b5ce460618 | |||
| 3c05b05196 | |||
| bdb2efdb6b | |||
| a27ba3ff4b | |||
| 4684207b54 | |||
| dd1be3039b | |||
| 8b30b770cd | |||
| 47caa91e85 | |||
| d71f3e09df | |||
| 06c7415827 | |||
| bd3e62617e | |||
| 00b48473a0 | |||
| 84facb13d0 | |||
| 96f90e18e8 | |||
| 8ff18e63ee | |||
| 381405ea99 | |||
| ae5c00397a | |||
| bd4509f1a7 | |||
| b8c84886a8 | |||
| 45021389bc | |||
| f674a29a64 | |||
| 0c9e3227d0 | |||
| be7e1479a1 | |||
| 19827fca20 | |||
| 5eb7cc40ed | |||
| d22db30166 | |||
| 6db61e7a59 | |||
| 86582de521 | |||
| a7c63c2eb3 | |||
| 081a0e21ee | |||
| 9ac9c05265 | |||
| b7daf79b26 | |||
| b67a3561a4 | |||
| 52ac6dbbaf | |||
| 72381ad8f3 | |||
| 6a065c46f4 | |||
| 092d0d7e67 | |||
| 5ca7285558 | |||
| 7576f9cd5e | |||
| 46b5725d98 | |||
| 72542fa6f9 | |||
| a250d0461b | |||
| c7795bfc48 | |||
| 5de46b7e40 | |||
| 99c70872c1 | |||
| 3566669303 | |||
| 4557d05256 | |||
| fa421d165e | |||
| ecf20020d7 | |||
| ae85af61c7 | |||
| 659bbbf4fb | |||
| 427e2dddc4 | |||
| d47483f957 | |||
| 4bd8e26ae7 | |||
| 01f47282ed | |||
| afdd37cd97 | |||
| addaffcd1d | |||
| 63f7ce20a4 | |||
| f37c23db7a | |||
| d2bde0be21 | |||
| 9c446ebbd6 | |||
| 0f00fb9a27 | |||
| 2d6f819c86 | |||
| 56683ac409 | |||
| a72523c7df | |||
| 46eeb0bc22 | |||
| 6e8baef9b2 | |||
| 947b621733 | |||
| 4cc00bdaf2 | |||
| 59ef569a63 | |||
| abae225915 | |||
| 05bdf9daae | |||
| 0a8192168a | |||
| 88fd5a517e | |||
| 74c5b616a4 | |||
| 22a61d715b | |||
| a90ec7c64a | |||
| b22812b43a | |||
| 4c0da8c3d5 | |||
| 9aa30f77b7 | |||
| 2dbef83fa6 | |||
| 6ec7f789ef | |||
| 31c0afe29e | |||
| 46b07863c1 | |||
| 445e91e6b5 | |||
| 9daf386d66 | |||
| 49b4079cd8 | |||
| 0ffa1838a2 | |||
| 0efca29e95 | |||
| 0ab933efff | |||
| 4ee4a34323 | |||
| 985ccd6bba | |||
| 570e7528a7 | |||
| 918585968d | |||
| cf918a897f | |||
| 5fc27c1136 | |||
| 6bcc48c462 | |||
| 4dc368c7d0 | |||
| 17f99ed928 | |||
| 954d239b52 | |||
| ea167cbefc | |||
| 90a436236d | |||
| 4479a3fbd5 | |||
| f5216b77f8 | |||
| 39dc288978 | |||
| f37005958f | |||
| dfdc14ea86 | |||
| 82712776cc | |||
| 439446816c | |||
| 940108661c | |||
| 0423f33e93 | |||
| c2a4a7a6c2 | |||
| ff4e3dd976 | |||
| 94b00b4e7a | |||
| 48252c3c3d | |||
| 37adce2efb | |||
| 358cddd9a7 | |||
| 418df2fd93 | |||
| cd153c76f2 | |||
| f30c14b277 | |||
| 3a29812241 | |||
| 67e6b647a2 | |||
| ea0795c8a9 | |||
| 099acfca1d | |||
| 8969d11a22 | |||
| eedf32d197 | |||
| 9c8642593c | |||
| 8e89a2ef1b | |||
| 316c2fdd4d | |||
| 6bbf1d0996 | |||
| e854ba3c44 | |||
| f681c8963d | |||
| 8d5f22e43d | |||
| a62de839be | |||
| 5af60b2ff4 | |||
| c8d7fce938 | |||
| 90fbc790d9 | |||
| 1ce3fc972a | |||
| 9ea3f0f240 | |||
| 868fa90097 | |||
| 55bb20cf29 | |||
| 7c0671c81b | |||
| 12a66bd83e | |||
| 1efdcd7b10 | |||
| 2d9bcdb87a | |||
| ac9cace8f6 | |||
| f9bf27579e | |||
| 667cae2e62 | |||
| e8e0491cb5 | |||
| ee12f0bd18 | |||
| 5f24193c49 | |||
| dd29d37154 | |||
| b63e3aca00 | |||
| 859674ce7e | |||
| ea8b9ce462 | |||
| b5720bd14e | |||
| cc99409a7e | |||
| fef3e21c70 | |||
| f3d76c433a | |||
| 31d5715723 | |||
| 592eef3cda | |||
| 0541748e5f | |||
| cf1d9e8372 | |||
| b096d8869e | |||
| 2acc14b04a | |||
| 1f1efb0e17 | |||
| 1c08d854fb | |||
| 9c252fb226 | |||
| 4bda3b9e9b | |||
| 21da3c8602 | |||
| 7ec43776ae | |||
| 07d7e68dc2 | |||
| 8785c33d06 | |||
| 661ebe439d | |||
| 4732fa36a6 | |||
| 8dad158ae6 | |||
| bfc343d1ee | |||
| ca723c3b47 | |||
| b6657351fc | |||
| f26032ed7d | |||
| 012f7665aa | |||
| c28e8142f4 | |||
| 1462acbb92 | |||
| c52c659b94 | |||
| 6bf358fc66 | |||
| e8f57d3ace | |||
| 766e7193b9 | |||
| 6fe762aa7b | |||
| 7065b1b3ba | |||
| 72b812acad | |||
| d7ffa21fbe | |||
| c95d64909a | |||
| a5b2b04317 | |||
| 4705194a1d | |||
| 19572a674e | |||
| a1247f4d96 | |||
| 52412dfe31 | |||
| ab02e6e7c3 | |||
| 9ef99a2b92 | |||
| 4e5fac4b88 | |||
| 7a14aaa17e | |||
| 650863836c | |||
| 3a69ac23c0 | |||
| b873c6ae4d | |||
| 4835b1b897 | |||
| 67def6319e | |||
| c56d9ac7ce | |||
| e6588c4307 | |||
| 712389ab24 | |||
| 5f1be38490 | |||
| 7982592c6e | |||
| 69574918b5 | |||
| f6783e8f5e | |||
| 913b00a4d4 | |||
| 22fa132110 | |||
| 5a30fc0300 | |||
| c774ffc979 | |||
| c93e7fb9cd | |||
| 3437888964 | |||
| b314e0bdda | |||
| 2bdde6a528 | |||
| c61cb80a8b | |||
| 4217aab933 | |||
| ffb2956d90 | |||
| 9744547fab | |||
| b580d1cf5b | |||
| 855c7b608e | |||
| 707ed9a828 | |||
| a3ea514521 | |||
| 3dfaec5033 | |||
| 778106c41b | |||
| c47e9cdde4 | |||
| 8dd76420c8 | |||
| dfe026ac2d | |||
| f0849d0ed1 | |||
| b7ca898b77 | |||
| 1b8b377f90 | |||
| 7227f1ac78 | |||
| 23f088105e | |||
| 3bbb6b1058 | |||
| 3a4895b21c | |||
| 4e6afe9b64 | |||
| dd4c20249f | |||
| b54b2d47e9 | |||
| 64fb587d0f | |||
| 2ca3c65300 | |||
| 549f346d5e | |||
| 80a879bddf | |||
| 13c17a000a | |||
| 96dea75bc8 | |||
| 035fce6191 | |||
| 2f5dd171d0 | |||
| e7598d4340 | |||
| 76d0a39a0f | |||
| 3f25f072c6 | |||
| 5c75f249c7 | |||
| 02bfe63245 | |||
| faa205a486 | |||
| 3a6d645ea3 | |||
| e65468b97a | |||
| edbe6015f6 | |||
| f642e11a7a | |||
| fdc87fe296 | |||
| 7396c7595f | |||
| d39849ad00 | |||
| d65ee902f7 | |||
| eada4b0fc3 | |||
| 6f9619126a | |||
| 4bc6007a4d | |||
| d3f5154c19 | |||
| 71aa29cc71 | |||
| 98d8015015 | |||
| 42a44f210d | |||
| 29ff86b74f | |||
| 381afa2741 | |||
| 82d4099541 | |||
| 5f659c8de7 | |||
| e054ea6683 | |||
| 0deafb768b | |||
| cd612b452c | |||
| 009939f866 | |||
| cd006ce78e | |||
| 71bf2aa59f | |||
| 714b935474 | |||
| 2a2b83a695 | |||
| acdaa95854 | |||
| 278c5f6142 | |||
| 8ca3cd3155 | |||
| 2b7d7ce2cf | |||
| a22efc2eb6 | |||
| 804c8eff91 | |||
| aec8ebe237 | |||
| 7353790ed1 | |||
| e09e8e5823 | |||
| 92773417b3 | |||
| 12dc4fde8a | |||
| d1e5186d4a | |||
| d06ba95374 | |||
| f0e6c8ea8e | |||
| c94c204da2 | |||
| 71617a1c70 | |||
| 9f684937c6 | |||
| ff6665c716 | |||
| aa8fd3c861 | |||
| e2b42804d5 | |||
| 0f6e942c5b | |||
| c0a81978bf | |||
| b76c882210 | |||
| 14cbfbc5a4 | |||
| 9b1761f71f | |||
| 73ca2e0fa4 | |||
| 4e4c7f7d7b | |||
| 33f2c3f220 | |||
| dcca0133fb | |||
| 408201b69b | |||
| e024628d46 | |||
| 6428f29373 | |||
| cfaa6ab6df | |||
| 91ee7565ac | |||
| 1bbcac2ab3 | |||
| 60b2353afe | |||
| 50cfa4c971 | |||
| 691bf8faca | |||
| 89b4ae6a6f | |||
| 605a67932f | |||
| 1774dc74e3 | |||
| 2d641bf049 | |||
| 94a06d9b6f | |||
| a485942731 | |||
| 2c1b3b2480 | |||
| f1f7c70aee | |||
| 718caf8cb1 | |||
| 545cd4ec12 | |||
| 444ea9ec7e | |||
| 13609a5c44 | |||
| d6ad21f6f9 | |||
| 593a32a689 | |||
| 7fed5534eb | |||
| 1560284831 | |||
| 558a86739f | |||
| bfd60b733a | |||
| ae26512601 | |||
| 498c2f5256 | |||
| 459f12d61f | |||
| bcd6e537e0 | |||
| 867c3413e9 | |||
| 0f808d5c60 | |||
| f5767dd865 | |||
| 631a855bac | |||
| c616b5b03b | |||
| 3e9f4a5060 | |||
| 31434186ab | |||
| e81ba1c431 | |||
| b219ab607f | |||
| cd8307f432 | |||
| a720105208 | |||
| 34692c41f2 | |||
| 8a8b945eb8 | |||
| 99569c52ac | |||
| f696dc715b | |||
| 21b8552386 | |||
| 4b1886700d | |||
| a83ca1f85b | |||
| 65553c156c | |||
| 440357d2e8 | |||
| 5e62b9077a | |||
| 6192ced214 | |||
| ae31fee8dd | |||
| e7b00cc76e | |||
| 7d29c5d766 | |||
| 15776c4ce3 | |||
| d720179deb | |||
| 0d69e0ac97 | |||
| 09e267f8bc | |||
| 705ceca42a | |||
| 58722d372e | |||
| f482b8b95c | |||
| 21e4dee0e2 | |||
| c7a12ad75b | |||
| 7cd77ae379 | |||
| d59c99ddfe | |||
| 85760cc844 | |||
| 0692464b85 | |||
| 3968222744 | |||
| c05368d92e | |||
| 404136cd72 | |||
| b1d5ed0066 | |||
| e22474e0a7 | |||
| 45b7304630 | |||
| 692536c584 | |||
| 4e3d85887c | |||
| 87852328da | |||
| 2207cd7b52 | |||
| f3cd4e38d7 | |||
| 2dce1c0ad9 | |||
| 258ecad277 | |||
| 7f5092c0d5 | |||
| a7f315f596 | |||
| 4dc4aa122b | |||
| e3f388af11 | |||
| 83196628c9 | |||
| 315c07d4f6 | |||
| 47dadf0a43 | |||
| c62039f327 | |||
| a5ea560edc | |||
| e09e933f9c | |||
| dbd00d5a8b | |||
| 2da772df8e | |||
| 4cdad0e83e | |||
| 2f780da305 | |||
| 9d8066f4b8 | |||
| 2cc49256a9 | |||
| 79ab2e11f8 | |||
| c1f4302e62 | |||
| f66ec9168c | |||
| 37aecf72cb | |||
| 3c7be5e9be | |||
| 89dbae8f8e | |||
| 5eec8f754d | |||
| 49a82c8388 | |||
| 26bad4a1cd | |||
| fa0a38d3aa | |||
| b56fd4d29a | |||
| 4520747167 | |||
| e444ecb2c7 | |||
| 1336c47d18 | |||
| 519a74e8d2 | |||
| dea7714ef3 | |||
| 74b88b407e | |||
| 57c28c61e0 | |||
| 87320348dd | |||
| fcb70e69c1 | |||
| 4859629850 | |||
| bd0d248fd0 | |||
| c24a3edb44 | |||
| d0f197ea3d | |||
| 5502d93cd5 | |||
| 073fd76aa2 | |||
| 492a3f6928 | |||
| 1ce8fa8bdd | |||
| 1bb90233b9 | |||
| 49ce92f540 | |||
| 2107da2e1a | |||
| d98321026d | |||
| 0b6fabbc71 | |||
| bb0fad2834 | |||
| 08f9722e33 | |||
| 62ca30bbc6 | |||
| 467403362d | |||
| 265a78cd23 | |||
| a0e13d0481 | |||
| 77fc6435a0 | |||
| cd7e5bf020 | |||
| 5e7388f686 | |||
| 1047e751e6 | |||
| c598871764 | |||
| 2921c66834 | |||
| 7bbb083c36 | |||
| 531650c9f2 | |||
| f3098741c3 | |||
| 9dbffef140 | |||
| c97e504686 | |||
| 0c4b807caa | |||
| 1eca2b6cb0 | |||
| 17cbb3eab0 | |||
| c72f2a2c96 | |||
| 610f531653 | |||
| 1e9b28b369 | |||
| 6d4caca6cc | |||
| 15953f832f | |||
| d346ed0570 | |||
| df520a1134 | |||
| f90fc1d5ec | |||
| 797904afb5 | |||
| 489fbb5e42 | |||
| 9dd5a9ef89 | |||
| 02213802c5 | |||
| 8365855475 | |||
| 55eb86d2d5 | |||
| 0a9b944431 | |||
| f1e229193c | |||
| 04e309aeff | |||
| 99eb31b312 | |||
| 287275d886 | |||
| af6f8b5391 | |||
| 3b9b103c3f | |||
| 0c55ab9001 | |||
| 9c88f70740 | |||
| 9ab003df4c | |||
| 7f8d03d192 | |||
| c64ffde11f | |||
| 1568008c67 | |||
| 84211576e4 | |||
| 553f5b063f | |||
| f5d1f288d0 | |||
| a2df92dd68 | |||
| 1c6e51f8b2 | |||
| ef5da49bc0 | |||
| 7545625af4 | |||
| e3055b95f6 | |||
| 78eed8629c |
@@ -1,14 +0,0 @@
|
|||||||
coverage:
|
|
||||||
precision: 2
|
|
||||||
round: down
|
|
||||||
range: "50...100"
|
|
||||||
|
|
||||||
status:
|
|
||||||
project:
|
|
||||||
default: on
|
|
||||||
patch:
|
|
||||||
default: on
|
|
||||||
changes:
|
|
||||||
default: off
|
|
||||||
|
|
||||||
comment: false
|
|
||||||
+13
-1
@@ -7,11 +7,23 @@ insert_final_newline = true
|
|||||||
|
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
continuation_indent_size = 8 #IntelliJ Idea specific workaround
|
|
||||||
|
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
ij_java_continuation_indent_size = 8
|
||||||
|
ij_java_use_single_class_imports = true
|
||||||
|
ij_java_class_count_to_use_import_on_demand = 99
|
||||||
|
ij_java_names_count_to_use_import_on_demand = 99
|
||||||
|
ij_java_packages_to_use_import_on_demand = *
|
||||||
|
|
||||||
|
[*.kt]
|
||||||
|
ij_kotlin_continuation_indent_size = 8
|
||||||
|
ij_kotlin_name_count_to_use_star_import = 99
|
||||||
|
ij_kotlin_name_count_to_use_star_import_for_members = 99
|
||||||
|
ij_kotlin_packages_to_use_import_on_demand = *
|
||||||
|
|
||||||
[*.yml]
|
[*.yml]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.java text eol=lf diff=java
|
||||||
|
*.kt text eol=lf diff=kotlin
|
||||||
|
*.kts text eol=lf diff=kotlin
|
||||||
|
|
||||||
|
gradlew text eol=lf
|
||||||
|
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
|
*.png binary
|
||||||
|
*.jar binary
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
name: Decompilation error
|
|
||||||
about: Create a report to help us improve jadx decompiler
|
|
||||||
title: "[core]"
|
|
||||||
labels: Core, bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Checks before report**
|
|
||||||
- check [latest unstable build](https://bintray.com/skylot/jadx/unstable/_latestVersion#files) (maybe issue already fixed)
|
|
||||||
- check [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A) section on wiki
|
|
||||||
- search existing issues by exception message
|
|
||||||
|
|
||||||
**Describe error**
|
|
||||||
- provide full name of method or class with error
|
|
||||||
- provide full java stacktrace
|
|
||||||
|
|
||||||
**Note**: no need to copy method fallback code (commented pseudocode)
|
|
||||||
- attach or provide link to apk file (double check apk version)
|
|
||||||
|
|
||||||
**Note**: GitHub don't allow attach files with `.apk` extension, but you can change extension by adding `.zip` at the end :)
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
name: Decompilation issue
|
||||||
|
description: Create a report to help us improve jadx decompiler
|
||||||
|
title: '[core] '
|
||||||
|
labels:
|
||||||
|
- Core
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**Checks before submit**
|
||||||
|
- check [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A) section on wiki
|
||||||
|
- try [latest unstable build](https://nightly.link/skylot/jadx/workflows/build-artifacts/master), maybe issue already fixed
|
||||||
|
- search existing issues by exception message
|
||||||
|
- type: textarea
|
||||||
|
id: details
|
||||||
|
attributes:
|
||||||
|
label: Issue details
|
||||||
|
placeholder: >-
|
||||||
|
Describe issue
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Relevant log output or stacktrace
|
||||||
|
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: java
|
||||||
|
- type: textarea
|
||||||
|
id: sample
|
||||||
|
attributes:
|
||||||
|
label: Provide sample and class/method full name
|
||||||
|
description: |
|
||||||
|
- sample: attach or provide a link
|
||||||
|
- full name of class or method with issue
|
||||||
|
- other details which may help to reproduce issue
|
||||||
|
- type: input
|
||||||
|
id: jadx-version
|
||||||
|
attributes:
|
||||||
|
label: Jadx version
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature Request
|
|
||||||
about: Suggest an idea for jadx
|
|
||||||
title: "[feature]"
|
|
||||||
labels: new feature
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Describe your idea:*
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: Suggest an idea for jadx
|
||||||
|
title: '[feature] '
|
||||||
|
labels:
|
||||||
|
- 'new feature'
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: details
|
||||||
|
attributes:
|
||||||
|
label: Describe your idea
|
||||||
|
placeholder: Feature details
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: jadx-gui issue
|
||||||
|
description: Create a bug report about issue found in jadx-gui
|
||||||
|
title: '[gui] '
|
||||||
|
labels:
|
||||||
|
- GUI
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**Checks before submit**
|
||||||
|
- check [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A) section on wiki
|
||||||
|
- try [latest unstable build](https://nightly.link/skylot/jadx/workflows/build-artifacts/master), maybe issue already fixed
|
||||||
|
- search existing issues by exception message
|
||||||
|
- type: textarea
|
||||||
|
id: details
|
||||||
|
attributes:
|
||||||
|
label: Issue details
|
||||||
|
placeholder: Describe issue and how to reproduce it
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: jadx-version
|
||||||
|
attributes:
|
||||||
|
label: Jadx version
|
||||||
|
placeholder: check `Help->About`
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: java-version
|
||||||
|
attributes:
|
||||||
|
label: Java version
|
||||||
|
placeholder: check `Help->About`
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: OS
|
||||||
|
options:
|
||||||
|
- label: Windows
|
||||||
|
- label: Linux
|
||||||
|
- label: macOS
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Set update schedule for GitHub Actions
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
:exclamation: Please review the [guidelines for contributing](../CONTRIBUTING.md#Pull-Request-Process)
|
:exclamation: Please review the [guidelines for contributing](https://github.com/skylot/jadx/blob/master/CONTRIBUTING.md#Pull-Request-Process)
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
Please describe your pull request.
|
Please describe your pull request.
|
||||||
Reference issue it fix.
|
Reference issue it fixes.
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
name: Build Artifacts
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master, build-test ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 21
|
||||||
|
|
||||||
|
- name: Set jadx version
|
||||||
|
run: |
|
||||||
|
JADX_REV=$(git rev-list --count HEAD)
|
||||||
|
JADX_VERSION="r${JADX_REV}.${GITHUB_SHA:0:7}"
|
||||||
|
echo "JADX_VERSION=$JADX_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: ./gradlew dist distWin
|
||||||
|
env:
|
||||||
|
JADX_BUILD_JAVA_VERSION: 11
|
||||||
|
|
||||||
|
- name: Save bundle artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ format('jadx-{0}', env.JADX_VERSION) }}
|
||||||
|
# Waiting fix for https://github.com/actions/upload-artifact/issues/39 to upload zip file
|
||||||
|
# Upload unpacked files for now
|
||||||
|
path: build/jadx/**/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 14
|
||||||
|
|
||||||
|
- name: Save Windows bundle artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ format('jadx-gui-{0}-no-jre-win', env.JADX_VERSION) }}
|
||||||
|
# Upload unpacked files for now
|
||||||
|
path: jadx-gui/build/jadx-gui-win/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 14
|
||||||
|
|
||||||
|
build-win-bundle:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: oracle-actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
release: 24
|
||||||
|
|
||||||
|
- name: Print Java version
|
||||||
|
shell: bash
|
||||||
|
run: java -version
|
||||||
|
|
||||||
|
- name: Set jadx version
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
JADX_REV=$(git rev-list --count HEAD)
|
||||||
|
JADX_VERSION="r${JADX_REV}.${GITHUB_SHA:0:7}"
|
||||||
|
echo "JADX_VERSION=$JADX_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: ./gradlew dist -PbundleJRE=true
|
||||||
|
|
||||||
|
- name: Save Windows with JRE bundle artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ format('jadx-gui-{0}-with-jre-win', env.JADX_VERSION) }}
|
||||||
|
# Upload unpacked files for now
|
||||||
|
path: jadx-gui/build/jadx-gui-with-jre-win/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 14
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: Build Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master, build-test ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-latest, windows-latest ]
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 21
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: ./gradlew build dist distWin
|
||||||
|
env:
|
||||||
|
JADX_BUILD_JAVA_VERSION: 11
|
||||||
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [master]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 9 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: ['java']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v3
|
||||||
|
with:
|
||||||
|
queries: +security-extended
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
# Don't build tests in jadx-core also skip tests execution and checkstyle tasks
|
||||||
|
- run: |
|
||||||
|
./gradlew clean build -x checkstyleTest -x checkstyleMain -x test -x ':jadx-core:testClasses'
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*.*.*"
|
||||||
|
|
||||||
|
# additional permissions for provided GitHub token to create new release
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-release-win-bundle:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: oracle-actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
release: 24
|
||||||
|
|
||||||
|
- name: Set jadx version
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const jadxVersion = context.ref.split('/').pop().substring(1)
|
||||||
|
core.exportVariable('JADX_VERSION', jadxVersion);
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: ./gradlew dist -PbundleJRE=true
|
||||||
|
|
||||||
|
- name: Save JRE bundle artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ format('jadx-gui-{0}-with-jre-win', env.JADX_VERSION) }}
|
||||||
|
path: ${{ format('build/distWinWithJre/jadx-gui-{0}-with-jre-win.zip', env.JADX_VERSION) }}
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: build-release-win-bundle
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 21
|
||||||
|
|
||||||
|
- name: Set jadx version and release name
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const jadxVersion = context.ref.split('/').pop().substring(1)
|
||||||
|
core.exportVariable('JADX_VERSION', jadxVersion);
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: ./gradlew dist distWin
|
||||||
|
env:
|
||||||
|
JADX_BUILD_JAVA_VERSION: 11
|
||||||
|
|
||||||
|
- name: Download Windows JRE bundle
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ format('jadx-gui-{0}-with-jre-win', env.JADX_VERSION) }}
|
||||||
|
path: ${{ format('build/jadx-gui-{0}-with-jre-win', env.JADX_VERSION) }}
|
||||||
|
|
||||||
|
- run: |
|
||||||
|
cd build
|
||||||
|
pwd
|
||||||
|
ls -l
|
||||||
|
ls jadx-gui-*-with-jre-win
|
||||||
|
mv jadx-gui-*-with-jre-win/jadx-gui-*-with-jre-win.zip .
|
||||||
|
mv distWin/jadx-gui-*-win.zip .
|
||||||
|
ls -l *.zip
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
name: ${{ env.JADX_VERSION }}
|
||||||
|
draft: true
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
files: build/jadx-*.zip
|
||||||
+11
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
# IntelliJ Idea files
|
# IntelliJ Idea files
|
||||||
.idea/
|
.idea/
|
||||||
|
.run/
|
||||||
out/
|
out/
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
@@ -20,14 +21,23 @@ build/
|
|||||||
classes/
|
classes/
|
||||||
idea/
|
idea/
|
||||||
.gradle/
|
.gradle/
|
||||||
|
.kotlin/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
jadx-output/
|
jadx-output/
|
||||||
*-tmp/
|
*-tmp/
|
||||||
|
**/tmp/
|
||||||
|
*.jobf
|
||||||
|
*.jadx
|
||||||
|
|
||||||
*.dex
|
|
||||||
*.class
|
*.class
|
||||||
|
*.jar
|
||||||
*.dump
|
*.dump
|
||||||
*.log
|
*.log
|
||||||
*.cfg
|
*.cfg
|
||||||
*.orig
|
*.orig
|
||||||
|
quark.json
|
||||||
|
|
||||||
|
cliff.toml
|
||||||
|
jadx-gui/src/main/resources/logback.xml
|
||||||
|
|||||||
+3
-26
@@ -7,31 +7,8 @@ before_script:
|
|||||||
|
|
||||||
stages:
|
stages:
|
||||||
- test
|
- test
|
||||||
- check
|
|
||||||
|
|
||||||
java-8:
|
build-test:
|
||||||
stage: test
|
stage: test
|
||||||
image: openjdk:8
|
image: eclipse-temurin:21
|
||||||
script: ./gradlew clean build
|
script: JADX_BUILD_JAVA_VERSION=11 JADX_TEST_JAVA_VERSION=11 ./gradlew clean build dist distWin
|
||||||
|
|
||||||
java-11:
|
|
||||||
stage: test
|
|
||||||
image: openjdk:11
|
|
||||||
script: ./gradlew clean build
|
|
||||||
|
|
||||||
java-12:
|
|
||||||
stage: test
|
|
||||||
image: gradle:jdk12 # latest gradle and jdk12
|
|
||||||
script: gradle clean build
|
|
||||||
|
|
||||||
check:
|
|
||||||
stage: check
|
|
||||||
image: openjdk:8
|
|
||||||
script:
|
|
||||||
- export JADX_LAST_TAG="$(git describe --abbrev=0 --tags)"
|
|
||||||
- export JADX_VERSION="${JADX_LAST_TAG:1}-dev-$(git rev-parse --short HEAD)"
|
|
||||||
- ./gradlew clean sonarqube -Dsonar.host.url="${SONAR_HOST}" -Dsonar.projectKey=jadx -Dsonar.organization="${SONAR_ORG}" -Dsonar.login="${SONAR_TOKEN}" -Dsonar.branch.name=dev || echo "Skip sonar build and upload"
|
|
||||||
- ./gradlew clean dist
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- build/jadx*.zip
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
jdk:
|
||||||
|
- openjdk11
|
||||||
|
install:
|
||||||
|
- echo "Jitpack is not supported. Use artifacts from Maven Central (https://search.maven.org/search?q=jadx), check usage help at https://github.com/skylot/jadx/wiki/Use-jadx-as-a-library"
|
||||||
|
- ./gradlew intentional-fail
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
branch: release
|
|
||||||
verifyConditions:
|
|
||||||
- '@semantic-release/github'
|
|
||||||
|
|
||||||
prepare:
|
|
||||||
- path: '@semantic-release/exec'
|
|
||||||
cmd: "JADX_VERSION=${nextRelease.version} ./gradlew clean dist"
|
|
||||||
|
|
||||||
preset: "angular"
|
|
||||||
|
|
||||||
generateNotes:
|
|
||||||
- path: '@semantic-release/release-notes-generator'
|
|
||||||
writerOpts:
|
|
||||||
groupBy: "type"
|
|
||||||
commitGroupsSort:
|
|
||||||
- "feat"
|
|
||||||
- "perf"
|
|
||||||
- "fix"
|
|
||||||
commitsSort: "header"
|
|
||||||
|
|
||||||
publish:
|
|
||||||
- path: '@semantic-release/exec'
|
|
||||||
cmd: "JADX_VERSION=${nextRelease.version} BINTRAY_PACKAGE=releases bash scripts/bintray-upload.sh"
|
|
||||||
- path: '@semantic-release/github'
|
|
||||||
assets:
|
|
||||||
- path: 'build/*.zip'
|
|
||||||
- path: 'build/*.exe'
|
|
||||||
|
|
||||||
success:
|
|
||||||
- path: '@semantic-release/github'
|
|
||||||
successComment: false
|
|
||||||
|
|
||||||
fail:
|
|
||||||
- path: '@semantic-release/github'
|
|
||||||
failComment: false
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="jadx-gui" type="Application" factoryName="Application">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="jadx.gui.JadxGUI"/>
|
||||||
|
<module name="jadx.jadx-gui.main"/>
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="-v"/>
|
||||||
|
<option name="VM_PARAMETERS"
|
||||||
|
value="-Xms128M -XX:MaxRAMPercentage=70.0 -Dawt.useSystemAAFontSettings=lcd -Dswing.aatext=true -Djava.util.Arrays.useLegacyMergeSort=true -Djdk.util.zip.disableZip64ExtraFieldValidation=true -XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED --enable-native-access=ALL-UNNAMED -Dsun.java2d.noddraw=true -Dsun.java2d.d3d=false -Dsun.java2d.ddforcevram=true -Dsun.java2d.ddblit=false -Dswing.useflipBufferStrategy=true"/>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true"/>
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
-41
@@ -1,41 +0,0 @@
|
|||||||
language: java
|
|
||||||
os: linux
|
|
||||||
dist: trusty
|
|
||||||
|
|
||||||
# don't build on tag push
|
|
||||||
if: tag IS blank
|
|
||||||
|
|
||||||
git:
|
|
||||||
depth: false
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- chmod +x gradlew
|
|
||||||
|
|
||||||
# override install to skip 'gradle assemble'
|
|
||||||
install: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- TERM=dumb
|
|
||||||
- JADX_LAST_TAG=$(git describe --abbrev=0 --tags)
|
|
||||||
- JADX_VERSION="${JADX_LAST_TAG:1}-b$TRAVIS_BUILD_NUMBER-$(git rev-parse --short HEAD)"
|
|
||||||
|
|
||||||
jdk:
|
|
||||||
- openjdk8
|
|
||||||
- openjdk11
|
|
||||||
|
|
||||||
script: ./gradlew clean build
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
include:
|
|
||||||
- stage: deploy-unstable
|
|
||||||
jdk: openjdk8
|
|
||||||
if: branch = master AND repo = env(MAIN_REPO) AND type = push
|
|
||||||
script: bash scripts/travis-master.sh
|
|
||||||
|
|
||||||
- stage: deploy-release
|
|
||||||
language: node_js
|
|
||||||
jdk: openjdk8
|
|
||||||
node_js: 11
|
|
||||||
if: branch = release AND repo = env(MAIN_REPO) AND type = push
|
|
||||||
script: bash scripts/travis-release.sh
|
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# Config for 'typos' spellchecker (https://github.com/crate-ci/typos)
|
||||||
|
|
||||||
|
[default.extend-words]
|
||||||
|
IPUT = "IPUT"
|
||||||
|
Laf = "Laf"
|
||||||
|
Darcula="Darcula"
|
||||||
|
|
||||||
|
[default]
|
||||||
|
extend-ignore-identifiers-re = [
|
||||||
|
"finaly", # intentional package name
|
||||||
|
]
|
||||||
|
|
||||||
|
[files]
|
||||||
|
extend-exclude = [
|
||||||
|
"config/",
|
||||||
|
"jadx-core/src/main/resources/",
|
||||||
|
"jadx-core/src/test/",
|
||||||
|
"jadx-gui/src/main/resources/i18n/",
|
||||||
|
"!jadx-gui/src/main/resources/i18n/Messages_en_US.properties",
|
||||||
|
]
|
||||||
+10
-23
@@ -3,7 +3,7 @@
|
|||||||
## Our Pledge
|
## Our Pledge
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
contributors and maintainers pledge to making participation in our project and
|
contributors and maintainers pledge to make participation in our project and
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||||
level of experience, education, socio-economic status, nationality, personal
|
level of experience, education, socio-economic status, nationality, personal
|
||||||
@@ -23,13 +23,13 @@ include:
|
|||||||
Examples of unacceptable behavior by participants include:
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
advances
|
advances
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
* Public or private harassment
|
* Public or private harassment
|
||||||
* Publishing others' private information, such as a physical or electronic
|
* Publishing others' private information, such as a physical or electronic
|
||||||
address, without explicit permission
|
address, without explicit permission
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
professional setting
|
professional setting
|
||||||
|
|
||||||
## Our Responsibilities
|
## Our Responsibilities
|
||||||
|
|
||||||
@@ -45,25 +45,12 @@ threatening, offensive, or harmful.
|
|||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
This Code of Conduct applies within all project spaces, and it also applies when
|
||||||
when an individual is representing the project or its community. Examples of
|
an individual is representing the project or its community in public spaces.
|
||||||
representing a project or community include using an official project e-mail
|
Examples of representing a project or community include using an official
|
||||||
address, posting via an official social media account, or acting as an appointed
|
project e-mail address, posting via an official social media account, or acting
|
||||||
representative at an online or offline event. Representation of a project may be
|
as an appointed representative at an online or offline event. Representation of
|
||||||
further defined and clarified by project maintainers.
|
a project may be further defined and clarified by project maintainers.
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported by contacting the project team at skylot@gmail.com. All
|
|
||||||
complaints will be reviewed and investigated and will result in a response that
|
|
||||||
is deemed necessary and appropriate to the circumstances. The project team is
|
|
||||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
||||||
Further details of specific enforcement policies may be posted separately.
|
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
||||||
faith may face temporary or permanent repercussions as determined by other
|
|
||||||
members of the project's leadership.
|
|
||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
|
|||||||
+10
-17
@@ -1,34 +1,27 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
|
Please note, we have [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
|
||||||
|
|
||||||
## Open Issue
|
## Open Issue
|
||||||
|
|
||||||
1. Before proceed please do:
|
1. Before proceed, please do:
|
||||||
- check [latest unstable build](https://bintray.com/skylot/jadx/unstable/_latestVersion#files) (maybe issue already fixed)
|
|
||||||
- check [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A) section on wiki
|
- check [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A) section on wiki
|
||||||
- search existing issues by exception message
|
- search existing issues by exception message
|
||||||
|
|
||||||
2. Describe error
|
2. Describe error:
|
||||||
- provide full name of method or class with error
|
- full name of method or class with error
|
||||||
- provide full java stacktrace
|
- full java stacktrace (no need to copy method fallback code (commented pseudocode))
|
||||||
|
- **IMPORTANT!:** attach or provide link to apk file (double check apk version)
|
||||||
|
|
||||||
**Note**: no need to copy method fallback code (commented pseudocode)
|
**Note**: GitHub don't allow attaching files with `.apk` extension, but you can change extension by adding `.zip` at the end :)
|
||||||
- attach or provide link to apk file (double check apk version)
|
|
||||||
|
|
||||||
**Note**: GitHub don't allow attach files with `.apk` extension, but you can change extension by adding `.zip` at the end :)
|
|
||||||
|
|
||||||
|
|
||||||
## Pull Request Process
|
## Pull Request Process
|
||||||
|
|
||||||
1. Please don't submit any code style fixes, dependencies updates or other changes which are not fixing any issues.
|
1. Please don't submit any code style fixes or dependencies updates changes.
|
||||||
|
|
||||||
1. Before open a PR please discuss the change you wish to make via issue. PR without corresponding issue will be rejected.
|
1. Use only features and API from Java 11 or below.
|
||||||
|
|
||||||
1. Use only features and API from Java 8 or below.
|
|
||||||
|
|
||||||
1. If possible don't add additional dependencies especially if they are big.
|
|
||||||
|
|
||||||
1. Make sure your code is correctly formatted, see description here: [Code Formatting](https://github.com/skylot/jadx/wiki/Code-Formatting).
|
1. Make sure your code is correctly formatted, see description here: [Code Formatting](https://github.com/skylot/jadx/wiki/Code-Formatting).
|
||||||
|
|
||||||
1. Make sure your changes is passing build: `./gradlew clean build dist`
|
1. Make sure your changes are passing build: `./gradlew clean build dist`
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
|
<img src="https://raw.githubusercontent.com/skylot/jadx/master/jadx-gui/src/main/resources/logos/jadx-logo.png" width="64" align="left" />
|
||||||
|
|
||||||
## JADX
|
## JADX
|
||||||
|
|
||||||
[](https://travis-ci.org/skylot/jadx)
|

|
||||||
[](https://codecov.io/gh/skylot/jadx)
|

|
||||||
[](https://lgtm.com/projects/g/skylot/jadx/alerts/)
|

|
||||||
[](https://sonarcloud.io/dashboard?id=jadx)
|

|
||||||
|

|
||||||
|
[](https://search.maven.org/search?q=g:io.github.skylot%20AND%20jadx)
|
||||||
|

|
||||||
[](http://www.apache.org/licenses/LICENSE-2.0.html)
|
[](http://www.apache.org/licenses/LICENSE-2.0.html)
|
||||||
[](https://github.com/semantic-release/semantic-release)
|
|
||||||
|
|
||||||
**jadx** - Dex to Java decompiler
|
**jadx** - Dex to Java decompiler
|
||||||
|
|
||||||
Command line and GUI tools for produce Java source code from Android Dex and Apk files
|
Command line and GUI tools for producing Java source code from Android Dex and Apk files
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Please note that in most cases **jadx** can't decompile all 100% of the code, so errors will occur.<br />
|
||||||
|
> Check [Troubleshooting guide](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A#decompilation-issues) for workarounds.
|
||||||
|
|
||||||
**Main features:**
|
**Main features:**
|
||||||
- decompile Dalvik bytecode to java classes from APK, dex, aar and zip files
|
- decompile Dalvik bytecode to Java code from APK, dex, aar, aab and zip files
|
||||||
- decode `AndroidManifest.xml` and other resources from `resources.arsc`
|
- decode `AndroidManifest.xml` and other resources from `resources.arsc`
|
||||||
- deobfuscator included
|
- deobfuscator included
|
||||||
|
|
||||||
@@ -21,38 +29,50 @@ Command line and GUI tools for produce Java source code from Android Dex and Apk
|
|||||||
- jump to declaration
|
- jump to declaration
|
||||||
- find usage
|
- find usage
|
||||||
- full text search
|
- full text search
|
||||||
|
- smali debugger, check [wiki page](https://github.com/skylot/jadx/wiki/Smali-debugger) for setup and usage
|
||||||
|
|
||||||
|
Jadx-gui key bindings can be found [here](https://github.com/skylot/jadx/wiki/JADX-GUI-Key-bindings)
|
||||||
|
|
||||||
See these features in action here: [jadx-gui features overview](https://github.com/skylot/jadx/wiki/jadx-gui-features-overview)
|
See these features in action here: [jadx-gui features overview](https://github.com/skylot/jadx/wiki/jadx-gui-features-overview)
|
||||||
|
|
||||||
|
<img src="https://user-images.githubusercontent.com/118523/142730720-839f017e-38db-423e-b53f-39f5f0a0316f.png" width="700"/>
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### Download
|
### Download
|
||||||
- latest [unstable build:  ](https://bintray.com/skylot/jadx/unstable/_latestVersion#files)
|
- release
|
||||||
- release from [github: ](https://github.com/skylot/jadx/releases/latest)
|
from [github: ](https://github.com/skylot/jadx/releases/latest)
|
||||||
- release from [bintray:  ](https://bintray.com/skylot/jadx/releases/_latestVersion#files)
|
- latest [unstable build ](https://nightly.link/skylot/jadx/workflows/build-artifacts/master)
|
||||||
|
|
||||||
After download unpack zip file go to `bin` directory and run:
|
After download unpack zip file go to `bin` directory and run:
|
||||||
- `jadx` - command line version
|
- `jadx` - command line version
|
||||||
- `jadx-gui` - UI version
|
- `jadx-gui` - UI version
|
||||||
|
|
||||||
On Windows run `.bat` files with double-click\
|
On Windows run `.bat` files with double-click\
|
||||||
**Note:** ensure you have installed Java 8 or later 64-bit version.
|
**Note:** ensure you have installed Java 11 or later 64-bit version.
|
||||||
For windows you can download it from [adoptopenjdk.net](https://adoptopenjdk.net/releases.html?variant=openjdk11&jvmVariant=hotspot#x64_win) (select "Install JRE").
|
For Windows, you can download it from [oracle.com](https://www.oracle.com/java/technologies/downloads/#jdk17-windows) (select x64 Installer).
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
1. Arch linux
|
- Arch Linux
|
||||||
```bash
|
[](https://archlinux.org/packages/extra/any/jadx/)
|
||||||
sudo pacman -S jadx
|
[](https://aur.archlinux.org/packages/jadx-git)
|
||||||
```
|
```bash
|
||||||
2. macOS
|
sudo pacman -S jadx
|
||||||
```bash
|
```
|
||||||
brew install jadx
|
- macOS
|
||||||
```
|
[](https://formulae.brew.sh/formula/jadx)
|
||||||
|
```bash
|
||||||
|
brew install jadx
|
||||||
|
```
|
||||||
|
- Flathub
|
||||||
|
[](https://flathub.org/apps/com.github.skylot.jadx)
|
||||||
|
```bash
|
||||||
|
flatpak install flathub com.github.skylot.jadx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use jadx as a library
|
||||||
|
You can use jadx in your java projects, check details on [wiki page](https://github.com/skylot/jadx/wiki/Use-jadx-as-a-library)
|
||||||
|
|
||||||
### Build from source
|
### Build from source
|
||||||
JDK 8 or higher must be installed:
|
JDK 11 or higher must be installed:
|
||||||
```
|
```
|
||||||
git clone https://github.com/skylot/jadx.git
|
git clone https://github.com/skylot/jadx.git
|
||||||
cd jadx
|
cd jadx
|
||||||
@@ -66,46 +86,150 @@ and also packed to `build/jadx-<version>.zip`
|
|||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
```
|
```
|
||||||
jadx[-gui] [options] <input file> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc)
|
jadx[-gui] [command] [options] <input files> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc, .aab, .xapk, .apkm, .jadx.kts)
|
||||||
|
commands (use '<command> --help' for command options):
|
||||||
|
plugins - manage jadx plugins
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-d, --output-dir - output directory
|
-d, --output-dir - output directory
|
||||||
-ds, --output-dir-src - output directory for sources
|
-ds, --output-dir-src - output directory for sources
|
||||||
-dr, --output-dir-res - output directory for resources
|
-dr, --output-dir-res - output directory for resources
|
||||||
-r, --no-res - do not decode resources
|
-r, --no-res - do not decode resources
|
||||||
-s, --no-src - do not decompile source code
|
-s, --no-src - do not decompile source code
|
||||||
--single-class - decompile a single class
|
-j, --threads-count - processing threads count, default: 4
|
||||||
--output-format - can be 'java' or 'json', default: java
|
--single-class - decompile a single class, full name, raw or alias
|
||||||
-e, --export-gradle - save as android gradle project
|
--single-class-output - file or dir for write if decompile a single class
|
||||||
-j, --threads-count - processing threads count, default: 4
|
--output-format - can be 'java' or 'json', default: java
|
||||||
--show-bad-code - show inconsistent code (incorrectly decompiled)
|
-e, --export-gradle - save as gradle project (set '--export-gradle-type' to 'auto')
|
||||||
--no-imports - disable use of imports, always write entire package name
|
--export-gradle-type - Gradle project template for export:
|
||||||
--no-debug-info - disable debug info
|
'auto' - detect automatically
|
||||||
--no-inline-anonymous - disable anonymous classes inline
|
'android-app' - Android Application (apk)
|
||||||
--no-replace-consts - don't replace constant value with matching constant field
|
'android-library' - Android Library (aar)
|
||||||
--escape-unicode - escape non latin characters in strings (with \u)
|
'simple-java' - simple Java
|
||||||
--respect-bytecode-access-modifiers - don't change original access modifiers
|
-m, --decompilation-mode - code output mode:
|
||||||
--deobf - activate deobfuscation
|
'auto' - trying best options (default)
|
||||||
--deobf-min - min length of name, renamed if shorter, default: 3
|
'restructure' - restore code structure (normal java code)
|
||||||
--deobf-max - max length of name, renamed if longer, default: 64
|
'simple' - simplified instructions (linear, with goto's)
|
||||||
--deobf-rewrite-cfg - force to save deobfuscation map
|
'fallback' - raw instructions without modifications
|
||||||
--deobf-use-sourcename - use source file name as class name alias
|
--show-bad-code - show inconsistent code (incorrectly decompiled)
|
||||||
--rename-flags - what to rename, comma-separated, 'case' for system case sensitivity, 'valid' for java identifiers, 'printable' characters, 'none' or 'all' (default)
|
--no-xml-pretty-print - do not prettify XML
|
||||||
--fs-case-sensitive - treat filesystem as case sensitive, false by default
|
--no-imports - disable use of imports, always write entire package name
|
||||||
--cfg - save methods control flow graph to dot file
|
--no-debug-info - disable debug info parsing and processing
|
||||||
--raw-cfg - save methods control flow graph (use raw instructions)
|
--add-debug-lines - add comments with debug line numbers if available
|
||||||
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
|
--no-inline-anonymous - disable anonymous classes inline
|
||||||
-v, --verbose - verbose output (set --log-level to DEBUG)
|
--no-inline-methods - disable methods inline
|
||||||
-q, --quiet - turn off output (set --log-level to QUIET)
|
--no-move-inner-classes - disable move inner classes into parent
|
||||||
--log-level - set log level, values: QUIET, PROGRESS, ERROR, WARN, INFO, DEBUG, default: PROGRESS
|
--no-inline-kotlin-lambda - disable inline for Kotlin lambdas
|
||||||
--version - print jadx version
|
--no-finally - don't extract finally block
|
||||||
-h, --help - print this help
|
--no-restore-switch-over-string - don't restore switch over string
|
||||||
Example:
|
--no-replace-consts - don't replace constant value with matching constant field
|
||||||
jadx -d out classes.dex
|
--escape-unicode - escape non latin characters in strings (with \u)
|
||||||
jadx --rename-flags "none" classes.dex
|
--respect-bytecode-access-modifiers - don't change original access modifiers
|
||||||
jadx --rename-flags "valid,printable" classes.dex
|
--mappings-path - deobfuscation mappings file or directory. Allowed formats: Tiny and Tiny v2 (both '.tiny'), Enigma (.mapping) or Enigma directory
|
||||||
jadx --log-level error app.apk
|
--mappings-mode - set mode for handling the deobfuscation mapping file:
|
||||||
|
'read' - just read, user can always save manually (default)
|
||||||
|
'read-and-autosave-every-change' - read and autosave after every change
|
||||||
|
'read-and-autosave-before-closing' - read and autosave before exiting the app or closing the project
|
||||||
|
'ignore' - don't read or save (can be used to skip loading mapping files referenced in the project file)
|
||||||
|
--deobf - activate deobfuscation
|
||||||
|
--deobf-min - min length of name, renamed if shorter, default: 3
|
||||||
|
--deobf-max - max length of name, renamed if longer, default: 64
|
||||||
|
--deobf-whitelist - space separated list of classes (full name) and packages (ends with '.*') to exclude from deobfuscation, default: android.support.v4.* android.support.v7.* android.support.v4.os.* android.support.annotation.Px androidx.core.os.* androidx.annotation.Px
|
||||||
|
--deobf-cfg-file - deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format), default: same dir and name as input file with '.jobf' extension
|
||||||
|
--deobf-cfg-file-mode - set mode for handling the JADX auto-generated names' deobfuscation map file:
|
||||||
|
'read' - read if found, don't save (default)
|
||||||
|
'read-or-save' - read if found, save otherwise (don't overwrite)
|
||||||
|
'overwrite' - don't read, always save
|
||||||
|
'ignore' - don't read and don't save
|
||||||
|
--deobf-res-name-source - better name source for resources:
|
||||||
|
'auto' - automatically select best name (default)
|
||||||
|
'resources' - use resources names
|
||||||
|
'code' - use R class fields names
|
||||||
|
--use-source-name-as-class-name-alias - use source name as class name alias:
|
||||||
|
'always' - always use source name if it's available
|
||||||
|
'if-better' - use source name if it seems better than the current one
|
||||||
|
'never' - never use source name, even if it's available
|
||||||
|
--source-name-repeat-limit - allow using source name if it appears less than a limit number, default: 10
|
||||||
|
--use-kotlin-methods-for-var-names - use kotlin intrinsic methods to rename variables, values: disable, apply, apply-and-hide, default: apply
|
||||||
|
--rename-flags - fix options (comma-separated list of):
|
||||||
|
'case' - fix case sensitivity issues (according to --fs-case-sensitive option),
|
||||||
|
'valid' - rename java identifiers to make them valid,
|
||||||
|
'printable' - remove non-printable chars from identifiers,
|
||||||
|
or single 'none' - to disable all renames
|
||||||
|
or single 'all' - to enable all (default)
|
||||||
|
--integer-format - how integers are displayed:
|
||||||
|
'auto' - automatically select (default)
|
||||||
|
'decimal' - use decimal
|
||||||
|
'hexadecimal' - use hexadecimal
|
||||||
|
--fs-case-sensitive - treat filesystem as case sensitive, false by default
|
||||||
|
--cfg - save methods control flow graph to dot file
|
||||||
|
--raw-cfg - save methods control flow graph (use raw instructions)
|
||||||
|
-f, --fallback - set '--decompilation-mode' to 'fallback' (deprecated)
|
||||||
|
--use-dx - use dx/d8 to convert java bytecode
|
||||||
|
--comments-level - set code comments level, values: error, warn, info, debug, user-only, none, default: info
|
||||||
|
--log-level - set log level, values: quiet, progress, error, warn, info, debug, default: progress
|
||||||
|
-v, --verbose - verbose output (set --log-level to DEBUG)
|
||||||
|
-q, --quiet - turn off output (set --log-level to QUIET)
|
||||||
|
--disable-plugins - comma separated list of plugin ids to disable, default:
|
||||||
|
--version - print jadx version
|
||||||
|
-h, --help - print this help
|
||||||
|
|
||||||
|
Plugin options (-P<name>=<value>):
|
||||||
|
dex-input: Load .dex and .apk files
|
||||||
|
- dex-input.verify-checksum - verify dex file checksum before load, values: [yes, no], default: yes
|
||||||
|
java-convert: Convert .class, .jar and .aar files to dex
|
||||||
|
- java-convert.mode - convert mode, values: [dx, d8, both], default: both
|
||||||
|
- java-convert.d8-desugar - use desugar in d8, values: [yes, no], default: no
|
||||||
|
kotlin-metadata: Use kotlin.Metadata annotation for code generation
|
||||||
|
- kotlin-metadata.class-alias - rename class alias, values: [yes, no], default: yes
|
||||||
|
- kotlin-metadata.method-args - rename function arguments, values: [yes, no], default: yes
|
||||||
|
- kotlin-metadata.fields - rename fields, values: [yes, no], default: yes
|
||||||
|
- kotlin-metadata.companion - rename companion object, values: [yes, no], default: yes
|
||||||
|
- kotlin-metadata.data-class - add data class modifier, values: [yes, no], default: yes
|
||||||
|
- kotlin-metadata.to-string - rename fields using toString, values: [yes, no], default: yes
|
||||||
|
- kotlin-metadata.getters - rename simple getters to field names, values: [yes, no], default: yes
|
||||||
|
kotlin-smap: Use kotlin.SourceDebugExtension annotation for rename class alias
|
||||||
|
- kotlin-smap.class-alias-source-dbg - rename class alias from SourceDebugExtension, values: [yes, no], default: no
|
||||||
|
rename-mappings: various mappings support
|
||||||
|
- rename-mappings.format - mapping format, values: [AUTO, TINY_FILE, TINY_2_FILE, ENIGMA_FILE, ENIGMA_DIR, SRG_FILE, XSRG_FILE, JAM_FILE, CSRG_FILE, TSRG_FILE, TSRG_2_FILE, PROGUARD_FILE, INTELLIJ_MIGRATION_MAP_FILE, RECAF_SIMPLE_FILE, JOBF_FILE], default: AUTO
|
||||||
|
- rename-mappings.invert - invert mapping on load, values: [yes, no], default: no
|
||||||
|
smali-input: Load .smali files
|
||||||
|
- smali-input.api-level - Android API level, default: 27
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
JADX_DISABLE_XML_SECURITY - set to 'true' to disable all security checks for XML files
|
||||||
|
JADX_DISABLE_ZIP_SECURITY - set to 'true' to disable all security checks for zip files
|
||||||
|
JADX_ZIP_MAX_ENTRIES_COUNT - maximum allowed number of entries in zip files (default: 100 000)
|
||||||
|
JADX_CONFIG_DIR - custom config directory, using system by default
|
||||||
|
JADX_CACHE_DIR - custom cache directory, using system by default
|
||||||
|
JADX_TMP_DIR - custom temp directory, using system by default
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
jadx -d out classes.dex
|
||||||
|
jadx --rename-flags "none" classes.dex
|
||||||
|
jadx --rename-flags "valid, printable" classes.dex
|
||||||
|
jadx --log-level ERROR app.apk
|
||||||
|
jadx -Pdex-input.verify-checksum=no app.apk
|
||||||
```
|
```
|
||||||
These options also worked on jadx-gui running from command line and override options from preferences dialog
|
These options also work in jadx-gui running from command line and override options from preferences' dialog
|
||||||
|
|
||||||
|
Usage for `plugins` command
|
||||||
|
```
|
||||||
|
usage: plugins [options]
|
||||||
|
options:
|
||||||
|
-i, --install <locationId> - install plugin with locationId
|
||||||
|
-j, --install-jar <path-to.jar> - install plugin from jar file
|
||||||
|
-l, --list - list installed plugins
|
||||||
|
-a, --available - list available plugins from jadx-plugins-list (aka marketplace)
|
||||||
|
-u, --update - update installed plugins
|
||||||
|
--uninstall <pluginId> - uninstall plugin with pluginId
|
||||||
|
--disable <pluginId> - disable plugin with pluginId
|
||||||
|
--enable <pluginId> - enable plugin with pluginId
|
||||||
|
--list-all - list all plugins including bundled and dropins
|
||||||
|
--list-versions <locationId> - fetch latest versions of plugin from locationId (will download all artefacts, limited to 10)
|
||||||
|
-h, --help - print this help
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
Please check wiki page [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A)
|
Please check wiki page [Troubleshooting Q&A](https://github.com/skylot/jadx/wiki/Troubleshooting-Q&A)
|
||||||
@@ -116,10 +240,5 @@ To support this project you can:
|
|||||||
- Submit decompilation issues, please read before proceed: [Open issue](CONTRIBUTING.md#Open-Issue)
|
- Submit decompilation issues, please read before proceed: [Open issue](CONTRIBUTING.md#Open-Issue)
|
||||||
- Open pull request, please follow these rules: [Pull Request Process](CONTRIBUTING.md#Pull-Request-Process)
|
- Open pull request, please follow these rules: [Pull Request Process](CONTRIBUTING.md#Pull-Request-Process)
|
||||||
|
|
||||||
### Related projects:
|
|
||||||
- [PyJadx](https://github.com/romainthomas/pyjadx) - python binding for jadx by [@romainthomas](https://github.com/romainthomas)
|
|
||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
*Licensed under the Apache 2.0 License*
|
*Licensed under the Apache 2.0 License*
|
||||||
|
|
||||||
*Copyright 2019 by Skylot*
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
To report a security issue, please open a [new security advisory](https://github.com/skylot/jadx/security/advisories/new).
|
||||||
|
Please fill the steps you took to create the issue, affected versions, and, if known, mitigations for the issue.
|
||||||
|
We will check and respond within 3 working days.
|
||||||
|
If the issue is confirmed as a vulnerability, we will apply required mitigations at the next release.
|
||||||
-161
@@ -1,161 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'org.sonarqube' version '2.8'
|
|
||||||
id 'com.github.ben-manes.versions' version '0.27.0'
|
|
||||||
id "com.diffplug.gradle.spotless" version "3.26.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
ext.jadxVersion = System.getenv('JADX_VERSION') ?: "dev"
|
|
||||||
version = jadxVersion
|
|
||||||
println("jadx version: ${jadxVersion}")
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
apply plugin: 'java'
|
|
||||||
apply plugin: 'jacoco'
|
|
||||||
apply plugin: 'checkstyle'
|
|
||||||
|
|
||||||
version = jadxVersion
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
if (!"$it".contains(':jadx-samples:')) {
|
|
||||||
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileJava {
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
|
||||||
version = jadxVersion
|
|
||||||
manifest {
|
|
||||||
mainAttributes('jadx-version': jadxVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile 'org.slf4j:slf4j-api:1.7.29'
|
|
||||||
|
|
||||||
testCompile 'ch.qos.logback:logback-classic:1.2.3'
|
|
||||||
testCompile 'org.hamcrest:hamcrest-library:2.2'
|
|
||||||
testCompile 'org.mockito:mockito-core:3.1.0'
|
|
||||||
testCompile 'org.assertj:assertj-core:3.14.0'
|
|
||||||
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
|
|
||||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
|
|
||||||
|
|
||||||
testCompile 'org.eclipse.jdt.core.compiler:ecj:4.6.1'
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
mavenCentral()
|
|
||||||
jcenter()
|
|
||||||
google()
|
|
||||||
}
|
|
||||||
|
|
||||||
jacoco {
|
|
||||||
toolVersion = "0.8.2"
|
|
||||||
}
|
|
||||||
jacocoTestReport {
|
|
||||||
reports {
|
|
||||||
xml.enabled = true
|
|
||||||
html.enabled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkstyleMain {
|
|
||||||
// exclude all sources in samples module
|
|
||||||
exclude '**/samples/**'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sonarqube {
|
|
||||||
properties {
|
|
||||||
property 'sonar.exclusions', '**/jadx/samples/**/*,**/test-app/**/*'
|
|
||||||
property 'sonar.coverage.exclusions', '**/jadx/gui/**/*'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spotless {
|
|
||||||
java {
|
|
||||||
target fileTree(rootDir).matching {
|
|
||||||
include 'jadx-cli/src/**/java/**/*.java'
|
|
||||||
include 'jadx-core/src/**/java/**/*.java'
|
|
||||||
include 'jadx-gui/src/**/java/**/*.java'
|
|
||||||
}
|
|
||||||
|
|
||||||
importOrderFile 'config/code-formatter/eclipse.importorder'
|
|
||||||
eclipse().configFile 'config/code-formatter/eclipse.xml'
|
|
||||||
removeUnusedImports()
|
|
||||||
|
|
||||||
lineEndings(com.diffplug.spotless.LineEnding.UNIX)
|
|
||||||
encoding("UTF-8")
|
|
||||||
trimTrailingWhitespace()
|
|
||||||
endWithNewline()
|
|
||||||
}
|
|
||||||
format 'misc', {
|
|
||||||
target '**/*.gradle', '**/*.md', '**/*.xml', '**/.gitignore', '**/.properties'
|
|
||||||
targetExclude ".gradle/**", ".idea/**"
|
|
||||||
|
|
||||||
lineEndings(com.diffplug.spotless.LineEnding.UNIX)
|
|
||||||
encoding("UTF-8")
|
|
||||||
trimTrailingWhitespace()
|
|
||||||
endWithNewline()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyUpdates.resolutionStrategy = {
|
|
||||||
componentSelection { rules ->
|
|
||||||
rules.all { ComponentSelection selection ->
|
|
||||||
boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm', 'atlassian'].any { qualifier ->
|
|
||||||
selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
|
|
||||||
}
|
|
||||||
if (rejected) {
|
|
||||||
selection.reject('Release candidate')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyArtifacts(type: Sync, dependsOn: ['jadx-cli:installDist', 'jadx-gui:installDist']) {
|
|
||||||
destinationDir file("$buildDir/jadx")
|
|
||||||
['jadx-cli', 'jadx-gui'].each {
|
|
||||||
from tasks.getByPath(":${it}:installDist").destinationDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task pack(type: Zip, dependsOn: copyArtifacts) {
|
|
||||||
destinationDir buildDir
|
|
||||||
archiveName "jadx-${jadxVersion}.zip"
|
|
||||||
from copyArtifacts.destinationDir
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyExe(type: Copy, dependsOn: 'jadx-gui:createExe') {
|
|
||||||
group 'jadx'
|
|
||||||
description = 'Copy exe to build dir'
|
|
||||||
destinationDir buildDir
|
|
||||||
from tasks.getByPath('jadx-gui:createExe').outputs
|
|
||||||
include '*.exe'
|
|
||||||
}
|
|
||||||
|
|
||||||
task dist(dependsOn: [pack, copyExe]) {
|
|
||||||
group 'jadx'
|
|
||||||
description = 'Build jadx distribution zip'
|
|
||||||
}
|
|
||||||
|
|
||||||
task samples(dependsOn: 'jadx-samples:samples') {
|
|
||||||
group 'jadx'
|
|
||||||
}
|
|
||||||
|
|
||||||
task cleanBuildDir(type: Delete) {
|
|
||||||
group 'jadx'
|
|
||||||
delete buildDir
|
|
||||||
}
|
|
||||||
|
|
||||||
test.dependsOn(samples)
|
|
||||||
|
|
||||||
clean.dependsOn(cleanBuildDir)
|
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import com.diffplug.gradle.spotless.FormatExtension
|
||||||
|
import com.diffplug.gradle.spotless.SpotlessExtension
|
||||||
|
import com.diffplug.spotless.LineEnding
|
||||||
|
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
|
||||||
|
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("com.github.ben-manes.versions") version "0.52.0"
|
||||||
|
id("se.patrikerdes.use-latest-versions") version "0.2.18"
|
||||||
|
id("com.diffplug.spotless") version "6.25.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
val jadxVersion by extra { System.getenv("JADX_VERSION") ?: "dev" }
|
||||||
|
println("jadx version: $jadxVersion")
|
||||||
|
version = jadxVersion
|
||||||
|
|
||||||
|
val jadxBuildJavaVersion by extra { getBuildJavaVersion() }
|
||||||
|
|
||||||
|
fun getBuildJavaVersion(): Int? {
|
||||||
|
val envVarName = "JADX_BUILD_JAVA_VERSION"
|
||||||
|
val buildJavaVer = System.getenv(envVarName)?.toInt() ?: return null
|
||||||
|
if (buildJavaVer < 11) {
|
||||||
|
throw GradleException("'$envVarName' can't be set to lower than 11")
|
||||||
|
}
|
||||||
|
println("Set Java toolchain for jadx build to version '$buildJavaVer'")
|
||||||
|
return buildJavaVer
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
apply(plugin = "java")
|
||||||
|
apply(plugin = "checkstyle")
|
||||||
|
apply(plugin = "com.diffplug.spotless")
|
||||||
|
apply(plugin = "com.github.ben-manes.versions")
|
||||||
|
apply(plugin = "se.patrikerdes.use-latest-versions")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
configure<SpotlessExtension> {
|
||||||
|
java {
|
||||||
|
importOrderFile("$rootDir/config/code-formatter/eclipse.importorder")
|
||||||
|
eclipse().configFile("$rootDir/config/code-formatter/eclipse.xml")
|
||||||
|
removeUnusedImports()
|
||||||
|
commonFormatOptions()
|
||||||
|
}
|
||||||
|
kotlin {
|
||||||
|
ktlint().editorConfigOverride(mapOf("indent_style" to "tab"))
|
||||||
|
commonFormatOptions()
|
||||||
|
}
|
||||||
|
kotlinGradle {
|
||||||
|
ktlint()
|
||||||
|
commonFormatOptions()
|
||||||
|
}
|
||||||
|
format("misc") {
|
||||||
|
target("**/*.gradle", "**/*.xml", "**/.gitignore", "**/.properties")
|
||||||
|
targetExclude(".gradle/**", ".idea/**", "*/build/**")
|
||||||
|
commonFormatOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<DependencyUpdatesTask>("dependencyUpdates") {
|
||||||
|
rejectVersionIf {
|
||||||
|
// disallow release candidates as upgradable versions from stable versions
|
||||||
|
isNonStable(candidate.version) && !isNonStable(currentVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun FormatExtension.commonFormatOptions() {
|
||||||
|
lineEndings = LineEnding.UNIX
|
||||||
|
encoding = Charsets.UTF_8
|
||||||
|
trimTrailingWhitespace()
|
||||||
|
endWithNewline()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isNonStable(version: String): Boolean {
|
||||||
|
val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase(Locale.getDefault()).contains(it) }
|
||||||
|
val regex = "^[0-9,.v-]+(-r)?$".toRegex()
|
||||||
|
val isStable = stableKeyword || regex.matches(version)
|
||||||
|
return isStable.not()
|
||||||
|
}
|
||||||
|
|
||||||
|
val copyArtifacts by tasks.registering(Copy::class) {
|
||||||
|
val jarCliPattern = "jadx-cli-(.*)-all.jar".toPattern()
|
||||||
|
from(tasks.getByPath(":jadx-cli:installShadowDist")) {
|
||||||
|
exclude("**/*.jar")
|
||||||
|
filter { line ->
|
||||||
|
jarCliPattern.matcher(line).replaceAll("jadx-$1-all.jar")
|
||||||
|
.replace("-jar \"\\\"\$CLASSPATH\\\"\"", "-cp \"\\\"\$CLASSPATH\\\"\" jadx.cli.JadxCLI")
|
||||||
|
.replace("-jar \"%CLASSPATH%\"", "-cp \"%CLASSPATH%\" jadx.cli.JadxCLI")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jarGuiPattern = "jadx-gui-(.*)-all.jar".toPattern()
|
||||||
|
from(tasks.getByPath(":jadx-gui:installShadowDist")) {
|
||||||
|
exclude("**/*.jar")
|
||||||
|
filter { line -> jarGuiPattern.matcher(line).replaceAll("jadx-$1-all.jar") }
|
||||||
|
}
|
||||||
|
from(tasks.getByPath(":jadx-gui:installShadowDist")) {
|
||||||
|
include("**/*.jar")
|
||||||
|
rename("jadx-gui-(.*)-all.jar", "jadx-$1-all.jar")
|
||||||
|
}
|
||||||
|
from(layout.projectDirectory) {
|
||||||
|
include("README.md")
|
||||||
|
include("LICENSE")
|
||||||
|
}
|
||||||
|
into(layout.buildDirectory.dir("jadx"))
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
|
val pack by tasks.registering(Zip::class) {
|
||||||
|
from(copyArtifacts)
|
||||||
|
archiveFileName.set("jadx-$jadxVersion.zip")
|
||||||
|
destinationDirectory.set(layout.buildDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
|
val distWin by tasks.registering(Zip::class) {
|
||||||
|
group = "jadx"
|
||||||
|
description = "Build Windows bundle"
|
||||||
|
|
||||||
|
val guiTask = tasks.getByPath("jadx-gui:copyDistWin")
|
||||||
|
dependsOn(guiTask)
|
||||||
|
from(guiTask.outputs)
|
||||||
|
|
||||||
|
destinationDirectory.set(layout.buildDirectory.dir("distWin"))
|
||||||
|
archiveFileName.set("jadx-gui-$jadxVersion-win.zip")
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
|
val distWinWithJre by tasks.registering(Zip::class) {
|
||||||
|
description = "Build Windows with JRE bundle"
|
||||||
|
|
||||||
|
val guiTask = tasks.getByPath(":jadx-gui:copyDistWinWithJre")
|
||||||
|
dependsOn(guiTask)
|
||||||
|
from(guiTask.outputs)
|
||||||
|
|
||||||
|
destinationDirectory.set(layout.buildDirectory.dir("distWinWithJre"))
|
||||||
|
archiveFileName.set("jadx-gui-$jadxVersion-with-jre-win.zip")
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
|
val dist by tasks.registering {
|
||||||
|
group = "jadx"
|
||||||
|
description = "Build jadx distribution zip bundles"
|
||||||
|
|
||||||
|
dependsOn(pack)
|
||||||
|
|
||||||
|
val os = DefaultNativePlatform.getCurrentOperatingSystem()
|
||||||
|
if (os.isWindows) {
|
||||||
|
if (project.hasProperty("bundleJRE")) {
|
||||||
|
println("Build win bundle with JRE")
|
||||||
|
dependsOn(distWinWithJre)
|
||||||
|
} else {
|
||||||
|
dependsOn(distWin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val cleanBuildDir by tasks.registering(Delete::class) {
|
||||||
|
delete(layout.buildDirectory)
|
||||||
|
}
|
||||||
|
tasks.getByName("clean").dependsOn(cleanBuildDir)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
plugins {
|
||||||
|
`kotlin-dsl`
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.21")
|
||||||
|
|
||||||
|
implementation("org.openrewrite:plugin:6.19.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
java
|
||||||
|
checkstyle
|
||||||
|
|
||||||
|
id("jadx-rewrite")
|
||||||
|
}
|
||||||
|
|
||||||
|
val jadxVersion: String by rootProject.extra
|
||||||
|
val jadxBuildJavaVersion: Int? by rootProject.extra
|
||||||
|
|
||||||
|
group = "io.github.skylot"
|
||||||
|
version = jadxVersion
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("org.slf4j:slf4j-api:2.0.17")
|
||||||
|
compileOnly("org.jetbrains:annotations:26.0.2")
|
||||||
|
|
||||||
|
testImplementation("ch.qos.logback:logback-classic:1.5.18")
|
||||||
|
testImplementation("org.assertj:assertj-core:3.27.3")
|
||||||
|
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter:5.12.2")
|
||||||
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
|
||||||
|
testCompileOnly("org.jetbrains:annotations:26.0.2")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
// required for: aapt-proto, r8, smali
|
||||||
|
google()
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
jadxBuildJavaVersion?.let { buildJavaVer ->
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(buildJavaVer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
compileJava {
|
||||||
|
options.encoding = "UTF-8"
|
||||||
|
// options.compilerArgs = listOf("-Xlint:deprecation")
|
||||||
|
}
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes("jadx-version" to jadxVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
maxParallelForks = Runtime.getRuntime().availableProcessors()
|
||||||
|
testLogging {
|
||||||
|
showExceptions = true
|
||||||
|
exceptionFormat = TestExceptionFormat.FULL
|
||||||
|
showCauses = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("jadx-java")
|
||||||
|
id("org.jetbrains.kotlin.jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
plugins {
|
||||||
|
id("jadx-java")
|
||||||
|
id("java-library")
|
||||||
|
id("maven-publish")
|
||||||
|
id("signing")
|
||||||
|
}
|
||||||
|
|
||||||
|
val jadxVersion: String by rootProject.extra
|
||||||
|
|
||||||
|
group = "io.github.skylot"
|
||||||
|
version = jadxVersion
|
||||||
|
|
||||||
|
java {
|
||||||
|
withJavadocJar()
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("mavenJava") {
|
||||||
|
artifactId = project.name
|
||||||
|
from(components["java"])
|
||||||
|
versionMapping {
|
||||||
|
usage("java-api") {
|
||||||
|
fromResolutionOf("runtimeClasspath")
|
||||||
|
}
|
||||||
|
usage("java-runtime") {
|
||||||
|
fromResolutionResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pom {
|
||||||
|
name.set(project.name)
|
||||||
|
description.set(project.description ?: "Dex to Java decompiler")
|
||||||
|
url.set("https://github.com/skylot/jadx")
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name.set("The Apache License, Version 2.0")
|
||||||
|
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id.set("skylot")
|
||||||
|
name.set("Skylot")
|
||||||
|
email.set(project.properties["libEmail"].toString())
|
||||||
|
url.set("https://github.com/skylot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection.set("scm:git:git://github.com/skylot/jadx.git")
|
||||||
|
developerConnection.set("scm:git:ssh://github.com:skylot/jadx.git")
|
||||||
|
url.set("https://github.com/skylot/jadx")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
val releasesRepoUrl = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||||
|
val snapshotsRepoUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||||
|
url = if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl
|
||||||
|
credentials {
|
||||||
|
username = project.properties["ossrhUser"].toString()
|
||||||
|
password = project.properties["ossrhPassword"].toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
isRequired = gradle.taskGraph.hasTask("publish")
|
||||||
|
sign(publishing.publications["mavenJava"])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tasks.javadoc {
|
||||||
|
val stdOptions = options as StandardJavadocDocletOptions
|
||||||
|
stdOptions.addBooleanOption("html5", true)
|
||||||
|
// disable 'missing' warnings
|
||||||
|
stdOptions.addStringOption("Xdoclint:all,-missing", "-quiet")
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
plugins {
|
||||||
|
id("org.openrewrite.rewrite")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:3.8.0")
|
||||||
|
rewrite("org.openrewrite.recipe:rewrite-logging-frameworks:3.8.0")
|
||||||
|
rewrite("org.openrewrite.recipe:rewrite-migrate-java:3.9.0")
|
||||||
|
rewrite("org.openrewrite.recipe:rewrite-static-analysis:2.9.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
rewrite {
|
||||||
|
// exclusion("src/test/java/jadx/tests/integration")
|
||||||
|
|
||||||
|
// activeRecipe("org.openrewrite.java.migrate.Java8toJava11")
|
||||||
|
|
||||||
|
// checkstyle auto fix
|
||||||
|
// activeRecipe("org.openrewrite.staticanalysis.CodeCleanup")
|
||||||
|
// setCheckstyleConfigFile(file("$rootDir/config/checkstyle/checkstyle.xml"))
|
||||||
|
|
||||||
|
// logging
|
||||||
|
// activeRecipe("org.openrewrite.java.logging.slf4j.Slf4jBestPractices")
|
||||||
|
// activeRecipe("org.openrewrite.java.logging.slf4j.LoggersNamedForEnclosingClass")
|
||||||
|
// activeRecipe("org.openrewrite.java.logging.slf4j.ParameterizedLogging")
|
||||||
|
// activeRecipe("org.openrewrite.java.logging.PrintStackTraceToLogError")
|
||||||
|
|
||||||
|
// testing
|
||||||
|
activeRecipe("org.openrewrite.java.testing.assertj.Assertj")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,6 +119,24 @@
|
|||||||
<module name="OuterTypeNumber"/>
|
<module name="OuterTypeNumber"/>
|
||||||
|
|
||||||
<module name="SuppressWarningsHolder"/>
|
<module name="SuppressWarningsHolder"/>
|
||||||
|
|
||||||
|
<module name="IllegalType">
|
||||||
|
<property name="illegalClassNames" value="java.util.ArrayList, java.util.HashMap, java.util.HashSet,
|
||||||
|
java.util.LinkedHashMap, java.util.LinkedHashSet, java.util.TreeMap, java.util.TreeSet"/>
|
||||||
|
</module>
|
||||||
|
<module name="IllegalImport">
|
||||||
|
<property name="illegalClasses" value="jadx.core.utils.DebugUtils"/>
|
||||||
|
<!-- don't use nullable annotations from RxJava -->
|
||||||
|
<property name="illegalClasses" value="io.reactivex.rxjava3.annotations.NonNull"/>
|
||||||
|
<property name="illegalClasses" value="io.reactivex.rxjava3.annotations.Nullable"/>
|
||||||
|
</module>
|
||||||
|
<module name="RegexpSinglelineJava">
|
||||||
|
<property name="id" value="printstacktrace"/>
|
||||||
|
<property name="format" value="\.printStackTrace\(\)"/>
|
||||||
|
<property name="ignoreComments" value="true"/>
|
||||||
|
<property name="message"
|
||||||
|
value="Using Throwable.printStackTrace() is forbidden. Use logger to print exception"/>
|
||||||
|
</module>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<module name="NewlineAtEndOfFile"/>
|
<module name="NewlineAtEndOfFile"/>
|
||||||
|
|||||||
+222
-170
@@ -1,77 +1,248 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<profiles version="16">
|
<profiles version="23">
|
||||||
<profile kind="CodeFormatterProfile" name="jadx eclipse" version="16">
|
<profile kind="CodeFormatterProfile" name="jadx eclipse" version="23">
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="separate_lines_if_wrapped"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
|
||||||
@@ -80,267 +251,148 @@
|
|||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="separate_lines_if_wrapped"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
|
||||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
|
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
SmaliTokenMaker.java
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
Refer to the following instructions to modify and use to generate SmaliTokenMarker
|
||||||
|
|
||||||
|
```shell
|
||||||
|
jflex SmaliTokenMaker.flex --skel skeleton.default
|
||||||
|
```
|
||||||
@@ -0,0 +1,679 @@
|
|||||||
|
/*
|
||||||
|
* Generated on 11/22/21, 8:58 PM
|
||||||
|
*/
|
||||||
|
package jadx.gui.ui.codearea;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import javax.swing.text.Segment;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.*;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 用于Smali代码高亮
|
||||||
|
* MartinKay@qq.com
|
||||||
|
*/
|
||||||
|
%%
|
||||||
|
|
||||||
|
%public
|
||||||
|
%class SmaliTokenMaker
|
||||||
|
%extends AbstractJFlexCTokenMaker
|
||||||
|
%unicode
|
||||||
|
/* Case sensitive */
|
||||||
|
%type org.fife.ui.rsyntaxtextarea.Token
|
||||||
|
|
||||||
|
|
||||||
|
%{
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. This must be here because JFlex does not generate a
|
||||||
|
* no-parameter constructor.
|
||||||
|
*/
|
||||||
|
public SmaliTokenMaker() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the token specified to the current linked list of tokens.
|
||||||
|
*
|
||||||
|
* @param tokenType The token's type.
|
||||||
|
* @see #addToken(int, int, int)
|
||||||
|
*/
|
||||||
|
private void addHyperlinkToken(int start, int end, int tokenType) {
|
||||||
|
int so = start + offsetShift;
|
||||||
|
addToken(zzBuffer, start,end, tokenType, so, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the token specified to the current linked list of tokens.
|
||||||
|
*
|
||||||
|
* @param tokenType The token's type.
|
||||||
|
*/
|
||||||
|
private void addToken(int tokenType) {
|
||||||
|
addToken(zzStartRead, zzMarkedPos-1, tokenType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the token specified to the current linked list of tokens.
|
||||||
|
*
|
||||||
|
* @param tokenType The token's type.
|
||||||
|
* @see #addHyperlinkToken(int, int, int)
|
||||||
|
*/
|
||||||
|
private void addToken(int start, int end, int tokenType) {
|
||||||
|
int so = start + offsetShift;
|
||||||
|
addToken(zzBuffer, start,end, tokenType, so, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the token specified to the current linked list of tokens.
|
||||||
|
*
|
||||||
|
* @param array The character array.
|
||||||
|
* @param start The starting offset in the array.
|
||||||
|
* @param end The ending offset in the array.
|
||||||
|
* @param tokenType The token's type.
|
||||||
|
* @param startOffset The offset in the document at which this token
|
||||||
|
* occurs.
|
||||||
|
* @param hyperlink Whether this token is a hyperlink.
|
||||||
|
*/
|
||||||
|
public void addToken(char[] array, int start, int end, int tokenType,
|
||||||
|
int startOffset, boolean hyperlink) {
|
||||||
|
super.addToken(array, start,end, tokenType, startOffset, hyperlink);
|
||||||
|
zzStartRead = zzMarkedPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public String[] getLineCommentStartAndEnd(int languageIndex) {
|
||||||
|
return new String[] { "#", null };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first token in the linked list of tokens generated
|
||||||
|
* from <code>text</code>. This method must be implemented by
|
||||||
|
* subclasses so they can correctly implement syntax highlighting.
|
||||||
|
*
|
||||||
|
* @param text The text from which to get tokens.
|
||||||
|
* @param initialTokenType The token type we should start with.
|
||||||
|
* @param startOffset The offset into the document at which
|
||||||
|
* <code>text</code> starts.
|
||||||
|
* @return The first <code>Token</code> in a linked list representing
|
||||||
|
* the syntax highlighted text.
|
||||||
|
*/
|
||||||
|
public Token getTokenList(Segment text, int initialTokenType, int startOffset) {
|
||||||
|
|
||||||
|
resetTokenList();
|
||||||
|
this.offsetShift = -text.offset + startOffset;
|
||||||
|
|
||||||
|
// Start off in the proper state.
|
||||||
|
int state = Token.NULL;
|
||||||
|
switch (initialTokenType) {
|
||||||
|
/* No multi-line comments */
|
||||||
|
/* No documentation comments */
|
||||||
|
default:
|
||||||
|
state = Token.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = text;
|
||||||
|
try {
|
||||||
|
yyreset(zzReader);
|
||||||
|
yybegin(state);
|
||||||
|
return yylex();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
return new TokenImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refills the input buffer.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if EOF was reached, otherwise
|
||||||
|
* <code>false</code>.
|
||||||
|
*/
|
||||||
|
private boolean zzRefill() {
|
||||||
|
return zzCurrentPos>=s.offset+s.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the scanner to read from a new input stream.
|
||||||
|
* Does not close the old reader.
|
||||||
|
*
|
||||||
|
* All internal variables are reset, the old input stream
|
||||||
|
* <b>cannot</b> be reused (internal buffer is discarded and lost).
|
||||||
|
* Lexical state is set to <tt>YY_INITIAL</tt>.
|
||||||
|
*
|
||||||
|
* @param reader the new input stream
|
||||||
|
*/
|
||||||
|
public final void yyreset(Reader reader) {
|
||||||
|
// 's' has been updated.
|
||||||
|
zzBuffer = s.array;
|
||||||
|
/*
|
||||||
|
* We replaced the line below with the two below it because zzRefill
|
||||||
|
* no longer "refills" the buffer (since the way we do it, it's always
|
||||||
|
* "full" the first time through, since it points to the segment's
|
||||||
|
* array). So, we assign zzEndRead here.
|
||||||
|
*/
|
||||||
|
//zzStartRead = zzEndRead = s.offset;
|
||||||
|
zzStartRead = s.offset;
|
||||||
|
zzEndRead = zzStartRead + s.count - 1;
|
||||||
|
zzCurrentPos = zzMarkedPos = zzPushbackPos = s.offset;
|
||||||
|
zzLexicalState = YYINITIAL;
|
||||||
|
zzReader = reader;
|
||||||
|
zzAtBOL = true;
|
||||||
|
zzAtEOF = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
Letter = [A-Za-z]
|
||||||
|
LetterOrUnderscore = ({Letter}|"_")
|
||||||
|
NonzeroDigit = [1-9]
|
||||||
|
Digit = ("0"|{NonzeroDigit})
|
||||||
|
HexDigit = ({Digit}|[A-Fa-f])
|
||||||
|
OctalDigit = ([0-7])
|
||||||
|
AnyCharacterButApostropheOrBackSlash = ([^\\'])
|
||||||
|
AnyCharacterButDoubleQuoteOrBackSlash = ([^\\\"\n])
|
||||||
|
EscapedSourceCharacter = ("u"{HexDigit}{HexDigit}{HexDigit}{HexDigit})
|
||||||
|
Escape = ("\\"(([btnfr\"'\\])|([0123]{OctalDigit}?{OctalDigit}?)|({OctalDigit}{OctalDigit}?)|{EscapedSourceCharacter}))
|
||||||
|
NonSeparator = ([^\t\f\r\n\ \(\)\{\}\[\]\;\,\.\=\>\<\!\~\?\:\+\-\*\/\&\|\^\%\"\']|"#"|"\\")
|
||||||
|
IdentifierStart = ({LetterOrUnderscore}|"$")
|
||||||
|
IdentifierPart = ({IdentifierStart}|{Digit}|("\\"{EscapedSourceCharacter}))
|
||||||
|
|
||||||
|
LineTerminator = (\n)
|
||||||
|
WhiteSpace = ([ \t\f]+)
|
||||||
|
|
||||||
|
CharLiteral = ([\']({AnyCharacterButApostropheOrBackSlash}|{Escape})[\'])
|
||||||
|
UnclosedCharLiteral = ([\'][^\'\n]*)
|
||||||
|
ErrorCharLiteral = ({UnclosedCharLiteral}[\'])
|
||||||
|
StringLiteral = ([\"]({AnyCharacterButDoubleQuoteOrBackSlash}|{Escape})*[\"])
|
||||||
|
UnclosedStringLiteral = ([\"]([\\].|[^\\\"])*[^\"]?)
|
||||||
|
ErrorStringLiteral = ({UnclosedStringLiteral}[\"])
|
||||||
|
|
||||||
|
/* No multi-line comments */
|
||||||
|
/* No documentation comments */
|
||||||
|
LineCommentBegin = "#"
|
||||||
|
|
||||||
|
IntegerLiteral = ({Digit}+)
|
||||||
|
HexLiteral = (0x{HexDigit}+)
|
||||||
|
FloatLiteral = (({Digit}+)("."{Digit}+)?(e[+-]?{Digit}+)? | ({Digit}+)?("."{Digit}+)(e[+-]?{Digit}+)?)
|
||||||
|
ErrorNumberFormat = (({IntegerLiteral}|{HexLiteral}|{FloatLiteral}){NonSeparator}+)
|
||||||
|
BooleanLiteral = ("true"|"false")
|
||||||
|
|
||||||
|
Separator = ([\(\)\{\}\[\]])
|
||||||
|
Separator2 = ([\;,.])
|
||||||
|
|
||||||
|
Identifier = ({IdentifierStart}{IdentifierPart}*)
|
||||||
|
|
||||||
|
URLGenDelim = ([:\/\?#\[\]@])
|
||||||
|
URLSubDelim = ([\!\$&'\(\)\*\+,;=])
|
||||||
|
URLUnreserved = ({LetterOrUnderscore}|{Digit}|[\-\.\~])
|
||||||
|
URLCharacter = ({URLGenDelim}|{URLSubDelim}|{URLUnreserved}|[%])
|
||||||
|
URLCharacters = ({URLCharacter}*)
|
||||||
|
URLEndCharacter = ([\/\$]|{Letter}|{Digit})
|
||||||
|
URL = (((https?|f(tp|ile))"://"|"www.")({URLCharacters}{URLEndCharacter})?)
|
||||||
|
|
||||||
|
|
||||||
|
/* Custom Regex */
|
||||||
|
/* fully-qualified name Rules */
|
||||||
|
SimpleName = ([a-zA-Z0-9_$]*)
|
||||||
|
QUALIFIED_TYPE_NAME = ("L"({SimpleName}{SLASH})*{SimpleName}*";")
|
||||||
|
/* Types */
|
||||||
|
VOID_TYPE = ("V")
|
||||||
|
BOOLEAN_TYPE = ("Z")
|
||||||
|
BYTE_TYPE = ("B")
|
||||||
|
SHORT_TYPE = ("S")
|
||||||
|
CHAR_TYPE = ("C")
|
||||||
|
INT_TYPE = ("I")
|
||||||
|
LONG_TYPE = ("J")
|
||||||
|
FLOAT_TYPE = ("F")
|
||||||
|
DOUBLE_TYPE = ("D")
|
||||||
|
/* Multi Args Types Highlight */
|
||||||
|
MULTI_ARGS_TYPES = (({BOOLEAN_TYPE}|{BYTE_TYPE}|{SHORT_TYPE}|{CHAR_TYPE}|{INT_TYPE}|{LONG_TYPE}|{FLOAT_TYPE}|{DOUBLE_TYPE})+);
|
||||||
|
|
||||||
|
/* Types fully-qualified name */
|
||||||
|
COMPOUND_METHOD_ARG_LITERAL = (({BOOLEAN_TYPE}|{BYTE_TYPE}|{SHORT_TYPE}|{CHAR_TYPE}|{INT_TYPE}|{LONG_TYPE}|{FLOAT_TYPE}|{DOUBLE_TYPE})+{QUALIFIED_TYPE_NAME})
|
||||||
|
|
||||||
|
|
||||||
|
LBRACK = ("[")
|
||||||
|
RBRACK = ("]")
|
||||||
|
LPAREN = ("(")
|
||||||
|
RPAREN = (")")
|
||||||
|
LBRACE = ("{")
|
||||||
|
RBRACE = ("}")
|
||||||
|
COLON = (":")
|
||||||
|
ASSIGN = ("=")
|
||||||
|
DOT = (".")
|
||||||
|
SUB = ("-")
|
||||||
|
COMMA = (",")
|
||||||
|
SLASH = ("/")
|
||||||
|
LT = ("<")
|
||||||
|
GT = (">")
|
||||||
|
ARROW = ("->")
|
||||||
|
SEMI = (";")
|
||||||
|
ARROW_FUNCTION = ({ARROW}[a-zA-Z_$<>]*)
|
||||||
|
CustomSeparator = ({Separator}|{ARROW_FUNCTION})
|
||||||
|
|
||||||
|
/* Register */
|
||||||
|
VREGISTER = ("v"("0"|[1-9])*)
|
||||||
|
PREGISTER = ("p"("0"|[1-9])*)
|
||||||
|
|
||||||
|
/* Flags */
|
||||||
|
FLAG_PSWITCH = (":pswitch_"{SimpleName})
|
||||||
|
FLAG_PSWITCH_DATA = (":pswitch_data_"{SimpleName})
|
||||||
|
FLAG_GOTO = (":goto_"{SimpleName})
|
||||||
|
FLAG_COND = (":cond_"{SimpleName})
|
||||||
|
FLAG_TRY_START = (":try_start_"{SimpleName})
|
||||||
|
FLAG_TRY_END = (":try_end_"{SimpleName})
|
||||||
|
FLAG_CATCH = (":catch_"{SimpleName})
|
||||||
|
FLAG_CATCHALL = (":catchall_"{SimpleName})
|
||||||
|
FLAG_ARRAY = (":array_"{SimpleName})
|
||||||
|
|
||||||
|
/* No string state */
|
||||||
|
/* No char state */
|
||||||
|
/* No MLC state */
|
||||||
|
/* No documentation comment state */
|
||||||
|
%state EOL_COMMENT
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
<YYINITIAL> {
|
||||||
|
|
||||||
|
/* Keywords Instructions Highlight */
|
||||||
|
"nop" |
|
||||||
|
"move" |
|
||||||
|
"move/from16" |
|
||||||
|
"move/16" |
|
||||||
|
"move-wide" |
|
||||||
|
"move-wide/from16" |
|
||||||
|
"move-wide/16" |
|
||||||
|
"move-object" |
|
||||||
|
"move-object/from16" |
|
||||||
|
"move-object/16" |
|
||||||
|
"move-result" |
|
||||||
|
"move-result-wide" |
|
||||||
|
"move-result-object" |
|
||||||
|
"move-exception" |
|
||||||
|
"return-void" |
|
||||||
|
"return" |
|
||||||
|
"return-wide" |
|
||||||
|
"return-object" |
|
||||||
|
"const/4" |
|
||||||
|
"const/16" |
|
||||||
|
"const" |
|
||||||
|
"const/high16" |
|
||||||
|
"const-wide/16" |
|
||||||
|
"const-wide/32" |
|
||||||
|
"const-wide" |
|
||||||
|
"const-wide/high16" |
|
||||||
|
"const-string" |
|
||||||
|
"const-string/jumbo" |
|
||||||
|
"const-class" |
|
||||||
|
"monitor-enter" |
|
||||||
|
"monitor-exit" |
|
||||||
|
"check-cast" |
|
||||||
|
"instance-of" |
|
||||||
|
"array-length" |
|
||||||
|
"new-instance" |
|
||||||
|
"new-array" |
|
||||||
|
"filled-new-array" |
|
||||||
|
"filled-new-array/range" |
|
||||||
|
"fill-array-data" |
|
||||||
|
"throw" |
|
||||||
|
"goto" |
|
||||||
|
"goto/16" |
|
||||||
|
"goto/32" |
|
||||||
|
"cmpl-float" |
|
||||||
|
"cmpg-float" |
|
||||||
|
"cmpl-double" |
|
||||||
|
"cmpg-double" |
|
||||||
|
"cmp-long" |
|
||||||
|
"if-eq" |
|
||||||
|
"if-ne" |
|
||||||
|
"if-lt" |
|
||||||
|
"if-ge" |
|
||||||
|
"if-gt" |
|
||||||
|
"if-le" |
|
||||||
|
"if-eqz" |
|
||||||
|
"if-nez" |
|
||||||
|
"if-ltz" |
|
||||||
|
"if-gez" |
|
||||||
|
"if-gtz" |
|
||||||
|
"if-lez" |
|
||||||
|
"aget" |
|
||||||
|
"aget-wide" |
|
||||||
|
"aget-object" |
|
||||||
|
"aget-boolean" |
|
||||||
|
"aget-byte" |
|
||||||
|
"aget-char" |
|
||||||
|
"aget-short" |
|
||||||
|
"aput" |
|
||||||
|
"aput-wide" |
|
||||||
|
"aput-object" |
|
||||||
|
"aput-boolean" |
|
||||||
|
"aput-byte" |
|
||||||
|
"aput-char" |
|
||||||
|
"aput-short" |
|
||||||
|
"iget" |
|
||||||
|
"iget-wide" |
|
||||||
|
"iget-object" |
|
||||||
|
"iget-boolean" |
|
||||||
|
"iget-byte" |
|
||||||
|
"iget-char" |
|
||||||
|
"iget-short" |
|
||||||
|
"iput" |
|
||||||
|
"iput-wide" |
|
||||||
|
"iput-object" |
|
||||||
|
"iput-boolean" |
|
||||||
|
"iput-byte" |
|
||||||
|
"iput-char" |
|
||||||
|
"iput-short" |
|
||||||
|
"sget" |
|
||||||
|
"sget-wide" |
|
||||||
|
"sget-object" |
|
||||||
|
"sget-boolean" |
|
||||||
|
"sget-byte" |
|
||||||
|
"sget-char" |
|
||||||
|
"sget-short" |
|
||||||
|
"sput" |
|
||||||
|
"sput-wide" |
|
||||||
|
"sput-object" |
|
||||||
|
"sput-boolean" |
|
||||||
|
"sput-byte" |
|
||||||
|
"sput-char" |
|
||||||
|
"sput-short" |
|
||||||
|
"invoke-virtual" |
|
||||||
|
"invoke-super" |
|
||||||
|
"invoke-direct" |
|
||||||
|
"invoke-static" |
|
||||||
|
"invoke-interface" |
|
||||||
|
"invoke-virtual/range" |
|
||||||
|
"invoke-super/range" |
|
||||||
|
"invoke-direct/range" |
|
||||||
|
"invoke-static/range" |
|
||||||
|
"invoke-interface/range" |
|
||||||
|
"neg-int" |
|
||||||
|
"not-int" |
|
||||||
|
"neg-long" |
|
||||||
|
"not-long" |
|
||||||
|
"neg-float" |
|
||||||
|
"neg-double" |
|
||||||
|
"int-to-long" |
|
||||||
|
"int-to-float" |
|
||||||
|
"int-to-double" |
|
||||||
|
"long-to-int" |
|
||||||
|
"long-to-float" |
|
||||||
|
"long-to-double" |
|
||||||
|
"float-to-int" |
|
||||||
|
"float-to-long" |
|
||||||
|
"float-to-double" |
|
||||||
|
"double-to-int" |
|
||||||
|
"double-to-long" |
|
||||||
|
"double-to-float" |
|
||||||
|
"int-to-byte" |
|
||||||
|
"int-to-char" |
|
||||||
|
"int-to-short" |
|
||||||
|
"add-int" |
|
||||||
|
"sub-int" |
|
||||||
|
"mul-int" |
|
||||||
|
"div-int" |
|
||||||
|
"rem-int" |
|
||||||
|
"and-int" |
|
||||||
|
"or-int" |
|
||||||
|
"xor-int" |
|
||||||
|
"shl-int" |
|
||||||
|
"shr-int" |
|
||||||
|
"ushr-int" |
|
||||||
|
"add-long" |
|
||||||
|
"sub-long" |
|
||||||
|
"mul-long" |
|
||||||
|
"div-long" |
|
||||||
|
"rem-long" |
|
||||||
|
"and-long" |
|
||||||
|
"or-long" |
|
||||||
|
"xor-long" |
|
||||||
|
"shl-long" |
|
||||||
|
"shr-long" |
|
||||||
|
"ushr-long" |
|
||||||
|
"add-float" |
|
||||||
|
"sub-float" |
|
||||||
|
"mul-float" |
|
||||||
|
"div-float" |
|
||||||
|
"rem-float" |
|
||||||
|
"add-double" |
|
||||||
|
"sub-double" |
|
||||||
|
"mul-double" |
|
||||||
|
"div-double" |
|
||||||
|
"rem-double" |
|
||||||
|
"add-int/2addr" |
|
||||||
|
"sub-int/2addr" |
|
||||||
|
"mul-int/2addr" |
|
||||||
|
"div-int/2addr" |
|
||||||
|
"rem-int/2addr" |
|
||||||
|
"and-int/2addr" |
|
||||||
|
"or-int/2addr" |
|
||||||
|
"xor-int/2addr" |
|
||||||
|
"shl-int/2addr" |
|
||||||
|
"shr-int/2addr" |
|
||||||
|
"ushr-int/2addr" |
|
||||||
|
"add-long/2addr" |
|
||||||
|
"sub-long/2addr" |
|
||||||
|
"mul-long/2addr" |
|
||||||
|
"div-long/2addr" |
|
||||||
|
"rem-long/2addr" |
|
||||||
|
"and-long/2addr" |
|
||||||
|
"or-long/2addr" |
|
||||||
|
"xor-long/2addr" |
|
||||||
|
"shl-long/2addr" |
|
||||||
|
"shr-long/2addr" |
|
||||||
|
"ushr-long/2addr" |
|
||||||
|
"add-float/2addr" |
|
||||||
|
"sub-float/2addr" |
|
||||||
|
"mul-float/2addr" |
|
||||||
|
"div-float/2addr" |
|
||||||
|
"rem-float/2addr" |
|
||||||
|
"add-double/2addr" |
|
||||||
|
"sub-double/2addr" |
|
||||||
|
"mul-double/2addr" |
|
||||||
|
"div-double/2addr" |
|
||||||
|
"rem-double/2addr" |
|
||||||
|
"add-int/lit16" |
|
||||||
|
"rsub-int" |
|
||||||
|
"mul-int/lit16" |
|
||||||
|
"div-int/lit16" |
|
||||||
|
"rem-int/lit16" |
|
||||||
|
"and-int/lit16" |
|
||||||
|
"or-int/lit16" |
|
||||||
|
"xor-int/lit16" |
|
||||||
|
"add-int/lit8" |
|
||||||
|
"rsub-int/lit8" |
|
||||||
|
"mul-int/lit8" |
|
||||||
|
"div-int/lit8" |
|
||||||
|
"rem-int/lit8" |
|
||||||
|
"and-int/lit8" |
|
||||||
|
"or-int/lit8" |
|
||||||
|
"xor-int/lit8" |
|
||||||
|
"shl-int/lit8" |
|
||||||
|
"shr-int/lit8" |
|
||||||
|
"ushr-int/lit8" |
|
||||||
|
"invoke-polymorphic" |
|
||||||
|
"invoke-polymorphic/range" |
|
||||||
|
"invoke-custom" |
|
||||||
|
"invoke-custom/range" |
|
||||||
|
"const-method-handle" |
|
||||||
|
"const-method-type" |
|
||||||
|
"packed-switch" |
|
||||||
|
"sparse-switch" { addToken(Token.FUNCTION); }
|
||||||
|
|
||||||
|
/* Keywords Modifiers(IDENTIFIER标识符、修饰符) Highlight */
|
||||||
|
"public" |
|
||||||
|
"private" |
|
||||||
|
"protected" |
|
||||||
|
"final" |
|
||||||
|
"annotation" |
|
||||||
|
"static" |
|
||||||
|
"synthetic" |
|
||||||
|
"constructor" |
|
||||||
|
"abstract" |
|
||||||
|
"enum" |
|
||||||
|
"interface" |
|
||||||
|
"transient" |
|
||||||
|
"bridge" |
|
||||||
|
"declared-synchronized" |
|
||||||
|
"volatile" |
|
||||||
|
"strictfp" |
|
||||||
|
"varargs" |
|
||||||
|
"native" { addToken(Token.RESERVED_WORD); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Keywords Directives Highlight */
|
||||||
|
".method" |
|
||||||
|
".end method" |
|
||||||
|
".implements" |
|
||||||
|
".class" |
|
||||||
|
".prologue" |
|
||||||
|
".source" |
|
||||||
|
".super" |
|
||||||
|
".field" |
|
||||||
|
".end field" |
|
||||||
|
".registers" |
|
||||||
|
".locals" |
|
||||||
|
".param" |
|
||||||
|
".line" |
|
||||||
|
".catch" |
|
||||||
|
".catchall" |
|
||||||
|
".annotation" |
|
||||||
|
".end annotation" |
|
||||||
|
".local" |
|
||||||
|
".end local" |
|
||||||
|
".restart local" |
|
||||||
|
".packed-switch" |
|
||||||
|
".end packed-switch" |
|
||||||
|
".array-data" |
|
||||||
|
".end array-data" |
|
||||||
|
".sparse-switch" |
|
||||||
|
".end sparse-switch" |
|
||||||
|
".end param" { addToken(Token.RESERVED_WORD_2); }
|
||||||
|
|
||||||
|
|
||||||
|
/* VARIABLE Register Highlight */
|
||||||
|
{VREGISTER} |
|
||||||
|
{PREGISTER} { addToken(Token.VARIABLE); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Data types Highlight */
|
||||||
|
{QUALIFIED_TYPE_NAME} |
|
||||||
|
{COMPOUND_METHOD_ARG_LITERAL} |
|
||||||
|
{MULTI_ARGS_TYPES} |
|
||||||
|
{QUALIFIED_TYPE_NAME} |
|
||||||
|
{VOID_TYPE} |
|
||||||
|
{BOOLEAN_TYPE} |
|
||||||
|
{BYTE_TYPE} |
|
||||||
|
{SHORT_TYPE} |
|
||||||
|
{CHAR_TYPE} |
|
||||||
|
{INT_TYPE} |
|
||||||
|
{LONG_TYPE} |
|
||||||
|
{FLOAT_TYPE} |
|
||||||
|
{DOUBLE_TYPE} { addToken(Token.DATA_TYPE); }
|
||||||
|
|
||||||
|
/* FLAGS */
|
||||||
|
{FLAG_PSWITCH} |
|
||||||
|
{FLAG_PSWITCH_DATA} |
|
||||||
|
{FLAG_GOTO} |
|
||||||
|
{FLAG_COND} |
|
||||||
|
{FLAG_TRY_START} |
|
||||||
|
{FLAG_TRY_END} |
|
||||||
|
{FLAG_CATCHALL} |
|
||||||
|
{FLAG_ARRAY} |
|
||||||
|
{FLAG_CATCH} { addToken(Token.MARKUP_TAG_NAME); }
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
|
/* No functions */
|
||||||
|
|
||||||
|
{BooleanLiteral} { addToken(Token.LITERAL_BOOLEAN); }
|
||||||
|
|
||||||
|
{LineTerminator} { addNullToken(); return firstToken; }
|
||||||
|
|
||||||
|
{Identifier} { addToken(Token.IDENTIFIER); }
|
||||||
|
|
||||||
|
{WhiteSpace} { addToken(Token.WHITESPACE); }
|
||||||
|
|
||||||
|
/* String/Character literals. */
|
||||||
|
{CharLiteral} { addToken(Token.LITERAL_CHAR); }
|
||||||
|
{UnclosedCharLiteral} { addToken(Token.ERROR_CHAR); addNullToken(); return firstToken; }
|
||||||
|
{ErrorCharLiteral} { addToken(Token.ERROR_CHAR); }
|
||||||
|
{StringLiteral} { addToken(Token.LITERAL_STRING_DOUBLE_QUOTE); }
|
||||||
|
{UnclosedStringLiteral} { addToken(Token.ERROR_STRING_DOUBLE); addNullToken(); return firstToken; }
|
||||||
|
{ErrorStringLiteral} { addToken(Token.ERROR_STRING_DOUBLE); }
|
||||||
|
|
||||||
|
/* Comment literals. */
|
||||||
|
/* No multi-line comments */
|
||||||
|
/* No documentation comments */
|
||||||
|
{LineCommentBegin} { start = zzMarkedPos-1; yybegin(EOL_COMMENT); }
|
||||||
|
|
||||||
|
/* Separators. */
|
||||||
|
{CustomSeparator} { addToken(Token.SEPARATOR); }
|
||||||
|
{Separator2} { addToken(Token.IDENTIFIER); }
|
||||||
|
|
||||||
|
/* Operators. */
|
||||||
|
"!" |
|
||||||
|
";" |
|
||||||
|
"." |
|
||||||
|
"=" |
|
||||||
|
"/" |
|
||||||
|
"'" |
|
||||||
|
"(" |
|
||||||
|
")" |
|
||||||
|
"," |
|
||||||
|
"->" |
|
||||||
|
";->" |
|
||||||
|
"<" |
|
||||||
|
">" |
|
||||||
|
"@" |
|
||||||
|
"[" |
|
||||||
|
"]" |
|
||||||
|
"{" |
|
||||||
|
"}" { addToken(Token.OPERATOR); }
|
||||||
|
|
||||||
|
/* Numbers */
|
||||||
|
{IntegerLiteral} { addToken(Token.LITERAL_NUMBER_DECIMAL_INT); }
|
||||||
|
{HexLiteral} { addToken(Token.LITERAL_NUMBER_HEXADECIMAL); }
|
||||||
|
{FloatLiteral} { addToken(Token.LITERAL_NUMBER_FLOAT); }
|
||||||
|
{ErrorNumberFormat} { addToken(Token.ERROR_NUMBER_FORMAT); }
|
||||||
|
|
||||||
|
/* Ended with a line not in a string or comment. */
|
||||||
|
<<EOF>> { addNullToken(); return firstToken; }
|
||||||
|
|
||||||
|
/* Catch any other (unhandled) characters. */
|
||||||
|
. { addToken(Token.IDENTIFIER); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* No char state */
|
||||||
|
|
||||||
|
/* No string state */
|
||||||
|
|
||||||
|
/* No multi-line comment state */
|
||||||
|
|
||||||
|
/* No documentation comment state */
|
||||||
|
|
||||||
|
<EOL_COMMENT> {
|
||||||
|
[^hwf\n]+ {}
|
||||||
|
{URL} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_EOL); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_EOL); start = zzMarkedPos; }
|
||||||
|
[hwf] {}
|
||||||
|
\n { addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; }
|
||||||
|
<<EOF>> { addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
|
||||||
|
/** This character denotes the end of file */
|
||||||
|
public static final int YYEOF = -1;
|
||||||
|
|
||||||
|
/** initial size of the lookahead buffer */
|
||||||
|
--- private static final int ZZ_BUFFERSIZE = ...;
|
||||||
|
|
||||||
|
/** lexical states */
|
||||||
|
--- lexical states, charmap
|
||||||
|
|
||||||
|
/* error codes */
|
||||||
|
private static final int ZZ_UNKNOWN_ERROR = 0;
|
||||||
|
private static final int ZZ_NO_MATCH = 1;
|
||||||
|
private static final int ZZ_PUSHBACK_2BIG = 2;
|
||||||
|
|
||||||
|
/* error messages for the codes above */
|
||||||
|
private static final String ZZ_ERROR_MSG[] = {
|
||||||
|
"Unkown internal scanner error",
|
||||||
|
"Error: could not match input",
|
||||||
|
"Error: pushback value was too large"
|
||||||
|
};
|
||||||
|
|
||||||
|
--- isFinal list
|
||||||
|
/** the input device */
|
||||||
|
private java.io.Reader zzReader;
|
||||||
|
|
||||||
|
/** the current state of the DFA */
|
||||||
|
private int zzState;
|
||||||
|
|
||||||
|
/** the current lexical state */
|
||||||
|
private int zzLexicalState = YYINITIAL;
|
||||||
|
|
||||||
|
/** this buffer contains the current text to be matched and is
|
||||||
|
the source of the yytext() string */
|
||||||
|
private char zzBuffer[];
|
||||||
|
|
||||||
|
/** the textposition at the last accepting state */
|
||||||
|
private int zzMarkedPos;
|
||||||
|
|
||||||
|
/** the textposition at the last state to be included in yytext */
|
||||||
|
private int zzPushbackPos;
|
||||||
|
|
||||||
|
/** the current text position in the buffer */
|
||||||
|
private int zzCurrentPos;
|
||||||
|
|
||||||
|
/** startRead marks the beginning of the yytext() string in the buffer */
|
||||||
|
private int zzStartRead;
|
||||||
|
|
||||||
|
/** endRead marks the last character in the buffer, that has been read
|
||||||
|
from input */
|
||||||
|
private int zzEndRead;
|
||||||
|
|
||||||
|
/** number of newlines encountered up to the start of the matched text */
|
||||||
|
private int yyline;
|
||||||
|
|
||||||
|
/** the number of characters up to the start of the matched text */
|
||||||
|
private int yychar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the number of characters from the last newline up to the start of the
|
||||||
|
* matched text
|
||||||
|
*/
|
||||||
|
private int yycolumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
|
||||||
|
*/
|
||||||
|
private boolean zzAtBOL = true;
|
||||||
|
|
||||||
|
/** zzAtEOF == true <=> the scanner is at the EOF */
|
||||||
|
private boolean zzAtEOF;
|
||||||
|
|
||||||
|
--- user class code
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new scanner
|
||||||
|
* There is also a java.io.InputStream version of this constructor.
|
||||||
|
*
|
||||||
|
* @param in the java.io.Reader to read input from.
|
||||||
|
*/
|
||||||
|
--- constructor declaration
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the input stream.
|
||||||
|
*/
|
||||||
|
public final void yyclose() throws java.io.IOException {
|
||||||
|
zzAtEOF = true; /* indicate end of file */
|
||||||
|
zzEndRead = zzStartRead; /* invalidate buffer */
|
||||||
|
|
||||||
|
if (zzReader != null)
|
||||||
|
zzReader.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enters a new lexical state
|
||||||
|
*
|
||||||
|
* @param newState the new lexical state
|
||||||
|
*/
|
||||||
|
public final void yybegin(int newState) {
|
||||||
|
zzLexicalState = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int yystate() {
|
||||||
|
return zzLexicalState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text matched by the current regular expression.
|
||||||
|
*/
|
||||||
|
public final String yytext() {
|
||||||
|
return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the character at position <tt>pos</tt> from the
|
||||||
|
* matched text.
|
||||||
|
*
|
||||||
|
* It is equivalent to yytext().charAt(pos), but faster
|
||||||
|
*
|
||||||
|
* @param pos the position of the character to fetch.
|
||||||
|
* A value from 0 to yylength()-1.
|
||||||
|
*
|
||||||
|
* @return the character at position pos
|
||||||
|
*/
|
||||||
|
public final char yycharat(int pos) {
|
||||||
|
return zzBuffer[zzStartRead+pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the length of the matched text region.
|
||||||
|
*/
|
||||||
|
public final int yylength() {
|
||||||
|
return zzMarkedPos-zzStartRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports an error that occured while scanning.
|
||||||
|
*
|
||||||
|
* In a wellformed scanner (no or only correct usage of
|
||||||
|
* yypushback(int) and a match-all fallback rule) this method
|
||||||
|
* will only be called with things that "Can't Possibly Happen".
|
||||||
|
* If this method is called, something is seriously wrong
|
||||||
|
* (e.g. a JFlex bug producing a faulty scanner etc.).
|
||||||
|
*
|
||||||
|
* Usual syntax/scanner level error handling should be done
|
||||||
|
* in error fallback rules.
|
||||||
|
*
|
||||||
|
* @param errorCode the code of the errormessage to display
|
||||||
|
*/
|
||||||
|
--- zzScanError declaration
|
||||||
|
String message;
|
||||||
|
try {
|
||||||
|
message = ZZ_ERROR_MSG[errorCode];
|
||||||
|
}
|
||||||
|
catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
|
||||||
|
}
|
||||||
|
|
||||||
|
--- throws clause
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes the specified amount of characters back into the input stream.
|
||||||
|
*
|
||||||
|
* They will be read again by then next call of the scanning method
|
||||||
|
*
|
||||||
|
* @param number the number of characters to be read again.
|
||||||
|
* This number must not be greater than yylength()!
|
||||||
|
*/
|
||||||
|
--- yypushback decl (contains zzScanError exception)
|
||||||
|
if ( number > yylength() )
|
||||||
|
zzScanError(ZZ_PUSHBACK_2BIG);
|
||||||
|
|
||||||
|
zzMarkedPos -= number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--- zzDoEOF
|
||||||
|
/**
|
||||||
|
* Resumes scanning until the next regular expression is matched,
|
||||||
|
* the end of input is encountered or an I/O-Error occurs.
|
||||||
|
*
|
||||||
|
* @return the next token
|
||||||
|
* @exception java.io.IOException if any I/O-Error occurs
|
||||||
|
*/
|
||||||
|
--- yylex declaration
|
||||||
|
int zzInput;
|
||||||
|
int zzAction;
|
||||||
|
|
||||||
|
// cached fields:
|
||||||
|
int zzCurrentPosL;
|
||||||
|
int zzMarkedPosL;
|
||||||
|
int zzEndReadL = zzEndRead;
|
||||||
|
char [] zzBufferL = zzBuffer;
|
||||||
|
char [] zzCMapL = ZZ_CMAP;
|
||||||
|
|
||||||
|
--- local declarations
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
zzMarkedPosL = zzMarkedPos;
|
||||||
|
|
||||||
|
--- start admin (line, char, col count)
|
||||||
|
zzAction = -1;
|
||||||
|
|
||||||
|
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
|
||||||
|
|
||||||
|
--- start admin (lexstate etc)
|
||||||
|
|
||||||
|
zzForAction: {
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
--- next input, line, col, char count, next transition, isFinal action
|
||||||
|
zzAction = zzState;
|
||||||
|
zzMarkedPosL = zzCurrentPosL;
|
||||||
|
--- line count update
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store back cached position
|
||||||
|
zzMarkedPos = zzMarkedPosL;
|
||||||
|
--- char count update
|
||||||
|
|
||||||
|
--- actions
|
||||||
|
default:
|
||||||
|
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
|
||||||
|
zzAtEOF = true;
|
||||||
|
--- eofvalue
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
--- no match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- main
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=JADX GUI
|
||||||
|
Comment=Dex to Java decompiler
|
||||||
|
Icon=jadx
|
||||||
|
Exec=jadx-gui %f
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Development;Java;
|
||||||
|
Keywords=Java;Decompiler;
|
||||||
|
StartupWMClass=jadx-gui-JadxGUI
|
||||||
+16
-1
@@ -1 +1,16 @@
|
|||||||
org.gradle.daemon=false
|
org.gradle.warning.mode=all
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
|
||||||
|
### Disable configuration cache for now: causing issues with spotless and version plugins
|
||||||
|
# org.gradle.configuration-cache=true
|
||||||
|
# org.gradle.configuration-cache.problems=warn
|
||||||
|
|
||||||
|
# Flags for google-java-format (optimize imports by spotless) for Java >= 16.
|
||||||
|
# Java < 9 will ignore unsupported flags (thanks to -XX:+IgnoreUnrecognizedVMOptions)
|
||||||
|
org.gradle.jvmargs=-XX:+IgnoreUnrecognizedVMOptions \
|
||||||
|
--add-exports='jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED' \
|
||||||
|
--add-exports='jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED' \
|
||||||
|
--add-exports='jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED' \
|
||||||
|
--add-exports='jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED' \
|
||||||
|
--add-exports='jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED'
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+4
-1
@@ -1,5 +1,8 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
|
distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright 2015 the original author or authors.
|
# Copyright © 2015-2021 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -15,80 +15,115 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
#
|
||||||
## Gradle start up script for UN*X
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
##
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
app_path=$0
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
# Need this for daisy-chained symlinks.
|
||||||
ls=`ls -ld "$PRG"`
|
while
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
[ -h "$app_path" ]
|
||||||
PRG="$link"
|
do
|
||||||
else
|
ls=$( ls -ld "$app_path" )
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
link=${ls#*' -> '}
|
||||||
fi
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
# This is normally unused
|
||||||
APP_BASE_NAME=`basename "$0"`
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD=maximum
|
||||||
|
|
||||||
warn () {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
die () {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
nonstop=false
|
nonstop=false
|
||||||
case "`uname`" in
|
case "$( uname )" in #(
|
||||||
CYGWIN* )
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
cygwin=true
|
Darwin* ) darwin=true ;; #(
|
||||||
;;
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
Darwin* )
|
NONSTOP* ) nonstop=true ;;
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
else
|
else
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
@@ -97,87 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD="java"
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
case $MAX_FD in #(
|
||||||
if [ $? -eq 0 ] ; then
|
max*)
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
# shellcheck disable=SC2039,SC3045
|
||||||
fi
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
ulimit -n $MAX_FD
|
warn "Could not query maximum file descriptor limit"
|
||||||
if [ $? -ne 0 ] ; then
|
esac
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
case $MAX_FD in #(
|
||||||
fi
|
'' | soft) :;; #(
|
||||||
else
|
*)
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
fi
|
# shellcheck disable=SC2039,SC3045
|
||||||
fi
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=`expr $i + 1`
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
0) set -- ;;
|
|
||||||
1) set -- "$args0" ;;
|
|
||||||
2) set -- "$args0" "$args1" ;;
|
|
||||||
3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
save () {
|
# * args from the command line
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
# * the main class name
|
||||||
echo " "
|
# * -classpath
|
||||||
}
|
# * -D...appname settings
|
||||||
APP_ARGS=`save "$@"`
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
Vendored
+27
-33
@@ -13,8 +13,10 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
@@ -25,10 +27,14 @@
|
|||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@@ -37,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -51,48 +57,36 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
exit /b 1
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'application'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile(project(':jadx-core'))
|
|
||||||
compile 'com.beust:jcommander:1.78'
|
|
||||||
compile 'ch.qos.logback:logback-classic:1.2.3'
|
|
||||||
}
|
|
||||||
|
|
||||||
application {
|
|
||||||
applicationName = 'jadx'
|
|
||||||
mainClassName = 'jadx.cli.JadxCLI'
|
|
||||||
applicationDefaultJvmArgs = ['-Xms128M', '-Xmx4g', '-XX:+UseG1GC']
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationDistribution.with {
|
|
||||||
into('') {
|
|
||||||
from '../.'
|
|
||||||
include 'README.md'
|
|
||||||
include 'NOTICE'
|
|
||||||
include 'LICENSE'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
plugins {
|
||||||
|
id("jadx-java")
|
||||||
|
id("jadx-library")
|
||||||
|
id("application")
|
||||||
|
|
||||||
|
// use shadow only for application scripts, jar will be copied from jadx-gui
|
||||||
|
id("com.gradleup.shadow") version "8.3.6"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":jadx-core"))
|
||||||
|
implementation(project(":jadx-plugins-tools"))
|
||||||
|
implementation(project(":jadx-commons:jadx-app-commons"))
|
||||||
|
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-dex-input"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-java-input"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-java-convert"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-smali-input"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-rename-mappings"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-kotlin-metadata"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-kotlin-source-debug-extension"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-script:jadx-script-plugin"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-xapk-input"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-aab-input"))
|
||||||
|
runtimeOnly(project(":jadx-plugins:jadx-apkm-input"))
|
||||||
|
|
||||||
|
implementation("org.jcommander:jcommander:2.0")
|
||||||
|
implementation("ch.qos.logback:logback-classic:1.5.18")
|
||||||
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
applicationName = "jadx"
|
||||||
|
mainClass.set("jadx.cli.JadxCLI")
|
||||||
|
applicationDefaultJvmArgs =
|
||||||
|
listOf(
|
||||||
|
"-Xms256M",
|
||||||
|
"-XX:MaxRAMPercentage=70.0",
|
||||||
|
// disable zip checks (#1962)
|
||||||
|
"-Djdk.util.zip.disableZip64ExtraFieldValidation=true",
|
||||||
|
// Foreign API access for 'directories' library (Windows only)
|
||||||
|
"--enable-native-access=ALL-UNNAMED",
|
||||||
|
)
|
||||||
|
applicationDistribution.from("$rootDir") {
|
||||||
|
include("README.md")
|
||||||
|
include("NOTICE")
|
||||||
|
include("LICENSE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.shadowJar {
|
||||||
|
// shadow jar not needed
|
||||||
|
configurations = listOf()
|
||||||
|
}
|
||||||
@@ -4,30 +4,45 @@ import java.io.PrintStream;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.beust.jcommander.JCommander;
|
import com.beust.jcommander.JCommander;
|
||||||
|
import com.beust.jcommander.Parameter;
|
||||||
import com.beust.jcommander.ParameterDescription;
|
import com.beust.jcommander.ParameterDescription;
|
||||||
import com.beust.jcommander.ParameterException;
|
import com.beust.jcommander.ParameterException;
|
||||||
import com.beust.jcommander.Parameterized;
|
import com.beust.jcommander.Parameterized;
|
||||||
|
|
||||||
import jadx.api.JadxDecompiler;
|
import jadx.api.JadxDecompiler;
|
||||||
|
import jadx.api.plugins.JadxPluginInfo;
|
||||||
|
import jadx.api.plugins.options.JadxPluginOptions;
|
||||||
|
import jadx.api.plugins.options.OptionDescription;
|
||||||
|
import jadx.core.plugins.JadxPluginManager;
|
||||||
|
import jadx.core.plugins.PluginContext;
|
||||||
|
import jadx.core.utils.Utils;
|
||||||
|
import jadx.plugins.tools.JadxExternalPluginsLoader;
|
||||||
|
|
||||||
public class JCommanderWrapper<T> {
|
public class JCommanderWrapper {
|
||||||
private final JCommander jc;
|
private final JCommander jc;
|
||||||
|
private final JadxCLIArgs argsObj;
|
||||||
|
|
||||||
public JCommanderWrapper(T obj) {
|
public JCommanderWrapper(JadxCLIArgs argsObj) {
|
||||||
this.jc = JCommander.newBuilder().addObject(obj).build();
|
JCommander.Builder builder = JCommander.newBuilder().addObject(argsObj);
|
||||||
|
builder.acceptUnknownOptions(true); // workaround for "default" command
|
||||||
|
JadxCLICommands.append(builder);
|
||||||
|
this.jc = builder.build();
|
||||||
|
this.argsObj = argsObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean parse(String[] args) {
|
public boolean parse(String[] args) {
|
||||||
try {
|
try {
|
||||||
jc.parse(args);
|
jc.parse(args);
|
||||||
|
applyFiles(argsObj);
|
||||||
return true;
|
return true;
|
||||||
} catch (ParameterException e) {
|
} catch (ParameterException e) {
|
||||||
System.err.println("Arguments parse error: " + e.getMessage());
|
System.err.println("Arguments parse error: " + e.getMessage());
|
||||||
@@ -36,70 +51,156 @@ public class JCommanderWrapper<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void overrideProvided(T obj) {
|
public void overrideProvided(JadxCLIArgs obj) {
|
||||||
List<ParameterDescription> fieldsParams = jc.getParameters();
|
applyFiles(obj);
|
||||||
List<ParameterDescription> parameters = new ArrayList<>(1 + fieldsParams.size());
|
for (ParameterDescription parameter : jc.getParameters()) {
|
||||||
parameters.add(jc.getMainParameterValue());
|
|
||||||
parameters.addAll(fieldsParams);
|
|
||||||
for (ParameterDescription parameter : parameters) {
|
|
||||||
if (parameter.isAssigned()) {
|
if (parameter.isAssigned()) {
|
||||||
// copy assigned field value to obj
|
overrideProperty(obj, parameter);
|
||||||
Parameterized parameterized = parameter.getParameterized();
|
|
||||||
Object val = parameterized.get(parameter.getObject());
|
|
||||||
parameterized.set(obj, val);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean processCommands() {
|
||||||
|
String parsedCommand = jc.getParsedCommand();
|
||||||
|
if (parsedCommand == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return JadxCLICommands.process(this, jc, parsedCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main parameter parsing doesn't work if accepting unknown options
|
||||||
|
*/
|
||||||
|
private void applyFiles(JadxCLIArgs argsObj) {
|
||||||
|
argsObj.setFiles(jc.getUnknownOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override assigned field value to obj
|
||||||
|
*/
|
||||||
|
private static void overrideProperty(JadxCLIArgs obj, ParameterDescription parameter) {
|
||||||
|
Parameterized parameterized = parameter.getParameterized();
|
||||||
|
Object providedValue = parameterized.get(parameter.getObject());
|
||||||
|
Object newValue = mergeValues(parameterized.getType(), providedValue, () -> parameterized.get(obj));
|
||||||
|
parameterized.set(obj, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
private static Object mergeValues(Class<?> type, Object value, Supplier<Object> prevValueProvider) {
|
||||||
|
if (type.isAssignableFrom(Map.class)) {
|
||||||
|
// merge maps instead replacing whole map
|
||||||
|
Map prevMap = (Map) prevValueProvider.get();
|
||||||
|
return Utils.mergeMaps(prevMap, (Map) value); // value map will override keys in prevMap
|
||||||
|
}
|
||||||
|
// simple override
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
public void printUsage() {
|
public void printUsage() {
|
||||||
// print usage in not sorted fields order (by default its sorted by description)
|
LogHelper.setLogLevel(LogHelper.LogLevelEnum.ERROR); // mute logger while printing help
|
||||||
|
|
||||||
|
// print usage in not sorted fields order (by default sorted by description)
|
||||||
PrintStream out = System.out;
|
PrintStream out = System.out;
|
||||||
out.println();
|
out.println();
|
||||||
out.println("jadx - dex to java decompiler, version: " + JadxDecompiler.getVersion());
|
out.println("jadx - dex to java decompiler, version: " + JadxDecompiler.getVersion());
|
||||||
out.println();
|
out.println();
|
||||||
out.println("usage: jadx [options] " + jc.getMainParameterDescription());
|
out.println("usage: jadx [command] [options] " + jc.getMainParameterDescription());
|
||||||
|
|
||||||
|
out.println("commands (use '<command> --help' for command options):");
|
||||||
|
for (String command : jc.getCommands().keySet()) {
|
||||||
|
out.println(" " + command + "\t - " + jc.getUsageFormatter().getCommandDescription(command));
|
||||||
|
}
|
||||||
|
out.println();
|
||||||
|
|
||||||
|
int maxNamesLen = printOptions(jc, out, true);
|
||||||
|
out.println(appendPluginOptions(maxNamesLen));
|
||||||
|
out.println();
|
||||||
|
out.println("Environment variables:");
|
||||||
|
out.println(" JADX_DISABLE_XML_SECURITY - set to 'true' to disable all security checks for XML files");
|
||||||
|
out.println(" JADX_DISABLE_ZIP_SECURITY - set to 'true' to disable all security checks for zip files");
|
||||||
|
out.println(" JADX_ZIP_MAX_ENTRIES_COUNT - maximum allowed number of entries in zip files (default: 100 000)");
|
||||||
|
out.println(" JADX_CONFIG_DIR - custom config directory, using system by default");
|
||||||
|
out.println(" JADX_CACHE_DIR - custom cache directory, using system by default");
|
||||||
|
out.println(" JADX_TMP_DIR - custom temp directory, using system by default");
|
||||||
|
out.println();
|
||||||
|
out.println("Examples:");
|
||||||
|
out.println(" jadx -d out classes.dex");
|
||||||
|
out.println(" jadx --rename-flags \"none\" classes.dex");
|
||||||
|
out.println(" jadx --rename-flags \"valid, printable\" classes.dex");
|
||||||
|
out.println(" jadx --log-level ERROR app.apk");
|
||||||
|
out.println(" jadx -Pdex-input.verify-checksum=no app.apk");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printUsage(JCommander subCommander) {
|
||||||
|
PrintStream out = System.out;
|
||||||
|
out.println("usage: " + subCommander.getProgramName() + " [options]");
|
||||||
|
printOptions(subCommander, out, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int printOptions(JCommander jc, PrintStream out, boolean addDefaults) {
|
||||||
out.println("options:");
|
out.println("options:");
|
||||||
|
|
||||||
List<ParameterDescription> params = jc.getParameters();
|
List<ParameterDescription> params = jc.getParameters();
|
||||||
Map<String, ParameterDescription> paramsMap = new LinkedHashMap<>(params.size());
|
Map<String, ParameterDescription> paramsMap = new HashMap<>(params.size());
|
||||||
int maxNamesLen = 0;
|
int maxNamesLen = 0;
|
||||||
for (ParameterDescription p : params) {
|
for (ParameterDescription p : params) {
|
||||||
paramsMap.put(p.getParameterized().getName(), p);
|
paramsMap.put(p.getParameterized().getName(), p);
|
||||||
int len = p.getNames().length();
|
int len = p.getNames().length();
|
||||||
if (len > maxNamesLen) {
|
String valueDesc = getValueDesc(p);
|
||||||
maxNamesLen = len;
|
if (valueDesc != null) {
|
||||||
|
len += 1 + valueDesc.length();
|
||||||
}
|
}
|
||||||
|
maxNamesLen = Math.max(maxNamesLen, len);
|
||||||
}
|
}
|
||||||
|
maxNamesLen += 3;
|
||||||
|
|
||||||
JadxCLIArgs args = (JadxCLIArgs) jc.getObjects().get(0);
|
Object args = jc.getObjects().get(0);
|
||||||
for (Field f : getFields(args.getClass())) {
|
for (Field f : getFields(args.getClass())) {
|
||||||
String name = f.getName();
|
String name = f.getName();
|
||||||
ParameterDescription p = paramsMap.get(name);
|
ParameterDescription p = paramsMap.get(name);
|
||||||
if (p == null) {
|
if (p == null || p.getParameter().hidden()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
StringBuilder opt = new StringBuilder();
|
StringBuilder opt = new StringBuilder();
|
||||||
opt.append(" ").append(p.getNames());
|
opt.append(" ").append(p.getNames());
|
||||||
addSpaces(opt, maxNamesLen - opt.length() + 3);
|
String valueDesc = getValueDesc(p);
|
||||||
opt.append("- ").append(p.getDescription());
|
if (valueDesc != null) {
|
||||||
String defaultValue = getDefaultValue(args, f, opt);
|
opt.append(' ').append(valueDesc);
|
||||||
if (defaultValue != null) {
|
}
|
||||||
opt.append(", default: ").append(defaultValue);
|
addSpaces(opt, maxNamesLen - opt.length());
|
||||||
|
String description = p.getDescription();
|
||||||
|
if (description.contains("\n")) {
|
||||||
|
String[] lines = description.split("\n");
|
||||||
|
opt.append("- ").append(lines[0]);
|
||||||
|
for (int i = 1; i < lines.length; i++) {
|
||||||
|
opt.append('\n');
|
||||||
|
addSpaces(opt, maxNamesLen + 2);
|
||||||
|
opt.append(lines[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opt.append("- ").append(description);
|
||||||
|
}
|
||||||
|
if (addDefaults) {
|
||||||
|
String defaultValue = getDefaultValue(args, f);
|
||||||
|
if (defaultValue != null && !description.contains("(default)")) {
|
||||||
|
opt.append(", default: ").append(defaultValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.println(opt);
|
out.println(opt);
|
||||||
}
|
}
|
||||||
out.println("Example:");
|
return maxNamesLen;
|
||||||
out.println(" jadx -d out classes.dex");
|
}
|
||||||
|
|
||||||
|
private static @Nullable String getValueDesc(ParameterDescription p) {
|
||||||
|
Parameter parameterAnnotation = p.getParameterAnnotation();
|
||||||
|
return parameterAnnotation == null ? null : parameterAnnotation.defaultValueDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all declared fields of the specified class and all super classes
|
* Get all declared fields of the specified class and all super classes
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private List<Field> getFields(Class<?> clazz) {
|
private static List<Field> getFields(Class<?> clazz) {
|
||||||
List<Field> fieldList = new LinkedList<>();
|
List<Field> fieldList = new ArrayList<>();
|
||||||
while (clazz != null) {
|
while (clazz != null) {
|
||||||
fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
||||||
clazz = clazz.getSuperclass();
|
clazz = clazz.getSuperclass();
|
||||||
@@ -108,7 +209,7 @@ public class JCommanderWrapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String getDefaultValue(JadxCLIArgs args, Field f, StringBuilder opt) {
|
private static String getDefaultValue(Object args, Field f) {
|
||||||
try {
|
try {
|
||||||
Class<?> fieldType = f.getType();
|
Class<?> fieldType = f.getType();
|
||||||
if (fieldType == int.class) {
|
if (fieldType == int.class) {
|
||||||
@@ -120,7 +221,7 @@ public class JCommanderWrapper<T> {
|
|||||||
if (Enum.class.isAssignableFrom(fieldType)) {
|
if (Enum.class.isAssignableFrom(fieldType)) {
|
||||||
Enum<?> val = (Enum<?>) f.get(args);
|
Enum<?> val = (Enum<?>) f.get(args);
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
return val.name();
|
return val.name().toLowerCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -134,4 +235,54 @@ public class JCommanderWrapper<T> {
|
|||||||
str.append(' ');
|
str.append(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String appendPluginOptions(int maxNamesLen) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int k = 1;
|
||||||
|
// load and init all options plugins to print all options
|
||||||
|
try (JadxDecompiler decompiler = new JadxDecompiler(argsObj.toJadxArgs())) {
|
||||||
|
JadxPluginManager pluginManager = decompiler.getPluginManager();
|
||||||
|
pluginManager.load(new JadxExternalPluginsLoader());
|
||||||
|
pluginManager.initAll();
|
||||||
|
try {
|
||||||
|
for (PluginContext context : pluginManager.getAllPluginContexts()) {
|
||||||
|
JadxPluginOptions options = context.getOptions();
|
||||||
|
if (options != null) {
|
||||||
|
if (appendPlugin(context.getPluginInfo(), context.getOptions(), sb, maxNamesLen)) {
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
pluginManager.unloadAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sb.length() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "\nPlugin options (-P<name>=<value>):" + sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean appendPlugin(JadxPluginInfo pluginInfo, JadxPluginOptions options, StringBuilder out, int maxNamesLen) {
|
||||||
|
List<OptionDescription> descs = options.getOptionsDescriptions();
|
||||||
|
if (descs.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out.append("\n ");
|
||||||
|
out.append(pluginInfo.getPluginId()).append(": ").append(pluginInfo.getDescription());
|
||||||
|
for (OptionDescription desc : descs) {
|
||||||
|
StringBuilder opt = new StringBuilder();
|
||||||
|
opt.append(" - ").append(desc.name());
|
||||||
|
addSpaces(opt, maxNamesLen - opt.length());
|
||||||
|
opt.append("- ").append(desc.description());
|
||||||
|
if (!desc.values().isEmpty()) {
|
||||||
|
opt.append(", values: ").append(desc.values());
|
||||||
|
}
|
||||||
|
if (desc.defaultValue() != null) {
|
||||||
|
opt.append(", default: ").append(desc.defaultValue());
|
||||||
|
}
|
||||||
|
out.append("\n").append(opt);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jadx.api.JadxArgs;
|
||||||
|
import jadx.api.security.JadxSecurityFlag;
|
||||||
|
import jadx.api.security.impl.JadxSecurity;
|
||||||
|
import jadx.commons.app.JadxCommonEnv;
|
||||||
|
import jadx.zip.security.DisabledZipSecurity;
|
||||||
|
import jadx.zip.security.IJadxZipSecurity;
|
||||||
|
import jadx.zip.security.JadxZipSecurity;
|
||||||
|
|
||||||
|
public class JadxAppCommon {
|
||||||
|
|
||||||
|
public static void applyEnvVars(JadxArgs jadxArgs) {
|
||||||
|
Set<JadxSecurityFlag> flags = JadxSecurityFlag.all();
|
||||||
|
IJadxZipSecurity zipSecurity;
|
||||||
|
|
||||||
|
boolean disableXmlSecurity = JadxCommonEnv.getBool("JADX_DISABLE_XML_SECURITY", false);
|
||||||
|
if (disableXmlSecurity) {
|
||||||
|
flags.remove(JadxSecurityFlag.SECURE_XML_PARSER);
|
||||||
|
// TODO: not related to 'xml security', but kept for compatibility
|
||||||
|
flags.remove(JadxSecurityFlag.VERIFY_APP_PACKAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean disableZipSecurity = JadxCommonEnv.getBool("JADX_DISABLE_ZIP_SECURITY", false);
|
||||||
|
if (disableZipSecurity) {
|
||||||
|
flags.remove(JadxSecurityFlag.SECURE_ZIP_READER);
|
||||||
|
zipSecurity = DisabledZipSecurity.INSTANCE;
|
||||||
|
} else {
|
||||||
|
JadxZipSecurity jadxZipSecurity = new JadxZipSecurity();
|
||||||
|
int maxZipEntriesCount = JadxCommonEnv.getInt("JADX_ZIP_MAX_ENTRIES_COUNT", -2);
|
||||||
|
if (maxZipEntriesCount != -2) {
|
||||||
|
jadxZipSecurity.setMaxEntriesCount(maxZipEntriesCount);
|
||||||
|
}
|
||||||
|
int zipBombMinUncompressedSize = JadxCommonEnv.getInt("JADX_ZIP_BOMB_MIN_UNCOMPRESSED_SIZE", -2);
|
||||||
|
if (zipBombMinUncompressedSize != -2) {
|
||||||
|
jadxZipSecurity.setZipBombMinUncompressedSize(zipBombMinUncompressedSize);
|
||||||
|
}
|
||||||
|
int setZipBombDetectionFactor = JadxCommonEnv.getInt("JADX_ZIP_BOMB_DETECTION_FACTOR", -2);
|
||||||
|
if (setZipBombDetectionFactor != -2) {
|
||||||
|
jadxZipSecurity.setZipBombDetectionFactor(setZipBombDetectionFactor);
|
||||||
|
}
|
||||||
|
zipSecurity = jadxZipSecurity;
|
||||||
|
}
|
||||||
|
jadxArgs.setSecurity(new JadxSecurity(flags, zipSecurity));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +1,132 @@
|
|||||||
package jadx.cli;
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import jadx.api.JadxArgs;
|
import jadx.api.JadxArgs;
|
||||||
import jadx.api.JadxDecompiler;
|
import jadx.api.JadxDecompiler;
|
||||||
|
import jadx.api.impl.AnnotatedCodeWriter;
|
||||||
import jadx.api.impl.NoOpCodeCache;
|
import jadx.api.impl.NoOpCodeCache;
|
||||||
|
import jadx.api.impl.SimpleCodeWriter;
|
||||||
|
import jadx.cli.LogHelper.LogLevelEnum;
|
||||||
|
import jadx.cli.plugins.JadxFilesGetter;
|
||||||
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||||
|
import jadx.plugins.tools.JadxExternalPluginsLoader;
|
||||||
|
|
||||||
public class JadxCLI {
|
public class JadxCLI {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class);
|
private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class);
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
int result = 0;
|
int result = 1;
|
||||||
try {
|
try {
|
||||||
JadxCLIArgs jadxArgs = new JadxCLIArgs();
|
result = execute(args);
|
||||||
if (jadxArgs.processArgs(args)) {
|
|
||||||
result = processAndSave(jadxArgs);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error("jadx error: {}", e.getMessage(), e);
|
|
||||||
result = 1;
|
|
||||||
} finally {
|
} finally {
|
||||||
System.exit(result);
|
System.exit(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processAndSave(JadxCLIArgs inputArgs) {
|
public static int execute(String[] args) {
|
||||||
JadxArgs args = inputArgs.toJadxArgs();
|
return execute(args, null);
|
||||||
args.setCodeCache(new NoOpCodeCache());
|
}
|
||||||
JadxDecompiler jadx = new JadxDecompiler(args);
|
|
||||||
|
public static int execute(String[] args, @Nullable Consumer<JadxArgs> argsMod) {
|
||||||
try {
|
try {
|
||||||
jadx.load();
|
JadxCLIArgs cliArgs = new JadxCLIArgs();
|
||||||
|
if (cliArgs.processArgs(args)) {
|
||||||
|
JadxArgs jadxArgs = buildArgs(cliArgs);
|
||||||
|
if (argsMod != null) {
|
||||||
|
argsMod.accept(jadxArgs);
|
||||||
|
}
|
||||||
|
return runSave(jadxArgs, cliArgs);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
} catch (JadxArgsValidateException e) {
|
} catch (JadxArgsValidateException e) {
|
||||||
LOG.error("Incorrect arguments: {}", e.getMessage());
|
LOG.error("Incorrect arguments: {}", e.getMessage());
|
||||||
return 1;
|
return 1;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOG.error("Process error:", e);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
jadx.save();
|
}
|
||||||
int errorsCount = jadx.getErrorsCount();
|
|
||||||
if (errorsCount != 0) {
|
private static JadxArgs buildArgs(JadxCLIArgs cliArgs) {
|
||||||
jadx.printErrorsReport();
|
LogHelper.initLogLevel(cliArgs);
|
||||||
LOG.error("finished with errors, count: {}", errorsCount);
|
LogHelper.setLogLevelsForLoadingStage();
|
||||||
} else {
|
JadxArgs jadxArgs = cliArgs.toJadxArgs();
|
||||||
|
jadxArgs.setCodeCache(new NoOpCodeCache());
|
||||||
|
jadxArgs.setPluginLoader(new JadxExternalPluginsLoader());
|
||||||
|
jadxArgs.setFilesGetter(JadxFilesGetter.INSTANCE);
|
||||||
|
initCodeWriterProvider(jadxArgs);
|
||||||
|
JadxAppCommon.applyEnvVars(jadxArgs);
|
||||||
|
return jadxArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int runSave(JadxArgs jadxArgs, JadxCLIArgs cliArgs) {
|
||||||
|
try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) {
|
||||||
|
jadx.load();
|
||||||
|
if (checkForErrors(jadx)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
LogHelper.setLogLevelsForDecompileStage();
|
||||||
|
if (!SingleClassMode.process(jadx, cliArgs)) {
|
||||||
|
save(jadx);
|
||||||
|
}
|
||||||
|
int errorsCount = jadx.getErrorsCount();
|
||||||
|
if (errorsCount != 0) {
|
||||||
|
jadx.printErrorsReport();
|
||||||
|
LOG.error("finished with errors, count: {}", errorsCount);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
LOG.info("done");
|
LOG.info("done");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initCodeWriterProvider(JadxArgs jadxArgs) {
|
||||||
|
switch (jadxArgs.getOutputFormat()) {
|
||||||
|
case JAVA:
|
||||||
|
jadxArgs.setCodeWriterProvider(SimpleCodeWriter::new);
|
||||||
|
break;
|
||||||
|
case JSON:
|
||||||
|
// needed for code offsets and source lines
|
||||||
|
jadxArgs.setCodeWriterProvider(AnnotatedCodeWriter::new);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkForErrors(JadxDecompiler jadx) {
|
||||||
|
if (jadx.getRoot().getClasses().isEmpty()) {
|
||||||
|
if (jadx.getArgs().isSkipResources()) {
|
||||||
|
LOG.error("Load failed! No classes for decompile!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!jadx.getArgs().isSkipSources()) {
|
||||||
|
LOG.warn("No classes to decompile; decoding resources only");
|
||||||
|
jadx.getArgs().setSkipSources(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jadx.getErrorsCount() > 0) {
|
||||||
|
LOG.error("Load with errors! Check log for details");
|
||||||
|
// continue processing
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void save(JadxDecompiler jadx) {
|
||||||
|
if (LogHelper.getLogLevel() == LogLevelEnum.QUIET) {
|
||||||
|
jadx.save();
|
||||||
|
} else {
|
||||||
|
LOG.info("processing ...");
|
||||||
|
jadx.save(500, (done, total) -> {
|
||||||
|
int progress = (int) (done * 100.0 / total);
|
||||||
|
System.out.printf("INFO - progress: %d of %d (%d%%)\r", done, total, progress);
|
||||||
|
});
|
||||||
|
// dumb line clear :)
|
||||||
|
System.out.print(" \r");
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,45 @@
|
|||||||
package jadx.cli;
|
package jadx.cli;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.beust.jcommander.DynamicParameter;
|
||||||
import com.beust.jcommander.IStringConverter;
|
import com.beust.jcommander.IStringConverter;
|
||||||
import com.beust.jcommander.Parameter;
|
import com.beust.jcommander.Parameter;
|
||||||
|
|
||||||
|
import jadx.api.CommentsLevel;
|
||||||
|
import jadx.api.DecompilationMode;
|
||||||
import jadx.api.JadxArgs;
|
import jadx.api.JadxArgs;
|
||||||
import jadx.api.JadxArgs.RenameEnum;
|
import jadx.api.JadxArgs.RenameEnum;
|
||||||
|
import jadx.api.JadxArgs.UseKotlinMethodsForVarNames;
|
||||||
import jadx.api.JadxDecompiler;
|
import jadx.api.JadxDecompiler;
|
||||||
import jadx.core.utils.exceptions.JadxException;
|
import jadx.api.args.GeneratedRenamesMappingFileMode;
|
||||||
|
import jadx.api.args.IntegerFormat;
|
||||||
|
import jadx.api.args.ResourceNameSource;
|
||||||
|
import jadx.api.args.UseSourceNameAsClassNameAlias;
|
||||||
|
import jadx.api.args.UserRenamesMappingsMode;
|
||||||
|
import jadx.core.deobf.conditions.DeobfWhitelist;
|
||||||
|
import jadx.core.export.ExportGradleType;
|
||||||
|
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||||
import jadx.core.utils.files.FileUtils;
|
import jadx.core.utils.files.FileUtils;
|
||||||
|
|
||||||
public class JadxCLIArgs {
|
public class JadxCLIArgs {
|
||||||
|
|
||||||
@Parameter(description = "<input file> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc)")
|
@Parameter(description = "<input files> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc, .aab, .xapk, .apkm, .jadx.kts)")
|
||||||
protected List<String> files = new ArrayList<>(1);
|
protected List<String> files = Collections.emptyList();
|
||||||
|
|
||||||
@Parameter(names = { "-d", "--output-dir" }, description = "output directory")
|
@Parameter(names = { "-d", "--output-dir" }, description = "output directory")
|
||||||
protected String outDir;
|
protected String outDir;
|
||||||
@@ -37,30 +56,76 @@ public class JadxCLIArgs {
|
|||||||
@Parameter(names = { "-s", "--no-src" }, description = "do not decompile source code")
|
@Parameter(names = { "-s", "--no-src" }, description = "do not decompile source code")
|
||||||
protected boolean skipSources = false;
|
protected boolean skipSources = false;
|
||||||
|
|
||||||
@Parameter(names = { "--single-class" }, description = "decompile a single class")
|
@Parameter(names = { "-j", "--threads-count" }, description = "processing threads count")
|
||||||
|
protected int threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;
|
||||||
|
|
||||||
|
@Parameter(names = { "--single-class" }, description = "decompile a single class, full name, raw or alias")
|
||||||
protected String singleClass = null;
|
protected String singleClass = null;
|
||||||
|
|
||||||
|
@Parameter(names = { "--single-class-output" }, description = "file or dir for write if decompile a single class")
|
||||||
|
protected String singleClassOutput = null;
|
||||||
|
|
||||||
@Parameter(names = { "--output-format" }, description = "can be 'java' or 'json'")
|
@Parameter(names = { "--output-format" }, description = "can be 'java' or 'json'")
|
||||||
protected String outputFormat = "java";
|
protected String outputFormat = "java";
|
||||||
|
|
||||||
@Parameter(names = { "-e", "--export-gradle" }, description = "save as android gradle project")
|
@Parameter(names = { "-e", "--export-gradle" }, description = "save as gradle project (set '--export-gradle-type' to 'auto')")
|
||||||
protected boolean exportAsGradleProject = false;
|
protected boolean exportAsGradleProject = false;
|
||||||
|
|
||||||
@Parameter(names = { "-j", "--threads-count" }, description = "processing threads count")
|
@Parameter(
|
||||||
protected int threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;
|
names = { "--export-gradle-type" },
|
||||||
|
description = "Gradle project template for export:"
|
||||||
|
+ "\n 'auto' - detect automatically"
|
||||||
|
+ "\n 'android-app' - Android Application (apk)"
|
||||||
|
+ "\n 'android-library' - Android Library (aar)"
|
||||||
|
+ "\n 'simple-java' - simple Java",
|
||||||
|
converter = ExportGradleTypeConverter.class
|
||||||
|
)
|
||||||
|
protected @Nullable ExportGradleType exportGradleType = null;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "-m", "--decompilation-mode" },
|
||||||
|
description = "code output mode:"
|
||||||
|
+ "\n 'auto' - trying best options (default)"
|
||||||
|
+ "\n 'restructure' - restore code structure (normal java code)"
|
||||||
|
+ "\n 'simple' - simplified instructions (linear, with goto's)"
|
||||||
|
+ "\n 'fallback' - raw instructions without modifications",
|
||||||
|
converter = DecompilationModeConverter.class
|
||||||
|
)
|
||||||
|
protected DecompilationMode decompilationMode = DecompilationMode.AUTO;
|
||||||
|
|
||||||
@Parameter(names = { "--show-bad-code" }, description = "show inconsistent code (incorrectly decompiled)")
|
@Parameter(names = { "--show-bad-code" }, description = "show inconsistent code (incorrectly decompiled)")
|
||||||
protected boolean showInconsistentCode = false;
|
protected boolean showInconsistentCode = false;
|
||||||
|
|
||||||
|
@Parameter(names = { "--no-xml-pretty-print" }, description = "do not prettify XML")
|
||||||
|
protected boolean skipXmlPrettyPrint = false;
|
||||||
|
|
||||||
@Parameter(names = { "--no-imports" }, description = "disable use of imports, always write entire package name")
|
@Parameter(names = { "--no-imports" }, description = "disable use of imports, always write entire package name")
|
||||||
protected boolean useImports = true;
|
protected boolean useImports = true;
|
||||||
|
|
||||||
@Parameter(names = { "--no-debug-info" }, description = "disable debug info")
|
@Parameter(names = { "--no-debug-info" }, description = "disable debug info parsing and processing")
|
||||||
protected boolean debugInfo = true;
|
protected boolean debugInfo = true;
|
||||||
|
|
||||||
|
@Parameter(names = { "--add-debug-lines" }, description = "add comments with debug line numbers if available")
|
||||||
|
protected boolean addDebugLines = false;
|
||||||
|
|
||||||
@Parameter(names = { "--no-inline-anonymous" }, description = "disable anonymous classes inline")
|
@Parameter(names = { "--no-inline-anonymous" }, description = "disable anonymous classes inline")
|
||||||
protected boolean inlineAnonymousClasses = true;
|
protected boolean inlineAnonymousClasses = true;
|
||||||
|
|
||||||
|
@Parameter(names = { "--no-inline-methods" }, description = "disable methods inline")
|
||||||
|
protected boolean inlineMethods = true;
|
||||||
|
|
||||||
|
@Parameter(names = { "--no-move-inner-classes" }, description = "disable move inner classes into parent")
|
||||||
|
protected boolean moveInnerClasses = true;
|
||||||
|
|
||||||
|
@Parameter(names = { "--no-inline-kotlin-lambda" }, description = "disable inline for Kotlin lambdas")
|
||||||
|
protected boolean allowInlineKotlinLambda = true;
|
||||||
|
|
||||||
|
@Parameter(names = "--no-finally", description = "don't extract finally block")
|
||||||
|
protected boolean extractFinally = true;
|
||||||
|
|
||||||
|
@Parameter(names = "--no-restore-switch-over-string", description = "don't restore switch over string")
|
||||||
|
protected boolean restoreSwitchOverString = true;
|
||||||
|
|
||||||
@Parameter(names = "--no-replace-consts", description = "don't replace constant value with matching constant field")
|
@Parameter(names = "--no-replace-consts", description = "don't replace constant value with matching constant field")
|
||||||
protected boolean replaceConsts = true;
|
protected boolean replaceConsts = true;
|
||||||
|
|
||||||
@@ -70,6 +135,22 @@ public class JadxCLIArgs {
|
|||||||
@Parameter(names = { "--respect-bytecode-access-modifiers" }, description = "don't change original access modifiers")
|
@Parameter(names = { "--respect-bytecode-access-modifiers" }, description = "don't change original access modifiers")
|
||||||
protected boolean respectBytecodeAccessModifiers = false;
|
protected boolean respectBytecodeAccessModifiers = false;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--mappings-path" },
|
||||||
|
description = "deobfuscation mappings file or directory. Allowed formats: Tiny and Tiny v2 (both '.tiny'), Enigma (.mapping) or Enigma directory"
|
||||||
|
)
|
||||||
|
protected Path userRenamesMappingsPath;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--mappings-mode" },
|
||||||
|
description = "set mode for handling the deobfuscation mapping file:"
|
||||||
|
+ "\n 'read' - just read, user can always save manually (default)"
|
||||||
|
+ "\n 'read-and-autosave-every-change' - read and autosave after every change"
|
||||||
|
+ "\n 'read-and-autosave-before-closing' - read and autosave before exiting the app or closing the project"
|
||||||
|
+ "\n 'ignore' - don't read or save (can be used to skip loading mapping files referenced in the project file)"
|
||||||
|
)
|
||||||
|
protected UserRenamesMappingsMode userRenamesMappingsMode = UserRenamesMappingsMode.getDefault();
|
||||||
|
|
||||||
@Parameter(names = { "--deobf" }, description = "activate deobfuscation")
|
@Parameter(names = { "--deobf" }, description = "activate deobfuscation")
|
||||||
protected boolean deobfuscationOn = false;
|
protected boolean deobfuscationOn = false;
|
||||||
|
|
||||||
@@ -79,23 +160,101 @@ public class JadxCLIArgs {
|
|||||||
@Parameter(names = { "--deobf-max" }, description = "max length of name, renamed if longer")
|
@Parameter(names = { "--deobf-max" }, description = "max length of name, renamed if longer")
|
||||||
protected int deobfuscationMaxLength = 64;
|
protected int deobfuscationMaxLength = 64;
|
||||||
|
|
||||||
@Parameter(names = { "--deobf-rewrite-cfg" }, description = "force to save deobfuscation map")
|
@Parameter(
|
||||||
protected boolean deobfuscationForceSave = false;
|
names = { "--deobf-whitelist" },
|
||||||
|
description = "space separated list of classes (full name) and packages (ends with '.*') to exclude from deobfuscation"
|
||||||
|
)
|
||||||
|
protected String deobfuscationWhitelistStr = DeobfWhitelist.DEFAULT_STR;
|
||||||
|
|
||||||
@Parameter(names = { "--deobf-use-sourcename" }, description = "use source file name as class name alias")
|
@Parameter(
|
||||||
protected boolean deobfuscationUseSourceNameAsAlias = false;
|
names = { "--deobf-cfg-file" },
|
||||||
|
description = "deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format),"
|
||||||
|
+ " default: same dir and name as input file with '.jobf' extension"
|
||||||
|
)
|
||||||
|
protected String generatedRenamesMappingFile;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--deobf-cfg-file-mode" },
|
||||||
|
description = "set mode for handling the JADX auto-generated names' deobfuscation map file:"
|
||||||
|
+ "\n 'read' - read if found, don't save (default)"
|
||||||
|
+ "\n 'read-or-save' - read if found, save otherwise (don't overwrite)"
|
||||||
|
+ "\n 'overwrite' - don't read, always save"
|
||||||
|
+ "\n 'ignore' - don't read and don't save",
|
||||||
|
converter = DeobfuscationMapFileModeConverter.class
|
||||||
|
)
|
||||||
|
protected GeneratedRenamesMappingFileMode generatedRenamesMappingFileMode = GeneratedRenamesMappingFileMode.getDefault();
|
||||||
|
|
||||||
|
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||||
|
@Parameter(
|
||||||
|
names = { "--deobf-use-sourcename" },
|
||||||
|
description = "use source file name as class name alias."
|
||||||
|
+ "\nDEPRECATED, use \"--use-source-name-as-class-name-alias\" instead",
|
||||||
|
hidden = true
|
||||||
|
)
|
||||||
|
@Deprecated
|
||||||
|
protected Boolean deobfuscationUseSourceNameAsAlias = null;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--deobf-res-name-source" },
|
||||||
|
description = "better name source for resources:"
|
||||||
|
+ "\n 'auto' - automatically select best name (default)"
|
||||||
|
+ "\n 'resources' - use resources names"
|
||||||
|
+ "\n 'code' - use R class fields names",
|
||||||
|
converter = ResourceNameSourceConverter.class
|
||||||
|
)
|
||||||
|
protected ResourceNameSource resourceNameSource = ResourceNameSource.AUTO;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--use-source-name-as-class-name-alias" },
|
||||||
|
description = "use source name as class name alias:"
|
||||||
|
+ "\n 'always' - always use source name if it's available"
|
||||||
|
+ "\n 'if-better' - use source name if it seems better than the current one"
|
||||||
|
+ "\n 'never' - never use source name, even if it's available",
|
||||||
|
converter = UseSourceNameAsClassNameConverter.class
|
||||||
|
)
|
||||||
|
protected UseSourceNameAsClassNameAlias useSourceNameAsClassNameAlias = null;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--source-name-repeat-limit" },
|
||||||
|
description = "allow using source name if it appears less than a limit number"
|
||||||
|
)
|
||||||
|
protected int sourceNameRepeatLimit = 10;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--use-kotlin-methods-for-var-names" },
|
||||||
|
description = "use kotlin intrinsic methods to rename variables, values: disable, apply, apply-and-hide",
|
||||||
|
converter = UseKotlinMethodsForVarNamesConverter.class
|
||||||
|
)
|
||||||
|
protected UseKotlinMethodsForVarNames useKotlinMethodsForVarNames = UseKotlinMethodsForVarNames.APPLY;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--use-headers-for-detect-resource-extensions" },
|
||||||
|
description = "Use headers for detect resource extensions if resource obfuscated"
|
||||||
|
)
|
||||||
|
protected boolean useHeadersForDetectResourceExtensions = false;
|
||||||
|
|
||||||
@Parameter(
|
@Parameter(
|
||||||
names = { "--rename-flags" },
|
names = { "--rename-flags" },
|
||||||
description = "what to rename, comma-separated,"
|
description = "fix options (comma-separated list of):"
|
||||||
+ " 'case' for system case sensitivity,"
|
+ "\n 'case' - fix case sensitivity issues (according to --fs-case-sensitive option),"
|
||||||
+ " 'valid' for java identifiers,"
|
+ "\n 'valid' - rename java identifiers to make them valid,"
|
||||||
+ " 'printable' characters,"
|
+ "\n 'printable' - remove non-printable chars from identifiers,"
|
||||||
+ " 'none' or 'all' (default)",
|
+ "\nor single 'none' - to disable all renames"
|
||||||
|
+ "\nor single 'all' - to enable all (default)",
|
||||||
converter = RenameConverter.class
|
converter = RenameConverter.class
|
||||||
)
|
)
|
||||||
protected Set<RenameEnum> renameFlags = EnumSet.allOf(RenameEnum.class);
|
protected Set<RenameEnum> renameFlags = EnumSet.allOf(RenameEnum.class);
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--integer-format" },
|
||||||
|
description = "how integers are displayed:"
|
||||||
|
+ "\n 'auto' - automatically select (default)"
|
||||||
|
+ "\n 'decimal' - use decimal"
|
||||||
|
+ "\n 'hexadecimal' - use hexadecimal",
|
||||||
|
converter = IntegerFormatConverter.class
|
||||||
|
)
|
||||||
|
protected IntegerFormat integerFormat = IntegerFormat.AUTO;
|
||||||
|
|
||||||
@Parameter(names = { "--fs-case-sensitive" }, description = "treat filesystem as case sensitive, false by default")
|
@Parameter(names = { "--fs-case-sensitive" }, description = "treat filesystem as case sensitive, false by default")
|
||||||
protected boolean fsCaseSensitive = false;
|
protected boolean fsCaseSensitive = false;
|
||||||
|
|
||||||
@@ -105,21 +264,34 @@ public class JadxCLIArgs {
|
|||||||
@Parameter(names = { "--raw-cfg" }, description = "save methods control flow graph (use raw instructions)")
|
@Parameter(names = { "--raw-cfg" }, description = "save methods control flow graph (use raw instructions)")
|
||||||
protected boolean rawCfgOutput = false;
|
protected boolean rawCfgOutput = false;
|
||||||
|
|
||||||
@Parameter(names = { "-f", "--fallback" }, description = "make simple dump (using goto instead of 'if', 'for', etc)")
|
@Parameter(names = { "-f", "--fallback" }, description = "set '--decompilation-mode' to 'fallback' (deprecated)")
|
||||||
protected boolean fallbackMode = false;
|
protected boolean fallbackMode = false;
|
||||||
|
|
||||||
|
@Parameter(names = { "--use-dx" }, description = "use dx/d8 to convert java bytecode")
|
||||||
|
protected boolean useDx = false;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--comments-level" },
|
||||||
|
description = "set code comments level, values: error, warn, info, debug, user-only, none",
|
||||||
|
converter = CommentsLevelConverter.class
|
||||||
|
)
|
||||||
|
protected CommentsLevel commentsLevel = CommentsLevel.INFO;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--log-level" },
|
||||||
|
description = "set log level, values: quiet, progress, error, warn, info, debug",
|
||||||
|
converter = LogLevelConverter.class
|
||||||
|
)
|
||||||
|
protected LogHelper.LogLevelEnum logLevel = LogHelper.LogLevelEnum.PROGRESS;
|
||||||
|
|
||||||
@Parameter(names = { "-v", "--verbose" }, description = "verbose output (set --log-level to DEBUG)")
|
@Parameter(names = { "-v", "--verbose" }, description = "verbose output (set --log-level to DEBUG)")
|
||||||
protected boolean verbose = false;
|
protected boolean verbose = false;
|
||||||
|
|
||||||
@Parameter(names = { "-q", "--quiet" }, description = "turn off output (set --log-level to QUIET)")
|
@Parameter(names = { "-q", "--quiet" }, description = "turn off output (set --log-level to QUIET)")
|
||||||
protected boolean quiet = false;
|
protected boolean quiet = false;
|
||||||
|
|
||||||
@Parameter(
|
@Parameter(names = { "--disable-plugins" }, description = "comma separated list of plugin ids to disable")
|
||||||
names = { "--log-level" },
|
protected String disablePlugins = "";
|
||||||
description = "set log level, values: QUIET, PROGRESS, ERROR, WARN, INFO, DEBUG",
|
|
||||||
converter = LogHelper.LogLevelConverter.class
|
|
||||||
)
|
|
||||||
protected LogHelper.LogLevelEnum logLevel = LogHelper.LogLevelEnum.PROGRESS;
|
|
||||||
|
|
||||||
@Parameter(names = { "--version" }, description = "print jadx version")
|
@Parameter(names = { "--version" }, description = "print jadx version")
|
||||||
protected boolean printVersion = false;
|
protected boolean printVersion = false;
|
||||||
@@ -127,29 +299,18 @@ public class JadxCLIArgs {
|
|||||||
@Parameter(names = { "-h", "--help" }, description = "print this help", help = true)
|
@Parameter(names = { "-h", "--help" }, description = "print this help", help = true)
|
||||||
protected boolean printHelp = false;
|
protected boolean printHelp = false;
|
||||||
|
|
||||||
|
@DynamicParameter(names = "-P", description = "Plugin options", hidden = true)
|
||||||
|
protected Map<String, String> pluginOptions = new HashMap<>();
|
||||||
|
|
||||||
public boolean processArgs(String[] args) {
|
public boolean processArgs(String[] args) {
|
||||||
JCommanderWrapper<JadxCLIArgs> jcw = new JCommanderWrapper<>(this);
|
JCommanderWrapper jcw = new JCommanderWrapper(this);
|
||||||
return jcw.parse(args) && process(jcw);
|
return jcw.parse(args) && process(jcw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public boolean process(JCommanderWrapper jcw) {
|
||||||
* Set values only for options provided in cmd.
|
if (jcw.processCommands()) {
|
||||||
* Used to merge saved options and options passed in command line.
|
|
||||||
*/
|
|
||||||
public boolean overrideProvided(String[] args) {
|
|
||||||
JCommanderWrapper<JadxCLIArgs> jcw = new JCommanderWrapper<>(newInstance());
|
|
||||||
if (!jcw.parse(args)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
jcw.overrideProvided(this);
|
|
||||||
return process(jcw);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected JadxCLIArgs newInstance() {
|
|
||||||
return new JadxCLIArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean process(JCommanderWrapper<JadxCLIArgs> jcw) {
|
|
||||||
if (printHelp) {
|
if (printHelp) {
|
||||||
jcw.printUsage();
|
jcw.printUsage();
|
||||||
return false;
|
return false;
|
||||||
@@ -158,15 +319,13 @@ public class JadxCLIArgs {
|
|||||||
System.out.println(JadxDecompiler.getVersion());
|
System.out.println(JadxDecompiler.getVersion());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
if (threadsCount <= 0) {
|
||||||
if (threadsCount <= 0) {
|
throw new JadxArgsValidateException("Threads count must be positive, got: " + threadsCount);
|
||||||
throw new JadxException("Threads count must be positive, got: " + threadsCount);
|
}
|
||||||
|
for (String fileName : files) {
|
||||||
|
if (fileName.startsWith("-")) {
|
||||||
|
throw new JadxArgsValidateException("Unknown option: " + fileName);
|
||||||
}
|
}
|
||||||
LogHelper.setLogLevelFromArgs(this);
|
|
||||||
} catch (JadxException e) {
|
|
||||||
System.err.println("ERROR: " + e.getMessage());
|
|
||||||
jcw.printUsage();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -180,30 +339,54 @@ public class JadxCLIArgs {
|
|||||||
args.setOutputFormat(JadxArgs.OutputFormatEnum.valueOf(outputFormat.toUpperCase()));
|
args.setOutputFormat(JadxArgs.OutputFormatEnum.valueOf(outputFormat.toUpperCase()));
|
||||||
args.setThreadsCount(threadsCount);
|
args.setThreadsCount(threadsCount);
|
||||||
args.setSkipSources(skipSources);
|
args.setSkipSources(skipSources);
|
||||||
if (singleClass != null) {
|
|
||||||
args.setClassFilter(className -> singleClass.equals(className));
|
|
||||||
}
|
|
||||||
args.setSkipResources(skipResources);
|
args.setSkipResources(skipResources);
|
||||||
args.setFallbackMode(fallbackMode);
|
if (fallbackMode) {
|
||||||
|
args.setDecompilationMode(DecompilationMode.FALLBACK);
|
||||||
|
} else {
|
||||||
|
args.setDecompilationMode(decompilationMode);
|
||||||
|
}
|
||||||
args.setShowInconsistentCode(showInconsistentCode);
|
args.setShowInconsistentCode(showInconsistentCode);
|
||||||
args.setCfgOutput(cfgOutput);
|
args.setCfgOutput(cfgOutput);
|
||||||
args.setRawCFGOutput(rawCfgOutput);
|
args.setRawCFGOutput(rawCfgOutput);
|
||||||
args.setReplaceConsts(replaceConsts);
|
args.setReplaceConsts(replaceConsts);
|
||||||
|
if (userRenamesMappingsPath != null) {
|
||||||
|
args.setUserRenamesMappingsPath(userRenamesMappingsPath);
|
||||||
|
}
|
||||||
|
args.setUserRenamesMappingsMode(userRenamesMappingsMode);
|
||||||
args.setDeobfuscationOn(deobfuscationOn);
|
args.setDeobfuscationOn(deobfuscationOn);
|
||||||
args.setDeobfuscationForceSave(deobfuscationForceSave);
|
args.setGeneratedRenamesMappingFile(FileUtils.toFile(generatedRenamesMappingFile));
|
||||||
|
args.setGeneratedRenamesMappingFileMode(generatedRenamesMappingFileMode);
|
||||||
args.setDeobfuscationMinLength(deobfuscationMinLength);
|
args.setDeobfuscationMinLength(deobfuscationMinLength);
|
||||||
args.setDeobfuscationMaxLength(deobfuscationMaxLength);
|
args.setDeobfuscationMaxLength(deobfuscationMaxLength);
|
||||||
args.setUseSourceNameAsClassAlias(deobfuscationUseSourceNameAsAlias);
|
args.setDeobfuscationWhitelist(Arrays.asList(deobfuscationWhitelistStr.split(" ")));
|
||||||
|
args.setUseSourceNameAsClassNameAlias(getUseSourceNameAsClassNameAlias());
|
||||||
|
args.setUseHeadersForDetectResourceExtensions(useHeadersForDetectResourceExtensions);
|
||||||
|
args.setSourceNameRepeatLimit(sourceNameRepeatLimit);
|
||||||
|
args.setUseKotlinMethodsForVarNames(useKotlinMethodsForVarNames);
|
||||||
|
args.setResourceNameSource(resourceNameSource);
|
||||||
args.setEscapeUnicode(escapeUnicode);
|
args.setEscapeUnicode(escapeUnicode);
|
||||||
args.setRespectBytecodeAccModifiers(respectBytecodeAccessModifiers);
|
args.setRespectBytecodeAccModifiers(respectBytecodeAccessModifiers);
|
||||||
args.setExportAsGradleProject(exportAsGradleProject);
|
args.setExportGradleType(exportGradleType);
|
||||||
|
if (exportAsGradleProject && exportGradleType == null) {
|
||||||
|
args.setExportGradleType(ExportGradleType.AUTO);
|
||||||
|
}
|
||||||
|
args.setSkipXmlPrettyPrint(skipXmlPrettyPrint);
|
||||||
args.setUseImports(useImports);
|
args.setUseImports(useImports);
|
||||||
args.setDebugInfo(debugInfo);
|
args.setDebugInfo(debugInfo);
|
||||||
|
args.setInsertDebugLines(addDebugLines);
|
||||||
args.setInlineAnonymousClasses(inlineAnonymousClasses);
|
args.setInlineAnonymousClasses(inlineAnonymousClasses);
|
||||||
args.setRenameCaseSensitive(isRenameCaseSensitive());
|
args.setInlineMethods(inlineMethods);
|
||||||
args.setRenameValid(isRenameValid());
|
args.setMoveInnerClasses(moveInnerClasses);
|
||||||
args.setRenamePrintable(isRenamePrintable());
|
args.setAllowInlineKotlinLambda(allowInlineKotlinLambda);
|
||||||
|
args.setExtractFinally(extractFinally);
|
||||||
|
args.setRestoreSwitchOverString(restoreSwitchOverString);
|
||||||
|
args.setRenameFlags(renameFlags);
|
||||||
args.setFsCaseSensitive(fsCaseSensitive);
|
args.setFsCaseSensitive(fsCaseSensitive);
|
||||||
|
args.setCommentsLevel(commentsLevel);
|
||||||
|
args.setIntegerFormat(integerFormat);
|
||||||
|
args.setUseDxInput(useDx);
|
||||||
|
args.setPluginOptions(pluginOptions);
|
||||||
|
args.setDisabledPlugins(Arrays.stream(disablePlugins.split(",")).map(String::trim).collect(Collectors.toSet()));
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,6 +394,10 @@ public class JadxCLIArgs {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFiles(List<String> files) {
|
||||||
|
this.files = files;
|
||||||
|
}
|
||||||
|
|
||||||
public String getOutDir() {
|
public String getOutDir() {
|
||||||
return outDir;
|
return outDir;
|
||||||
}
|
}
|
||||||
@@ -223,6 +410,14 @@ public class JadxCLIArgs {
|
|||||||
return outDirRes;
|
return outDirRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSingleClass() {
|
||||||
|
return singleClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSingleClassOutput() {
|
||||||
|
return singleClassOutput;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSkipResources() {
|
public boolean isSkipResources() {
|
||||||
return skipResources;
|
return skipResources;
|
||||||
}
|
}
|
||||||
@@ -239,6 +434,14 @@ public class JadxCLIArgs {
|
|||||||
return fallbackMode;
|
return fallbackMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseDx() {
|
||||||
|
return useDx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecompilationMode getDecompilationMode() {
|
||||||
|
return decompilationMode;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isShowInconsistentCode() {
|
public boolean isShowInconsistentCode() {
|
||||||
return showInconsistentCode;
|
return showInconsistentCode;
|
||||||
}
|
}
|
||||||
@@ -251,10 +454,42 @@ public class JadxCLIArgs {
|
|||||||
return debugInfo;
|
return debugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAddDebugLines() {
|
||||||
|
return addDebugLines;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isInlineAnonymousClasses() {
|
public boolean isInlineAnonymousClasses() {
|
||||||
return inlineAnonymousClasses;
|
return inlineAnonymousClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInlineMethods() {
|
||||||
|
return inlineMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMoveInnerClasses() {
|
||||||
|
return moveInnerClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllowInlineKotlinLambda() {
|
||||||
|
return allowInlineKotlinLambda;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExtractFinally() {
|
||||||
|
return extractFinally;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRestoreSwitchOverString() {
|
||||||
|
return restoreSwitchOverString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getUserRenamesMappingsPath() {
|
||||||
|
return userRenamesMappingsPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRenamesMappingsMode getUserRenamesMappingsMode() {
|
||||||
|
return userRenamesMappingsMode;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDeobfuscationOn() {
|
public boolean isDeobfuscationOn() {
|
||||||
return deobfuscationOn;
|
return deobfuscationOn;
|
||||||
}
|
}
|
||||||
@@ -267,12 +502,51 @@ public class JadxCLIArgs {
|
|||||||
return deobfuscationMaxLength;
|
return deobfuscationMaxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDeobfuscationForceSave() {
|
public String getDeobfuscationWhitelistStr() {
|
||||||
return deobfuscationForceSave;
|
return deobfuscationWhitelistStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getGeneratedRenamesMappingFile() {
|
||||||
|
return generatedRenamesMappingFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedRenamesMappingFileMode getGeneratedRenamesMappingFileMode() {
|
||||||
|
return generatedRenamesMappingFileMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UseSourceNameAsClassNameAlias getUseSourceNameAsClassNameAlias() {
|
||||||
|
if (useSourceNameAsClassNameAlias != null) {
|
||||||
|
return useSourceNameAsClassNameAlias;
|
||||||
|
} else if (deobfuscationUseSourceNameAsAlias != null) {
|
||||||
|
// noinspection deprecation
|
||||||
|
return UseSourceNameAsClassNameAlias.create(deobfuscationUseSourceNameAsAlias);
|
||||||
|
} else {
|
||||||
|
return UseSourceNameAsClassNameAlias.getDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSourceNameRepeatLimit() {
|
||||||
|
return sourceNameRepeatLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #getUseSourceNameAsClassNameAlias()} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean isDeobfuscationUseSourceNameAsAlias() {
|
public boolean isDeobfuscationUseSourceNameAsAlias() {
|
||||||
return deobfuscationUseSourceNameAsAlias;
|
return getUseSourceNameAsClassNameAlias().toBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceNameSource getResourceNameSource() {
|
||||||
|
return resourceNameSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UseKotlinMethodsForVarNames getUseKotlinMethodsForVarNames() {
|
||||||
|
return useKotlinMethodsForVarNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerFormat getIntegerFormat() {
|
||||||
|
return integerFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEscapeUnicode() {
|
public boolean isEscapeUnicode() {
|
||||||
@@ -299,6 +573,10 @@ public class JadxCLIArgs {
|
|||||||
return exportAsGradleProject;
|
return exportAsGradleProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSkipXmlPrettyPrint() {
|
||||||
|
return skipXmlPrettyPrint;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRenameCaseSensitive() {
|
public boolean isRenameCaseSensitive() {
|
||||||
return renameFlags.contains(RenameEnum.CASE);
|
return renameFlags.contains(RenameEnum.CASE);
|
||||||
}
|
}
|
||||||
@@ -315,6 +593,26 @@ public class JadxCLIArgs {
|
|||||||
return fsCaseSensitive;
|
return fsCaseSensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseHeadersForDetectResourceExtensions() {
|
||||||
|
return useHeadersForDetectResourceExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommentsLevel getCommentsLevel() {
|
||||||
|
return commentsLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogHelper.LogLevelEnum getLogLevel() {
|
||||||
|
return logLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getPluginOptions() {
|
||||||
|
return pluginOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisablePlugins() {
|
||||||
|
return disablePlugins;
|
||||||
|
}
|
||||||
|
|
||||||
static class RenameConverter implements IStringConverter<Set<RenameEnum>> {
|
static class RenameConverter implements IStringConverter<Set<RenameEnum>> {
|
||||||
private final String paramName;
|
private final String paramName;
|
||||||
|
|
||||||
@@ -333,9 +631,9 @@ public class JadxCLIArgs {
|
|||||||
Set<RenameEnum> set = EnumSet.noneOf(RenameEnum.class);
|
Set<RenameEnum> set = EnumSet.noneOf(RenameEnum.class);
|
||||||
for (String s : value.split(",")) {
|
for (String s : value.split(",")) {
|
||||||
try {
|
try {
|
||||||
set.add(RenameEnum.valueOf(s.toUpperCase(Locale.ROOT)));
|
set.add(RenameEnum.valueOf(s.trim().toUpperCase(Locale.ROOT)));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalArgumentException(
|
throw new JadxArgsValidateException(
|
||||||
'\'' + s + "' is unknown for parameter " + paramName
|
'\'' + s + "' is unknown for parameter " + paramName
|
||||||
+ ", possible values are " + enumValuesString(RenameEnum.values()));
|
+ ", possible values are " + enumValuesString(RenameEnum.values()));
|
||||||
}
|
}
|
||||||
@@ -344,9 +642,88 @@ public class JadxCLIArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CommentsLevelConverter extends BaseEnumConverter<CommentsLevel> {
|
||||||
|
public CommentsLevelConverter() {
|
||||||
|
super(CommentsLevel::valueOf, CommentsLevel::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UseKotlinMethodsForVarNamesConverter extends BaseEnumConverter<UseKotlinMethodsForVarNames> {
|
||||||
|
public UseKotlinMethodsForVarNamesConverter() {
|
||||||
|
super(UseKotlinMethodsForVarNames::valueOf, UseKotlinMethodsForVarNames::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DeobfuscationMapFileModeConverter extends BaseEnumConverter<GeneratedRenamesMappingFileMode> {
|
||||||
|
public DeobfuscationMapFileModeConverter() {
|
||||||
|
super(GeneratedRenamesMappingFileMode::valueOf, GeneratedRenamesMappingFileMode::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ResourceNameSourceConverter extends BaseEnumConverter<ResourceNameSource> {
|
||||||
|
public ResourceNameSourceConverter() {
|
||||||
|
super(ResourceNameSource::valueOf, ResourceNameSource::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UseSourceNameAsClassNameConverter extends BaseEnumConverter<UseSourceNameAsClassNameAlias> {
|
||||||
|
public UseSourceNameAsClassNameConverter() {
|
||||||
|
super(UseSourceNameAsClassNameAlias::valueOf, UseSourceNameAsClassNameAlias::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DecompilationModeConverter extends BaseEnumConverter<DecompilationMode> {
|
||||||
|
public DecompilationModeConverter() {
|
||||||
|
super(DecompilationMode::valueOf, DecompilationMode::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExportGradleTypeConverter extends BaseEnumConverter<ExportGradleType> {
|
||||||
|
public ExportGradleTypeConverter() {
|
||||||
|
super(ExportGradleType::valueOf, ExportGradleType::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LogLevelConverter extends BaseEnumConverter<LogHelper.LogLevelEnum> {
|
||||||
|
public LogLevelConverter() {
|
||||||
|
super(LogHelper.LogLevelEnum::valueOf, LogHelper.LogLevelEnum::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IntegerFormatConverter extends BaseEnumConverter<IntegerFormat> {
|
||||||
|
public IntegerFormatConverter() {
|
||||||
|
super(IntegerFormat::valueOf, IntegerFormat::values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class BaseEnumConverter<E extends Enum<E>> implements IStringConverter<E> {
|
||||||
|
private final Function<String, E> parse;
|
||||||
|
private final Supplier<E[]> values;
|
||||||
|
|
||||||
|
public BaseEnumConverter(Function<String, E> parse, Supplier<E[]> values) {
|
||||||
|
this.parse = parse;
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E convert(String value) {
|
||||||
|
try {
|
||||||
|
return parse.apply(stringAsEnumName(value));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new JadxArgsValidateException(
|
||||||
|
'\'' + value + "' is unknown, possible values are: " + enumValuesString(values.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String enumValuesString(Enum<?>[] values) {
|
public static String enumValuesString(Enum<?>[] values) {
|
||||||
return Arrays.stream(values)
|
return Stream.of(values)
|
||||||
.map(v -> '\'' + v.name().toLowerCase(Locale.ROOT) + '\'')
|
.map(v -> v.name().replace('_', '-').toLowerCase(Locale.ROOT))
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String stringAsEnumName(String value) {
|
||||||
|
// inverse of enumValuesString conversion
|
||||||
|
return value.replace('-', '_').toUpperCase(Locale.ROOT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.beust.jcommander.JCommander;
|
||||||
|
|
||||||
|
import jadx.cli.commands.CommandPlugins;
|
||||||
|
import jadx.cli.commands.ICommand;
|
||||||
|
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||||
|
|
||||||
|
public class JadxCLICommands {
|
||||||
|
private static final Map<String, ICommand> COMMANDS_MAP = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
JadxCLICommands.register(new CommandPlugins());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(ICommand command) {
|
||||||
|
COMMANDS_MAP.put(command.name(), command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void append(JCommander.Builder builder) {
|
||||||
|
COMMANDS_MAP.forEach(builder::addCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean process(JCommanderWrapper jcw, JCommander jc, String parsedCommand) {
|
||||||
|
ICommand command = COMMANDS_MAP.get(parsedCommand);
|
||||||
|
if (command == null) {
|
||||||
|
throw new JadxArgsValidateException("Unknown command: " + parsedCommand
|
||||||
|
+ ". Expected one of: " + COMMANDS_MAP.keySet());
|
||||||
|
}
|
||||||
|
JCommander subCommander = jc.getCommands().get(parsedCommand);
|
||||||
|
command.process(jcw, subCommander);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package jadx.cli;
|
package jadx.cli;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.beust.jcommander.IStringConverter;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
import ch.qos.logback.classic.Level;
|
||||||
import ch.qos.logback.classic.Logger;
|
import ch.qos.logback.classic.Logger;
|
||||||
|
|
||||||
@@ -31,35 +31,81 @@ public class LogHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setLogLevelFromArgs(JadxCLIArgs args) {
|
@Nullable("For disable log level control")
|
||||||
|
private static LogLevelEnum logLevelValue;
|
||||||
|
|
||||||
|
public static void initLogLevel(JadxCLIArgs args) {
|
||||||
|
logLevelValue = getLogLevelFromArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LogLevelEnum getLogLevelFromArgs(JadxCLIArgs args) {
|
||||||
if (isCustomLogConfig()) {
|
if (isCustomLogConfig()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (args.quiet) {
|
||||||
|
return LogLevelEnum.QUIET;
|
||||||
|
}
|
||||||
|
if (args.verbose) {
|
||||||
|
return LogLevelEnum.DEBUG;
|
||||||
|
}
|
||||||
|
return args.logLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLogLevel(LogLevelEnum newLogLevel) {
|
||||||
|
logLevelValue = newLogLevel;
|
||||||
|
applyLogLevel(logLevelValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLogLevelsForLoadingStage() {
|
||||||
|
if (logLevelValue == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LogLevelEnum logLevel = args.logLevel;
|
if (logLevelValue == LogLevelEnum.PROGRESS) {
|
||||||
if (args.quiet) {
|
// show load errors
|
||||||
logLevel = LogLevelEnum.QUIET;
|
LogHelper.applyLogLevel(LogLevelEnum.ERROR);
|
||||||
} else if (args.verbose) {
|
fixForShowProgress();
|
||||||
logLevel = LogLevelEnum.DEBUG;
|
return;
|
||||||
}
|
}
|
||||||
|
applyLogLevel(logLevelValue);
|
||||||
applyLogLevel(logLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void applyLogLevel(LogLevelEnum logLevel) {
|
public static void setLogLevelsForDecompileStage() {
|
||||||
|
if (logLevelValue == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applyLogLevel(logLevelValue);
|
||||||
|
if (logLevelValue == LogLevelEnum.PROGRESS) {
|
||||||
|
fixForShowProgress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show progress: change to 'INFO' for control classes
|
||||||
|
*/
|
||||||
|
private static void fixForShowProgress() {
|
||||||
|
setLevelForClass(JadxCLI.class, Level.INFO);
|
||||||
|
setLevelForClass(JadxDecompiler.class, Level.INFO);
|
||||||
|
setLevelForClass(SingleClassMode.class, Level.INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyLogLevel(@NotNull LogLevelEnum logLevel) {
|
||||||
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
rootLogger.setLevel(logLevel.getLevel());
|
rootLogger.setLevel(logLevel.getLevel());
|
||||||
|
|
||||||
if (logLevel != LogLevelEnum.QUIET) {
|
|
||||||
// show progress for all levels except quiet
|
|
||||||
setLevelForClass(JadxCLI.class, Level.INFO);
|
|
||||||
setLevelForClass(JadxDecompiler.class, Level.INFO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setLevelForClass(Class<?> cls, Level level) {
|
@Nullable
|
||||||
|
public static LogLevelEnum getLogLevel() {
|
||||||
|
return logLevelValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLevelForClass(Class<?> cls, Level level) {
|
||||||
((Logger) LoggerFactory.getLogger(cls)).setLevel(level);
|
((Logger) LoggerFactory.getLogger(cls)).setLevel(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setLevelForPackage(String pkgName, Level level) {
|
||||||
|
((Logger) LoggerFactory.getLogger(pkgName)).setLevel(level);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to detect if user provide custom logback config via -Dlogback.configurationFile=
|
* Try to detect if user provide custom logback config via -Dlogback.configurationFile=
|
||||||
*/
|
*/
|
||||||
@@ -76,18 +122,4 @@ public class LogHelper {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LogLevelConverter implements IStringConverter<LogLevelEnum> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LogLevelEnum convert(String value) {
|
|
||||||
try {
|
|
||||||
return LogLevelEnum.valueOf(value.toUpperCase());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
'\'' + value + "' is unknown log level, possible values are "
|
|
||||||
+ JadxCLIArgs.enumValuesString(LogLevelEnum.values()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.api.ICodeInfo;
|
||||||
|
import jadx.api.JadxDecompiler;
|
||||||
|
import jadx.core.dex.attributes.AFlag;
|
||||||
|
import jadx.core.dex.nodes.ClassNode;
|
||||||
|
import jadx.core.dex.visitors.SaveCode;
|
||||||
|
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||||
|
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||||
|
import jadx.core.utils.files.FileUtils;
|
||||||
|
|
||||||
|
public class SingleClassMode {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(SingleClassMode.class);
|
||||||
|
|
||||||
|
public static boolean process(JadxDecompiler jadx, JadxCLIArgs cliArgs) {
|
||||||
|
String singleClass = cliArgs.getSingleClass();
|
||||||
|
String singleClassOutput = cliArgs.getSingleClassOutput();
|
||||||
|
if (singleClass == null && singleClassOutput == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ClassNode clsForProcess;
|
||||||
|
if (singleClass != null) {
|
||||||
|
clsForProcess = jadx.getRoot().resolveClass(singleClass);
|
||||||
|
if (clsForProcess == null) {
|
||||||
|
clsForProcess = jadx.getRoot().getClasses().stream()
|
||||||
|
.filter(cls -> cls.getClassInfo().getAliasFullName().equals(singleClass))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
if (clsForProcess == null) {
|
||||||
|
throw new JadxArgsValidateException("Input class not found: " + singleClass);
|
||||||
|
}
|
||||||
|
if (clsForProcess.contains(AFlag.DONT_GENERATE)) {
|
||||||
|
throw new JadxArgsValidateException("Input class can't be saved by current jadx settings (marked as DONT_GENERATE)");
|
||||||
|
}
|
||||||
|
if (clsForProcess.isInner()) {
|
||||||
|
clsForProcess = clsForProcess.getTopParentClass();
|
||||||
|
LOG.warn("Input class is inner, parent class will be saved: {}", clsForProcess.getFullName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// singleClassOutput is set
|
||||||
|
// expect only one class to be loaded
|
||||||
|
List<ClassNode> classes = jadx.getRoot().getClasses().stream()
|
||||||
|
.filter(c -> !c.isInner() && !c.contains(AFlag.DONT_GENERATE))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
int size = classes.size();
|
||||||
|
if (size == 1) {
|
||||||
|
clsForProcess = classes.get(0);
|
||||||
|
} else {
|
||||||
|
throw new JadxArgsValidateException("Found " + size + " classes, single class output can't be used");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ICodeInfo codeInfo;
|
||||||
|
try {
|
||||||
|
codeInfo = clsForProcess.decompile();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new JadxRuntimeException("Class decompilation failed", e);
|
||||||
|
}
|
||||||
|
String fileExt = SaveCode.getFileExtension(jadx.getRoot());
|
||||||
|
File out;
|
||||||
|
if (singleClassOutput == null) {
|
||||||
|
out = new File(jadx.getArgs().getOutDirSrc(), clsForProcess.getClassInfo().getAliasFullPath() + fileExt);
|
||||||
|
} else {
|
||||||
|
if (singleClassOutput.endsWith(fileExt)) {
|
||||||
|
// treat as file name
|
||||||
|
out = new File(singleClassOutput);
|
||||||
|
} else {
|
||||||
|
// treat as directory
|
||||||
|
out = new File(singleClassOutput, clsForProcess.getShortName() + fileExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File resultOut = FileUtils.prepareFile(out);
|
||||||
|
if (clsForProcess.getClassInfo().hasAlias()) {
|
||||||
|
LOG.info("Saving class '{}' (alias: '{}') to file '{}'",
|
||||||
|
clsForProcess.getClassInfo().getFullName(), clsForProcess.getFullName(), resultOut.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
LOG.info("Saving class '{}' to file '{}'", clsForProcess.getFullName(), resultOut.getAbsolutePath());
|
||||||
|
}
|
||||||
|
SaveCode.save(codeInfo.getCodeStr(), resultOut);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package jadx.cli.clst;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.api.JadxArgs;
|
||||||
|
import jadx.api.JadxDecompiler;
|
||||||
|
import jadx.api.args.UseSourceNameAsClassNameAlias;
|
||||||
|
import jadx.core.clsp.ClsSet;
|
||||||
|
import jadx.core.dex.nodes.RootNode;
|
||||||
|
import jadx.core.utils.files.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for convert dex or jar to jadx classes set (.jcst)
|
||||||
|
*/
|
||||||
|
public class ConvertToClsSet {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ConvertToClsSet.class);
|
||||||
|
|
||||||
|
public static void usage() {
|
||||||
|
LOG.info("<android API level (number)> <output .jcst file> <several input dex or jar files> ");
|
||||||
|
LOG.info("Arguments to update core.jcst: "
|
||||||
|
+ "<android API level (number)> "
|
||||||
|
+ "<jadx root>/jadx-core/src/main/resources/clst/core.jcst "
|
||||||
|
+ "<sdk_root>/platforms/android-<api level>/android.jar"
|
||||||
|
+ "<sdk_root>/platforms/android-<api level>/optional/android.car.jar "
|
||||||
|
+ "<sdk_root>/platforms/android-<api level>/optional/org.apache.http.legacy.jar");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (args.length != 5) {
|
||||||
|
usage();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
int androidApiLevel = Integer.parseInt(args[0]);
|
||||||
|
List<Path> inputPaths = Stream.of(args).skip(1).map(Paths::get).collect(Collectors.toList());
|
||||||
|
Path output = inputPaths.remove(0);
|
||||||
|
|
||||||
|
JadxArgs jadxArgs = new JadxArgs();
|
||||||
|
jadxArgs.setInputFiles(FileUtils.toFiles(inputPaths));
|
||||||
|
|
||||||
|
// disable not needed passes executed at prepare stage
|
||||||
|
jadxArgs.setDeobfuscationOn(false);
|
||||||
|
jadxArgs.setRenameFlags(EnumSet.noneOf(JadxArgs.RenameEnum.class));
|
||||||
|
jadxArgs.setUseSourceNameAsClassNameAlias(UseSourceNameAsClassNameAlias.NEVER);
|
||||||
|
jadxArgs.setMoveInnerClasses(false);
|
||||||
|
jadxArgs.setInlineAnonymousClasses(false);
|
||||||
|
jadxArgs.setInlineMethods(false);
|
||||||
|
|
||||||
|
// don't require/load class set file
|
||||||
|
jadxArgs.setLoadJadxClsSetFile(false);
|
||||||
|
|
||||||
|
try (JadxDecompiler decompiler = new JadxDecompiler(jadxArgs)) {
|
||||||
|
decompiler.load();
|
||||||
|
RootNode root = decompiler.getRoot();
|
||||||
|
ClsSet set = new ClsSet(root);
|
||||||
|
set.setAndroidApiLevel(androidApiLevel);
|
||||||
|
set.loadFrom(root);
|
||||||
|
set.save(output);
|
||||||
|
|
||||||
|
LOG.info("Output: {}", output);
|
||||||
|
LOG.info("done");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Failed with error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package jadx.cli.commands;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.beust.jcommander.JCommander;
|
||||||
|
import com.beust.jcommander.Parameter;
|
||||||
|
import com.beust.jcommander.Parameters;
|
||||||
|
|
||||||
|
import jadx.api.plugins.JadxPluginInfo;
|
||||||
|
import jadx.cli.JCommanderWrapper;
|
||||||
|
import jadx.cli.LogHelper;
|
||||||
|
import jadx.core.utils.StringUtils;
|
||||||
|
import jadx.plugins.tools.JadxPluginsList;
|
||||||
|
import jadx.plugins.tools.JadxPluginsTools;
|
||||||
|
import jadx.plugins.tools.data.JadxPluginMetadata;
|
||||||
|
import jadx.plugins.tools.data.JadxPluginUpdate;
|
||||||
|
|
||||||
|
@Parameters(commandDescription = "manage jadx plugins")
|
||||||
|
public class CommandPlugins implements ICommand {
|
||||||
|
|
||||||
|
@Parameter(names = { "-i", "--install" }, description = "install plugin with locationId", defaultValueDescription = "<locationId>")
|
||||||
|
protected String install;
|
||||||
|
|
||||||
|
@Parameter(names = { "-j", "--install-jar" }, description = "install plugin from jar file", defaultValueDescription = "<path-to.jar>")
|
||||||
|
protected String installJar;
|
||||||
|
|
||||||
|
@Parameter(names = { "-l", "--list" }, description = "list installed plugins")
|
||||||
|
protected boolean list;
|
||||||
|
|
||||||
|
@Parameter(names = { "-a", "--available" }, description = "list available plugins from jadx-plugins-list (aka marketplace)")
|
||||||
|
protected boolean available;
|
||||||
|
|
||||||
|
@Parameter(names = { "-u", "--update" }, description = "update installed plugins")
|
||||||
|
protected boolean update;
|
||||||
|
|
||||||
|
@Parameter(names = { "--uninstall" }, description = "uninstall plugin with pluginId", defaultValueDescription = "<pluginId>")
|
||||||
|
protected String uninstall;
|
||||||
|
|
||||||
|
@Parameter(names = { "--disable" }, description = "disable plugin with pluginId", defaultValueDescription = "<pluginId>")
|
||||||
|
protected String disable;
|
||||||
|
|
||||||
|
@Parameter(names = { "--enable" }, description = "enable plugin with pluginId", defaultValueDescription = "<pluginId>")
|
||||||
|
protected String enable;
|
||||||
|
|
||||||
|
@Parameter(names = { "--list-all" }, description = "list all plugins including bundled and dropins")
|
||||||
|
protected boolean listAll;
|
||||||
|
|
||||||
|
@Parameter(
|
||||||
|
names = { "--list-versions" },
|
||||||
|
description = "fetch latest versions of plugin from locationId (will download all artefacts, limited to 10)",
|
||||||
|
defaultValueDescription = "<locationId>"
|
||||||
|
)
|
||||||
|
protected String listVersions;
|
||||||
|
|
||||||
|
@Parameter(names = { "-h", "--help" }, description = "print this help", help = true)
|
||||||
|
protected boolean printHelp = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "plugins";
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnnecessaryReturnStatement")
|
||||||
|
@Override
|
||||||
|
public void process(JCommanderWrapper jcw, JCommander subCommander) {
|
||||||
|
if (printHelp) {
|
||||||
|
jcw.printUsage(subCommander);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> unknownOptions = new HashSet<>(subCommander.getUnknownOptions());
|
||||||
|
boolean verbose = unknownOptions.remove("-v") || unknownOptions.remove("--verbose");
|
||||||
|
LogHelper.setLogLevel(verbose ? LogHelper.LogLevelEnum.DEBUG : LogHelper.LogLevelEnum.INFO);
|
||||||
|
|
||||||
|
if (!unknownOptions.isEmpty()) {
|
||||||
|
System.out.println("Error: found unknown options: " + unknownOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (install != null) {
|
||||||
|
installPlugin(install);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (installJar != null) {
|
||||||
|
installPlugin("file:" + installJar);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (uninstall != null) {
|
||||||
|
boolean uninstalled = JadxPluginsTools.getInstance().uninstall(uninstall);
|
||||||
|
System.out.println(uninstalled ? "Uninstalled" : "Plugin not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
|
List<JadxPluginUpdate> updates = JadxPluginsTools.getInstance().updateAll();
|
||||||
|
if (updates.isEmpty()) {
|
||||||
|
System.out.println("No updates");
|
||||||
|
} else {
|
||||||
|
System.out.println("Installed updates: " + updates.size());
|
||||||
|
for (JadxPluginUpdate update : updates) {
|
||||||
|
System.out.println(" " + update.getPluginId() + ": " + update.getOldVersion() + " -> " + update.getNewVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (list) {
|
||||||
|
printPlugins(JadxPluginsTools.getInstance().getInstalled());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (listAll) {
|
||||||
|
printAllPlugins();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (listVersions != null) {
|
||||||
|
printVersions(listVersions, 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (available) {
|
||||||
|
List<JadxPluginMetadata> availableList = JadxPluginsList.getInstance().get();
|
||||||
|
System.out.println("Available plugins: " + availableList.size());
|
||||||
|
for (JadxPluginMetadata plugin : availableList) {
|
||||||
|
System.out.println(" - " + plugin.getName() + ": " + plugin.getDescription()
|
||||||
|
+ " (" + plugin.getLocationId() + ")");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disable != null) {
|
||||||
|
if (JadxPluginsTools.getInstance().changeDisabledStatus(disable, true)) {
|
||||||
|
System.out.println("Plugin '" + disable + "' disabled.");
|
||||||
|
} else {
|
||||||
|
System.out.println("Plugin '" + disable + "' already disabled.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (enable != null) {
|
||||||
|
if (JadxPluginsTools.getInstance().changeDisabledStatus(enable, false)) {
|
||||||
|
System.out.println("Plugin '" + enable + "' enabled.");
|
||||||
|
} else {
|
||||||
|
System.out.println("Plugin '" + enable + "' already enabled.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printPlugins(List<JadxPluginMetadata> installed) {
|
||||||
|
System.out.println("Installed plugins: " + installed.size());
|
||||||
|
for (JadxPluginMetadata plugin : installed) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(" - ").append(plugin.getPluginId());
|
||||||
|
String version = plugin.getVersion();
|
||||||
|
if (version != null) {
|
||||||
|
sb.append(" (").append(version).append(')');
|
||||||
|
}
|
||||||
|
if (plugin.isDisabled()) {
|
||||||
|
sb.append(" (disabled)");
|
||||||
|
}
|
||||||
|
sb.append(" - ").append(plugin.getName());
|
||||||
|
sb.append(": ").append(formatDescription(plugin.getDescription()));
|
||||||
|
System.out.println(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printVersions(String locationId, int limit) {
|
||||||
|
System.out.println("Loading ...");
|
||||||
|
List<JadxPluginMetadata> versions = JadxPluginsTools.getInstance().getVersionsByLocation(locationId, 1, limit);
|
||||||
|
if (versions.isEmpty()) {
|
||||||
|
System.out.println("No versions found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JadxPluginMetadata plugin = versions.get(0);
|
||||||
|
System.out.println("Versions for plugin id: " + plugin.getPluginId());
|
||||||
|
for (JadxPluginMetadata version : versions) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(" - ").append(version.getVersion());
|
||||||
|
String reqVer = version.getRequiredJadxVersion();
|
||||||
|
if (StringUtils.notBlank(reqVer)) {
|
||||||
|
sb.append(", require jadx: ").append(reqVer);
|
||||||
|
}
|
||||||
|
System.out.println(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printAllPlugins() {
|
||||||
|
List<JadxPluginMetadata> installed = JadxPluginsTools.getInstance().getInstalled();
|
||||||
|
printPlugins(installed);
|
||||||
|
Set<String> installedSet = installed.stream().map(JadxPluginMetadata::getPluginId).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
List<JadxPluginInfo> plugins = JadxPluginsTools.getInstance().getAllPluginsInfo();
|
||||||
|
System.out.println("Other plugins: " + plugins.size());
|
||||||
|
for (JadxPluginInfo plugin : plugins) {
|
||||||
|
if (!installedSet.contains(plugin.getPluginId())) {
|
||||||
|
System.out.println(" - " + plugin.getPluginId()
|
||||||
|
+ " - " + plugin.getName()
|
||||||
|
+ ": " + formatDescription(plugin.getDescription()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatDescription(String desc) {
|
||||||
|
if (desc.contains("\n")) {
|
||||||
|
// remove new lines
|
||||||
|
desc = desc.replaceAll("\\R+", " ");
|
||||||
|
}
|
||||||
|
int maxLen = 512;
|
||||||
|
if (desc.length() > maxLen) {
|
||||||
|
// truncate very long descriptions
|
||||||
|
desc = desc.substring(0, maxLen) + " ...";
|
||||||
|
}
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installPlugin(String locationId) {
|
||||||
|
JadxPluginMetadata plugin = JadxPluginsTools.getInstance().install(locationId);
|
||||||
|
System.out.println("Plugin installed: " + plugin.getPluginId() + ":" + plugin.getVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package jadx.cli.commands;
|
||||||
|
|
||||||
|
import com.beust.jcommander.JCommander;
|
||||||
|
|
||||||
|
import jadx.cli.JCommanderWrapper;
|
||||||
|
|
||||||
|
public interface ICommand {
|
||||||
|
String name();
|
||||||
|
|
||||||
|
void process(JCommanderWrapper jcw, JCommander subCommander);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package jadx.cli.plugins;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import jadx.commons.app.JadxCommonFiles;
|
||||||
|
import jadx.commons.app.JadxTempFiles;
|
||||||
|
import jadx.core.plugins.files.IJadxFilesGetter;
|
||||||
|
|
||||||
|
public class JadxFilesGetter implements IJadxFilesGetter {
|
||||||
|
|
||||||
|
public static final JadxFilesGetter INSTANCE = new JadxFilesGetter();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getConfigDir() {
|
||||||
|
return JadxCommonFiles.getConfigDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getCacheDir() {
|
||||||
|
return JadxCommonFiles.getCacheDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getTempDir() {
|
||||||
|
return JadxTempFiles.getTempRootDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JadxFilesGetter() {
|
||||||
|
// singleton
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package jadx.cli.tools;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.api.JadxArgs;
|
||||||
|
import jadx.core.dex.nodes.RootNode;
|
||||||
|
import jadx.core.utils.android.TextResMapFile;
|
||||||
|
import jadx.core.xmlgen.ResTableBinaryParser;
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
import jadx.zip.ZipContent;
|
||||||
|
import jadx.zip.ZipReader;
|
||||||
|
|
||||||
|
import static jadx.core.utils.files.FileUtils.expandDirs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for convert '.arsc' to simple text file with mapping id to resource name
|
||||||
|
*/
|
||||||
|
public class ConvertArscFile {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ConvertArscFile.class);
|
||||||
|
private static int rewritesCount;
|
||||||
|
|
||||||
|
public static void usage() {
|
||||||
|
LOG.info("<res-map file> <input .arsc/android.jar files or dir>");
|
||||||
|
LOG.info("");
|
||||||
|
LOG.info("Note: If res-map already exists - it will be merged and updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
if (args.length < 2) {
|
||||||
|
usage();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
List<Path> inputPaths = Stream.of(args).map(Paths::get).collect(Collectors.toList());
|
||||||
|
Path resMapFile = inputPaths.remove(0);
|
||||||
|
List<Path> inputResFiles = filterAndSort(expandDirs(inputPaths));
|
||||||
|
Map<Integer, String> resMap;
|
||||||
|
if (Files.isReadable(resMapFile)) {
|
||||||
|
resMap = TextResMapFile.read(resMapFile);
|
||||||
|
} else {
|
||||||
|
resMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
LOG.info("Input entries count: {}", resMap.size());
|
||||||
|
|
||||||
|
RootNode root = new RootNode(new JadxArgs()); // not really needed
|
||||||
|
ZipReader zipReader = new ZipReader();
|
||||||
|
rewritesCount = 0;
|
||||||
|
for (Path resFile : inputResFiles) {
|
||||||
|
ResTableBinaryParser resTableParser = new ResTableBinaryParser(root, true);
|
||||||
|
if (resFile.getFileName().toString().endsWith(".jar")) {
|
||||||
|
// Load resources.arsc from android.jar
|
||||||
|
try (ZipContent zip = zipReader.open(resFile.toFile())) {
|
||||||
|
IZipEntry entry = zip.searchEntry("resources.arsc");
|
||||||
|
if (entry == null) {
|
||||||
|
LOG.error("Failed to load \"resources.arsc\" from {}", resFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (InputStream inputStream = entry.getInputStream()) {
|
||||||
|
resTableParser.decode(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Load resources.arsc from extracted file
|
||||||
|
try (InputStream inputStream = Files.newInputStream(resFile)) {
|
||||||
|
resTableParser.decode(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<Integer, String> singleResMap = resTableParser.getResStorage().getResourcesNames();
|
||||||
|
mergeResMaps(resMap, singleResMap);
|
||||||
|
LOG.info("{} entries count: {}, after merge: {}", resFile.getFileName(), singleResMap.size(), resMap.size());
|
||||||
|
}
|
||||||
|
LOG.info("Output entries count: {}", resMap.size());
|
||||||
|
LOG.info("Total rewrites count: {}", rewritesCount);
|
||||||
|
TextResMapFile.write(resMapFile, resMap);
|
||||||
|
LOG.info("Result file size: {} B", resMapFile.toFile().length());
|
||||||
|
LOG.info("done");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Path> filterAndSort(List<Path> inputPaths) {
|
||||||
|
return inputPaths.stream()
|
||||||
|
.filter(p -> {
|
||||||
|
String fileName = p.getFileName().toString();
|
||||||
|
return fileName.endsWith(".arsc") || fileName.endsWith(".jar");
|
||||||
|
})
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mergeResMaps(Map<Integer, String> mainResMap, Map<Integer, String> newResMap) {
|
||||||
|
for (Map.Entry<Integer, String> entry : newResMap.entrySet()) {
|
||||||
|
Integer id = entry.getKey();
|
||||||
|
String name = entry.getValue();
|
||||||
|
String prevName = mainResMap.put(id, name);
|
||||||
|
if (prevName != null && !name.equals(prevName)) {
|
||||||
|
LOG.debug("Rewrite id: {} from: '{}' to: '{}'", Integer.toHexString(id), prevName, name);
|
||||||
|
rewritesCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
<!-- Jadx logger config. Used both in cli and gui -->
|
||||||
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<encoder>
|
<encoder>
|
||||||
@@ -5,6 +7,9 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- jadx-gui -->
|
||||||
|
<logger name="com.pinterest.ktlint" level="INFO"/>
|
||||||
|
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.LinkOption;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.api.plugins.loader.JadxBasePluginLoader;
|
||||||
|
import jadx.core.plugins.files.SingleDirFilesGetter;
|
||||||
|
import jadx.core.utils.Utils;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.fail;
|
||||||
|
|
||||||
|
public class BaseCliIntegrationTest {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(BaseCliIntegrationTest.class);
|
||||||
|
|
||||||
|
static final PathMatcher LOG_ALL_FILES = path -> {
|
||||||
|
LOG.debug("File in result dir: {}", path);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
Path testDir;
|
||||||
|
|
||||||
|
Path outputDir;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
outputDir = testDir.resolve("output");
|
||||||
|
}
|
||||||
|
|
||||||
|
int execJadxCli(String sampleName, String... options) {
|
||||||
|
return execJadxCli(buildArgs(List.of(options), sampleName));
|
||||||
|
}
|
||||||
|
|
||||||
|
int execJadxCli(String[] args) {
|
||||||
|
return JadxCLI.execute(args, jadxArgs -> {
|
||||||
|
// don't use global config and plugins
|
||||||
|
jadxArgs.setFilesGetter(new SingleDirFilesGetter(testDir));
|
||||||
|
jadxArgs.setPluginLoader(new JadxBasePluginLoader());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] buildArgs(List<String> options, String... inputSamples) {
|
||||||
|
List<String> args = new ArrayList<>(options);
|
||||||
|
args.add("-v");
|
||||||
|
args.add("-d");
|
||||||
|
args.add(outputDir.toAbsolutePath().toString());
|
||||||
|
|
||||||
|
for (String inputSample : inputSamples) {
|
||||||
|
try {
|
||||||
|
URL resource = getClass().getClassLoader().getResource(inputSample);
|
||||||
|
assertThat(resource).isNotNull();
|
||||||
|
String sampleFile = resource.toURI().getRawPath();
|
||||||
|
args.add(sampleFile);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
fail("Failed to load sample: " + inputSample, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decompile(String... inputSamples) throws IOException {
|
||||||
|
int result = execJadxCli(buildArgs(List.of(), inputSamples));
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
List<Path> resultJavaFiles = collectJavaFilesInDir(outputDir);
|
||||||
|
assertThat(resultJavaFiles).isNotEmpty();
|
||||||
|
|
||||||
|
// do not copy input files as resources
|
||||||
|
for (Path path : collectFilesInDir(outputDir, LOG_ALL_FILES)) {
|
||||||
|
for (String inputSample : inputSamples) {
|
||||||
|
assertThat(path.toAbsolutePath().toString()).doesNotContain(inputSample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printFiles(List<Path> files) {
|
||||||
|
LOG.info("Output files (count: {}):", files.size());
|
||||||
|
for (Path file : files) {
|
||||||
|
LOG.info(" {}", file);
|
||||||
|
}
|
||||||
|
LOG.info("");
|
||||||
|
}
|
||||||
|
|
||||||
|
String pathToUniformString(Path path) {
|
||||||
|
return path.toString().replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
Path printFileContent(Path file) {
|
||||||
|
try {
|
||||||
|
String content = Files.readString(outputDir.resolve(file));
|
||||||
|
String spacer = Utils.strRepeat("=", 70);
|
||||||
|
LOG.info("File content: {}\n{}\n{}\n{}", file, spacer, content, spacer);
|
||||||
|
return file;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to load file: " + file, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Path> collectJavaFilesInDir(Path dir) throws IOException {
|
||||||
|
PathMatcher javaMatcher = dir.getFileSystem().getPathMatcher("glob:**.java");
|
||||||
|
return collectFilesInDir(dir, javaMatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Path> collectAllFilesInDir(Path dir) throws IOException {
|
||||||
|
try (Stream<Path> pathStream = Files.walk(dir)) {
|
||||||
|
List<Path> files = pathStream
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.map(dir::relativize)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
printFiles(files);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Path> collectFilesInDir(Path dir, PathMatcher matcher) throws IOException {
|
||||||
|
try (Stream<Path> pathStream = Files.walk(dir)) {
|
||||||
|
List<Path> files = pathStream
|
||||||
|
.filter(p -> Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS))
|
||||||
|
.filter(matcher::matches)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
printFiles(files);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package jadx.cli;
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static jadx.core.utils.Utils.newConstStringMap;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
public class JadxCLIArgsTest {
|
public class JadxCLIArgsTest {
|
||||||
|
|
||||||
@@ -13,38 +16,72 @@ public class JadxCLIArgsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvertedBooleanOption() {
|
public void testInvertedBooleanOption() {
|
||||||
assertThat(parse("--no-replace-consts").isReplaceConsts(), is(false));
|
assertThat(parse("--no-replace-consts").isReplaceConsts()).isFalse();
|
||||||
assertThat(parse("").isReplaceConsts(), is(true));
|
assertThat(parse("").isReplaceConsts()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEscapeUnicodeOption() {
|
public void testEscapeUnicodeOption() {
|
||||||
assertThat(parse("--escape-unicode").isEscapeUnicode(), is(true));
|
assertThat(parse("--escape-unicode").isEscapeUnicode()).isTrue();
|
||||||
assertThat(parse("").isEscapeUnicode(), is(false));
|
assertThat(parse("").isEscapeUnicode()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSrcOption() {
|
public void testSrcOption() {
|
||||||
assertThat(parse("--no-src").isSkipSources(), is(true));
|
assertThat(parse("--no-src").isSkipSources()).isTrue();
|
||||||
assertThat(parse("-s").isSkipSources(), is(true));
|
assertThat(parse("-s").isSkipSources()).isTrue();
|
||||||
assertThat(parse("").isSkipSources(), is(false));
|
assertThat(parse("").isSkipSources()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOptionsOverride() {
|
public void testOptionsOverride() {
|
||||||
assertThat(override(new JadxCLIArgs(), "--no-imports").isUseImports(), is(false));
|
assertThat(override(new JadxCLIArgs(), "--no-imports").isUseImports()).isFalse();
|
||||||
assertThat(override(new JadxCLIArgs(), "--no-debug-info").isDebugInfo(), is(false));
|
assertThat(override(new JadxCLIArgs(), "--no-debug-info").isDebugInfo()).isFalse();
|
||||||
assertThat(override(new JadxCLIArgs(), "").isUseImports(), is(true));
|
assertThat(override(new JadxCLIArgs(), "").isUseImports()).isTrue();
|
||||||
|
|
||||||
JadxCLIArgs args = new JadxCLIArgs();
|
JadxCLIArgs args = new JadxCLIArgs();
|
||||||
args.useImports = false;
|
args.useImports = false;
|
||||||
assertThat(override(args, "--no-imports").isUseImports(), is(false));
|
assertThat(override(args, "--no-imports").isUseImports()).isFalse();
|
||||||
args.debugInfo = false;
|
args.debugInfo = false;
|
||||||
assertThat(override(args, "--no-debug-info").isDebugInfo(), is(false));
|
assertThat(override(args, "--no-debug-info").isDebugInfo()).isFalse();
|
||||||
|
|
||||||
args = new JadxCLIArgs();
|
args = new JadxCLIArgs();
|
||||||
args.useImports = false;
|
args.useImports = false;
|
||||||
assertThat(override(args, "").isUseImports(), is(false));
|
assertThat(override(args, "").isUseImports()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPluginOptionsOverride() {
|
||||||
|
// add key to empty base map
|
||||||
|
checkPluginOptionsMerge(
|
||||||
|
Collections.emptyMap(),
|
||||||
|
"-Poption=otherValue",
|
||||||
|
newConstStringMap("option", "otherValue"));
|
||||||
|
|
||||||
|
// override one key
|
||||||
|
checkPluginOptionsMerge(
|
||||||
|
newConstStringMap("option", "value"),
|
||||||
|
"-Poption=otherValue",
|
||||||
|
newConstStringMap("option", "otherValue"));
|
||||||
|
|
||||||
|
// merge different keys
|
||||||
|
checkPluginOptionsMerge(
|
||||||
|
Collections.singletonMap("option1", "value1"),
|
||||||
|
"-Poption2=otherValue2",
|
||||||
|
newConstStringMap("option1", "value1", "option2", "otherValue2"));
|
||||||
|
|
||||||
|
// merge and override
|
||||||
|
checkPluginOptionsMerge(
|
||||||
|
newConstStringMap("option1", "value1", "option2", "value2"),
|
||||||
|
"-Poption2=otherValue2",
|
||||||
|
newConstStringMap("option1", "value1", "option2", "otherValue2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPluginOptionsMerge(Map<String, String> baseMap, String providedArgs, Map<String, String> expectedMap) {
|
||||||
|
JadxCLIArgs args = new JadxCLIArgs();
|
||||||
|
args.pluginOptions = baseMap;
|
||||||
|
Map<String, String> resultMap = override(args, providedArgs).getPluginOptions();
|
||||||
|
assertThat(resultMap).isEqualTo(expectedMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JadxCLIArgs parse(String... args) {
|
private JadxCLIArgs parse(String... args) {
|
||||||
@@ -52,15 +89,24 @@ public class JadxCLIArgsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JadxCLIArgs parse(JadxCLIArgs jadxArgs, String... args) {
|
private JadxCLIArgs parse(JadxCLIArgs jadxArgs, String... args) {
|
||||||
boolean res = jadxArgs.processArgs(args);
|
return check(jadxArgs, jadxArgs.processArgs(args));
|
||||||
assertThat(res, is(true));
|
|
||||||
LOG.info("Jadx args: {}", jadxArgs.toJadxArgs());
|
|
||||||
return jadxArgs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JadxCLIArgs override(JadxCLIArgs jadxArgs, String... args) {
|
private JadxCLIArgs override(JadxCLIArgs jadxArgs, String... args) {
|
||||||
boolean res = jadxArgs.overrideProvided(args);
|
return check(jadxArgs, overrideProvided(jadxArgs, args));
|
||||||
assertThat(res, is(true));
|
}
|
||||||
|
|
||||||
|
private static boolean overrideProvided(JadxCLIArgs jadxArgs, String[] args) {
|
||||||
|
JCommanderWrapper jcw = new JCommanderWrapper(new JadxCLIArgs());
|
||||||
|
if (!jcw.parse(args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
jcw.overrideProvided(jadxArgs);
|
||||||
|
return jadxArgs.process(jcw);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JadxCLIArgs check(JadxCLIArgs jadxArgs, boolean res) {
|
||||||
|
assertThat(res).isTrue();
|
||||||
LOG.info("Jadx args: {}", jadxArgs.toJadxArgs());
|
LOG.info("Jadx args: {}", jadxArgs.toJadxArgs());
|
||||||
return jadxArgs;
|
return jadxArgs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
import jadx.api.JadxArgs.RenameEnum;
|
import jadx.api.JadxArgs.RenameEnum;
|
||||||
import jadx.cli.JadxCLIArgs.RenameConverter;
|
import jadx.cli.JadxCLIArgs.RenameConverter;
|
||||||
|
import jadx.core.utils.exceptions.JadxArgsValidateException;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
public class RenameConverterTest {
|
public class RenameConverterTest {
|
||||||
|
|
||||||
@@ -24,26 +24,24 @@ public class RenameConverterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void all() {
|
public void all() {
|
||||||
Set<RenameEnum> set = converter.convert("all");
|
Set<RenameEnum> set = converter.convert("all");
|
||||||
assertEquals(3, set.size());
|
assertThat(set).hasSize(3);
|
||||||
assertTrue(set.contains(RenameEnum.CASE));
|
assertThat(set).contains(RenameEnum.CASE);
|
||||||
assertTrue(set.contains(RenameEnum.VALID));
|
assertThat(set).contains(RenameEnum.VALID);
|
||||||
assertTrue(set.contains(RenameEnum.PRINTABLE));
|
assertThat(set).contains(RenameEnum.PRINTABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void none() {
|
public void none() {
|
||||||
Set<RenameEnum> set = converter.convert("none");
|
Set<RenameEnum> set = converter.convert("none");
|
||||||
assertTrue(set.isEmpty());
|
assertThat(set).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void wrong() {
|
public void wrong() {
|
||||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
|
JadxArgsValidateException thrown = assertThrows(JadxArgsValidateException.class,
|
||||||
() -> converter.convert("wrong"),
|
() -> converter.convert("wrong"),
|
||||||
"Expected convert() to throw, but it didn't");
|
"Expected convert() to throw, but it didn't");
|
||||||
|
|
||||||
assertEquals("'wrong' is unknown for parameter someParam, "
|
assertThat(thrown.getMessage()).isEqualTo("'wrong' is unknown for parameter someParam, possible values are case, valid, printable");
|
||||||
+ "possible values are 'case', 'valid', 'printable'",
|
|
||||||
thrown.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package jadx.cli;
|
||||||
|
|
||||||
|
import org.assertj.core.api.Condition;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class TestExport extends BaseCliIntegrationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicExport() throws Exception {
|
||||||
|
int result = execJadxCli("samples/small.apk");
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
assertThat(collectAllFilesInDir(outputDir))
|
||||||
|
.map(this::pathToUniformString)
|
||||||
|
.haveExactly(2, new Condition<>(f -> f.startsWith("sources/") && f.endsWith(".java"), "sources"))
|
||||||
|
.haveExactly(10, new Condition<>(f -> f.startsWith("resources/"), "resources"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("resources/AndroidManifest.xml"), "manifest"))
|
||||||
|
.hasSize(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGradleExportApk() throws Exception {
|
||||||
|
int result = execJadxCli("samples/small.apk", "--export-gradle");
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
assertThat(collectAllFilesInDir(outputDir))
|
||||||
|
.describedAs("check output files")
|
||||||
|
.map(this::pathToUniformString)
|
||||||
|
.haveExactly(2, new Condition<>(f -> f.endsWith(".java"), "java classes"))
|
||||||
|
.haveExactly(0, new Condition<>(f -> f.endsWith("classes.dex"), "dex files"))
|
||||||
|
.hasSize(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGradleExportAAR() throws Exception {
|
||||||
|
int result = execJadxCli("samples/test-lib.aar", "--export-gradle");
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
assertThat(collectAllFilesInDir(outputDir))
|
||||||
|
.describedAs("check output files")
|
||||||
|
.map(this::printFileContent)
|
||||||
|
.map(this::pathToUniformString)
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.startsWith("lib/src/main/java/") && f.endsWith(".java"), "java"))
|
||||||
|
.haveExactly(0, new Condition<>(f -> f.endsWith(".jar"), "jar files"))
|
||||||
|
.hasSize(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGradleExportSimpleJava() throws Exception {
|
||||||
|
int result = execJadxCli("samples/HelloWorld.class", "--export-gradle");
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
assertThat(collectAllFilesInDir(outputDir))
|
||||||
|
.describedAs("check output files")
|
||||||
|
.map(this::printFileContent)
|
||||||
|
.map(this::pathToUniformString)
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.endsWith(".java") && f.startsWith("app/src/main/java/"), "java"))
|
||||||
|
.haveExactly(0, new Condition<>(f -> f.endsWith(".class"), "class files"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("settings.gradle.kts"), "settings"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("app/build.gradle.kts"), "build"))
|
||||||
|
.hasSize(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGradleExportInvalidType() throws Exception {
|
||||||
|
int result = execJadxCli("samples/HelloWorld.class", "--export-gradle-type", "android-app");
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
// expect output in 'android-app' template, but most fields will be set to UNKNOWN.
|
||||||
|
assertThat(collectAllFilesInDir(outputDir))
|
||||||
|
.describedAs("check output files")
|
||||||
|
.map(this::printFileContent)
|
||||||
|
.map(this::pathToUniformString)
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.endsWith(".java") && f.startsWith("app/src/main/java/"), "java"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("settings.gradle"), "settings"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("build.gradle"), "build"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("app/build.gradle"), "app build"))
|
||||||
|
.hasSize(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package jadx.cli;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.assertj.core.api.Condition;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class TestInput extends BaseCliIntegrationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHelp() {
|
||||||
|
int result = execJadxCli(new String[] { "--help" });
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApkInput() throws Exception {
|
||||||
|
int result = execJadxCli(buildArgs(List.of(), "samples/small.apk"));
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
assertThat(collectAllFilesInDir(outputDir))
|
||||||
|
.describedAs("check output files")
|
||||||
|
.map(p -> p.getFileName().toString())
|
||||||
|
.haveExactly(2, new Condition<>(f -> f.endsWith(".java"), "java classes"))
|
||||||
|
.haveExactly(9, new Condition<>(f -> f.endsWith(".xml"), "xml resources"))
|
||||||
|
.haveExactly(1, new Condition<>(f -> f.equals("AndroidManifest.xml"), "manifest"))
|
||||||
|
.hasSize(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDexInput() throws Exception {
|
||||||
|
decompile("samples/hello.dex");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSmaliInput() throws Exception {
|
||||||
|
decompile("samples/HelloWorld.smali");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClassInput() throws Exception {
|
||||||
|
decompile("samples/HelloWorld.class");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleInput() throws Exception {
|
||||||
|
decompile("samples/hello.dex", "samples/HelloWorld.smali");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFallbackMode() throws Exception {
|
||||||
|
int result = execJadxCli(buildArgs(List.of("-f"), "samples/hello.dex"));
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
List<Path> files = collectJavaFilesInDir(outputDir);
|
||||||
|
assertThat(files).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleMode() throws Exception {
|
||||||
|
int result = execJadxCli(buildArgs(List.of("--decompilation-mode", "simple"), "samples/hello.dex"));
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
List<Path> files = collectJavaFilesInDir(outputDir);
|
||||||
|
assertThat(files).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResourceOnly() throws Exception {
|
||||||
|
int result = execJadxCli(buildArgs(List.of(), "samples/resources-only.apk"));
|
||||||
|
assertThat(result).isEqualTo(0);
|
||||||
|
List<Path> files = collectFilesInDir(outputDir,
|
||||||
|
path -> path.getFileName().toString().equalsIgnoreCase("AndroidManifest.xml"));
|
||||||
|
assertThat(files).isNotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package jadx.plugins.tools.utils;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static jadx.plugins.tools.utils.PluginUtils.extractVersion;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class PluginUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtractVersion() {
|
||||||
|
assertThat(extractVersion("plugin-name-v1.2.3.jar")).isEqualTo("1.2.3");
|
||||||
|
assertThat(extractVersion("plugin-name-v1.2.jar")).isEqualTo("1.2");
|
||||||
|
assertThat(extractVersion("1.2.3.jar")).isEqualTo("1.2.3");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,26 @@
|
|||||||
|
.class Lsmali/HelloWorld;
|
||||||
|
.super Ljava/lang/Object;
|
||||||
|
.source "HelloWorld.java"
|
||||||
|
|
||||||
|
.method constructor <init>()V
|
||||||
|
.registers 1
|
||||||
|
|
||||||
|
.line 1
|
||||||
|
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
|
|
||||||
|
.method public static main([Ljava/lang/String;)V
|
||||||
|
.registers 2
|
||||||
|
|
||||||
|
.line 3
|
||||||
|
sget-object p0, Ljava/lang/System;->out:Ljava/io/PrintStream;
|
||||||
|
|
||||||
|
const-string v0, "Hello, World"
|
||||||
|
|
||||||
|
invoke-virtual {p0, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
||||||
|
|
||||||
|
.line 4
|
||||||
|
return-void
|
||||||
|
.end method
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,6 @@
|
|||||||
|
## jadx app commons
|
||||||
|
|
||||||
|
This module contains common utilities used in jadx apps (cli and gui) and not needed in jadx-code module:
|
||||||
|
- `JadxCommonFiles` - wrapper for `dev.dirs:directories` lib to get
|
||||||
|
'config' and 'cache' directories in cross-platform way
|
||||||
|
- `JadxCommonEnv` - utils for work with environment variables
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id("jadx-library")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("io.get-coursier.util:directories-jni:0.1.3")
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package jadx.commons.app;
|
||||||
|
|
||||||
|
public class JadxCommonEnv {
|
||||||
|
|
||||||
|
public static String get(String varName, String defValue) {
|
||||||
|
String strValue = System.getenv(varName);
|
||||||
|
return isNullOrEmpty(strValue) ? defValue : strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getBool(String varName, boolean defValue) {
|
||||||
|
String strValue = System.getenv(varName);
|
||||||
|
if (isNullOrEmpty(strValue)) {
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
return strValue.equalsIgnoreCase("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getInt(String varName, int defValue) {
|
||||||
|
String strValue = System.getenv(varName);
|
||||||
|
if (isNullOrEmpty(strValue)) {
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
return Integer.parseInt(strValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isNullOrEmpty(String value) {
|
||||||
|
return value == null || value.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package jadx.commons.app;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import dev.dirs.ProjectDirectories;
|
||||||
|
import dev.dirs.impl.Windows;
|
||||||
|
import dev.dirs.impl.WindowsPowerShell;
|
||||||
|
import dev.dirs.jni.WindowsJni;
|
||||||
|
|
||||||
|
public class JadxCommonFiles {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(JadxCommonFiles.class);
|
||||||
|
|
||||||
|
private static final Path CONFIG_DIR;
|
||||||
|
private static final Path CACHE_DIR;
|
||||||
|
|
||||||
|
public static Path getConfigDir() {
|
||||||
|
return CONFIG_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path getCacheDir() {
|
||||||
|
return CACHE_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
DirsLoader loader = new DirsLoader();
|
||||||
|
loader.init();
|
||||||
|
CONFIG_DIR = loader.getConfigDir();
|
||||||
|
CACHE_DIR = loader.getCacheDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DirsLoader {
|
||||||
|
private @Nullable ProjectDirectories dirs;
|
||||||
|
private Path configDir;
|
||||||
|
private Path cacheDir;
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
try {
|
||||||
|
configDir = loadEnvDir("JADX_CONFIG_DIR", pd -> pd.configDir);
|
||||||
|
cacheDir = loadEnvDir("JADX_CACHE_DIR", pd -> pd.cacheDir);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to init common directories", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path loadEnvDir(String envVar, Function<ProjectDirectories, String> dirFunc) throws IOException {
|
||||||
|
String envDir = JadxCommonEnv.get(envVar, null);
|
||||||
|
String dirStr;
|
||||||
|
if (envDir != null) {
|
||||||
|
dirStr = envDir;
|
||||||
|
} else {
|
||||||
|
dirStr = dirFunc.apply(loadDirs());
|
||||||
|
}
|
||||||
|
Path path = Path.of(dirStr).toAbsolutePath();
|
||||||
|
Files.createDirectories(path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized ProjectDirectories loadDirs() {
|
||||||
|
ProjectDirectories currentDirs = dirs;
|
||||||
|
if (currentDirs != null) {
|
||||||
|
return currentDirs;
|
||||||
|
}
|
||||||
|
LOG.debug("Loading system dirs ...");
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
ProjectDirectories loadedDirs = ProjectDirectories.from("io.github", "skylot", "jadx", DirsLoader::getWinDirs);
|
||||||
|
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("Loaded system dirs ({}ms): config: {}, cache: {}",
|
||||||
|
System.currentTimeMillis() - start, loadedDirs.configDir, loadedDirs.cacheDir);
|
||||||
|
}
|
||||||
|
dirs = loadedDirs;
|
||||||
|
return loadedDirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return JNI or Foreign implementation
|
||||||
|
*/
|
||||||
|
private static Windows getWinDirs() {
|
||||||
|
Windows defSup = Windows.getDefaultSupplier().get();
|
||||||
|
if (defSup instanceof WindowsPowerShell) {
|
||||||
|
return new WindowsJni();
|
||||||
|
}
|
||||||
|
return defSup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getCacheDir() {
|
||||||
|
return cacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getConfigDir() {
|
||||||
|
return configDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package jadx.commons.app;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public class JadxTempFiles {
|
||||||
|
private static final String JADX_TMP_INSTANCE_PREFIX = "jadx-instance-";
|
||||||
|
|
||||||
|
private static final Path TEMP_ROOT_DIR = createTempRootDir();
|
||||||
|
|
||||||
|
public static Path getTempRootDir() {
|
||||||
|
return TEMP_ROOT_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path createTempRootDir() {
|
||||||
|
try {
|
||||||
|
String jadxTmpDir = System.getenv("JADX_TMP_DIR");
|
||||||
|
Path dir;
|
||||||
|
if (jadxTmpDir != null) {
|
||||||
|
dir = Files.createTempDirectory(Paths.get(jadxTmpDir), JADX_TMP_INSTANCE_PREFIX);
|
||||||
|
} else {
|
||||||
|
dir = Files.createTempDirectory(JADX_TMP_INSTANCE_PREFIX);
|
||||||
|
}
|
||||||
|
dir.toFile().deleteOnExit();
|
||||||
|
return dir;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to create temp root directory", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
## jadx zip
|
||||||
|
|
||||||
|
Custom zip reader implementation to fight tampering and provide additional security checks
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
plugins {
|
||||||
|
id("jadx-library")
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package jadx.zip;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public interface IZipEntry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip entry name
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncompressed bytes
|
||||||
|
*/
|
||||||
|
byte[] getBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream of uncompressed bytes.
|
||||||
|
*/
|
||||||
|
InputStream getInputStream();
|
||||||
|
|
||||||
|
long getCompressedSize();
|
||||||
|
|
||||||
|
long getUncompressedSize();
|
||||||
|
|
||||||
|
boolean isDirectory();
|
||||||
|
|
||||||
|
File getZipFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if {@link #getBytes()} method is more optimal to use other than
|
||||||
|
* {@link #getInputStream()}
|
||||||
|
*/
|
||||||
|
boolean preferBytes();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package jadx.zip;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface IZipParser extends Closeable {
|
||||||
|
|
||||||
|
ZipContent open() throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package jadx.zip;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class ZipContent implements Closeable {
|
||||||
|
private final IZipParser zipParser;
|
||||||
|
private final List<IZipEntry> entries;
|
||||||
|
private final Map<String, IZipEntry> entriesMap;
|
||||||
|
|
||||||
|
public ZipContent(IZipParser zipParser, List<IZipEntry> entries) {
|
||||||
|
this.zipParser = zipParser;
|
||||||
|
this.entries = entries;
|
||||||
|
this.entriesMap = entries.stream().collect(Collectors.toMap(IZipEntry::getName, Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IZipEntry> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable IZipEntry searchEntry(String fileName) {
|
||||||
|
return entriesMap.get(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
zipParser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package jadx.zip;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import jadx.zip.fallback.FallbackZipParser;
|
||||||
|
import jadx.zip.parser.JadxZipParser;
|
||||||
|
import jadx.zip.security.IJadxZipSecurity;
|
||||||
|
import jadx.zip.security.JadxZipSecurity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jadx wrapper to provide custom zip parser ({@link JadxZipParser})
|
||||||
|
* with fallback to default Java implementation.
|
||||||
|
*/
|
||||||
|
public class ZipReader {
|
||||||
|
private final ZipReaderOptions options;
|
||||||
|
|
||||||
|
public ZipReader() {
|
||||||
|
this(ZipReaderOptions.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipReader(Set<ZipReaderFlags> flags) {
|
||||||
|
this(new ZipReaderOptions(new JadxZipSecurity(), flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipReader(IJadxZipSecurity security) {
|
||||||
|
this(new ZipReaderOptions(security, ZipReaderFlags.none()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipReader(ZipReaderOptions options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
public ZipContent open(File zipFile) throws IOException {
|
||||||
|
try {
|
||||||
|
JadxZipParser jadxParser = new JadxZipParser(zipFile, options);
|
||||||
|
IZipParser detectedParser = detectParser(zipFile, jadxParser);
|
||||||
|
if (detectedParser != jadxParser) {
|
||||||
|
jadxParser.close();
|
||||||
|
}
|
||||||
|
return detectedParser.open();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (options.getFlags().contains(ZipReaderFlags.DONT_USE_FALLBACK)) {
|
||||||
|
throw new IOException("Failed to open zip: " + zipFile, e);
|
||||||
|
}
|
||||||
|
// switch to fallback parser
|
||||||
|
return buildFallbackParser(zipFile).open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit valid entries in a zip file.
|
||||||
|
* Return not null value from visitor to stop iteration.
|
||||||
|
*/
|
||||||
|
public <R> @Nullable R visitEntries(File file, Function<IZipEntry, R> visitor) {
|
||||||
|
try (ZipContent content = open(file)) {
|
||||||
|
for (IZipEntry entry : content.getEntries()) {
|
||||||
|
R result = visitor.apply(entry);
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to process zip file: " + file.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readEntries(File file, BiConsumer<IZipEntry, InputStream> visitor) {
|
||||||
|
visitEntries(file, entry -> {
|
||||||
|
if (!entry.isDirectory()) {
|
||||||
|
try (InputStream in = entry.getInputStream()) {
|
||||||
|
visitor.accept(entry, in);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to process zip entry: " + entry, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipReaderOptions getOptions() {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IZipParser detectParser(File zipFile, JadxZipParser jadxParser) {
|
||||||
|
if (zipFile.getName().endsWith(".apk")
|
||||||
|
|| options.getFlags().contains(ZipReaderFlags.DONT_USE_FALLBACK)) {
|
||||||
|
return jadxParser;
|
||||||
|
}
|
||||||
|
if (!jadxParser.canOpen()) {
|
||||||
|
return buildFallbackParser(zipFile);
|
||||||
|
}
|
||||||
|
// default
|
||||||
|
if (options.getFlags().contains(ZipReaderFlags.FALLBACK_AS_DEFAULT)) {
|
||||||
|
return buildFallbackParser(zipFile);
|
||||||
|
}
|
||||||
|
return jadxParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FallbackZipParser buildFallbackParser(File zipFile) {
|
||||||
|
return new FallbackZipParser(zipFile, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package jadx.zip;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public enum ZipReaderFlags {
|
||||||
|
/**
|
||||||
|
* Search all local file headers by signature without reading
|
||||||
|
* 'central directory' and 'end of central directory' entries
|
||||||
|
*/
|
||||||
|
IGNORE_CENTRAL_DIR_ENTRIES,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable additional checks to verify zip data and report possible tampering
|
||||||
|
*/
|
||||||
|
REPORT_TAMPERING,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use fallback (java built-in implementation) parser as default.
|
||||||
|
* Custom implementation will be used for '*.apk' files only.
|
||||||
|
*/
|
||||||
|
FALLBACK_AS_DEFAULT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use only jadx custom parser and do not switch to fallback on errors.
|
||||||
|
*/
|
||||||
|
DONT_USE_FALLBACK;
|
||||||
|
|
||||||
|
public static Set<ZipReaderFlags> none() {
|
||||||
|
return EnumSet.noneOf(ZipReaderFlags.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package jadx.zip;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jadx.zip.security.IJadxZipSecurity;
|
||||||
|
import jadx.zip.security.JadxZipSecurity;
|
||||||
|
|
||||||
|
public class ZipReaderOptions {
|
||||||
|
|
||||||
|
public static ZipReaderOptions getDefault() {
|
||||||
|
return new ZipReaderOptions(new JadxZipSecurity(), ZipReaderFlags.none());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final IJadxZipSecurity zipSecurity;
|
||||||
|
private final Set<ZipReaderFlags> flags;
|
||||||
|
|
||||||
|
public ZipReaderOptions(IJadxZipSecurity zipSecurity, Set<ZipReaderFlags> flags) {
|
||||||
|
this.zipSecurity = zipSecurity;
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IJadxZipSecurity getZipSecurity() {
|
||||||
|
return zipSecurity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ZipReaderFlags> getFlags() {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package jadx.zip.fallback;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
|
||||||
|
public class FallbackZipEntry implements IZipEntry {
|
||||||
|
private final FallbackZipParser parser;
|
||||||
|
private final ZipEntry zipEntry;
|
||||||
|
|
||||||
|
public FallbackZipEntry(FallbackZipParser parser, ZipEntry zipEntry) {
|
||||||
|
this.parser = parser;
|
||||||
|
this.zipEntry = zipEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipEntry getZipEntry() {
|
||||||
|
return zipEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return zipEntry.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preferBytes() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return parser.getBytes(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return parser.getInputStream(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCompressedSize() {
|
||||||
|
return zipEntry.getCompressedSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getUncompressedSize() {
|
||||||
|
return zipEntry.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirectory() {
|
||||||
|
return zipEntry.isDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getZipFile() {
|
||||||
|
return parser.getZipFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package jadx.zip.fallback;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
import jadx.zip.IZipParser;
|
||||||
|
import jadx.zip.ZipContent;
|
||||||
|
import jadx.zip.ZipReaderOptions;
|
||||||
|
import jadx.zip.io.LimitedInputStream;
|
||||||
|
import jadx.zip.security.IJadxZipSecurity;
|
||||||
|
|
||||||
|
public class FallbackZipParser implements IZipParser {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(FallbackZipParser.class);
|
||||||
|
private final File file;
|
||||||
|
private final IJadxZipSecurity zipSecurity;
|
||||||
|
private final boolean useLimitedDataStream;
|
||||||
|
|
||||||
|
private ZipFile zipFile;
|
||||||
|
|
||||||
|
public FallbackZipParser(File file, ZipReaderOptions options) {
|
||||||
|
this.file = file;
|
||||||
|
this.zipSecurity = options.getZipSecurity();
|
||||||
|
this.useLimitedDataStream = zipSecurity.useLimitedDataStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZipContent open() throws IOException {
|
||||||
|
zipFile = new ZipFile(file);
|
||||||
|
|
||||||
|
int maxEntriesCount = zipSecurity.getMaxEntriesCount();
|
||||||
|
if (maxEntriesCount == -1) {
|
||||||
|
maxEntriesCount = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IZipEntry> list = new ArrayList<>();
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
FallbackZipEntry zipEntry = new FallbackZipEntry(this, entries.nextElement());
|
||||||
|
if (isValidEntry(zipEntry)) {
|
||||||
|
list.add(zipEntry);
|
||||||
|
if (list.size() > maxEntriesCount) {
|
||||||
|
throw new IllegalStateException("Max entries count limit exceeded: " + list.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ZipContent(this, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidEntry(IZipEntry zipEntry) {
|
||||||
|
boolean validEntry = zipSecurity.isValidEntry(zipEntry);
|
||||||
|
if (!validEntry) {
|
||||||
|
LOG.warn("Zip entry '{}' is invalid and excluded from processing", zipEntry);
|
||||||
|
}
|
||||||
|
return validEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes(FallbackZipEntry entry) {
|
||||||
|
try (InputStream is = getEntryStream(entry)) {
|
||||||
|
return is.readAllBytes();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to read bytes for entry: " + entry.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream(FallbackZipEntry entry) {
|
||||||
|
try {
|
||||||
|
return getEntryStream(entry);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to open input stream for entry: " + entry.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream getEntryStream(FallbackZipEntry entry) throws IOException {
|
||||||
|
InputStream entryStream = zipFile.getInputStream(entry.getZipEntry());
|
||||||
|
InputStream stream;
|
||||||
|
if (useLimitedDataStream) {
|
||||||
|
stream = new LimitedInputStream(entryStream, entry.getUncompressedSize());
|
||||||
|
} else {
|
||||||
|
stream = entryStream;
|
||||||
|
}
|
||||||
|
return new BufferedInputStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getZipFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
if (zipFile != null) {
|
||||||
|
zipFile.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
zipFile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package jadx.zip.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class ByteBufferBackedInputStream extends InputStream {
|
||||||
|
private final ByteBuffer buf;
|
||||||
|
private int markedPosition = 0;
|
||||||
|
|
||||||
|
public ByteBufferBackedInputStream(ByteBuffer buf) {
|
||||||
|
this.buf = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (!buf.hasRemaining()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return buf.get() & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
|
public int read(byte[] bytes, int off, int len) throws IOException {
|
||||||
|
if (!buf.hasRemaining()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int readLen = Math.min(len, buf.remaining());
|
||||||
|
buf.get(bytes, off, readLen);
|
||||||
|
return readLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void mark(int unused) {
|
||||||
|
markedPosition = buf.position();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void reset() {
|
||||||
|
buf.position(markedPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package jadx.zip.io;
|
||||||
|
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class LimitedInputStream extends FilterInputStream {
|
||||||
|
private final long maxSize;
|
||||||
|
|
||||||
|
private long currentPos;
|
||||||
|
private long markPos;
|
||||||
|
|
||||||
|
public LimitedInputStream(InputStream in, long maxSize) {
|
||||||
|
super(in);
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAndCheckPos(long count) {
|
||||||
|
currentPos += count;
|
||||||
|
if (currentPos > maxSize) {
|
||||||
|
throw new IllegalStateException("Read limit exceeded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
int data = super.read();
|
||||||
|
if (data != -1) {
|
||||||
|
addAndCheckPos(1);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
int count = super.read(b, off, len);
|
||||||
|
if (count > 0) {
|
||||||
|
addAndCheckPos(count);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
long skipped = super.skip(n);
|
||||||
|
if (skipped > 0) {
|
||||||
|
addAndCheckPos(skipped);
|
||||||
|
}
|
||||||
|
return skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mark(int readLimit) {
|
||||||
|
super.mark(readLimit);
|
||||||
|
markPos = currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() throws IOException {
|
||||||
|
super.reset();
|
||||||
|
currentPos = markPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package jadx.zip.parser;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
|
||||||
|
public final class JadxZipEntry implements IZipEntry {
|
||||||
|
private final JadxZipParser parser;
|
||||||
|
private final String fileName;
|
||||||
|
private final int compressMethod;
|
||||||
|
private final int entryStart;
|
||||||
|
private final int dataStart;
|
||||||
|
private final long compressedSize;
|
||||||
|
private final long uncompressedSize;
|
||||||
|
|
||||||
|
JadxZipEntry(JadxZipParser parser, String fileName, int entryStart, int dataStart,
|
||||||
|
int compressMethod, long compressedSize, long uncompressedSize) {
|
||||||
|
this.parser = parser;
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.entryStart = entryStart;
|
||||||
|
this.dataStart = dataStart;
|
||||||
|
this.compressMethod = compressMethod;
|
||||||
|
this.compressedSize = compressedSize;
|
||||||
|
this.uncompressedSize = uncompressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSizesValid() {
|
||||||
|
if (compressedSize <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (uncompressedSize <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return compressedSize <= uncompressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCompressedSize() {
|
||||||
|
return compressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getUncompressedSize() {
|
||||||
|
return uncompressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirectory() {
|
||||||
|
return fileName.endsWith("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preferBytes() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return parser.getBytes(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return parser.getInputStream(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntryStart() {
|
||||||
|
return entryStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDataStart() {
|
||||||
|
return dataStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCompressMethod() {
|
||||||
|
return compressMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getZipFile() {
|
||||||
|
return parser.getZipFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return parser.getZipFile().getName() + ':' + fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
package jadx.zip.parser;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
import jadx.zip.IZipParser;
|
||||||
|
import jadx.zip.ZipContent;
|
||||||
|
import jadx.zip.ZipReaderFlags;
|
||||||
|
import jadx.zip.ZipReaderOptions;
|
||||||
|
import jadx.zip.fallback.FallbackZipParser;
|
||||||
|
import jadx.zip.io.ByteBufferBackedInputStream;
|
||||||
|
import jadx.zip.io.LimitedInputStream;
|
||||||
|
import jadx.zip.security.IJadxZipSecurity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom and simple zip parser to fight tampering.
|
||||||
|
* Many zip features aren't supported:
|
||||||
|
* - Compression methods other than STORE or DEFLATE
|
||||||
|
* - Zip64
|
||||||
|
* - Checksum verification
|
||||||
|
* - Multi file archives
|
||||||
|
*/
|
||||||
|
public final class JadxZipParser implements IZipParser {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(JadxZipParser.class);
|
||||||
|
|
||||||
|
private static final byte LOCAL_FILE_HEADER_START = 0x50;
|
||||||
|
private static final int LOCAL_FILE_HEADER_SIGN = 0x04034b50;
|
||||||
|
private static final int CD_SIGN = 0x02014b50;
|
||||||
|
private static final int END_OF_CD_SIGN = 0x06054b50;
|
||||||
|
|
||||||
|
private final File zipFile;
|
||||||
|
private final ZipReaderOptions options;
|
||||||
|
private final IJadxZipSecurity zipSecurity;
|
||||||
|
private final Set<ZipReaderFlags> flags;
|
||||||
|
private final boolean verify;
|
||||||
|
private final boolean useLimitedDataStream;
|
||||||
|
|
||||||
|
private RandomAccessFile file;
|
||||||
|
private FileChannel fileChannel;
|
||||||
|
private ByteBuffer byteBuffer;
|
||||||
|
|
||||||
|
private int endOfCDStart = -2;
|
||||||
|
|
||||||
|
private @Nullable ZipContent fallbackZipContent;
|
||||||
|
|
||||||
|
public JadxZipParser(File zipFile, ZipReaderOptions options) {
|
||||||
|
this.zipFile = zipFile;
|
||||||
|
this.options = options;
|
||||||
|
this.zipSecurity = options.getZipSecurity();
|
||||||
|
this.flags = options.getFlags();
|
||||||
|
this.verify = options.getFlags().contains(ZipReaderFlags.REPORT_TAMPERING);
|
||||||
|
this.useLimitedDataStream = zipSecurity.useLimitedDataStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZipContent open() throws IOException {
|
||||||
|
load();
|
||||||
|
try {
|
||||||
|
int maxEntriesCount = zipSecurity.getMaxEntriesCount();
|
||||||
|
if (maxEntriesCount == -1) {
|
||||||
|
maxEntriesCount = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
List<IZipEntry> entries;
|
||||||
|
if (flags.contains(ZipReaderFlags.IGNORE_CENTRAL_DIR_ENTRIES)) {
|
||||||
|
entries = searchLocalFileHeaders(maxEntriesCount);
|
||||||
|
} else {
|
||||||
|
entries = loadFromCentralDirs(maxEntriesCount);
|
||||||
|
}
|
||||||
|
return new ZipContent(this, entries);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (flags.contains(ZipReaderFlags.DONT_USE_FALLBACK)) {
|
||||||
|
throw new IOException("Failed to open zip: " + zipFile + ", error: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
LOG.warn("Zip open failed, switching to fallback parser, zip: {}", zipFile, e);
|
||||||
|
return initFallbackParser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantIfStatement")
|
||||||
|
public boolean canOpen() {
|
||||||
|
try {
|
||||||
|
load();
|
||||||
|
int eocdStart = searchEndOfCDStart();
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
buf.position(eocdStart + 4);
|
||||||
|
int diskNum = readU2(buf);
|
||||||
|
if (diskNum == 0xFFFF) {
|
||||||
|
// Zip64
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("Jadx parser can't open zip file: {}", zipFile, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidEntry(JadxZipEntry zipEntry) {
|
||||||
|
boolean validEntry = zipSecurity.isValidEntry(zipEntry);
|
||||||
|
if (!validEntry) {
|
||||||
|
LOG.warn("Zip entry '{}' is invalid and excluded from processing", zipEntry);
|
||||||
|
}
|
||||||
|
return validEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load() throws IOException {
|
||||||
|
if (byteBuffer != null) {
|
||||||
|
// already loaded
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file = new RandomAccessFile(zipFile, "r");
|
||||||
|
long size = file.length();
|
||||||
|
if (size >= Integer.MAX_VALUE) {
|
||||||
|
throw new IOException("Zip file is too big");
|
||||||
|
}
|
||||||
|
int fileLen = (int) size;
|
||||||
|
if (fileLen < 100 * 1024 * 1024) {
|
||||||
|
// load files smaller than 100MB directly into memory
|
||||||
|
byte[] bytes = new byte[fileLen];
|
||||||
|
file.readFully(bytes);
|
||||||
|
byteBuffer = ByteBuffer.wrap(bytes).asReadOnlyBuffer();
|
||||||
|
file.close();
|
||||||
|
file = null;
|
||||||
|
} else {
|
||||||
|
// for big files - use a memory mapped file
|
||||||
|
fileChannel = file.getChannel();
|
||||||
|
byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
|
||||||
|
}
|
||||||
|
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IZipEntry> searchLocalFileHeaders(int maxEntriesCount) {
|
||||||
|
List<IZipEntry> entries = new ArrayList<>();
|
||||||
|
while (true) {
|
||||||
|
int start = searchEntryStart();
|
||||||
|
if (start == -1) {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
JadxZipEntry zipEntry = loadFileEntry(start);
|
||||||
|
if (isValidEntry(zipEntry)) {
|
||||||
|
entries.add(zipEntry);
|
||||||
|
if (entries.size() > maxEntriesCount) {
|
||||||
|
throw new IllegalStateException("Max entries count limit exceeded: " + entries.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IZipEntry> loadFromCentralDirs(int maxEntriesCount) throws IOException {
|
||||||
|
int eocdStart = searchEndOfCDStart();
|
||||||
|
if (eocdStart < 0) {
|
||||||
|
throw new RuntimeException("End of central directory not found");
|
||||||
|
}
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
buf.position(eocdStart + 10);
|
||||||
|
int entriesCount = readU2(buf);
|
||||||
|
buf.position(eocdStart + 16);
|
||||||
|
int cdOffset = buf.getInt();
|
||||||
|
|
||||||
|
if (entriesCount > maxEntriesCount) {
|
||||||
|
throw new IllegalStateException("Max entries count limit exceeded: " + entriesCount);
|
||||||
|
}
|
||||||
|
List<IZipEntry> entries = new ArrayList<>(entriesCount);
|
||||||
|
buf.position(cdOffset);
|
||||||
|
for (int i = 0; i < entriesCount; i++) {
|
||||||
|
JadxZipEntry zipEntry = loadCDEntry();
|
||||||
|
if (isValidEntry(zipEntry)) {
|
||||||
|
entries.add(zipEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JadxZipEntry loadCDEntry() {
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
int start = buf.position();
|
||||||
|
buf.position(start + 28);
|
||||||
|
int fileNameLen = readU2(buf);
|
||||||
|
int extraFieldLen = readU2(buf);
|
||||||
|
int commentLen = readU2(buf);
|
||||||
|
buf.position(start + 42);
|
||||||
|
int fileEntryStart = buf.getInt();
|
||||||
|
int entryEnd = start + 46 + fileNameLen + extraFieldLen + commentLen;
|
||||||
|
JadxZipEntry entry = loadFileEntry(fileEntryStart);
|
||||||
|
if (verify) {
|
||||||
|
compareCDAndLFH(buf, start, entry);
|
||||||
|
}
|
||||||
|
if (!entry.isSizesValid()) {
|
||||||
|
entry = fixEntryFromCD(entry, start);
|
||||||
|
}
|
||||||
|
buf.position(entryEnd);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JadxZipEntry fixEntryFromCD(JadxZipEntry entry, int start) {
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
buf.position(start + 10);
|
||||||
|
int comprMethod = readU2(buf);
|
||||||
|
buf.position(start + 20);
|
||||||
|
int comprSize = buf.getInt();
|
||||||
|
int unComprSize = buf.getInt();
|
||||||
|
return new JadxZipEntry(this, entry.getName(), start, entry.getDataStart(), comprMethod, comprSize, unComprSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void compareCDAndLFH(ByteBuffer buf, int start, JadxZipEntry entry) {
|
||||||
|
buf.position(start + 10);
|
||||||
|
int comprMethod = readU2(buf);
|
||||||
|
if (comprMethod != entry.getCompressMethod()) {
|
||||||
|
LOG.warn("Compression method differ in CD {} and LFH {} for {}",
|
||||||
|
comprMethod, entry.getCompressMethod(), entry);
|
||||||
|
}
|
||||||
|
buf.position(start + 20);
|
||||||
|
int comprSize = buf.getInt();
|
||||||
|
int unComprSize = buf.getInt();
|
||||||
|
if (comprSize != entry.getCompressedSize()) {
|
||||||
|
LOG.warn("Compressed size differ in CD {} and LFH {} for {}",
|
||||||
|
comprSize, entry.getCompressedSize(), entry);
|
||||||
|
}
|
||||||
|
if (unComprSize != entry.getUncompressedSize()) {
|
||||||
|
LOG.warn("Uncompressed size differ in CD {} and LFH {} for {}",
|
||||||
|
unComprSize, entry.getUncompressedSize(), entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JadxZipEntry loadFileEntry(int start) {
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
buf.position(start + 8);
|
||||||
|
int comprMethod = readU2(buf);
|
||||||
|
buf.position(start + 18);
|
||||||
|
int comprSize = buf.getInt();
|
||||||
|
int unComprSize = buf.getInt();
|
||||||
|
int fileNameLen = readU2(buf);
|
||||||
|
int extraFieldLen = readU2(buf);
|
||||||
|
String fileName = readString(buf, fileNameLen);
|
||||||
|
int dataStart = start + 30 + fileNameLen + extraFieldLen;
|
||||||
|
buf.position(dataStart + comprSize);
|
||||||
|
return new JadxZipEntry(this, fileName, start, dataStart, comprMethod, comprSize, unComprSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int searchEndOfCDStart() throws IOException {
|
||||||
|
if (endOfCDStart != -2) {
|
||||||
|
return endOfCDStart;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
int pos = buf.limit() - 22;
|
||||||
|
int minPos = Math.max(0, pos - 0xffff);
|
||||||
|
while (true) {
|
||||||
|
buf.position(pos);
|
||||||
|
int sign = buf.getInt();
|
||||||
|
if (sign == END_OF_CD_SIGN) {
|
||||||
|
endOfCDStart = pos;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
pos--;
|
||||||
|
if (pos < minPos) {
|
||||||
|
throw new IOException("End of central directory record not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int searchEntryStart() {
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
while (true) {
|
||||||
|
int start = buf.position();
|
||||||
|
if (start + 4 > buf.limit()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
byte b = buf.get();
|
||||||
|
if (b == LOCAL_FILE_HEADER_START) {
|
||||||
|
buf.position(start);
|
||||||
|
int sign = buf.getInt();
|
||||||
|
if (sign == LOCAL_FILE_HEADER_SIGN) {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized InputStream getInputStream(JadxZipEntry entry) {
|
||||||
|
if (verify) {
|
||||||
|
verifyEntry(entry);
|
||||||
|
}
|
||||||
|
InputStream stream;
|
||||||
|
if (entry.getCompressMethod() == 8) {
|
||||||
|
try {
|
||||||
|
stream = ZipDeflate.decompressEntryToStream(byteBuffer, entry);
|
||||||
|
} catch (Exception e) {
|
||||||
|
entryParseFailed(entry, e);
|
||||||
|
return useFallbackParser(entry).getInputStream();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// treat any other compression methods values as UNCOMPRESSED
|
||||||
|
stream = bufferToStream(byteBuffer, entry.getDataStart(), (int) entry.getUncompressedSize());
|
||||||
|
}
|
||||||
|
if (useLimitedDataStream) {
|
||||||
|
return new LimitedInputStream(stream, entry.getUncompressedSize());
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized byte[] getBytes(JadxZipEntry entry) {
|
||||||
|
if (verify) {
|
||||||
|
verifyEntry(entry);
|
||||||
|
}
|
||||||
|
if (entry.getCompressMethod() == 8) {
|
||||||
|
try {
|
||||||
|
return ZipDeflate.decompressEntryToBytes(byteBuffer, entry);
|
||||||
|
} catch (Exception e) {
|
||||||
|
entryParseFailed(entry, e);
|
||||||
|
return useFallbackParser(entry).getBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// treat any other compression methods values as UNCOMPRESSED
|
||||||
|
return bufferToBytes(byteBuffer, entry.getDataStart(), (int) entry.getUncompressedSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyEntry(JadxZipEntry entry) {
|
||||||
|
int compressMethod = entry.getCompressMethod();
|
||||||
|
if (compressMethod == 0) {
|
||||||
|
if (entry.getCompressedSize() != entry.getUncompressedSize()) {
|
||||||
|
LOG.warn("Not equal sizes for STORE method: compressed: {}, uncompressed: {}, entry: {}",
|
||||||
|
entry.getCompressedSize(), entry.getUncompressedSize(), entry);
|
||||||
|
}
|
||||||
|
} else if (compressMethod != 8) {
|
||||||
|
LOG.warn("Unknown compress method: {} in entry: {}", compressMethod, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void entryParseFailed(JadxZipEntry entry, Exception e) {
|
||||||
|
if (isEncrypted(entry)) {
|
||||||
|
throw new RuntimeException("Entry is encrypted, failed to decompress: " + entry, e);
|
||||||
|
}
|
||||||
|
if (flags.contains(ZipReaderFlags.DONT_USE_FALLBACK)) {
|
||||||
|
throw new RuntimeException("Failed to decompress zip entry: " + entry + ", error: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
LOG.warn("Entry '{}' parse failed, switching to fallback parser", entry, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
private IZipEntry useFallbackParser(JadxZipEntry entry) {
|
||||||
|
LOG.debug("useFallbackParser used for {}", entry);
|
||||||
|
IZipEntry zipEntry = initFallbackParser().searchEntry(entry.getName());
|
||||||
|
if (zipEntry == null) {
|
||||||
|
throw new RuntimeException("Fallback parser can't find entry: " + entry);
|
||||||
|
}
|
||||||
|
return zipEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
private ZipContent initFallbackParser() {
|
||||||
|
if (fallbackZipContent == null) {
|
||||||
|
try {
|
||||||
|
fallbackZipContent = new FallbackZipParser(zipFile, options).open();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Fallback parser failed to open file: " + zipFile, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fallbackZipContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEncrypted(JadxZipEntry entry) {
|
||||||
|
int flags = readFlags(entry);
|
||||||
|
return (flags & 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readFlags(JadxZipEntry entry) {
|
||||||
|
ByteBuffer buf = byteBuffer;
|
||||||
|
buf.position(entry.getEntryStart() + 6);
|
||||||
|
return readU2(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] bufferToBytes(ByteBuffer buf, int start, int size) {
|
||||||
|
byte[] data = new byte[size];
|
||||||
|
buf.position(start);
|
||||||
|
buf.get(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InputStream bufferToStream(ByteBuffer buf, int start, int size) {
|
||||||
|
buf.position(start);
|
||||||
|
ByteBuffer streamBuf = buf.slice();
|
||||||
|
streamBuf.limit(size);
|
||||||
|
return new ByteBufferBackedInputStream(streamBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int readU2(ByteBuffer buf) {
|
||||||
|
return buf.getShort() & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readString(ByteBuffer buf, int fileNameLen) {
|
||||||
|
byte[] bytes = new byte[fileNameLen];
|
||||||
|
buf.get(bytes);
|
||||||
|
return new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
if (fileChannel != null) {
|
||||||
|
fileChannel.close();
|
||||||
|
}
|
||||||
|
if (file != null) {
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
if (fallbackZipContent != null) {
|
||||||
|
fallbackZipContent.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
fileChannel = null;
|
||||||
|
file = null;
|
||||||
|
byteBuffer = null;
|
||||||
|
endOfCDStart = -2;
|
||||||
|
fallbackZipContent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getZipFile() {
|
||||||
|
return zipFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "JadxZipParser{" + zipFile + '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package jadx.zip.parser;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.zip.DataFormatException;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
import static jadx.zip.parser.JadxZipParser.bufferToStream;
|
||||||
|
|
||||||
|
final class ZipDeflate {
|
||||||
|
private static final int BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
|
static byte[] decompressEntryToBytes(ByteBuffer buf, JadxZipEntry entry) throws DataFormatException {
|
||||||
|
buf.position(entry.getDataStart());
|
||||||
|
ByteBuffer entryBuf = buf.slice();
|
||||||
|
entryBuf.limit((int) entry.getCompressedSize());
|
||||||
|
byte[] out = new byte[(int) entry.getUncompressedSize()];
|
||||||
|
Inflater inflater = new Inflater(true);
|
||||||
|
inflater.setInput(entryBuf);
|
||||||
|
int written = inflater.inflate(out);
|
||||||
|
inflater.end();
|
||||||
|
if (written != out.length) {
|
||||||
|
throw new DataFormatException("Unexpected size of decompressed entry: " + entry
|
||||||
|
+ ", got: " + written + ", expected: " + out.length);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InputStream decompressEntryToStream(ByteBuffer buf, JadxZipEntry entry) {
|
||||||
|
InputStream stream = bufferToStream(buf, entry.getDataStart(), (int) entry.getCompressedSize());
|
||||||
|
Inflater inflater = new Inflater(true);
|
||||||
|
return new InflaterInputStream(stream, inflater, BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package jadx.zip.security;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
|
||||||
|
public class DisabledZipSecurity implements IJadxZipSecurity {
|
||||||
|
|
||||||
|
public static final DisabledZipSecurity INSTANCE = new DisabledZipSecurity();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidEntry(IZipEntry entry) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidEntryName(String entryName) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInSubDirectory(File baseDir, File file) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useLimitedDataStream() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxEntriesCount() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package jadx.zip.security;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
|
||||||
|
public interface IJadxZipSecurity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if zip entry is valid and safe to process
|
||||||
|
*/
|
||||||
|
boolean isValidEntry(IZipEntry entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the zip entry name is valid.
|
||||||
|
* This check should be part of {@link #isValidEntry(IZipEntry)} method.
|
||||||
|
*/
|
||||||
|
boolean isValidEntryName(String entryName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use limited InputStream for entry uncompressed data
|
||||||
|
*/
|
||||||
|
boolean useLimitedDataStream();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max entries count expected in a zip file, fail zip open if the limit exceeds.
|
||||||
|
* Return -1 to disable entries count check.
|
||||||
|
*/
|
||||||
|
int getMaxEntriesCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a file will be inside baseDir after a system resolves its path
|
||||||
|
*/
|
||||||
|
boolean isInSubDirectory(File baseDir, File file);
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package jadx.zip.security;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import jadx.zip.IZipEntry;
|
||||||
|
|
||||||
|
public class JadxZipSecurity implements IJadxZipSecurity {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(JadxZipSecurity.class);
|
||||||
|
|
||||||
|
private static final File CWD = getCWD();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of uncompressed zip entry shouldn't be bigger of compressed in zipBombDetectionFactor
|
||||||
|
* times
|
||||||
|
*/
|
||||||
|
private int zipBombDetectionFactor = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip entries that have an uncompressed size of less than zipBombMinUncompressedSize are considered
|
||||||
|
* safe
|
||||||
|
*/
|
||||||
|
private int zipBombMinUncompressedSize = 25 * 1024 * 1024;
|
||||||
|
|
||||||
|
private int maxEntriesCount = 100_000;
|
||||||
|
|
||||||
|
private boolean useLimitedDataStream = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidEntry(IZipEntry entry) {
|
||||||
|
return isValidEntryName(entry.getName()) && !isZipBomb(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useLimitedDataStream() {
|
||||||
|
return useLimitedDataStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxEntriesCount() {
|
||||||
|
return maxEntriesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that entry name contains no any traversals and prevents cases like "../classes.dex",
|
||||||
|
* to limit output only to the specified directory
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValidEntryName(String entryName) {
|
||||||
|
if (entryName.contains("..")) { // quick pre-check
|
||||||
|
if (entryName.contains("../") || entryName.contains("..\\")) {
|
||||||
|
LOG.error("Path traversal attack detected in entry: '{}'", entryName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
File currentPath = CWD;
|
||||||
|
File canonical = new File(currentPath, entryName).getCanonicalFile();
|
||||||
|
if (isInSubDirectoryInternal(currentPath, canonical)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// check failed
|
||||||
|
}
|
||||||
|
LOG.error("Invalid file name or path traversal attack detected: {}", entryName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInSubDirectory(File baseDir, File file) {
|
||||||
|
try {
|
||||||
|
return isInSubDirectoryInternal(baseDir.getCanonicalFile(), file.getCanonicalFile());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isZipBomb(IZipEntry entry) {
|
||||||
|
long compressedSize = entry.getCompressedSize();
|
||||||
|
long uncompressedSize = entry.getUncompressedSize();
|
||||||
|
boolean invalidSize = compressedSize < 0 || uncompressedSize < 0;
|
||||||
|
boolean possibleZipBomb = uncompressedSize >= zipBombMinUncompressedSize
|
||||||
|
&& compressedSize * zipBombDetectionFactor < uncompressedSize;
|
||||||
|
if (invalidSize || possibleZipBomb) {
|
||||||
|
LOG.error("Potential zip bomb attack detected, invalid sizes: compressed {}, uncompressed {}, name {}",
|
||||||
|
compressedSize, uncompressedSize, entry.getName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isInSubDirectoryInternal(File baseDir, File file) {
|
||||||
|
File current = file;
|
||||||
|
while (true) {
|
||||||
|
if (current == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (current.equals(baseDir)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
current = current.getParentFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxEntriesCount(int maxEntriesCount) {
|
||||||
|
this.maxEntriesCount = maxEntriesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZipBombDetectionFactor(int zipBombDetectionFactor) {
|
||||||
|
this.zipBombDetectionFactor = zipBombDetectionFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZipBombMinUncompressedSize(int zipBombMinUncompressedSize) {
|
||||||
|
this.zipBombMinUncompressedSize = zipBombMinUncompressedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseLimitedDataStream(boolean useLimitedDataStream) {
|
||||||
|
this.useLimitedDataStream = useLimitedDataStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File getCWD() {
|
||||||
|
try {
|
||||||
|
return new File(".").getCanonicalFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to init current working dir constant", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
dependencies {
|
|
||||||
runtime files('clsp-data/android-29-clst.jar')
|
|
||||||
runtime files('clsp-data/android-29-res.jar')
|
|
||||||
|
|
||||||
compile files('lib/dx-1.16.jar') // TODO: dx don't support java version > 9 (53)
|
|
||||||
|
|
||||||
compile 'org.ow2.asm:asm:7.2'
|
|
||||||
compile 'org.jetbrains:annotations:18.0.0'
|
|
||||||
compile 'com.google.code.gson:gson:2.8.6'
|
|
||||||
|
|
||||||
compile 'org.smali:baksmali:2.3.4'
|
|
||||||
compile('org.smali:smali:2.3.4') {
|
|
||||||
exclude group: 'com.google.guava'
|
|
||||||
}
|
|
||||||
compile 'com.google.guava:guava:28.1-jre'
|
|
||||||
|
|
||||||
testCompile 'org.apache.commons:commons-lang3:3.9'
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
plugins {
|
||||||
|
id("jadx-library")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":jadx-plugins:jadx-input-api"))
|
||||||
|
api(project(":jadx-commons:jadx-zip"))
|
||||||
|
|
||||||
|
implementation("com.google.code.gson:gson:2.13.1")
|
||||||
|
|
||||||
|
testImplementation("org.apache.commons:commons-lang3:3.17.0")
|
||||||
|
|
||||||
|
testImplementation(project(":jadx-plugins:jadx-dex-input"))
|
||||||
|
testRuntimeOnly(project(":jadx-plugins:jadx-smali-input"))
|
||||||
|
testRuntimeOnly(project(":jadx-plugins:jadx-java-convert"))
|
||||||
|
testRuntimeOnly(project(":jadx-plugins:jadx-java-input"))
|
||||||
|
testRuntimeOnly(project(":jadx-plugins:jadx-raung-input"))
|
||||||
|
|
||||||
|
testImplementation("org.eclipse.jdt:ecj") {
|
||||||
|
version {
|
||||||
|
prefer("3.33.0")
|
||||||
|
strictly("[3.33, 3.34[") // from 3.34 compiled with Java 17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testImplementation("tools.profiler:async-profiler:4.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
val jadxTestJavaVersion = getTestJavaVersion()
|
||||||
|
|
||||||
|
fun getTestJavaVersion(): Int? {
|
||||||
|
val envVarName = "JADX_TEST_JAVA_VERSION"
|
||||||
|
val testJavaVer = System.getenv(envVarName)?.toInt() ?: return null
|
||||||
|
val currentJavaVer = java.toolchain.languageVersion.get().asInt()
|
||||||
|
if (testJavaVer < currentJavaVer) {
|
||||||
|
throw GradleException("'$envVarName' can't be set to lower version than $currentJavaVer")
|
||||||
|
}
|
||||||
|
println("Set Java toolchain for core tests to version '$testJavaVer'")
|
||||||
|
return testJavaVer
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<Test>("test") {
|
||||||
|
jadxTestJavaVersion?.let { testJavaVer ->
|
||||||
|
javaLauncher =
|
||||||
|
javaToolchains.launcherFor {
|
||||||
|
languageVersion = JavaLanguageVersion.of(testJavaVer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable cache to allow test's rerun,
|
||||||
|
// because most tests are integration and depends on plugins and environment
|
||||||
|
outputs.cacheIf { false }
|
||||||
|
|
||||||
|
// exclude temp tests
|
||||||
|
exclude("**/tmp/*")
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user