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