Support 7z extraction, and fix .xz extraction which would have crashed at runtime
Commons Compress declares its LZMA/LZMA2 support against org.tukaani:xz as an *optional* dependency, so nothing pulled it in transitively and nothing failed at build time. The app nevertheless advertised .xz as extractable, so the first user to open one would have got NoClassDefFoundError: org/tukaani/xz/FilterOptions. XZCompressorInputStream references org/tukaani/xz/XZInputStream directly. The library is now declared, and a round-trip test covers the path that was silently missing. That same library is what 7z needs, and Commons Compress already ships a pure-Java 7z reader, so 7z extraction costs no native code and no further dependency. The docs had assumed the format was off limits and said so in three places, including the customer-facing store copy. 7z is the only format here that cannot arrive through a stream: its header sits at the end of the file, so the reader has to seek. That is now a capability the backend advertises, StorageSource.openSeekable: the all-files backend answers with a real FileChannel, the SAF fallback with null, so folder mode reports needs-a-seekable-file instead of failing obscurely. Entry names go through the same ArchivePath.safeRelativePath zip-slip guard. 7z creation stays deferred.
This commit is contained in:
@@ -25,7 +25,7 @@ holds length-checked listing copy. The screenshots are captured: 5 phone (1080×
|
||||
| UI | Jetpack Compose, BOM 2026.06.01, Material 3 |
|
||||
| Build | Gradle 9.3.1, Android Gradle Plugin 9.1.0 |
|
||||
| Storage access | `MANAGE_EXTERNAL_STORAGE` ("All files access") with a Storage Access Framework fallback |
|
||||
| Archives | Apache Commons Compress (pure Java — no NDK) |
|
||||
| Archives | Apache Commons Compress + XZ for Java (both pure Java — no NDK) |
|
||||
| SDK levels | `compileSdk`/`targetSdk` 36, `minSdk` 26 |
|
||||
|
||||
`targetSdk` is 36 because Google Play requires new apps and updates to target
|
||||
@@ -141,10 +141,13 @@ UI.** Translated UI text has to be supplied in `values-<locale>/`.
|
||||
|
||||
- **"Open with" and Share only work in the all-files mode.** A SAF path is relative to the
|
||||
granted tree rather than a filesystem path, so it cannot be handed to `FileProvider`.
|
||||
- **RAR and 7z are refused**, not supported. The stated reason is only half right: RAR
|
||||
genuinely needs native code (the Commons Compress jar this app ships contains no RAR
|
||||
classes at all), but **7z does not** — `SevenZFile`/`SevenZOutputFile` are already inside
|
||||
that same jar, so 7z read, and AES-256-encrypted 7z write, is an unpack away.
|
||||
- **RAR, CAB, ISO and WIM are refused**, not supported — they need native code, which this
|
||||
project deliberately does not ship. (The Commons Compress jar contains no RAR classes at
|
||||
all.) **7z is different**: Commons Compress reads it in pure Java, so it *is* supported —
|
||||
but the format needs a seekable channel rather than a stream, because its header lives at
|
||||
the end of the file. All-files access can supply one; the SAF fallback cannot, so 7z
|
||||
extraction reports that plainly in folder mode instead of half-working.
|
||||
- **7z files can be opened but not created** — writing stays ZIP-only.
|
||||
- **Archive extraction does not restore original timestamps or permissions**, and there is
|
||||
no archive encryption or password support.
|
||||
- **Cancellation happens between entries**, so a single very large file finishes before a
|
||||
|
||||
Reference in New Issue
Block a user