android: move unzip function to FileUtil and use SecurityException
This commit is contained in:
parent
296ccb698d
commit
19674ec78d
|
@ -23,17 +23,14 @@ import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||||
import org.yuzu.yuzu_emu.getPublicFilesDir
|
import org.yuzu.yuzu_emu.getPublicFilesDir
|
||||||
import java.io.BufferedInputStream
|
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.FilenameFilter
|
import java.io.FilenameFilter
|
||||||
import java.io.IOException
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
|
||||||
import java.util.zip.ZipOutputStream
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
class ImportExportSavesFragment : DialogFragment() {
|
class ImportExportSavesFragment : DialogFragment() {
|
||||||
|
@ -124,33 +121,6 @@ class ImportExportSavesFragment : DialogFragment() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the save files located in the given zip file and copies them to the saves folder.
|
|
||||||
* @exception IOException if the file was being created outside of the target directory
|
|
||||||
*/
|
|
||||||
private fun unzip(zipStream: InputStream, destDir: File): Boolean {
|
|
||||||
val zis = ZipInputStream(BufferedInputStream(zipStream))
|
|
||||||
var entry: ZipEntry? = zis.nextEntry
|
|
||||||
while (entry != null) {
|
|
||||||
val entryName = entry.name
|
|
||||||
val entryFile = File(destDir, entryName)
|
|
||||||
if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
|
|
||||||
zis.close()
|
|
||||||
throw IOException("Entry is outside of the target dir: " + entryFile.name)
|
|
||||||
}
|
|
||||||
if (entry.isDirectory) {
|
|
||||||
entryFile.mkdirs()
|
|
||||||
} else {
|
|
||||||
entryFile.parentFile?.mkdirs()
|
|
||||||
entryFile.createNewFile()
|
|
||||||
entryFile.outputStream().use { fos -> zis.copyTo(fos) }
|
|
||||||
}
|
|
||||||
entry = zis.nextEntry
|
|
||||||
}
|
|
||||||
zis.close()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
|
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
|
||||||
*/
|
*/
|
||||||
|
@ -204,7 +174,7 @@ class ImportExportSavesFragment : DialogFragment() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
unzip(inputZip, cacheSaveDir)
|
FileUtil.unzip(inputZip, cacheSaveDir)
|
||||||
cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
|
cacheSaveDir.list(filterTitleId)?.forEach { savePath ->
|
||||||
File(savesFolder, savePath).deleteRecursively()
|
File(savesFolder, savePath).deleteRecursively()
|
||||||
File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)
|
File(cacheSaveDir, savePath).copyRecursively(File(savesFolder, savePath), true)
|
||||||
|
|
|
@ -9,10 +9,14 @@ import android.net.Uri
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
|
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
|
||||||
|
import java.io.BufferedInputStream
|
||||||
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
object FileUtil {
|
object FileUtil {
|
||||||
const val PATH_TREE = "tree"
|
const val PATH_TREE = "tree"
|
||||||
|
@ -276,6 +280,34 @@ object FileUtil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the given zip file into the given directory.
|
||||||
|
* @exception IOException if the file was being created outside of the target directory
|
||||||
|
*/
|
||||||
|
@Throws(SecurityException::class)
|
||||||
|
fun unzip(zipStream: InputStream, destDir: File): Boolean {
|
||||||
|
ZipInputStream(BufferedInputStream(zipStream)).use { zis ->
|
||||||
|
var entry: ZipEntry? = zis.nextEntry
|
||||||
|
while (entry != null) {
|
||||||
|
val entryName = entry.name
|
||||||
|
val entryFile = File(destDir, entryName)
|
||||||
|
if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath + File.separator)) {
|
||||||
|
throw SecurityException("Entry is outside of the target dir: " + entryFile.name)
|
||||||
|
}
|
||||||
|
if (entry.isDirectory) {
|
||||||
|
entryFile.mkdirs()
|
||||||
|
} else {
|
||||||
|
entryFile.parentFile?.mkdirs()
|
||||||
|
entryFile.createNewFile()
|
||||||
|
entryFile.outputStream().use { fos -> zis.copyTo(fos) }
|
||||||
|
}
|
||||||
|
entry = zis.nextEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun isRootTreeUri(uri: Uri): Boolean {
|
fun isRootTreeUri(uri: Uri): Boolean {
|
||||||
val paths = uri.pathSegments
|
val paths = uri.pathSegments
|
||||||
return paths.size == 2 && PATH_TREE == paths[0]
|
return paths.size == 2 && PATH_TREE == paths[0]
|
||||||
|
|
Reference in New Issue