diff --git a/app/build.gradle b/app/build.gradle index 6bf0bc9d..27fdbdfa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,7 +64,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:84c71fdcc1' + implementation 'com.github.SimpleMobileTools:Simple-Commons:db25f91be3' implementation 'com.github.tibbi:AndroidPdfViewer:e6a533125b' implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' @@ -72,4 +72,5 @@ dependencies { implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'me.grantland:autofittextview:0.2.1' + implementation 'net.lingala.zip4j:zip4j:2.11.5' } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/DecompressActivity.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/DecompressActivity.kt index 284d434e..415f4255 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/DecompressActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/DecompressActivity.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.filemanager.pro.activities import android.annotation.SuppressLint import android.net.Uri import android.os.Bundle +import com.simplemobiletools.commons.dialogs.EnterPasswordDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.NavigationIcon @@ -13,14 +14,21 @@ import com.simplemobiletools.filemanager.pro.adapters.DecompressItemsAdapter import com.simplemobiletools.filemanager.pro.extensions.config import com.simplemobiletools.filemanager.pro.models.ListItem import kotlinx.android.synthetic.main.activity_decompress.* +import net.lingala.zip4j.exception.ZipException +import net.lingala.zip4j.exception.ZipException.Type +import net.lingala.zip4j.io.inputstream.ZipInputStream +import net.lingala.zip4j.model.LocalFileHeader import java.io.BufferedInputStream -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream class DecompressActivity : SimpleActivity() { + companion object { + private const val PASSWORD = "password" + } + private val allFiles = ArrayList() private var currentPath = "" private var uri: Uri? = null + private var password: String? = null override fun onCreate(savedInstanceState: Bundle?) { isMaterialActivity = true @@ -36,10 +44,11 @@ class DecompressActivity : SimpleActivity() { return } + password = savedInstanceState?.getString(PASSWORD, null) + val realPath = getRealPathFromURI(uri!!) decompress_toolbar.title = realPath?.getFilenameFromPath() ?: Uri.decode(uri.toString().getFilenameFromPath()) - fillAllListItems(uri!!) - updateCurrentPath("") + setupFilesList() } override fun onResume() { @@ -47,6 +56,11 @@ class DecompressActivity : SimpleActivity() { setupToolbar(decompress_toolbar, NavigationIcon.Arrow) } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putString(PASSWORD, password) + } + private fun setupOptionsMenu() { decompress_toolbar.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { @@ -57,6 +71,12 @@ class DecompressActivity : SimpleActivity() { } } + private fun setupFilesList() { + fillAllListItems(uri!!) + updateCurrentPath("") + } + + override fun onBackPressed() { if (currentPath.isEmpty()) { super.onBackPressed() @@ -99,6 +119,9 @@ class DecompressActivity : SimpleActivity() { try { val inputStream = contentResolver.openInputStream(uri!!) val zipInputStream = ZipInputStream(BufferedInputStream(inputStream!!)) + if (password != null) { + zipInputStream.setPassword(password?.toCharArray()) + } val buffer = ByteArray(1024) zipInputStream.use { @@ -106,7 +129,7 @@ class DecompressActivity : SimpleActivity() { val entry = zipInputStream.nextEntry ?: break val filename = title.toString().substringBeforeLast(".") val parent = "$destination/$filename" - val newPath = "$parent/${entry.name.trimEnd('/')}" + val newPath = "$parent/${entry.fileName.trimEnd('/')}" if (!getDoesFilePathExist(parent)) { if (!createDirectorySync(parent)) { @@ -161,10 +184,25 @@ class DecompressActivity : SimpleActivity() { } val zipInputStream = ZipInputStream(BufferedInputStream(inputStream)) - var zipEntry: ZipEntry? + if (password != null) { + zipInputStream.setPassword(password?.toCharArray()) + } + var zipEntry: LocalFileHeader? while (true) { try { zipEntry = zipInputStream.nextEntry + } catch (passwordException: ZipException) { + if (passwordException.type == Type.WRONG_PASSWORD) { + if (password != null) { + showErrorToast(getString(R.string.invalid_password)) + finish() + } else { + askForPassword() + } + return + } else { + break + } } catch (ignored: Exception) { break } @@ -173,10 +211,23 @@ class DecompressActivity : SimpleActivity() { break } - val lastModified = if (isOreoPlus()) zipEntry.lastModifiedTime.toMillis() else 0 - val filename = zipEntry.name.removeSuffix("/") + val lastModified = if (isOreoPlus()) zipEntry.lastModifiedTime else 0 + val filename = zipEntry.fileName.removeSuffix("/") val listItem = ListItem(filename, filename.getFilenameFromPath(), zipEntry.isDirectory, 0, 0L, lastModified, false, false) allFiles.add(listItem) } } + + private fun askForPassword() { + EnterPasswordDialog( + this, + callback = { newPassword -> + password = newPassword + setupFilesList() + }, + cancelCallback = { + finish() + } + ) + } }