pull/34/head
parent
dfd21b5c5c
commit
8316e13987
@ -0,0 +1,81 @@ |
||||
package io.legado.app.help.storage |
||||
|
||||
import android.content.Context |
||||
import io.legado.app.App |
||||
import io.legado.app.help.FileHelp |
||||
import io.legado.app.lib.webdav.WebDav |
||||
import io.legado.app.lib.webdav.http.HttpAuth |
||||
import io.legado.app.utils.ZipUtils |
||||
import io.legado.app.utils.getPrefString |
||||
import org.jetbrains.anko.doAsync |
||||
import org.jetbrains.anko.selector |
||||
import org.jetbrains.anko.uiThread |
||||
import kotlin.math.min |
||||
|
||||
object WebDavHelp { |
||||
|
||||
fun getWebDavUrl(): String? { |
||||
var url = App.INSTANCE.getPrefString("web_dav_url") |
||||
if (url.isNullOrBlank()) return null |
||||
if (!url.endsWith("/")) url += "/" |
||||
return url |
||||
} |
||||
|
||||
private fun initWebDav(): Boolean { |
||||
val account = App.INSTANCE.getPrefString("web_dav_account") |
||||
val password = App.INSTANCE.getPrefString("web_dav_password") |
||||
if (!account.isNullOrBlank() && !password.isNullOrBlank()) { |
||||
HttpAuth.auth = HttpAuth.Auth(account, password) |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
private fun getWebDavFileNames(): ArrayList<String> { |
||||
val url = getWebDavUrl() |
||||
val names = arrayListOf<String>() |
||||
if (!url.isNullOrBlank() && initWebDav()) { |
||||
val files = WebDav(url + "legado/").listFiles() |
||||
files.reversed() |
||||
for (index: Int in 0 until min(10, files.size)) { |
||||
files[index].displayName?.let { |
||||
names.add(it) |
||||
} |
||||
} |
||||
} |
||||
return names |
||||
} |
||||
|
||||
fun showRestoreDialog(context: Context) { |
||||
doAsync { |
||||
val names = getWebDavFileNames() |
||||
if (names.isNotEmpty()) { |
||||
uiThread { |
||||
context.selector(title = "选择恢复文件", items = names) { _, index -> |
||||
if (index in 0 until names.size) { |
||||
restoreWebDav(names[index]) |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
Restore.restore() |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun restoreWebDav(name: String) { |
||||
doAsync { |
||||
getWebDavUrl()?.let { |
||||
val file = WebDav(it + "legado/" + name) |
||||
val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip" |
||||
file.downloadTo(zipFilePath, true) |
||||
ZipUtils.unzipFile(zipFilePath, Backup.defaultPath) |
||||
Restore.restore() |
||||
} |
||||
} |
||||
} |
||||
|
||||
fun backUpWebDav() { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,420 @@ |
||||
package io.legado.app.utils |
||||
|
||||
import android.util.Log |
||||
import java.io.* |
||||
import java.util.* |
||||
import java.util.zip.ZipEntry |
||||
import java.util.zip.ZipFile |
||||
import java.util.zip.ZipOutputStream |
||||
|
||||
/** |
||||
* <pre> |
||||
* author: Blankj |
||||
* blog : http://blankj.com |
||||
* time : 2016/08/27 |
||||
* desc : utils about zip |
||||
</pre> * |
||||
*/ |
||||
object ZipUtils { |
||||
|
||||
/** |
||||
* Zip the files. |
||||
* |
||||
* @param srcFiles The source of files. |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @return `true`: success<br></br>`false`: fail |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun zipFiles( |
||||
srcFiles: Collection<String>, |
||||
zipFilePath: String |
||||
): Boolean { |
||||
return zipFiles(srcFiles, zipFilePath, null) |
||||
} |
||||
|
||||
/** |
||||
* Zip the files. |
||||
* |
||||
* @param srcFilePaths The paths of source files. |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @param comment The comment. |
||||
* @return `true`: success<br></br>`false`: fail |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun zipFiles( |
||||
srcFilePaths: Collection<String>?, |
||||
zipFilePath: String?, |
||||
comment: String? |
||||
): Boolean { |
||||
if (srcFilePaths == null || zipFilePath == null) return false |
||||
var zos: ZipOutputStream? = null |
||||
try { |
||||
zos = ZipOutputStream(FileOutputStream(zipFilePath)) |
||||
for (srcFile in srcFilePaths) { |
||||
if (!zipFile(getFileByPath(srcFile)!!, "", zos, comment)) return false |
||||
} |
||||
return true |
||||
} finally { |
||||
if (zos != null) { |
||||
zos.finish() |
||||
zos.close() |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Zip the files. |
||||
* |
||||
* @param srcFiles The source of files. |
||||
* @param zipFile The ZIP file. |
||||
* @param comment The comment. |
||||
* @return `true`: success<br></br>`false`: fail |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
@JvmOverloads |
||||
fun zipFiles( |
||||
srcFiles: Collection<File>?, |
||||
zipFile: File?, |
||||
comment: String? = null |
||||
): Boolean { |
||||
if (srcFiles == null || zipFile == null) return false |
||||
var zos: ZipOutputStream? = null |
||||
try { |
||||
zos = ZipOutputStream(FileOutputStream(zipFile)) |
||||
for (srcFile in srcFiles) { |
||||
if (!zipFile(srcFile, "", zos, comment)) return false |
||||
} |
||||
return true |
||||
} finally { |
||||
if (zos != null) { |
||||
zos.finish() |
||||
zos.close() |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Zip the file. |
||||
* |
||||
* @param srcFilePath The path of source file. |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @return `true`: success<br></br>`false`: fail |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun zipFile( |
||||
srcFilePath: String, |
||||
zipFilePath: String |
||||
): Boolean { |
||||
return zipFile(getFileByPath(srcFilePath), getFileByPath(zipFilePath), null) |
||||
} |
||||
|
||||
/** |
||||
* Zip the file. |
||||
* |
||||
* @param srcFilePath The path of source file. |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @param comment The comment. |
||||
* @return `true`: success<br></br>`false`: fail |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun zipFile( |
||||
srcFilePath: String, |
||||
zipFilePath: String, |
||||
comment: String |
||||
): Boolean { |
||||
return zipFile(getFileByPath(srcFilePath), getFileByPath(zipFilePath), comment) |
||||
} |
||||
|
||||
/** |
||||
* Zip the file. |
||||
* |
||||
* @param srcFile The source of file. |
||||
* @param zipFile The ZIP file. |
||||
* @param comment The comment. |
||||
* @return `true`: success<br></br>`false`: fail |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
@JvmOverloads |
||||
fun zipFile( |
||||
srcFile: File?, |
||||
zipFile: File?, |
||||
comment: String? = null |
||||
): Boolean { |
||||
if (srcFile == null || zipFile == null) return false |
||||
ZipOutputStream(FileOutputStream(zipFile)).use { zos -> |
||||
return zipFile( |
||||
srcFile, |
||||
"", |
||||
zos, |
||||
comment |
||||
) |
||||
} |
||||
} |
||||
|
||||
@Throws(IOException::class) |
||||
private fun zipFile( |
||||
srcFile: File, |
||||
rootPath: String, |
||||
zos: ZipOutputStream, |
||||
comment: String? |
||||
): Boolean { |
||||
var rootPath = rootPath |
||||
if (!srcFile.exists()) return true |
||||
rootPath = rootPath + (if (isSpace(rootPath)) "" else File.separator) + srcFile.name |
||||
if (srcFile.isDirectory) { |
||||
val fileList = srcFile.listFiles() |
||||
if (fileList == null || fileList.isEmpty()) { |
||||
val entry = ZipEntry("$rootPath/") |
||||
entry.comment = comment |
||||
zos.putNextEntry(entry) |
||||
zos.closeEntry() |
||||
} else { |
||||
for (file in fileList) { |
||||
if (!zipFile(file, rootPath, zos, comment)) return false |
||||
} |
||||
} |
||||
} else { |
||||
BufferedInputStream(FileInputStream(srcFile)).use { `is` -> |
||||
val entry = ZipEntry(rootPath) |
||||
entry.comment = comment |
||||
zos.putNextEntry(entry) |
||||
zos.write(`is`.readBytes()) |
||||
zos.closeEntry() |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
/** |
||||
* Unzip the file. |
||||
* |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @param destDirPath The path of destination directory. |
||||
* @return the unzipped files |
||||
* @throws IOException if unzip unsuccessfully |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun unzipFile(zipFilePath: String, destDirPath: String): List<File>? { |
||||
return unzipFileByKeyword(zipFilePath, destDirPath, null) |
||||
} |
||||
|
||||
/** |
||||
* Unzip the file. |
||||
* |
||||
* @param zipFile The ZIP file. |
||||
* @param destDir The destination directory. |
||||
* @return the unzipped files |
||||
* @throws IOException if unzip unsuccessfully |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun unzipFile( |
||||
zipFile: File, |
||||
destDir: File |
||||
): List<File>? { |
||||
return unzipFileByKeyword(zipFile, destDir, null) |
||||
} |
||||
|
||||
/** |
||||
* Unzip the file by keyword. |
||||
* |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @param destDirPath The path of destination directory. |
||||
* @param keyword The keyboard. |
||||
* @return the unzipped files |
||||
* @throws IOException if unzip unsuccessfully |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun unzipFileByKeyword( |
||||
zipFilePath: String, |
||||
destDirPath: String, |
||||
keyword: String? |
||||
): List<File>? { |
||||
return unzipFileByKeyword( |
||||
getFileByPath(zipFilePath), |
||||
getFileByPath(destDirPath), |
||||
keyword |
||||
) |
||||
} |
||||
|
||||
/** |
||||
* Unzip the file by keyword. |
||||
* |
||||
* @param zipFile The ZIP file. |
||||
* @param destDir The destination directory. |
||||
* @param keyword The keyboard. |
||||
* @return the unzipped files |
||||
* @throws IOException if unzip unsuccessfully |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun unzipFileByKeyword( |
||||
zipFile: File?, |
||||
destDir: File?, |
||||
keyword: String? |
||||
): List<File>? { |
||||
if (zipFile == null || destDir == null) return null |
||||
val files = ArrayList<File>() |
||||
val zip = ZipFile(zipFile) |
||||
val entries = zip.entries() |
||||
try { |
||||
if (isSpace(keyword)) { |
||||
while (entries.hasMoreElements()) { |
||||
val entry = entries.nextElement() as ZipEntry |
||||
val entryName = entry.name |
||||
if (entryName.contains("../")) { |
||||
Log.e("ZipUtils", "entryName: $entryName is dangerous!") |
||||
continue |
||||
} |
||||
if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files |
||||
} |
||||
} else { |
||||
while (entries.hasMoreElements()) { |
||||
val entry = entries.nextElement() as ZipEntry |
||||
val entryName = entry.name |
||||
if (entryName.contains("../")) { |
||||
Log.e("ZipUtils", "entryName: $entryName is dangerous!") |
||||
continue |
||||
} |
||||
if (entryName.contains(keyword!!)) { |
||||
if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files |
||||
} |
||||
} |
||||
} |
||||
} finally { |
||||
zip.close() |
||||
} |
||||
return files |
||||
} |
||||
|
||||
@Throws(IOException::class) |
||||
private fun unzipChildFile( |
||||
destDir: File, |
||||
files: MutableList<File>, |
||||
zip: ZipFile, |
||||
entry: ZipEntry, |
||||
name: String |
||||
): Boolean { |
||||
val file = File(destDir, name) |
||||
files.add(file) |
||||
if (entry.isDirectory) { |
||||
return createOrExistsDir(file) |
||||
} else { |
||||
if (!createOrExistsFile(file)) return false |
||||
BufferedInputStream(zip.getInputStream(entry)).use { `in` -> |
||||
BufferedOutputStream(FileOutputStream(file)).use { out -> |
||||
out.write(`in`.readBytes()) |
||||
} |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
/** |
||||
* Return the files' path in ZIP file. |
||||
* |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @return the files' path in ZIP file |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun getFilesPath(zipFilePath: String): List<String>? { |
||||
return getFilesPath(getFileByPath(zipFilePath)) |
||||
} |
||||
|
||||
/** |
||||
* Return the files' path in ZIP file. |
||||
* |
||||
* @param zipFile The ZIP file. |
||||
* @return the files' path in ZIP file |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun getFilesPath(zipFile: File?): List<String>? { |
||||
if (zipFile == null) return null |
||||
val paths = ArrayList<String>() |
||||
val zip = ZipFile(zipFile) |
||||
val entries = zip.entries() |
||||
while (entries.hasMoreElements()) { |
||||
val entryName = (entries.nextElement() as ZipEntry).name |
||||
if (entryName.contains("../")) { |
||||
Log.e("ZipUtils", "entryName: $entryName is dangerous!") |
||||
paths.add(entryName) |
||||
} else { |
||||
paths.add(entryName) |
||||
} |
||||
} |
||||
zip.close() |
||||
return paths |
||||
} |
||||
|
||||
/** |
||||
* Return the files' comment in ZIP file. |
||||
* |
||||
* @param zipFilePath The path of ZIP file. |
||||
* @return the files' comment in ZIP file |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun getComments(zipFilePath: String): List<String>? { |
||||
return getComments(getFileByPath(zipFilePath)) |
||||
} |
||||
|
||||
/** |
||||
* Return the files' comment in ZIP file. |
||||
* |
||||
* @param zipFile The ZIP file. |
||||
* @return the files' comment in ZIP file |
||||
* @throws IOException if an I/O error has occurred |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun getComments(zipFile: File?): List<String>? { |
||||
if (zipFile == null) return null |
||||
val comments = ArrayList<String>() |
||||
val zip = ZipFile(zipFile) |
||||
val entries = zip.entries() |
||||
while (entries.hasMoreElements()) { |
||||
val entry = entries.nextElement() as ZipEntry |
||||
comments.add(entry.comment) |
||||
} |
||||
zip.close() |
||||
return comments |
||||
} |
||||
|
||||
private fun createOrExistsDir(file: File?): Boolean { |
||||
return file != null && if (file.exists()) file.isDirectory else file.mkdirs() |
||||
} |
||||
|
||||
private fun createOrExistsFile(file: File?): Boolean { |
||||
if (file == null) return false |
||||
if (file.exists()) return file.isFile |
||||
if (!createOrExistsDir(file.parentFile)) return false |
||||
return try { |
||||
file.createNewFile() |
||||
} catch (e: IOException) { |
||||
e.printStackTrace() |
||||
false |
||||
} |
||||
} |
||||
|
||||
private fun getFileByPath(filePath: String): File? { |
||||
return if (isSpace(filePath)) null else File(filePath) |
||||
} |
||||
|
||||
private fun isSpace(s: String?): Boolean { |
||||
if (s == null) return true |
||||
var i = 0 |
||||
val len = s.length |
||||
while (i < len) { |
||||
if (!Character.isWhitespace(s[i])) { |
||||
return false |
||||
} |
||||
++i |
||||
} |
||||
return true |
||||
} |
||||
} |
Loading…
Reference in new issue