From 3c2f1b92c5422c3edf3005c86271828f98679a27 Mon Sep 17 00:00:00 2001 From: Ruman Kim Date: Fri, 7 Jun 2019 20:06:38 +0900 Subject: [PATCH 01/18] Update LICENSE --- LICENSE | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index ff84f06..b30d16b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,22 +1,22 @@ -https://code.google.com/p/ziparchive/ - -The MIT License (MIT) +MIT License Copyright (c) 2013 yamamura tatsuhiko +Copyright (c) 2019 Ruman Kim -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 1f8c18f059ec81aa390d776e6ab5547aee34a4d9 Mon Sep 17 00:00:00 2001 From: Ruman Date: Fri, 7 Jun 2019 22:44:38 +0900 Subject: [PATCH 02/18] Chang iOS ZipArchiver to SSZipArchive https://github.com/ZipArchive/ZipArchive --- Assets/Plugins/Android/zipper.jar.meta | 29 +- Assets/Plugins/Ionic.Zip.dll | Bin 462336 -> 0 bytes Assets/Plugins/Ionic.Zip.dll.meta | 7 - Assets/Plugins/Zip.cs | 47 +- Assets/Plugins/iOS/Editor.meta | 8 + .../iOS/Editor/XcodePostProcessSteps.cs | 36 + .../iOS/Editor/XcodePostProcessSteps.cs.meta | 11 + Assets/Plugins/iOS/SSZipArchive.meta | 8 + Assets/Plugins/iOS/SSZipArchive/LICENSE.txt | 20 + .../Plugins/iOS/SSZipArchive/LICENSE.txt.meta | 7 + .../Plugins/iOS/SSZipArchive/SSZipArchive.h | 147 + .../iOS/SSZipArchive/SSZipArchive.h.meta | 32 + .../Plugins/iOS/SSZipArchive/SSZipArchive.m | 1231 ++++++++ .../iOS/SSZipArchive/SSZipArchive.m.meta | 32 + Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h | 68 + .../iOS/SSZipArchive/SSZipCommon.h.meta | 32 + Assets/Plugins/iOS/SSZipArchive/ZipArchive.h | 19 + .../iOS/SSZipArchive/ZipArchive.h.meta | 32 + Assets/Plugins/iOS/SSZipArchive/minizip.meta | 8 + .../Plugins/iOS/SSZipArchive/minizip/LICENSE | 17 + .../iOS/SSZipArchive/minizip/LICENSE.meta | 7 + Assets/Plugins/iOS/SSZipArchive/minizip/mz.h | 251 ++ .../iOS/SSZipArchive/minizip/mz.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_compat.c | 991 ++++++ .../iOS/SSZipArchive/minizip/mz_compat.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_compat.h | 250 ++ .../iOS/SSZipArchive/minizip/mz_compat.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_crypt.c | 196 ++ .../iOS/SSZipArchive/minizip/mz_crypt.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_crypt.h | 66 + .../iOS/SSZipArchive/minizip/mz_crypt.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_crypt_apple.c | 532 ++++ .../minizip/mz_crypt_apple.c.meta | 32 + .../Plugins/iOS/SSZipArchive/minizip/mz_os.c | 403 +++ .../iOS/SSZipArchive/minizip/mz_os.c.meta | 32 + .../Plugins/iOS/SSZipArchive/minizip/mz_os.h | 174 ++ .../iOS/SSZipArchive/minizip/mz_os.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_os_posix.c | 329 ++ .../SSZipArchive/minizip/mz_os_posix.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm.c | 623 ++++ .../iOS/SSZipArchive/minizip/mz_strm.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm.h | 134 + .../iOS/SSZipArchive/minizip/mz_strm.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_buf.c | 416 +++ .../SSZipArchive/minizip/mz_strm_buf.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_buf.h | 43 + .../SSZipArchive/minizip/mz_strm_buf.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_mem.c | 303 ++ .../SSZipArchive/minizip/mz_strm_mem.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_mem.h | 49 + .../SSZipArchive/minizip/mz_strm_mem.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_os.h | 41 + .../SSZipArchive/minizip/mz_strm_os.h.meta | 32 + .../SSZipArchive/minizip/mz_strm_os_posix.c | 228 ++ .../minizip/mz_strm_os_posix.c.meta | 32 + .../SSZipArchive/minizip/mz_strm_pkcrypt.c | 384 +++ .../minizip/mz_strm_pkcrypt.c.meta | 32 + .../SSZipArchive/minizip/mz_strm_pkcrypt.h | 47 + .../minizip/mz_strm_pkcrypt.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_split.c | 474 +++ .../SSZipArchive/minizip/mz_strm_split.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_split.h | 44 + .../SSZipArchive/minizip/mz_strm_split.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_wzaes.c | 407 +++ .../SSZipArchive/minizip/mz_strm_wzaes.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_wzaes.h | 47 + .../SSZipArchive/minizip/mz_strm_wzaes.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_zlib.c | 426 +++ .../SSZipArchive/minizip/mz_strm_zlib.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_strm_zlib.h | 44 + .../SSZipArchive/minizip/mz_strm_zlib.h.meta | 32 + .../Plugins/iOS/SSZipArchive/minizip/mz_zip.c | 2771 +++++++++++++++++ .../iOS/SSZipArchive/minizip/mz_zip.c.meta | 32 + .../Plugins/iOS/SSZipArchive/minizip/mz_zip.h | 248 ++ .../iOS/SSZipArchive/minizip/mz_zip.h.meta | 32 + .../iOS/SSZipArchive/minizip/mz_zip_rw.c | 2100 +++++++++++++ .../iOS/SSZipArchive/minizip/mz_zip_rw.c.meta | 32 + .../iOS/SSZipArchive/minizip/mz_zip_rw.h | 292 ++ .../iOS/SSZipArchive/minizip/mz_zip_rw.h.meta | 32 + Assets/Plugins/iOS/UnityZipFile.mm | 58 +- Assets/Plugins/iOS/UnityZipFile.mm.meta | 30 +- 81 files changed, 15075 insertions(+), 52 deletions(-) delete mode 100755 Assets/Plugins/Ionic.Zip.dll delete mode 100644 Assets/Plugins/Ionic.Zip.dll.meta create mode 100644 Assets/Plugins/iOS/Editor.meta create mode 100644 Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs create mode 100644 Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs.meta create mode 100644 Assets/Plugins/iOS/SSZipArchive.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/LICENSE.txt create mode 100644 Assets/Plugins/iOS/SSZipArchive/LICENSE.txt.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m create mode 100644 Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/ZipArchive.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/ZipArchive.h.meta create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c.meta create mode 100755 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h create mode 100644 Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h.meta diff --git a/Assets/Plugins/Android/zipper.jar.meta b/Assets/Plugins/Android/zipper.jar.meta index cd73fdf..b1b4208 100644 --- a/Assets/Plugins/Android/zipper.jar.meta +++ b/Assets/Plugins/Android/zipper.jar.meta @@ -1,4 +1,31 @@ fileFormatVersion: 2 guid: d92153e6d88864707b56d9e4fabc1209 -DefaultImporter: +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Ionic.Zip.dll b/Assets/Plugins/Ionic.Zip.dll deleted file mode 100755 index 723126698600ccbc874af936cfbca217df592f54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462336 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.=V}<(|A)Od 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

_qWQLiIv5`{`^y~E*hPbx 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

Y$45- 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ⅈ`tdT^Q*sS(y$Ey8A#1hF<$k>o2BQqaNkF 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 z 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

  • Zq(`_-yQPV7aCkRNIp&-m_`?eEIA)KH>nO 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 Jr2jhy{tbJeCz=2N diff --git a/Assets/Plugins/Ionic.Zip.dll.meta b/Assets/Plugins/Ionic.Zip.dll.meta deleted file mode 100644 index c46d9b8..0000000 --- a/Assets/Plugins/Ionic.Zip.dll.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4004f0d460b114c95bff6bbf651624e3 -MonoAssemblyImporter: - serializedVersion: 1 - iconMap: {} - executionOrder: {} - userData: diff --git a/Assets/Plugins/Zip.cs b/Assets/Plugins/Zip.cs index 2bbd4cd..0e60fba 100644 --- a/Assets/Plugins/Zip.cs +++ b/Assets/Plugins/Zip.cs @@ -1,10 +1,9 @@ using UnityEngine; -using System.Collections; using System; +using System.Collections; using System.Runtime.InteropServices; -using Ionic.Zip; -using System.Text; using System.IO; +using System.IO.Compression; public class ZipUtil { @@ -23,12 +22,24 @@ public class ZipUtil public static void Unzip (string zipFilePath, string location) { #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX - Directory.CreateDirectory (location); - - using (ZipFile zip = ZipFile.Read (zipFilePath)) { - - zip.ExtractAll (location, ExtractExistingFileAction.OverwriteSilently); - } + if (!location.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + location += Path.DirectorySeparatorChar; + + Directory.CreateDirectory(location); + + using (ZipArchive archive = ZipFile.Open(zipFilePath, ZipArchiveMode.Update)) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + string fullPath = Path.Combine(location, entry.FullName); + + if (string.IsNullOrEmpty(entry.Name)) + System.IO.Directory.CreateDirectory(fullPath); + else + entry.ExtractToFile(fullPath, true); + } + } + #elif UNITY_ANDROID using (AndroidJavaClass zipper = new AndroidJavaClass ("com.tsw.zipper")) { zipper.CallStatic ("unzip", zipFilePath, location); @@ -43,13 +54,17 @@ public static void Zip (string zipFileName, params string[] files) #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX string path = Path.GetDirectoryName(zipFileName); Directory.CreateDirectory (path); - - using (ZipFile zip = new ZipFile()) { - foreach (string file in files) { - zip.AddFile(file, ""); - } - zip.Save (zipFileName); - } + + // todo + // System.IO.Compression.ZipFile.ExtractToDirectory(srcPath, destPath); + + + // using (ZipFile zip = new ZipFile()) { + // foreach (string file in files) { + // zip.AddFile(file, ""); + // } + // zip.Save (zipFileName); + // } #elif UNITY_ANDROID using (AndroidJavaClass zipper = new AndroidJavaClass ("com.tsw.zipper")) { { diff --git a/Assets/Plugins/iOS/Editor.meta b/Assets/Plugins/iOS/Editor.meta new file mode 100644 index 0000000..cb0ce44 --- /dev/null +++ b/Assets/Plugins/iOS/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e7e54571267f24f698ed1cb69fb83b82 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs b/Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs new file mode 100644 index 0000000..2b5751e --- /dev/null +++ b/Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs @@ -0,0 +1,36 @@ + + +using UnityEditor; +using UnityEditor.Callbacks; +using System.Collections; +using UnityEditor.iOS.Xcode; +using System.IO; + +// https://forum.unity.com/threads/how-to-disable-the-filtering-of-emoji-characters.399028/ +public class XcodePostProcessSteps { + + // A post process step to modify the generated Xcode project. + [PostProcessBuild] + public static void DisableEmojiFilter(BuildTarget buildTarget, string pathToBuiltProject) { + + // Only continue if we're building for iOS + if (buildTarget == BuildTarget.iOS) { + + // Get Xcode project + string pbxprojPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj"; + PBXProject proj = new PBXProject(); + proj.ReadFromString(File.ReadAllText(pbxprojPath)); + + string target = proj.TargetGuidByName("Unity-iPhone"); + proj.SetBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", "HAVE_INTTYPES_H HAVE_PKCRYPT HAVE_STDINT_H HAVE_WZAES HAVE_ZLIB MZ_ZIP_NO_SIGNING $(inherited)"); + + proj.AddFrameworkToProject(target, "Security.framework", false); + proj.AddFileToBuild(target, proj.AddFile ("usr/lib/libiconv.2.tbd", "libiconv.2.tbd", PBXSourceTree.Sdk)); + proj.AddFileToBuild(target, proj.AddFile("usr/lib/libz.tbd", "libz.tbd", PBXSourceTree.Sdk)); + proj.AddBuildProperty(target, "GCC_ENABLE_OBJC_EXCEPTIONS", "YES"); + + // Write changes to the Xcode project + File.WriteAllText(pbxprojPath, proj.WriteToString()); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs.meta b/Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs.meta new file mode 100644 index 0000000..b238aa5 --- /dev/null +++ b/Assets/Plugins/iOS/Editor/XcodePostProcessSteps.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a1990d1e7d6b148309de5741d9b12413 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive.meta b/Assets/Plugins/iOS/SSZipArchive.meta new file mode 100644 index 0000000..ae47dde --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b53255760286456e8412a0422d02548 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/LICENSE.txt b/Assets/Plugins/iOS/SSZipArchive/LICENSE.txt new file mode 100755 index 0000000..e118fa4 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2010-2015, Sam Soffes, https://soff.es + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Assets/Plugins/iOS/SSZipArchive/LICENSE.txt.meta b/Assets/Plugins/iOS/SSZipArchive/LICENSE.txt.meta new file mode 100644 index 0000000..7ed6352 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/LICENSE.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 737c87f2a6ccb4b269f559547bf91905 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h new file mode 100755 index 0000000..655ac3b --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h @@ -0,0 +1,147 @@ +// +// SSZipArchive.h +// SSZipArchive +// +// Created by Sam Soffes on 7/21/10. +// Copyright (c) Sam Soffes 2010-2015. All rights reserved. +// + +#ifndef _SSZIPARCHIVE_H +#define _SSZIPARCHIVE_H + +#import +#include "SSZipCommon.h" + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const SSZipArchiveErrorDomain; +typedef NS_ENUM(NSInteger, SSZipArchiveErrorCode) { + SSZipArchiveErrorCodeFailedOpenZipFile = -1, + SSZipArchiveErrorCodeFailedOpenFileInZip = -2, + SSZipArchiveErrorCodeFileInfoNotLoadable = -3, + SSZipArchiveErrorCodeFileContentNotReadable = -4, + SSZipArchiveErrorCodeFailedToWriteFile = -5, + SSZipArchiveErrorCodeInvalidArguments = -6, +}; + +@protocol SSZipArchiveDelegate; + +@interface SSZipArchive : NSObject + +// Password check ++ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path; ++ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError * _Nullable * _Nullable)error NS_SWIFT_NOTHROW; + +// Unzip ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination; ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id)delegate; + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + error:(NSError * *)error; + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + error:(NSError * *)error + delegate:(nullable id)delegate NS_REFINED_FOR_SWIFT; + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + preserveAttributes:(BOOL)preserveAttributes + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + error:(NSError * *)error + delegate:(nullable id)delegate; + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler; + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler; + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + preserveAttributes:(BOOL)preserveAttributes + overwrite:(BOOL)overwrite + nestedZipLevel:(NSInteger)nestedZipLevel + password:(nullable NSString *)password + error:(NSError **)error + delegate:(nullable id)delegate + progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler; + +// Zip +// default compression level is Z_DEFAULT_COMPRESSION (from "zlib.h") +// keepParentDirectory: if YES, then unzipping will give `directoryName/fileName`. If NO, then unzipping will just give `fileName`. Default is NO. + +// without password ++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths; ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath; + ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory; + +// with optional password, default encryption is AES +// don't use AES if you need compatibility with native macOS unzip and Archive Utility ++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths withPassword:(nullable NSString *)password; ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password; ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password; ++ (BOOL)createZipFileAtPath:(NSString *)path + withContentsOfDirectory:(NSString *)directoryPath + keepParentDirectory:(BOOL)keepParentDirectory + withPassword:(nullable NSString *)password + andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler; ++ (BOOL)createZipFileAtPath:(NSString *)path + withContentsOfDirectory:(NSString *)directoryPath + keepParentDirectory:(BOOL)keepParentDirectory + compressionLevel:(int)compressionLevel + password:(nullable NSString *)password + AES:(BOOL)aes + progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER; +- (BOOL)open; + +/// write empty folder +- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password; +/// write file +- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password; +- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password; +- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes; +/// write data +- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password; +- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes; + +- (BOOL)close; + +@end + +@protocol SSZipArchiveDelegate + +@optional + +- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo; +- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath; + +- (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; +- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; +- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; +- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath unzippedFilePath:(NSString *)unzippedFilePath; + +- (void)zipArchiveProgressEvent:(unsigned long long)loaded total:(unsigned long long)total; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* _SSZIPARCHIVE_H */ diff --git a/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h.meta b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h.meta new file mode 100644 index 0000000..48b0917 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: b46ac17d063b346999c087edeee5735a +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m new file mode 100755 index 0000000..827d51f --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m @@ -0,0 +1,1231 @@ +// +// SSZipArchive.m +// SSZipArchive +// +// Created by Sam Soffes on 7/21/10. +// Copyright (c) Sam Soffes 2010-2015. All rights reserved. +// + +#import "SSZipArchive.h" +#include "minizip/mz_compat.h" +#include "minizip/mz_zip.h" +#include +#include + +NSString *const SSZipArchiveErrorDomain = @"SSZipArchiveErrorDomain"; + +#define CHUNK 16384 + +int _zipOpenEntry(zipFile entry, NSString *name, const zip_fileinfo *zipfi, int level, NSString *password, BOOL aes); +BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo); + +#ifndef API_AVAILABLE +// Xcode 7- compatibility +#define API_AVAILABLE(...) +#endif + +@interface NSData(SSZipArchive) +- (NSString *)_base64RFC4648 API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)); +- (NSString *)_hexString; +@end + +@interface NSString (SSZipArchive) +- (NSString *)_sanitizedPath; +@end + +@interface SSZipArchive () +- (instancetype)init NS_DESIGNATED_INITIALIZER; +@end + +@implementation SSZipArchive +{ + /// path for zip file + NSString *_path; + zipFile _zip; +} + +#pragma mark - Password check + ++ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path { + // Begin opening + zipFile zip = unzOpen(path.fileSystemRepresentation); + if (zip == NULL) { + return NO; + } + + BOOL passwordProtected = NO; + int ret = unzGoToFirstFile(zip); + if (ret == UNZ_OK) { + do { + ret = unzOpenCurrentFile(zip); + if (ret != UNZ_OK) { + // attempting with an arbitrary password to workaround `unzOpenCurrentFile` limitation on AES encrypted files + ret = unzOpenCurrentFilePassword(zip, ""); + unzCloseCurrentFile(zip); + if (ret == UNZ_OK || ret == MZ_PASSWORD_ERROR) { + passwordProtected = YES; + } + break; + } + unz_file_info fileInfo = {}; + ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + unzCloseCurrentFile(zip); + if (ret != UNZ_OK) { + break; + } else if ((fileInfo.flag & MZ_ZIP_FLAG_ENCRYPTED) == 1) { + passwordProtected = YES; + break; + } + + ret = unzGoToNextFile(zip); + } while (ret == UNZ_OK); + } + + unzClose(zip); + return passwordProtected; +} + ++ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError **)error { + if (error) { + *error = nil; + } + + zipFile zip = unzOpen(path.fileSystemRepresentation); + if (zip == NULL) { + if (error) { + *error = [NSError errorWithDomain:SSZipArchiveErrorDomain + code:SSZipArchiveErrorCodeFailedOpenZipFile + userInfo:@{NSLocalizedDescriptionKey: @"failed to open zip file"}]; + } + return NO; + } + + // Initialize passwordValid to YES (No password required) + BOOL passwordValid = YES; + int ret = unzGoToFirstFile(zip); + if (ret == UNZ_OK) { + do { + if (pw.length == 0) { + ret = unzOpenCurrentFile(zip); + } else { + ret = unzOpenCurrentFilePassword(zip, [pw cStringUsingEncoding:NSUTF8StringEncoding]); + } + if (ret != UNZ_OK) { + if (ret != MZ_PASSWORD_ERROR) { + if (error) { + *error = [NSError errorWithDomain:SSZipArchiveErrorDomain + code:SSZipArchiveErrorCodeFailedOpenFileInZip + userInfo:@{NSLocalizedDescriptionKey: @"failed to open first file in zip file"}]; + } + } + passwordValid = NO; + break; + } + unz_file_info fileInfo = {}; + ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + if (ret != UNZ_OK) { + if (error) { + *error = [NSError errorWithDomain:SSZipArchiveErrorDomain + code:SSZipArchiveErrorCodeFileInfoNotLoadable + userInfo:@{NSLocalizedDescriptionKey: @"failed to retrieve info for file"}]; + } + passwordValid = NO; + break; + } else if ((fileInfo.flag & 1) == 1) { + unsigned char buffer[10] = {0}; + int readBytes = unzReadCurrentFile(zip, buffer, (unsigned)MIN(10UL,fileInfo.uncompressed_size)); + if (readBytes < 0) { + // Let's assume error Z_DATA_ERROR is caused by an invalid password + // Let's assume other errors are caused by Content Not Readable + if (readBytes != Z_DATA_ERROR) { + if (error) { + *error = [NSError errorWithDomain:SSZipArchiveErrorDomain + code:SSZipArchiveErrorCodeFileContentNotReadable + userInfo:@{NSLocalizedDescriptionKey: @"failed to read contents of file entry"}]; + } + } + passwordValid = NO; + break; + } + passwordValid = YES; + break; + } + + unzCloseCurrentFile(zip); + ret = unzGoToNextFile(zip); + } while (ret == UNZ_OK); + } + + unzClose(zip); + return passwordValid; +} + +#pragma mark - Unzipping + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination +{ + return [self unzipFileAtPath:path toDestination:destination delegate:nil]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(nullable NSString *)password error:(NSError **)error +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:error delegate:nil progressHandler:nil completionHandler:nil]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id)delegate +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:delegate progressHandler:nil completionHandler:nil]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + error:(NSError **)error + delegate:(nullable id)delegate +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + overwrite:(BOOL)overwrite + password:(NSString *)password + progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + preserveAttributes:(BOOL)preserveAttributes + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + error:(NSError * *)error + delegate:(nullable id)delegate +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:preserveAttributes overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + preserveAttributes:(BOOL)preserveAttributes + overwrite:(BOOL)overwrite + password:(nullable NSString *)password + error:(NSError **)error + delegate:(nullable id)delegate + progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler +{ + return [self unzipFileAtPath:path toDestination:destination preserveAttributes:preserveAttributes overwrite:overwrite nestedZipLevel:0 password:password error:error delegate:delegate progressHandler:progressHandler completionHandler:completionHandler]; +} + ++ (BOOL)unzipFileAtPath:(NSString *)path + toDestination:(NSString *)destination + preserveAttributes:(BOOL)preserveAttributes + overwrite:(BOOL)overwrite + nestedZipLevel:(NSInteger)nestedZipLevel + password:(nullable NSString *)password + error:(NSError **)error + delegate:(nullable id)delegate + progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler + completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler +{ + // Guard against empty strings + if (path.length == 0 || destination.length == 0) + { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"received invalid argument(s)"}; + NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeInvalidArguments userInfo:userInfo]; + if (error) + { + *error = err; + } + if (completionHandler) + { + completionHandler(nil, NO, err); + } + return NO; + } + + // Begin opening + zipFile zip = unzOpen(path.fileSystemRepresentation); + if (zip == NULL) + { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open zip file"}; + NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenZipFile userInfo:userInfo]; + if (error) + { + *error = err; + } + if (completionHandler) + { + completionHandler(nil, NO, err); + } + return NO; + } + + NSDictionary * fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; + unsigned long long fileSize = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue]; + unsigned long long currentPosition = 0; + + unz_global_info globalInfo = {}; + unzGetGlobalInfo(zip, &globalInfo); + + // Begin unzipping + int ret = 0; + ret = unzGoToFirstFile(zip); + if (ret != UNZ_OK && ret != MZ_END_OF_LIST) + { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open first file in zip file"}; + NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:userInfo]; + if (error) + { + *error = err; + } + if (completionHandler) + { + completionHandler(nil, NO, err); + } + unzClose(zip); + return NO; + } + + BOOL success = YES; + BOOL canceled = NO; + int crc_ret = 0; + unsigned char buffer[4096] = {0}; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSMutableArray *directoriesModificationDates = [[NSMutableArray alloc] init]; + + // Message delegate + if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) { + [delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo]; + } + if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { + [delegate zipArchiveProgressEvent:currentPosition total:fileSize]; + } + + NSInteger currentFileNumber = -1; + NSError *unzippingError; + do { + currentFileNumber++; + if (ret == MZ_END_OF_LIST) { + break; + } + @autoreleasepool { + if (password.length == 0) { + ret = unzOpenCurrentFile(zip); + } else { + ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSUTF8StringEncoding]); + } + + if (ret != UNZ_OK) { + unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:@{NSLocalizedDescriptionKey: @"failed to open file in zip file"}]; + success = NO; + break; + } + + // Reading data and write to file + unz_file_info fileInfo; + memset(&fileInfo, 0, sizeof(unz_file_info)); + + ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + if (ret != UNZ_OK) { + unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:@{NSLocalizedDescriptionKey: @"failed to retrieve info for file"}]; + success = NO; + unzCloseCurrentFile(zip); + break; + } + + currentPosition += fileInfo.compressed_size; + + // Message delegate + if ([delegate respondsToSelector:@selector(zipArchiveShouldUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { + if (![delegate zipArchiveShouldUnzipFileAtIndex:currentFileNumber + totalFiles:(NSInteger)globalInfo.number_entry + archivePath:path + fileInfo:fileInfo]) { + success = NO; + canceled = YES; + break; + } + } + if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { + [delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry + archivePath:path fileInfo:fileInfo]; + } + if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { + [delegate zipArchiveProgressEvent:(NSInteger)currentPosition total:(NSInteger)fileSize]; + } + + char *filename = (char *)malloc(fileInfo.size_filename + 1); + if (filename == NULL) + { + success = NO; + break; + } + + unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0); + filename[fileInfo.size_filename] = '\0'; + + BOOL fileIsSymbolicLink = _fileIsSymbolicLink(&fileInfo); + + NSString * strPath = [SSZipArchive _filenameStringWithCString:filename + version_made_by:fileInfo.version + general_purpose_flag:fileInfo.flag + size:fileInfo.size_filename]; + if ([strPath hasPrefix:@"__MACOSX/"]) { + // ignoring resource forks: https://superuser.com/questions/104500/what-is-macosx-folder + unzCloseCurrentFile(zip); + ret = unzGoToNextFile(zip); + free(filename); + continue; + } + + // Check if it contains directory + BOOL isDirectory = NO; + if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') { + isDirectory = YES; + } + free(filename); + + // Sanitize paths in the file name. + strPath = [strPath _sanitizedPath]; + if (!strPath.length) { + // if filename data is unsalvageable, we default to currentFileNumber + strPath = @(currentFileNumber).stringValue; + } + + NSString *fullPath = [destination stringByAppendingPathComponent:strPath]; + NSError *err = nil; + NSDictionary *directoryAttr; + if (preserveAttributes) { + NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.mz_dos_date]; + directoryAttr = @{NSFileCreationDate: modDate, NSFileModificationDate: modDate}; + [directoriesModificationDates addObject: @{@"path": fullPath, @"modDate": modDate}]; + } + if (isDirectory) { + [fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr error:&err]; + } else { + [fileManager createDirectoryAtPath:fullPath.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:directoryAttr error:&err]; + } + if (err != nil) { + if ([err.domain isEqualToString:NSCocoaErrorDomain] && + err.code == 640) { + unzippingError = err; + unzCloseCurrentFile(zip); + success = NO; + break; + } + NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription); + } + + if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) { + //FIXME: couldBe CRC Check? + unzCloseCurrentFile(zip); + ret = unzGoToNextFile(zip); + continue; + } + + if (isDirectory && !fileIsSymbolicLink) { + // nothing to read/write for a directory + } else if (!fileIsSymbolicLink) { + // ensure we are not creating stale file entries + int readBytes = unzReadCurrentFile(zip, buffer, 4096); + if (readBytes >= 0) { + FILE *fp = fopen(fullPath.fileSystemRepresentation, "wb"); + while (fp) { + if (readBytes > 0) { + if (0 == fwrite(buffer, readBytes, 1, fp)) { + if (ferror(fp)) { + NSString *message = [NSString stringWithFormat:@"Failed to write file (check your free space)"]; + NSLog(@"[SSZipArchive] %@", message); + success = NO; + unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFailedToWriteFile userInfo:@{NSLocalizedDescriptionKey: message}]; + break; + } + } + } else { + break; + } + readBytes = unzReadCurrentFile(zip, buffer, 4096); + if (readBytes < 0) { + // Let's assume error Z_DATA_ERROR is caused by an invalid password + // Let's assume other errors are caused by Content Not Readable + success = NO; + } + } + + if (fp) { + fclose(fp); + + if (nestedZipLevel + && [fullPath.pathExtension.lowercaseString isEqualToString:@"zip"] + && [self unzipFileAtPath:fullPath + toDestination:fullPath.stringByDeletingLastPathComponent + preserveAttributes:preserveAttributes + overwrite:overwrite + nestedZipLevel:nestedZipLevel - 1 + password:password + error:nil + delegate:nil + progressHandler:nil + completionHandler:nil]) { + [directoriesModificationDates removeLastObject]; + [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil]; + } else if (preserveAttributes) { + + // Set the original datetime property + if (fileInfo.mz_dos_date != 0) { + NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.mz_dos_date]; + NSDictionary *attr = @{NSFileModificationDate: orgDate}; + + if (attr) { + if (![fileManager setAttributes:attr ofItemAtPath:fullPath error:nil]) { + // Can't set attributes + NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting modification date"); + } + } + } + + // Set the original permissions on the file (+read/write to solve #293) + uLong permissions = fileInfo.external_fa >> 16 | 0b110000000; + if (permissions != 0) { + // Store it into a NSNumber + NSNumber *permissionsValue = @(permissions); + + // Retrieve any existing attributes + NSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]]; + + // Set the value in the attributes dict + [attrs setObject:permissionsValue forKey:NSFilePosixPermissions]; + + // Update attributes + if (![fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil]) { + // Unable to set the permissions attribute + NSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions"); + } + } + } + } + else + { + // if we couldn't open file descriptor we can validate global errno to see the reason + int errnoSave = errno; + BOOL isSeriousError = NO; + switch (errnoSave) { + case EISDIR: + // Is a directory + // assumed case + break; + + case ENOSPC: + case EMFILE: + // No space left on device + // or + // Too many open files + isSeriousError = YES; + break; + + default: + // ignore case + // Just log the error + { + NSError *errorObject = [NSError errorWithDomain:NSPOSIXErrorDomain + code:errnoSave + userInfo:nil]; + NSLog(@"[SSZipArchive] Failed to open file on unzipping.(%@)", errorObject); + } + break; + } + + if (isSeriousError) { + // serious case + unzippingError = [NSError errorWithDomain:NSPOSIXErrorDomain + code:errnoSave + userInfo:nil]; + unzCloseCurrentFile(zip); + // Log the error + NSLog(@"[SSZipArchive] Failed to open file on unzipping.(%@)", unzippingError); + + // Break unzipping + success = NO; + break; + } + } + } else { + // Let's assume error Z_DATA_ERROR is caused by an invalid password + // Let's assume other errors are caused by Content Not Readable + success = NO; + break; + } + } + else + { + // Assemble the path for the symbolic link + NSMutableString *destinationPath = [NSMutableString string]; + int bytesRead = 0; + while ((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0) + { + buffer[bytesRead] = 0; + [destinationPath appendString:@((const char *)buffer)]; + } + if (bytesRead < 0) { + // Let's assume error Z_DATA_ERROR is caused by an invalid password + // Let's assume other errors are caused by Content Not Readable + success = NO; + break; + } + + // Check if the symlink exists and delete it if we're overwriting + if (overwrite) + { + if ([fileManager fileExistsAtPath:fullPath]) + { + NSError *error = nil; + BOOL removeSuccess = [fileManager removeItemAtPath:fullPath error:&error]; + if (!removeSuccess) + { + NSString *message = [NSString stringWithFormat:@"Failed to delete existing symbolic link at \"%@\"", error.localizedDescription]; + NSLog(@"[SSZipArchive] %@", message); + success = NO; + unzippingError = [NSError errorWithDomain:SSZipArchiveErrorDomain code:error.code userInfo:@{NSLocalizedDescriptionKey: message}]; + } + } + } + + // Create the symbolic link (making sure it stays relative if it was relative before) + int symlinkError = symlink([destinationPath cStringUsingEncoding:NSUTF8StringEncoding], + [fullPath cStringUsingEncoding:NSUTF8StringEncoding]); + + if (symlinkError != 0) + { + // Bubble the error up to the completion handler + NSString *message = [NSString stringWithFormat:@"Failed to create symbolic link at \"%@\" to \"%@\" - symlink() error code: %d", fullPath, destinationPath, errno]; + NSLog(@"[SSZipArchive] %@", message); + success = NO; + unzippingError = [NSError errorWithDomain:NSPOSIXErrorDomain code:symlinkError userInfo:@{NSLocalizedDescriptionKey: message}]; + } + } + + crc_ret = unzCloseCurrentFile(zip); + if (crc_ret == MZ_CRC_ERROR) { + // CRC ERROR + success = NO; + break; + } + ret = unzGoToNextFile(zip); + + // Message delegate + if ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { + [delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry + archivePath:path fileInfo:fileInfo]; + } else if ([delegate respondsToSelector: @selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:unzippedFilePath:)]) { + [delegate zipArchiveDidUnzipFileAtIndex: currentFileNumber totalFiles: (NSInteger)globalInfo.number_entry + archivePath:path unzippedFilePath: fullPath]; + } + + if (progressHandler) + { + progressHandler(strPath, fileInfo, currentFileNumber, globalInfo.number_entry); + } + } + } while (ret == UNZ_OK && success); + + // Close + unzClose(zip); + + // The process of decompressing the .zip archive causes the modification times on the folders + // to be set to the present time. So, when we are done, they need to be explicitly set. + // set the modification date on all of the directories. + if (success && preserveAttributes) { + NSError * err = nil; + for (NSDictionary * d in directoriesModificationDates) { + if (![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: [d objectForKey:@"modDate"]} ofItemAtPath:[d objectForKey:@"path"] error:&err]) { + NSLog(@"[SSZipArchive] Set attributes failed for directory: %@.", [d objectForKey:@"path"]); + } + if (err) { + NSLog(@"[SSZipArchive] Error setting directory file modification date attribute: %@", err.localizedDescription); + } + } + } + + // Message delegate + if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) { + [delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination]; + } + // final progress event = 100% + if (!canceled && [delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) { + [delegate zipArchiveProgressEvent:fileSize total:fileSize]; + } + + NSError *retErr = nil; + if (crc_ret == MZ_CRC_ERROR) + { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"crc check failed for file"}; + retErr = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:userInfo]; + } + + if (error) { + if (unzippingError) { + *error = unzippingError; + } + else { + *error = retErr; + } + } + if (completionHandler) + { + if (unzippingError) { + completionHandler(path, success, unzippingError); + } + else + { + completionHandler(path, success, retErr); + } + } + return success; +} + +#pragma mark - Zipping ++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths +{ + return [SSZipArchive createZipFileAtPath:path withFilesAtPaths:paths withPassword:nil]; +} ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath { + return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath withPassword:nil]; +} + ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory { + return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirectory withPassword:nil]; +} + ++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths withPassword:(NSString *)password +{ + SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path]; + BOOL success = [zipArchive open]; + if (success) { + for (NSString *filePath in paths) { + success &= [zipArchive writeFile:filePath withPassword:password]; + } + success &= [zipArchive close]; + } + return success; +} + ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password { + return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:NO withPassword:password]; +} + + ++ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password { + return [SSZipArchive createZipFileAtPath:path + withContentsOfDirectory:directoryPath + keepParentDirectory:keepParentDirectory + withPassword:password + andProgressHandler:nil + ]; +} + ++ (BOOL)createZipFileAtPath:(NSString *)path + withContentsOfDirectory:(NSString *)directoryPath + keepParentDirectory:(BOOL)keepParentDirectory + withPassword:(nullable NSString *)password + andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler { + return [self createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirectory compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES progressHandler:progressHandler]; +} + ++ (BOOL)createZipFileAtPath:(NSString *)path + withContentsOfDirectory:(NSString *)directoryPath + keepParentDirectory:(BOOL)keepParentDirectory + compressionLevel:(int)compressionLevel + password:(nullable NSString *)password + AES:(BOOL)aes + progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler { + + SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path]; + BOOL success = [zipArchive open]; + if (success) { + // use a local fileManager (queue/thread compatibility) + NSFileManager *fileManager = [[NSFileManager alloc] init]; + NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath]; + NSArray *allObjects = dirEnumerator.allObjects; + NSUInteger total = allObjects.count, complete = 0; + if (keepParentDirectory && !total) { + allObjects = @[@""]; + total = 1; + } + for (__strong NSString *fileName in allObjects) { + NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName]; + + if (keepParentDirectory) { + fileName = [directoryPath.lastPathComponent stringByAppendingPathComponent:fileName]; + } + + BOOL isDir; + [fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir]; + if (!isDir) { + // file + success &= [zipArchive writeFileAtPath:fullFilePath withFileName:fileName compressionLevel:compressionLevel password:password AES:aes]; + } else { + // directory + if (![fileManager enumeratorAtPath:fullFilePath].nextObject) { + // empty directory + success &= [zipArchive writeFolderAtPath:fullFilePath withFolderName:fileName withPassword:password]; + } + } + if (progressHandler) { + complete++; + progressHandler(complete, total); + } + } + success &= [zipArchive close]; + } + return success; +} + +// disabling `init` because designated initializer is `initWithPath:` +- (instancetype)init { @throw nil; } + +// designated initializer +- (instancetype)initWithPath:(NSString *)path +{ + if ((self = [super init])) { + _path = [path copy]; + } + return self; +} + + +- (BOOL)open +{ + NSAssert((_zip == NULL), @"Attempting to open an archive which is already open"); + _zip = zipOpen(_path.fileSystemRepresentation, APPEND_STATUS_CREATE); + return (NULL != _zip); +} + +- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password +{ + NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened"); + + zip_fileinfo zipInfo = {}; + + [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path]; + + int error = _zipOpenEntry(_zip, [folderName stringByAppendingString:@"/"], &zipInfo, Z_NO_COMPRESSION, password, NO); + const void *buffer = NULL; + zipWriteInFileInZip(_zip, buffer, 0); + zipCloseFileInZip(_zip); + return error == ZIP_OK; +} + +- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password +{ + return [self writeFileAtPath:path withFileName:nil withPassword:password]; +} + +- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password +{ + return [self writeFileAtPath:path withFileName:fileName compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES]; +} + +// supports writing files with logical folder/directory structure +// *path* is the absolute path of the file that will be compressed +// *fileName* is the relative name of the file how it is stored within the zip e.g. /folder/subfolder/text1.txt +- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes +{ + NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened"); + + FILE *input = fopen(path.fileSystemRepresentation, "r"); + if (NULL == input) { + return NO; + } + + if (!fileName) { + fileName = path.lastPathComponent; + } + + zip_fileinfo zipInfo = {}; + + [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path]; + + void *buffer = malloc(CHUNK); + if (buffer == NULL) + { + fclose(input); + return NO; + } + + int error = _zipOpenEntry(_zip, fileName, &zipInfo, compressionLevel, password, aes); + + while (!feof(input) && !ferror(input)) + { + unsigned int len = (unsigned int) fread(buffer, 1, CHUNK, input); + zipWriteInFileInZip(_zip, buffer, len); + } + + zipCloseFileInZip(_zip); + free(buffer); + fclose(input); + return error == ZIP_OK; +} + +- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password +{ + return [self writeData:data filename:filename compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES]; +} + +- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes +{ + if (!_zip) { + return NO; + } + if (!data) { + return NO; + } + zip_fileinfo zipInfo = {}; + [SSZipArchive zipInfo:&zipInfo setDate:[NSDate date]]; + + int error = _zipOpenEntry(_zip, filename, &zipInfo, compressionLevel, password, aes); + + zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length); + + zipCloseFileInZip(_zip); + return error == ZIP_OK; +} + +- (BOOL)close +{ + NSAssert((_zip != NULL), @"[SSZipArchive] Attempting to close an archive which was never opened"); + int error = zipClose(_zip, NULL); + _zip = nil; + return error == ZIP_OK; +} + +#pragma mark - Private + ++ (NSString *)_filenameStringWithCString:(const char *)filename + version_made_by:(uint16_t)version_made_by + general_purpose_flag:(uint16_t)flag + size:(uint16_t)size_filename { + + // Respect Language encoding flag only reading filename as UTF-8 when this is set + // when file entry created on dos system. + // + // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + // Bit 11: Language encoding flag (EFS). If this bit is set, + // the filename and comment fields for this file + // MUST be encoded using UTF-8. (see APPENDIX D) + uint16_t made_by = version_made_by >> 8; + BOOL made_on_dos = made_by == 0; + BOOL languageEncoding = (flag & (1 << 11)) != 0; + if (!languageEncoding && made_on_dos) { + // APPNOTE.TXT D.1: + // D.2 If general purpose bit 11 is unset, the file name and comment should conform + // to the original ZIP character encoding. If general purpose bit 11 is set, the + // filename and comment must support The Unicode Standard, Version 4.1.0 or + // greater using the character encoding form defined by the UTF-8 storage + // specification. The Unicode Standard is published by the The Unicode + // Consortium (www.unicode.org). UTF-8 encoded data stored within ZIP files + // is expected to not include a byte order mark (BOM). + + // Code Page 437 corresponds to kCFStringEncodingDOSLatinUS + NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingDOSLatinUS); + NSString* strPath = [NSString stringWithCString:filename encoding:encoding]; + if (strPath) { + return strPath; + } + } + + // attempting unicode encoding + NSString * strPath = @(filename); + if (strPath) { + return strPath; + } + + // if filename is non-unicode, detect and transform Encoding + NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename]; +// Testing availability of @available (https://stackoverflow.com/a/46927445/1033581) +#if __clang_major__ < 9 + // Xcode 8- + if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_9_2) { +#else + // Xcode 9+ + if (@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)) { +#endif + // supported encodings are in [NSString availableStringEncodings] + [NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil]; + } else { + // fallback to a simple manual detect for macOS 10.9 or older + NSArray *encodings = @[@(kCFStringEncodingGB_18030_2000), @(kCFStringEncodingShiftJIS)]; + for (NSNumber *encoding in encodings) { + strPath = [NSString stringWithCString:filename encoding:(NSStringEncoding)CFStringConvertEncodingToNSStringEncoding(encoding.unsignedIntValue)]; + if (strPath) { + break; + } + } + } + if (strPath) { + return strPath; + } + + // if filename encoding is non-detected, we default to something based on data + // _hexString is more readable than _base64RFC4648 for debugging unknown encodings + strPath = [data _hexString]; + return strPath; +} + ++ (void)zipInfo:(zip_fileinfo *)zipInfo setAttributesOfItemAtPath:(NSString *)path +{ + NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil]; + if (attr) + { + NSDate *fileDate = (NSDate *)[attr objectForKey:NSFileModificationDate]; + if (fileDate) + { + [self zipInfo:zipInfo setDate:fileDate]; + } + + // Write permissions into the external attributes, for details on this see here: https://unix.stackexchange.com/a/14727 + // Get the permissions value from the files attributes + NSNumber *permissionsValue = (NSNumber *)[attr objectForKey:NSFilePosixPermissions]; + if (permissionsValue != nil) { + // Get the short value for the permissions + short permissionsShort = permissionsValue.shortValue; + + // Convert this into an octal by adding 010000, 010000 being the flag for a regular file + NSInteger permissionsOctal = 0100000 + permissionsShort; + + // Convert this into a long value + uLong permissionsLong = @(permissionsOctal).unsignedLongValue; + + // Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte + + // Casted back to an unsigned int to match type of external_fa in minizip + zipInfo->external_fa = (unsigned int)(permissionsLong << 16L); + } + } +} + ++ (void)zipInfo:(zip_fileinfo *)zipInfo setDate:(NSDate *)date +{ + NSCalendar *currentCalendar = SSZipArchive._gregorian; + NSCalendarUnit flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; + NSDateComponents *components = [currentCalendar components:flags fromDate:date]; + struct tm tmz_date; + tmz_date.tm_sec = (unsigned int)components.second; + tmz_date.tm_min = (unsigned int)components.minute; + tmz_date.tm_hour = (unsigned int)components.hour; + tmz_date.tm_mday = (unsigned int)components.day; + // ISO/IEC 9899 struct tm is 0-indexed for January but NSDateComponents for gregorianCalendar is 1-indexed for January + tmz_date.tm_mon = (unsigned int)components.month - 1; + // ISO/IEC 9899 struct tm is 0-indexed for AD 1900 but NSDateComponents for gregorianCalendar is 1-indexed for AD 1 + tmz_date.tm_year = (unsigned int)components.year - 1900; + zipInfo->mz_dos_date = mz_zip_tm_to_dosdate(&tmz_date); +} + ++ (NSCalendar *)_gregorian +{ + static NSCalendar *gregorian; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; + }); + + return gregorian; +} + +// Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html +// Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss +// YYYYYYY is years from 1980 = 0 +// sssss is (seconds/2). +// +// 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24 +// 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 3 = 14:33:06 ++ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime +{ + // the whole `_dateWithMSDOSFormat:` method is equivalent but faster than this one line, + // essentially because `mktime` is slow: + //NSDate *date = [NSDate dateWithTimeIntervalSince1970:dosdate_to_time_t(msdosDateTime)]; + static const UInt32 kYearMask = 0xFE000000; + static const UInt32 kMonthMask = 0x1E00000; + static const UInt32 kDayMask = 0x1F0000; + static const UInt32 kHourMask = 0xF800; + static const UInt32 kMinuteMask = 0x7E0; + static const UInt32 kSecondMask = 0x1F; + + NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @"[SSZipArchive] MSDOS date masks don't add up"); + + NSDateComponents *components = [[NSDateComponents alloc] init]; + components.year = 1980 + ((msdosDateTime & kYearMask) >> 25); + components.month = (msdosDateTime & kMonthMask) >> 21; + components.day = (msdosDateTime & kDayMask) >> 16; + components.hour = (msdosDateTime & kHourMask) >> 11; + components.minute = (msdosDateTime & kMinuteMask) >> 5; + components.second = (msdosDateTime & kSecondMask) * 2; + + NSDate *date = [self._gregorian dateFromComponents:components]; + return date; +} + +@end + +int _zipOpenEntry(zipFile entry, NSString *name, const zip_fileinfo *zipfi, int level, NSString *password, BOOL aes) +{ + // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + uint16_t made_on_darwin = 19 << 8; + return zipOpenNewFileInZip5(entry, name.fileSystemRepresentation, zipfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.UTF8String, aes, made_on_darwin, 0, 0); +} + +#pragma mark - Private tools for file info + +BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo) +{ + // + // Determine whether this is a symbolic link: + // - File is stored with 'version made by' value of UNIX (3), + // as per https://www.pkware.com/documents/casestudies/APPNOTE.TXT + // in the upper byte of the version field. + // - BSD4.4 st_mode constants are stored in the high 16 bits of the + // external file attributes (defacto standard, verified against libarchive) + // + // The original constants can be found here: + // https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/stat.h + // + const uLong ZipUNIXVersion = 3; + const uLong BSD_SFMT = 0170000; + const uLong BSD_IFLNK = 0120000; + + BOOL fileIsSymbolicLink = ((fileInfo->version >> 8) == ZipUNIXVersion) && BSD_IFLNK == (BSD_SFMT & (fileInfo->external_fa >> 16)); + return fileIsSymbolicLink; +} + +#pragma mark - Private tools for unreadable encodings + +@implementation NSData (SSZipArchive) + +// `base64EncodedStringWithOptions` uses a base64 alphabet with '+' and '/'. +// we got those alternatives to make it compatible with filenames: https://en.wikipedia.org/wiki/Base64 +// * modified Base64 encoding for IMAP mailbox names (RFC 3501): uses '+' and ',' +// * modified Base64 for URL and filenames (RFC 4648): uses '-' and '_' +- (NSString *)_base64RFC4648 +{ + NSString *strName = [self base64EncodedStringWithOptions:0]; + strName = [strName stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + strName = [strName stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + return strName; +} + +// initWithBytesNoCopy from NSProgrammer, Jan 25 '12: https://stackoverflow.com/a/9009321/1033581 +// hexChars from Peter, Aug 19 '14: https://stackoverflow.com/a/25378464/1033581 +// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://stackoverflow.com/a/33501154/1033581 +- (NSString *)_hexString +{ + const char *hexChars = "0123456789ABCDEF"; + NSUInteger length = self.length; + const unsigned char *bytes = self.bytes; + char *chars = malloc(length * 2); + if (chars == NULL) { + // we directly raise an exception instead of using NSAssert to make sure assertion is not disabled as this is irrecoverable + [NSException raise:@"NSInternalInconsistencyException" format:@"failed malloc" arguments:nil]; + return nil; + } + char *s = chars; + NSUInteger i = length; + while (i--) { + *s++ = hexChars[*bytes >> 4]; + *s++ = hexChars[*bytes & 0xF]; + bytes++; + } + NSString *str = [[NSString alloc] initWithBytesNoCopy:chars + length:length * 2 + encoding:NSASCIIStringEncoding + freeWhenDone:YES]; + return str; +} + +@end + +#pragma mark Private tools for security + +@implementation NSString (SSZipArchive) + +// One implementation alternative would be to use the algorithm found at mz_path_resolve from https://github.com/nmoinvaz/minizip/blob/dev/mz_os.c, +// but making sure to work with unichar values and not ascii values to avoid breaking Unicode characters containing 2E ('.') or 2F ('/') in their decomposition +/// Sanitize path traversal characters to prevent directory backtracking. Ignoring these characters mimicks the default behavior of the Unarchiving tool on macOS. +- (NSString *)_sanitizedPath +{ + // Change Windows paths to Unix paths: https://en.wikipedia.org/wiki/Path_(computing) + // Possible improvement: only do this if the archive was created on a non-Unix system + NSString *strPath = [self stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; + + // Percent-encode file path (where path is defined by https://tools.ietf.org/html/rfc8089) + // The key part is to allow characters "." and "/" and disallow "%". + // CharacterSet.urlPathAllowed seems to do the job +#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __WATCH_OS_VERSION_MIN_REQUIRED >= 20000 || __TV_OS_VERSION_MIN_REQUIRED >= 90000) + strPath = [strPath stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet]; +#else + // Testing availability of @available (https://stackoverflow.com/a/46927445/1033581) +#if __clang_major__ < 9 + // Xcode 8- + if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4) { +#else + // Xcode 9+ + if (@available(macOS 10.9, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) { +#endif + strPath = [strPath stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet]; + } else { + strPath = [strPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } +#endif + + // `NSString.stringByAddingPercentEncodingWithAllowedCharacters:` may theorically fail: https://stackoverflow.com/questions/33558933/ + // But because we auto-detect encoding using `NSString.stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:`, + // we likely already prevent UTF-16, UTF-32 and invalid Unicode in the form of unpaired surrogate chars: https://stackoverflow.com/questions/53043876/ + // To be on the safe side, we will still perform a guard check. + if (strPath == nil) { + return nil; + } + + // Add scheme "file:///" to support sanitation on names with a colon like "file:a/../../../usr/bin" + strPath = [@"file:///" stringByAppendingString:strPath]; + + // Sanitize path traversal characters to prevent directory backtracking. Ignoring these characters mimicks the default behavior of the Unarchiving tool on macOS. + // "../../../../../../../../../../../tmp/test.txt" -> "tmp/test.txt" + // "a/b/../c.txt" -> "a/c.txt" + strPath = [NSURL URLWithString:strPath].standardizedURL.absoluteString; + + // Remove the "file:///" scheme + strPath = [strPath substringFromIndex:8]; + + // Remove the percent-encoding +#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __WATCH_OS_VERSION_MIN_REQUIRED >= 20000 || __TV_OS_VERSION_MIN_REQUIRED >= 90000) + strPath = strPath.stringByRemovingPercentEncoding; +#else + // Testing availability of @available (https://stackoverflow.com/a/46927445/1033581) +#if __clang_major__ < 9 + // Xcode 8- + if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4) { +#else + // Xcode 9+ + if (@available(macOS 10.9, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) { +#endif + strPath = strPath.stringByRemovingPercentEncoding; + } else { + strPath = [strPath stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } +#endif + + return strPath; +} + +@end diff --git a/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m.meta b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m.meta new file mode 100644 index 0000000..b2beea4 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/SSZipArchive.m.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 118808f2f3a094596a61047b09da7e1e +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h b/Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h new file mode 100755 index 0000000..78fa282 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h @@ -0,0 +1,68 @@ +#ifndef SSZipCommon +#define SSZipCommon + +// typedefs moved from mz_compat.h to here for public access + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + uint64_t number_entry; /* total number of entries in the central dir on this disk */ + uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */ + uint16_t size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uint32_t number_entry; /* total number of entries in the central dir on this disk */ + uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */ + uint16_t size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +/* https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT */ +typedef struct unz_file_info64_s +{ + uint16_t version; /* version made by 2 bytes */ + uint16_t version_needed; /* version needed to extract 2 bytes */ + uint16_t flag; /* general purpose bit flag 2 bytes */ + uint16_t compression_method; /* compression method 2 bytes */ + uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */ + uint32_t crc; /* crc-32 4 bytes */ + uint64_t compressed_size; /* compressed size 8 bytes */ + uint64_t uncompressed_size; /* uncompressed size 8 bytes */ + uint16_t size_filename; /* filename length 2 bytes */ + uint16_t size_file_extra; /* extra field length 2 bytes */ + uint16_t size_file_comment; /* file comment length 2 bytes */ + + uint32_t disk_num_start; /* disk number start 4 bytes */ + uint16_t internal_fa; /* internal file attributes 2 bytes */ + uint32_t external_fa; /* external file attributes 4 bytes */ + + uint64_t disk_offset; + + uint16_t size_file_extra_internal; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uint16_t version; /* version made by 2 bytes */ + uint16_t version_needed; /* version needed to extract 2 bytes */ + uint16_t flag; /* general purpose bit flag 2 bytes */ + uint16_t compression_method; /* compression method 2 bytes */ + uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */ + uint32_t crc; /* crc-32 4 bytes */ + uint32_t compressed_size; /* compressed size 4 bytes */ + uint32_t uncompressed_size; /* uncompressed size 4 bytes */ + uint16_t size_filename; /* filename length 2 bytes */ + uint16_t size_file_extra; /* extra field length 2 bytes */ + uint16_t size_file_comment; /* file comment length 2 bytes */ + + uint16_t disk_num_start; /* disk number start 2 bytes */ + uint16_t internal_fa; /* internal file attributes 2 bytes */ + uint32_t external_fa; /* external file attributes 4 bytes */ + + uint64_t disk_offset; +} unz_file_info; + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h.meta b/Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h.meta new file mode 100644 index 0000000..73d476c --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/SSZipCommon.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 717145442346b4b0a830ab9e93940795 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/ZipArchive.h b/Assets/Plugins/iOS/SSZipArchive/ZipArchive.h new file mode 100755 index 0000000..7a53df8 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/ZipArchive.h @@ -0,0 +1,19 @@ +// +// ZipArchive.h +// ZipArchive +// +// Created by Serhii Mumriak on 12/1/15. +// Copyright © 2015 smumryak. All rights reserved. +// + +#import + +//! Project version number for ZipArchive. +FOUNDATION_EXPORT double ZipArchiveVersionNumber; + +//! Project version string for ZipArchive. +FOUNDATION_EXPORT const unsigned char ZipArchiveVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + +#import "SSZipArchive.h" diff --git a/Assets/Plugins/iOS/SSZipArchive/ZipArchive.h.meta b/Assets/Plugins/iOS/SSZipArchive/ZipArchive.h.meta new file mode 100644 index 0000000..630357a --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/ZipArchive.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 78b4bcd5bec14425da2ccc7b9e11f2ae +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip.meta b/Assets/Plugins/iOS/SSZipArchive/minizip.meta new file mode 100644 index 0000000..d396f8d --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9bb971585ca214df592de7df3caecf14 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE b/Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE new file mode 100755 index 0000000..086295a --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE @@ -0,0 +1,17 @@ +Condition of use and distribution are the same as zlib: + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE.meta new file mode 100644 index 0000000..7389f4a --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cedaf81b4c11049b6ad16e7153a24458 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz.h new file mode 100755 index 0000000..abfe178 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz.h @@ -0,0 +1,251 @@ +/* mz.h -- Errors codes, zip flags and magic + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_H +#define MZ_H + +/***************************************************************************/ + +/* MZ_VERSION */ +#define MZ_VERSION ("2.8.7") + +/* MZ_ERROR */ +#define MZ_OK (0) /* zlib */ +#define MZ_STREAM_ERROR (-1) /* zlib */ +#define MZ_DATA_ERROR (-3) /* zlib */ +#define MZ_MEM_ERROR (-4) /* zlib */ +#define MZ_BUF_ERROR (-5) /* zlib */ +#define MZ_VERSION_ERROR (-6) /* zlib */ + +#define MZ_END_OF_LIST (-100) +#define MZ_END_OF_STREAM (-101) + +#define MZ_PARAM_ERROR (-102) +#define MZ_FORMAT_ERROR (-103) +#define MZ_INTERNAL_ERROR (-104) +#define MZ_CRC_ERROR (-105) +#define MZ_CRYPT_ERROR (-106) +#define MZ_EXIST_ERROR (-107) +#define MZ_PASSWORD_ERROR (-108) +#define MZ_SUPPORT_ERROR (-109) +#define MZ_HASH_ERROR (-110) +#define MZ_OPEN_ERROR (-111) +#define MZ_CLOSE_ERROR (-112) +#define MZ_SEEK_ERROR (-113) +#define MZ_TELL_ERROR (-114) +#define MZ_READ_ERROR (-115) +#define MZ_WRITE_ERROR (-116) +#define MZ_SIGN_ERROR (-117) +#define MZ_SYMLINK_ERROR (-118) + +/* MZ_OPEN */ +#define MZ_OPEN_MODE_READ (0x01) +#define MZ_OPEN_MODE_WRITE (0x02) +#define MZ_OPEN_MODE_READWRITE (MZ_OPEN_MODE_READ | MZ_OPEN_MODE_WRITE) +#define MZ_OPEN_MODE_APPEND (0x04) +#define MZ_OPEN_MODE_CREATE (0x08) +#define MZ_OPEN_MODE_EXISTING (0x10) + +/* MZ_SEEK */ +#define MZ_SEEK_SET (0) +#define MZ_SEEK_CUR (1) +#define MZ_SEEK_END (2) + +/* MZ_COMPRESS */ +#define MZ_COMPRESS_METHOD_STORE (0) +#define MZ_COMPRESS_METHOD_DEFLATE (8) +#define MZ_COMPRESS_METHOD_BZIP2 (12) +#define MZ_COMPRESS_METHOD_LZMA (14) +#define MZ_COMPRESS_METHOD_AES (99) + +#define MZ_COMPRESS_LEVEL_DEFAULT (-1) +#define MZ_COMPRESS_LEVEL_FAST (2) +#define MZ_COMPRESS_LEVEL_NORMAL (6) +#define MZ_COMPRESS_LEVEL_BEST (9) + +/* MZ_ZIP_FLAG */ +#define MZ_ZIP_FLAG_ENCRYPTED (1 << 0) +#define MZ_ZIP_FLAG_LZMA_EOS_MARKER (1 << 1) +#define MZ_ZIP_FLAG_DEFLATE_MAX (1 << 1) +#define MZ_ZIP_FLAG_DEFLATE_NORMAL (0) +#define MZ_ZIP_FLAG_DEFLATE_FAST (1 << 2) +#define MZ_ZIP_FLAG_DEFLATE_SUPER_FAST (MZ_ZIP_FLAG_DEFLATE_FAST | \ + MZ_ZIP_FLAG_DEFLATE_MAX) +#define MZ_ZIP_FLAG_DATA_DESCRIPTOR (1 << 3) +#define MZ_ZIP_FLAG_UTF8 (1 << 11) +#define MZ_ZIP_FLAG_MASK_LOCAL_INFO (1 << 13) + +/* MZ_ZIP_EXTENSION */ +#define MZ_ZIP_EXTENSION_ZIP64 (0x0001) +#define MZ_ZIP_EXTENSION_NTFS (0x000a) +#define MZ_ZIP_EXTENSION_AES (0x9901) +#define MZ_ZIP_EXTENSION_UNIX1 (0x000d) +#define MZ_ZIP_EXTENSION_SIGN (0x10c5) +#define MZ_ZIP_EXTENSION_HASH (0x1a51) +#define MZ_ZIP_EXTENSION_CDCD (0xcdcd) + +/* MZ_ZIP64 */ +#define MZ_ZIP64_AUTO (0) +#define MZ_ZIP64_FORCE (1) +#define MZ_ZIP64_DISABLE (2) + +/* MZ_HOST_SYSTEM */ +#define MZ_HOST_SYSTEM(VERSION_MADEBY) ((uint8_t)(VERSION_MADEBY >> 8)) +#define MZ_HOST_SYSTEM_MSDOS (0) +#define MZ_HOST_SYSTEM_UNIX (3) +#define MZ_HOST_SYSTEM_WINDOWS_NTFS (10) +#define MZ_HOST_SYSTEM_OSX_DARWIN (19) + +/* MZ_PKCRYPT */ +#define MZ_PKCRYPT_HEADER_SIZE (12) + +/* MZ_AES */ +#define MZ_AES_VERSION (1) +#define MZ_AES_ENCRYPTION_MODE_128 (0x01) +#define MZ_AES_ENCRYPTION_MODE_192 (0x02) +#define MZ_AES_ENCRYPTION_MODE_256 (0x03) +#define MZ_AES_KEY_LENGTH(MODE) (8 * (MODE & 3) + 8) +#define MZ_AES_KEY_LENGTH_MAX (32) +#define MZ_AES_BLOCK_SIZE (16) +#define MZ_AES_HEADER_SIZE(MODE) ((4 * (MODE & 3) + 4) + 2) +#define MZ_AES_FOOTER_SIZE (10) + +/* MZ_HASH */ +#define MZ_HASH_MD5 (10) +#define MZ_HASH_MD5_SIZE (16) +#define MZ_HASH_SHA1 (20) +#define MZ_HASH_SHA1_SIZE (20) +#define MZ_HASH_SHA256 (23) +#define MZ_HASH_SHA256_SIZE (32) +#define MZ_HASH_MAX_SIZE (256) + +/* MZ_ENCODING */ +#define MZ_ENCODING_CODEPAGE_437 (437) +#define MZ_ENCODING_CODEPAGE_932 (932) +#define MZ_ENCODING_CODEPAGE_936 (936) +#define MZ_ENCODING_CODEPAGE_950 (950) +#define MZ_ENCODING_UTF8 (65001) + +/* MZ_UTILITY */ +#define MZ_UNUSED(SYMBOL) ((void)SYMBOL) + +#ifndef MZ_CUSTOM_ALLOC +#define MZ_ALLOC(SIZE) (malloc(SIZE)) +#endif +#ifndef MZ_CUSTOM_FREE +#define MZ_FREE(PTR) (free(PTR)) +#endif + +#if defined(_WINDOWS) && defined(MZ_EXPORTS) +#define MZ_EXPORT __declspec(dllexport) +#else +#define MZ_EXPORT +#endif + +/***************************************************************************/ + +#include /* size_t, NULL, malloc */ +#include /* time_t, time() */ +#include /* memset, strncpy, strlen */ +#include + +#ifdef HAVE_STDINT_H +# include +#endif + +#ifndef __INT8_TYPE__ +typedef signed char int8_t; +#endif +#ifndef __INT16_TYPE__ +typedef short int16_t; +#endif +#ifndef __INT32_TYPE__ +typedef int int32_t; +#endif +#ifndef __INT64_TYPE__ +typedef long long int64_t; +#endif +#ifndef __UINT8_TYPE__ +typedef unsigned char uint8_t; +#endif +#ifndef __UINT16_TYPE__ +typedef unsigned short uint16_t; +#endif +#ifndef __UINT32_TYPE__ +typedef unsigned int uint32_t; +#endif +#ifndef __UINT64_TYPE__ +typedef unsigned long long uint64_t; +#endif + +#ifdef HAVE_INTTYPES_H +# include +#endif + +#ifndef PRId8 +# define PRId8 "hhd" +#endif +#ifndef PRId16 +# define PRId16 "hd" +#endif +#ifndef PRId32 +# define PRId32 "d" +#endif +#ifndef PRIu32 +# define PRIu32 "u" +#endif +#ifndef PRIx32 +# define PRIx32 "x" +#endif +#if ULONG_MAX == 4294967295UL +# ifndef PRId64 +# define PRId64 "lld" +# endif +# ifndef PRIu64 +# define PRIu64 "llu" +# endif +# ifndef PRIx64 +# define PRIx64 "llx" +# endif +#else +# ifndef PRId64 +# define PRId64 "ld" +# endif +# ifndef PRIu64 +# define PRIu64 "lu" +# endif +# ifndef PRIx64 +# define PRIx64 "lx" +# endif +#endif + +#ifndef INT16_MAX +# define INT16_MAX 32767 +#endif +#ifndef INT32_MAX +# define INT32_MAX 2147483647L +#endif +#ifndef INT64_MAX +# define INT64_MAX 9223372036854775807LL +#endif +#ifndef UINT16_MAX +# define UINT16_MAX 65535U +#endif +#ifndef UINT32_MAX +# define UINT32_MAX 4294967295UL +#endif +#ifndef UINT64_MAX +# define UINT64_MAX 18446744073709551615ULL +#endif + +/***************************************************************************/ + +#endif \ No newline at end of file diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz.h.meta new file mode 100644 index 0000000..d27c8e1 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 114f5cf8f192e474487c7825cb29a3d1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c new file mode 100755 index 0000000..6092606 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c @@ -0,0 +1,991 @@ +/* mz_compat.c -- Backwards compatible interface for older versions + Version 2.8.6, April 8, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 1998-2010 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_os.h" +#include "mz_strm.h" +#include "mz_strm_mem.h" +#include "mz_strm_os.h" +#include "mz_strm_zlib.h" +#include "mz_zip.h" + +#include /* SEEK */ + +#include "mz_compat.h" + +/***************************************************************************/ + +typedef struct mz_compat_s { + void *stream; + void *handle; + uint64_t entry_index; + int64_t entry_pos; + int64_t total_out; +} mz_compat; + +/***************************************************************************/ + +static int32_t zipConvertAppendToStreamMode(int append) +{ + int32_t mode = MZ_OPEN_MODE_WRITE; + switch (append) + { + case APPEND_STATUS_CREATE: + mode |= MZ_OPEN_MODE_CREATE; + break; + case APPEND_STATUS_CREATEAFTER: + mode |= MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_APPEND; + break; + case APPEND_STATUS_ADDINZIP: + mode |= MZ_OPEN_MODE_READ; + break; + } + return mode; +} + +zipFile zipOpen(const char *path, int append) +{ + zlib_filefunc64_def pzlib = mz_stream_os_get_interface(); + return zipOpen2(path, append, NULL, &pzlib); +} + +zipFile zipOpen64(const void *path, int append) +{ + zlib_filefunc64_def pzlib = mz_stream_os_get_interface(); + return zipOpen2(path, append, NULL, &pzlib); +} + +zipFile zipOpen2(const char *path, int append, const char **globalcomment, + zlib_filefunc_def *pzlib_filefunc_def) +{ + return zipOpen2_64(path, append, globalcomment, pzlib_filefunc_def); +} + +zipFile zipOpen2_64(const void *path, int append, const char **globalcomment, + zlib_filefunc64_def *pzlib_filefunc_def) +{ + zipFile zip = NULL; + int32_t mode = zipConvertAppendToStreamMode(append); + void *stream = NULL; + + if (pzlib_filefunc_def) + { + if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL) + return NULL; + } + else + { + if (mz_stream_os_create(&stream) == NULL) + return NULL; + } + + if (mz_stream_open(stream, path, mode) != MZ_OK) + { + mz_stream_delete(&stream); + return NULL; + } + + zip = zipOpen_MZ(stream, append, globalcomment); + + if (zip == NULL) + { + mz_stream_delete(&stream); + return NULL; + } + + return zip; +} + +zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment) +{ + mz_compat *compat = NULL; + int32_t err = MZ_OK; + int32_t mode = zipConvertAppendToStreamMode(append); + void *handle = NULL; + + mz_zip_create(&handle); + err = mz_zip_open(handle, stream, mode); + + if (err != MZ_OK) + { + mz_zip_delete(&handle); + return NULL; + } + + if (globalcomment != NULL) + mz_zip_get_comment(handle, globalcomment); + + compat = (mz_compat *)MZ_ALLOC(sizeof(mz_compat)); + if (compat != NULL) + { + compat->handle = handle; + compat->stream = stream; + } + else + { + mz_zip_delete(&handle); + } + + return (zipFile)compat; +} + +int zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi, + const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global, + uint16_t size_extrafield_global, const char *comment, uint16_t compression_method, int level, + int raw, int windowBits, int memLevel, int strategy, const char *password, + signed char aes, uint16_t version_madeby, uint16_t flag_base, int zip64) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file file_info; + uint64_t dos_date = 0; + + MZ_UNUSED(strategy); + MZ_UNUSED(memLevel); + MZ_UNUSED(windowBits); + MZ_UNUSED(size_extrafield_local); + MZ_UNUSED(extrafield_local); + + if (compat == NULL) + return ZIP_PARAMERROR; + + memset(&file_info, 0, sizeof(file_info)); + + if (zipfi != NULL) + { + if (zipfi->mz_dos_date != 0) + dos_date = zipfi->mz_dos_date; + else + dos_date = mz_zip_tm_to_dosdate(&zipfi->tmz_date); + + file_info.modified_date = mz_zip_dosdate_to_time_t(dos_date); + file_info.external_fa = zipfi->external_fa; + file_info.internal_fa = zipfi->internal_fa; + } + + if (filename == NULL) + filename = "-"; + + file_info.compression_method = compression_method; + file_info.filename = filename; + /* file_info.extrafield_local = extrafield_local; */ + /* file_info.extrafield_local_size = size_extrafield_local; */ + file_info.extrafield = extrafield_global; + file_info.extrafield_size = size_extrafield_global; + file_info.version_madeby = version_madeby; + file_info.comment = comment; + file_info.flag = flag_base; + if (zip64) + file_info.zip64 = MZ_ZIP64_FORCE; + else + file_info.zip64 = MZ_ZIP64_DISABLE; +#ifdef HAVE_WZAES + if ((aes && password != NULL) || (raw && (file_info.flag & MZ_ZIP_FLAG_ENCRYPTED))) + file_info.aes_version = MZ_AES_VERSION; +#endif + + return mz_zip_entry_write_open(compat->handle, &file_info, (int16_t)level, (uint8_t)raw, password); +} + +int zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len) +{ + mz_compat *compat = (mz_compat *)file; + int32_t written = 0; + if (compat == NULL || len >= INT32_MAX) + return ZIP_PARAMERROR; + written = mz_zip_entry_write(compat->handle, buf, (int32_t)len); + if ((written < 0) || ((uint32_t)written != len)) + return ZIP_ERRNO; + return ZIP_OK; +} + +int zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32) +{ + return zipCloseFileInZipRaw64(file, uncompressed_size, crc32); +} + +int zipCloseFileInZipRaw64(zipFile file, int64_t uncompressed_size, uint32_t crc32) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return ZIP_PARAMERROR; + return mz_zip_entry_close_raw(compat->handle, uncompressed_size, crc32); +} + +int zipCloseFileInZip(zipFile file) +{ + return zipCloseFileInZip64(file); +} + +int zipCloseFileInZip64(zipFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return ZIP_PARAMERROR; + return mz_zip_entry_close(compat->handle); +} + +int zipClose(zipFile file, const char *global_comment) +{ + return zipClose_64(file, global_comment); +} + +int zipClose_64(zipFile file, const char *global_comment) +{ + return zipClose2_64(file, global_comment, MZ_VERSION_MADEBY); +} + +int zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + + if (compat->handle != NULL) + err = zipClose2_MZ(file, global_comment, version_madeby); + + if (compat->stream != NULL) + { + mz_stream_close(compat->stream); + mz_stream_delete(&compat->stream); + } + + MZ_FREE(compat); + + return err; +} + +/* Only closes the zip handle, does not close the stream */ +int zipClose_MZ(zipFile file, const char *global_comment) +{ + return zipClose2_MZ(file, global_comment, MZ_VERSION_MADEBY); +} + +/* Only closes the zip handle, does not close the stream */ +int zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + + if (compat == NULL) + return ZIP_PARAMERROR; + if (compat->handle == NULL) + return err; + + if (global_comment != NULL) + mz_zip_set_comment(compat->handle, global_comment); + + mz_zip_set_version_madeby(compat->handle, version_madeby); + err = mz_zip_close(compat->handle); + mz_zip_delete(&compat->handle); + + return err; +} + +void* zipGetStream(zipFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return NULL; + return (void *)compat->stream; +} + +/***************************************************************************/ + +unzFile unzOpen(const char *path) +{ + return unzOpen64(path); +} + +unzFile unzOpen64(const void *path) +{ + zlib_filefunc64_def pzlib = mz_stream_os_get_interface(); + return unzOpen2(path, &pzlib); +} + +unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def) +{ + return unzOpen2_64(path, pzlib_filefunc_def); +} + +unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def) +{ + unzFile unz = NULL; + void *stream = NULL; + + if (pzlib_filefunc_def) + { + if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL) + return NULL; + } + else + { + if (mz_stream_os_create(&stream) == NULL) + return NULL; + } + + if (mz_stream_open(stream, path, MZ_OPEN_MODE_READ) != MZ_OK) + { + mz_stream_delete(&stream); + return NULL; + } + + unz = unzOpen_MZ(stream); + if (unz == NULL) + { + mz_stream_delete(&stream); + return NULL; + } + return unz; +} + +unzFile unzOpen_MZ(void *stream) +{ + mz_compat *compat = NULL; + int32_t err = MZ_OK; + void *handle = NULL; + + mz_zip_create(&handle); + err = mz_zip_open(handle, stream, MZ_OPEN_MODE_READ); + + if (err != MZ_OK) + { + mz_zip_delete(&handle); + return NULL; + } + + compat = (mz_compat *)MZ_ALLOC(sizeof(mz_compat)); + if (compat != NULL) + { + compat->handle = handle; + compat->stream = stream; + + mz_zip_goto_first_entry(compat->handle); + } + else + { + mz_zip_delete(&handle); + } + + return (unzFile)compat; +} + +int unzClose(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + + if (compat == NULL) + return UNZ_PARAMERROR; + + if (compat->handle != NULL) + err = unzClose_MZ(file); + + if (compat->stream != NULL) + { + mz_stream_close(compat->stream); + mz_stream_delete(&compat->stream); + } + + MZ_FREE(compat); + + return err; +} + +/* Only closes the zip handle, does not close the stream */ +int unzClose_MZ(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + + if (compat == NULL) + return UNZ_PARAMERROR; + + err = mz_zip_close(compat->handle); + mz_zip_delete(&compat->handle); + + return err; +} + +int unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) +{ + mz_compat *compat = (mz_compat *)file; + unz_global_info64 global_info64; + int32_t err = MZ_OK; + + memset(pglobal_info32, 0, sizeof(unz_global_info)); + if (compat == NULL) + return UNZ_PARAMERROR; + + err = unzGetGlobalInfo64(file, &global_info64); + if (err == MZ_OK) + { + pglobal_info32->number_entry = (uint32_t)global_info64.number_entry; + pglobal_info32->size_comment = global_info64.size_comment; + pglobal_info32->number_disk_with_CD = global_info64.number_disk_with_CD; + } + return err; +} + +int unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info) +{ + mz_compat *compat = (mz_compat *)file; + const char *comment_ptr = NULL; + int32_t err = MZ_OK; + + memset(pglobal_info, 0, sizeof(unz_global_info64)); + if (compat == NULL) + return UNZ_PARAMERROR; + err = mz_zip_get_comment(compat->handle, &comment_ptr); + if (err == MZ_OK) + pglobal_info->size_comment = (uint16_t)strlen(comment_ptr); + if ((err == MZ_OK) || (err == MZ_EXIST_ERROR)) + err = mz_zip_get_number_entry(compat->handle, &pglobal_info->number_entry); + if (err == MZ_OK) + err = mz_zip_get_disk_number_with_cd(compat->handle, &pglobal_info->number_disk_with_CD); + return err; +} + +int unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size) +{ + mz_compat *compat = (mz_compat *)file; + const char *comment_ptr = NULL; + int32_t err = MZ_OK; + + if (comment == NULL || comment_size == 0) + return UNZ_PARAMERROR; + err = mz_zip_get_comment(compat->handle, &comment_ptr); + if (err == MZ_OK) + { + strncpy(comment, comment_ptr, comment_size - 1); + comment[comment_size - 1] = 0; + } + return err; +} + +int unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + int32_t err = MZ_OK; + void *stream = NULL; + + if (compat == NULL) + return UNZ_PARAMERROR; + if (method != NULL) + *method = 0; + if (level != NULL) + *level = 0; + + compat->total_out = 0; + err = mz_zip_entry_read_open(compat->handle, (uint8_t)raw, password); + if (err == MZ_OK) + err = mz_zip_entry_get_info(compat->handle, &file_info); + if (err == MZ_OK) + { + if (method != NULL) + { + *method = file_info->compression_method; + } + + if (level != NULL) + { + *level = 6; + switch (file_info->flag & 0x06) + { + case MZ_ZIP_FLAG_DEFLATE_SUPER_FAST: + *level = 1; + break; + case MZ_ZIP_FLAG_DEFLATE_FAST: + *level = 2; + break; + case MZ_ZIP_FLAG_DEFLATE_MAX: + *level = 9; + break; + } + } + } + if (err == MZ_OK) + err = mz_zip_get_stream(compat->handle, &stream); + if (err == MZ_OK) + compat->entry_pos = mz_stream_tell(stream); + return err; +} + +int unzOpenCurrentFile(unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +int unzOpenCurrentFilePassword(unzFile file, const char *password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +int unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +int unzReadCurrentFile(unzFile file, void *buf, uint32_t len) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + if (compat == NULL || len >= INT32_MAX) + return UNZ_PARAMERROR; + err = mz_zip_entry_read(compat->handle, buf, (int32_t)len); + if (err > 0) + compat->total_out += (uint32_t)err; + return err; +} + +int unzCloseCurrentFile(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + if (compat == NULL) + return UNZ_PARAMERROR; + err = mz_zip_entry_close(compat->handle); + return err; +} + +int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename, + uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + uint16_t bytes_to_copy = 0; + int32_t err = MZ_OK; + + if (compat == NULL) + return UNZ_PARAMERROR; + + err = mz_zip_entry_get_info(compat->handle, &file_info); + + if ((err == MZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info->version_madeby; + pfile_info->version_needed = file_info->version_needed; + pfile_info->flag = file_info->flag; + pfile_info->compression_method = file_info->compression_method; + pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date); + //mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date); + //pfile_info->tmu_date.tm_year += 1900; + pfile_info->crc = file_info->crc; + + pfile_info->size_filename = file_info->filename_size; + pfile_info->size_file_extra = file_info->extrafield_size; + pfile_info->size_file_comment = file_info->comment_size; + + pfile_info->disk_num_start = (uint16_t)file_info->disk_number; + pfile_info->internal_fa = file_info->internal_fa; + pfile_info->external_fa = file_info->external_fa; + + pfile_info->compressed_size = (uint32_t)file_info->compressed_size; + pfile_info->uncompressed_size = (uint32_t)file_info->uncompressed_size; + + if (filename_size > 0 && filename != NULL && file_info->filename != NULL) + { + bytes_to_copy = filename_size; + if (bytes_to_copy > file_info->filename_size) + bytes_to_copy = file_info->filename_size; + memcpy(filename, file_info->filename, bytes_to_copy); + if (bytes_to_copy < filename_size) + filename[bytes_to_copy] = 0; + } + if (extrafield_size > 0 && extrafield != NULL) + { + bytes_to_copy = extrafield_size; + if (bytes_to_copy > file_info->extrafield_size) + bytes_to_copy = file_info->extrafield_size; + memcpy(extrafield, file_info->extrafield, bytes_to_copy); + } + if (comment_size > 0 && comment != NULL && file_info->comment != NULL) + { + bytes_to_copy = comment_size; + if (bytes_to_copy > file_info->comment_size) + bytes_to_copy = file_info->comment_size; + memcpy(comment, file_info->comment, bytes_to_copy); + if (bytes_to_copy < comment_size) + comment[bytes_to_copy] = 0; + } + } + return err; +} + +int unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename, + uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + uint16_t bytes_to_copy = 0; + int32_t err = MZ_OK; + + if (compat == NULL) + return UNZ_PARAMERROR; + + err = mz_zip_entry_get_info(compat->handle, &file_info); + + if ((err == MZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info->version_madeby; + pfile_info->version_needed = file_info->version_needed; + pfile_info->flag = file_info->flag; + pfile_info->compression_method = file_info->compression_method; + pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date); + //mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date); + //pfile_info->tmu_date.tm_year += 1900; + pfile_info->crc = file_info->crc; + + pfile_info->size_filename = file_info->filename_size; + pfile_info->size_file_extra = file_info->extrafield_size; + pfile_info->size_file_comment = file_info->comment_size; + + pfile_info->disk_num_start = file_info->disk_number; + pfile_info->internal_fa = file_info->internal_fa; + pfile_info->external_fa = file_info->external_fa; + + pfile_info->compressed_size = (uint64_t)file_info->compressed_size; + pfile_info->uncompressed_size = (uint64_t)file_info->uncompressed_size; + + if (filename_size > 0 && filename != NULL && file_info->filename != NULL) + { + bytes_to_copy = filename_size; + if (bytes_to_copy > file_info->filename_size) + bytes_to_copy = file_info->filename_size; + memcpy(filename, file_info->filename, bytes_to_copy); + if (bytes_to_copy < filename_size) + filename[bytes_to_copy] = 0; + } + + if (extrafield_size > 0 && extrafield != NULL) + { + bytes_to_copy = extrafield_size; + if (bytes_to_copy > file_info->extrafield_size) + bytes_to_copy = file_info->extrafield_size; + memcpy(extrafield, file_info->extrafield, bytes_to_copy); + } + + if (comment_size > 0 && comment != NULL && file_info->comment != NULL) + { + bytes_to_copy = comment_size; + if (bytes_to_copy > file_info->comment_size) + bytes_to_copy = file_info->comment_size; + memcpy(comment, file_info->comment, bytes_to_copy); + if (bytes_to_copy < comment_size) + comment[bytes_to_copy] = 0; + } + } + return err; +} + +int unzGoToFirstFile(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return UNZ_PARAMERROR; + compat->entry_index = 0; + return mz_zip_goto_first_entry(compat->handle); +} + +int unzGoToNextFile(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + if (compat == NULL) + return UNZ_PARAMERROR; + err = mz_zip_goto_next_entry(compat->handle); + if (err != MZ_END_OF_LIST) + compat->entry_index += 1; + return err; +} + +int unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + uint64_t preserve_index = 0; + int32_t err = MZ_OK; + int32_t result = 0; + + if (compat == NULL) + return UNZ_PARAMERROR; + + preserve_index = compat->entry_index; + + err = mz_zip_goto_first_entry(compat->handle); + while (err == MZ_OK) + { + err = mz_zip_entry_get_info(compat->handle, &file_info); + if (err != MZ_OK) + break; + + if (filename_compare_func != NULL) + result = filename_compare_func(file, filename, file_info->filename); + else + result = strcmp(filename, file_info->filename); + + if (result == 0) + return MZ_OK; + + err = mz_zip_goto_next_entry(compat->handle); + } + + compat->entry_index = preserve_index; + return err; +} + +/***************************************************************************/ + +int unzGetFilePos(unzFile file, unz_file_pos *file_pos) +{ + mz_compat *compat = (mz_compat *)file; + int32_t offset = 0; + + if (compat == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + + offset = unzGetOffset(file); + if (offset < 0) + return offset; + + file_pos->pos_in_zip_directory = (uint32_t)offset; + file_pos->num_of_file = (uint32_t)compat->entry_index; + return MZ_OK; +} + +int unzGoToFilePos(unzFile file, unz_file_pos *file_pos) +{ + mz_compat *compat = (mz_compat *)file; + unz64_file_pos file_pos64; + + if (compat == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + + return unzGoToFilePos64(file, &file_pos64); +} + +int unzGetFilePos64(unzFile file, unz64_file_pos *file_pos) +{ + mz_compat *compat = (mz_compat *)file; + int64_t offset = 0; + + if (compat == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + + offset = unzGetOffset64(file); + if (offset < 0) + return (int)offset; + + file_pos->pos_in_zip_directory = offset; + file_pos->num_of_file = compat->entry_index; + return UNZ_OK; +} + +int unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos) +{ + mz_compat *compat = (mz_compat *)file; + int32_t err = MZ_OK; + + if (compat == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + + err = mz_zip_goto_entry(compat->handle, file_pos->pos_in_zip_directory); + if (err == MZ_OK) + compat->entry_index = file_pos->num_of_file; + return err; +} + +int32_t unzGetOffset(unzFile file) +{ + return (int32_t)unzGetOffset64(file); +} + +int64_t unzGetOffset64(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return UNZ_PARAMERROR; + return mz_zip_get_entry(compat->handle); +} + +int unzSetOffset(unzFile file, uint32_t pos) +{ + return unzSetOffset64(file, pos); +} + +int unzSetOffset64(unzFile file, int64_t pos) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return UNZ_PARAMERROR; + return (int)mz_zip_goto_entry(compat->handle, pos); +} + +int unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + int32_t err = MZ_OK; + int32_t bytes_to_copy = 0; + + if (compat == NULL || buf == NULL || len >= INT32_MAX) + return UNZ_PARAMERROR; + + err = mz_zip_entry_get_local_info(compat->handle, &file_info); + if (err != MZ_OK) + return err; + + bytes_to_copy = (int32_t)len; + if (bytes_to_copy > file_info->extrafield_size) + bytes_to_copy = file_info->extrafield_size; + + memcpy(buf, file_info->extrafield, bytes_to_copy); + return MZ_OK; +} + +int64_t unztell(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return UNZ_PARAMERROR; + return (int64_t)compat->total_out; +} + +int32_t unzTell(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return UNZ_PARAMERROR; + return (int32_t)compat->total_out; +} + +int64_t unzTell64(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return UNZ_PARAMERROR; + return (int64_t)compat->total_out; +} + +int unzSeek(unzFile file, int32_t offset, int origin) +{ + return unzSeek64(file, offset, origin); +} + +int unzSeek64(unzFile file, int64_t offset, int origin) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + int64_t position = 0; + int32_t err = MZ_OK; + void *stream = NULL; + + if (compat == NULL) + return UNZ_PARAMERROR; + err = mz_zip_entry_get_info(compat->handle, &file_info); + if (err != MZ_OK) + return err; + if (file_info->compression_method != MZ_COMPRESS_METHOD_STORE) + return UNZ_ERRNO; + + if (origin == SEEK_SET) + position = offset; + else if (origin == SEEK_CUR) + position = compat->total_out + offset; + else if (origin == SEEK_END) + position = (int64_t)file_info->compressed_size + offset; + else + return UNZ_PARAMERROR; + + if (position > (int64_t)file_info->compressed_size) + return UNZ_PARAMERROR; + + err = mz_zip_get_stream(compat->handle, &stream); + if (err == MZ_OK) + err = mz_stream_seek(stream, compat->entry_pos + position, MZ_SEEK_SET); + if (err == MZ_OK) + compat->total_out = position; + return err; +} + +int unzEndOfFile(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + mz_zip_file *file_info = NULL; + int32_t err = MZ_OK; + + if (compat == NULL) + return UNZ_PARAMERROR; + err = mz_zip_entry_get_info(compat->handle, &file_info); + if (err != MZ_OK) + return err; + if (compat->total_out == (int64_t)file_info->uncompressed_size) + return 1; + return 0; +} + +void* unzGetStream(unzFile file) +{ + mz_compat *compat = (mz_compat *)file; + if (compat == NULL) + return NULL; + return (void *)compat->stream; +} + +/***************************************************************************/ + +void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_os_get_interface(); +} + +void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_os_get_interface(); +} + +void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_os_get_interface(); +} + +void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_os_get_interface(); +} + +void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_os_get_interface(); +} + +void fill_win32_filefunc64W(zlib_filefunc64_def *pzlib_filefunc_def) +{ + /* NOTE: You should no longer pass in widechar string to open function */ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_os_get_interface(); +} + +void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + *pzlib_filefunc_def = mz_stream_mem_get_interface(); +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c.meta new file mode 100644 index 0000000..fa852e0 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 17e882229eeb248999be779ea129f655 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h new file mode 100755 index 0000000..011fbfb --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h @@ -0,0 +1,250 @@ +/* mz_compat.h -- Backwards compatible interface for older versions + Version 2.8.6, April 8, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 1998-2010 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_COMPAT_H +#define MZ_COMPAT_H + +#include "mz.h" +#include "../SSZipCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +#if defined(HAVE_ZLIB) && defined(MAX_MEM_LEVEL) +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +#endif +#ifndef MAX_WBITS +#define MAX_WBITS 15 +#endif +#ifndef DEF_MEM_LEVEL +#define DEF_MEM_LEVEL 8 +#endif + +#ifndef ZEXPORT +# define ZEXPORT MZ_EXPORT +#endif + +/***************************************************************************/ + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zip_file__; +typedef zip_file__ *zipFile; +#else +typedef void *zipFile; +#endif + +/***************************************************************************/ + +typedef void *zlib_filefunc_def; +typedef void *zlib_filefunc64_def; +typedef const char *zipcharpc; + +typedef struct tm tm_unz; +typedef struct tm tm_zip; + +typedef uint64_t ZPOS64_T; + +/***************************************************************************/ + +// ZipArchive 2.x uses dos_date +#define MZ_COMPAT_VERSION 120 + +#if MZ_COMPAT_VERSION <= 110 +#define mz_dos_date dosDate +#else +#define mz_dos_date dos_date +#endif + +typedef struct +{ + uint32_t mz_dos_date; + struct tm tmz_date; + uint16_t internal_fa; /* internal file attributes 2 bytes */ + uint32_t external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +/***************************************************************************/ + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (-1) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#define Z_BZIP2ED (12) + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +/***************************************************************************/ +/* Writing a zip file */ + +ZEXPORT zipFile zipOpen(const char *path, int append); +ZEXPORT zipFile zipOpen64(const void *path, int append); +ZEXPORT zipFile zipOpen2(const char *path, int append, const char **globalcomment, + zlib_filefunc_def *pzlib_filefunc_def); +ZEXPORT zipFile zipOpen2_64(const void *path, int append, const char **globalcomment, + zlib_filefunc64_def *pzlib_filefunc_def); + zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment); + +ZEXPORT int zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi, + const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global, + uint16_t size_extrafield_global, const char *comment, uint16_t compression_method, int level, + int raw, int windowBits, int memLevel, int strategy, const char *password, + signed char aes, uint16_t version_madeby, uint16_t flag_base, int zip64); + +ZEXPORT int zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len); + +ZEXPORT int zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32); +ZEXPORT int zipCloseFileInZipRaw64(zipFile file, int64_t uncompressed_size, uint32_t crc32); +ZEXPORT int zipCloseFileInZip(zipFile file); +ZEXPORT int zipCloseFileInZip64(zipFile file); + +ZEXPORT int zipClose(zipFile file, const char *global_comment); +ZEXPORT int zipClose_64(zipFile file, const char *global_comment); +ZEXPORT int zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby); + int zipClose_MZ(zipFile file, const char *global_comment); + int zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby); +ZEXPORT void* zipGetStream(zipFile file); + +/***************************************************************************/ + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unz_file__; +typedef unz_file__ *unzFile; +#else +typedef void *unzFile; +#endif + +/***************************************************************************/ + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (-1) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) +#define UNZ_BADPASSWORD (-106) + +/***************************************************************************/ + +typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2); +typedef int (*unzIteratorFunction)(unzFile file); +typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename, + uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, + uint16_t comment_size); + +/***************************************************************************/ +/* Reading a zip file */ + +ZEXPORT unzFile unzOpen(const char *path); +ZEXPORT unzFile unzOpen64(const void *path); +ZEXPORT unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def); +ZEXPORT unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def); + unzFile unzOpen_MZ(void *stream); + +ZEXPORT int unzClose(unzFile file); + int unzClose_MZ(unzFile file); + +ZEXPORT int unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32); +ZEXPORT int unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info); +ZEXPORT int unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size); + +ZEXPORT int unzOpenCurrentFile(unzFile file); +ZEXPORT int unzOpenCurrentFilePassword(unzFile file, const char *password); +ZEXPORT int unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw); +ZEXPORT int unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password); +ZEXPORT int unzReadCurrentFile(unzFile file, void *buf, uint32_t len); +ZEXPORT int unzCloseCurrentFile(unzFile file); + + +ZEXPORT int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename, + uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, + uint16_t comment_size); +ZEXPORT int unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename, + uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, + uint16_t comment_size); + +ZEXPORT int unzGoToFirstFile(unzFile file); +ZEXPORT int unzGoToNextFile(unzFile file); +ZEXPORT int unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func); + +ZEXPORT int unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len); + +/***************************************************************************/ +/* Raw access to zip file */ + +typedef struct unz_file_pos_s +{ + uint32_t pos_in_zip_directory; /* offset in zip file directory */ + uint32_t num_of_file; /* # of file */ +} unz_file_pos; + +ZEXPORT int unzGetFilePos(unzFile file, unz_file_pos *file_pos); +ZEXPORT int unzGoToFilePos(unzFile file, unz_file_pos *file_pos); + +typedef struct unz64_file_pos_s +{ + int64_t pos_in_zip_directory; /* offset in zip file directory */ + uint64_t num_of_file; /* # of file */ +} unz64_file_pos; + +ZEXPORT int unzGetFilePos64(unzFile file, unz64_file_pos *file_pos); +ZEXPORT int unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos); + +ZEXPORT int64_t unzGetOffset64(unzFile file); +ZEXPORT int32_t unzGetOffset(unzFile file); +ZEXPORT int unzSetOffset64(unzFile file, int64_t pos); +ZEXPORT int unzSetOffset(unzFile file, uint32_t pos); +ZEXPORT int64_t unztell(unzFile file); +ZEXPORT int32_t unzTell(unzFile file); +ZEXPORT int64_t unzTell64(unzFile file); +ZEXPORT int unzSeek(unzFile file, int32_t offset, int origin); +ZEXPORT int unzSeek64(unzFile file, int64_t offset, int origin); +ZEXPORT int unzEndOfFile(unzFile file); +ZEXPORT void* unzGetStream(unzFile file); + +/***************************************************************************/ + +ZEXPORT void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def); +ZEXPORT void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def); +ZEXPORT void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def); +ZEXPORT void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def); +ZEXPORT void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def); +ZEXPORT void fill_win32_filefunc64W(zlib_filefunc64_def *pzlib_filefunc_def); +ZEXPORT void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h.meta new file mode 100644 index 0000000..c5a4980 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_compat.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: ff497155816644c76a41548ff4953db8 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c new file mode 100755 index 0000000..ac708fc --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c @@ -0,0 +1,196 @@ +/* mz_crypt.c -- Crypto/hash functions + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_crypt.h" + +#if defined(HAVE_ZLIB) +# include "zlib.h" +# if defined(ZLIBNG_VERNUM) +# include "zlib-ng.h" +# endif +#elif defined(HAVE_LZMA) +# include "lzma.h" +#endif + +/***************************************************************************/ +/* Define z_crc_t in zlib 1.2.5 and less or if using zlib-ng */ + +#if defined(HAVE_ZLIB) && defined(ZLIBNG_VERNUM) +# if defined(ZLIB_COMPAT) +# define ZLIB_PREFIX(x) x +# else +# define ZLIB_PREFIX(x) zng_ ## x +# endif + typedef uint32_t z_crc_t; +#elif defined(HAVE_ZLIB) +# define ZLIB_PREFIX(x) x +# if (ZLIB_VERNUM < 0x1270) + typedef unsigned long z_crc_t; +# endif +#endif + +/***************************************************************************/ + +uint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size) +{ +#if defined(HAVE_ZLIB) + return (uint32_t)ZLIB_PREFIX(crc32)((z_crc_t)value, buf, (uInt)size); +#elif defined(HAVE_LZMA) + return (uint32_t)lzma_crc32(buf, (size_t)size, (uint32_t)value); +#else + static uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + value = ~value; + + while (size > 0) + { + value = (value >> 8) ^ crc32_table[(value ^ *buf) & 0xFF]; + + buf += 1; + size -= 1; + } + + return ~value; +#endif +} + +#ifndef MZ_ZIP_NO_ENCRYPTION +int32_t mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt, + int32_t salt_length, int32_t iteration_count, uint8_t *key, int32_t key_length) +{ + void *hmac1 = NULL; + void *hmac2 = NULL; + void *hmac3 = NULL; + int32_t err = MZ_OK; + uint16_t i = 0; + uint16_t j = 0; + uint16_t k = 0; + uint16_t block_count = 0; + uint8_t uu[MZ_HASH_SHA1_SIZE]; + uint8_t ux[MZ_HASH_SHA1_SIZE]; + + if (password == NULL || salt == NULL || key == NULL) + return MZ_PARAM_ERROR; + + memset(key, 0, key_length); + + mz_crypt_hmac_create(&hmac1); + mz_crypt_hmac_create(&hmac2); + mz_crypt_hmac_create(&hmac3); + + mz_crypt_hmac_set_algorithm(hmac1, MZ_HASH_SHA1); + mz_crypt_hmac_set_algorithm(hmac2, MZ_HASH_SHA1); + mz_crypt_hmac_set_algorithm(hmac3, MZ_HASH_SHA1); + + err = mz_crypt_hmac_init(hmac1, password, password_length); + if (err == MZ_OK) + err = mz_crypt_hmac_init(hmac2, password, password_length); + if (err == MZ_OK) + err = mz_crypt_hmac_update(hmac2, salt, salt_length); + + block_count = 1 + ((uint16_t)key_length - 1) / MZ_HASH_SHA1_SIZE; + + for (i = 0; (err == MZ_OK) && (i < block_count); i += 1) + { + memset(ux, 0, sizeof(ux)); + + err = mz_crypt_hmac_copy(hmac2, hmac3); + if (err != MZ_OK) + break; + + uu[0] = (uint8_t)((i + 1) >> 24); + uu[1] = (uint8_t)((i + 1) >> 16); + uu[2] = (uint8_t)((i + 1) >> 8); + uu[3] = (uint8_t)(i + 1); + + for (j = 0, k = 4; j < iteration_count; j += 1) + { + err = mz_crypt_hmac_update(hmac3, uu, k); + if (err == MZ_OK) + err = mz_crypt_hmac_end(hmac3, uu, sizeof(uu)); + if (err != MZ_OK) + break; + + for(k = 0; k < MZ_HASH_SHA1_SIZE; k += 1) + ux[k] ^= uu[k]; + + err = mz_crypt_hmac_copy(hmac1, hmac3); + if (err != MZ_OK) + break; + } + + if (err != MZ_OK) + break; + + j = 0; + k = i * MZ_HASH_SHA1_SIZE; + + while (j < MZ_HASH_SHA1_SIZE && k < key_length) + key[k++] = ux[j++]; + } + + /* hmac3 uses the same provider as hmac2, so it must be deleted + before the context is destroyed. */ + mz_crypt_hmac_delete(&hmac3); + mz_crypt_hmac_delete(&hmac1); + mz_crypt_hmac_delete(&hmac2); + + return err; +} +#endif + +/***************************************************************************/ + diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c.meta new file mode 100644 index 0000000..5af0dc5 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: c8dc885b0f07141f6bc0c78ab4020a3b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h new file mode 100755 index 0000000..9e34fa1 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h @@ -0,0 +1,66 @@ +/* mz_crypt.h -- Crypto/hash functions + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_CRYPT_H +#define MZ_CRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +uint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size); + +int32_t mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt, + int32_t salt_length, int32_t iteration_count, uint8_t *key, int32_t key_length); + +/***************************************************************************/ + +int32_t mz_crypt_rand(uint8_t *buf, int32_t size); + +void mz_crypt_sha_reset(void *handle); +int32_t mz_crypt_sha_begin(void *handle); +int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size); +int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size); +void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm); +void* mz_crypt_sha_create(void **handle); +void mz_crypt_sha_delete(void **handle); + +void mz_crypt_aes_reset(void *handle); +int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size); +int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size); +int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length); +int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length); +void mz_crypt_aes_set_mode(void *handle, int32_t mode); +void* mz_crypt_aes_create(void **handle); +void mz_crypt_aes_delete(void **handle); + +void mz_crypt_hmac_reset(void *handle); +int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length); +int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size); +int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size); +int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle); +void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm); +void* mz_crypt_hmac_create(void **handle); +void mz_crypt_hmac_delete(void **handle); + +int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size, + const char *cert_pwd, uint8_t **signature, int32_t *signature_size); +int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h.meta new file mode 100644 index 0000000..88ce22e --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: b137f411973e847a2b5af13f0e12533c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c new file mode 100755 index 0000000..2e0cc73 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c @@ -0,0 +1,532 @@ +/* mz_crypt_apple.c -- Crypto/hash functions for Apple + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" + +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ + +int32_t mz_crypt_rand(uint8_t *buf, int32_t size) +{ + if (SecRandomCopyBytes(kSecRandomDefault, size, buf) != errSecSuccess) + return 0; + return size; +} + +/***************************************************************************/ + +typedef struct mz_crypt_sha_s { + CC_SHA1_CTX ctx1; + CC_SHA256_CTX ctx256; + int32_t error; + int32_t initialized; + uint16_t algorithm; +} mz_crypt_sha; + +/***************************************************************************/ + +void mz_crypt_sha_reset(void *handle) +{ + mz_crypt_sha *sha = (mz_crypt_sha *)handle; + + sha->error = 0; + sha->initialized = 0; +} + +int32_t mz_crypt_sha_begin(void *handle) +{ + mz_crypt_sha *sha = (mz_crypt_sha *)handle; + + if (sha == NULL) + return MZ_PARAM_ERROR; + + mz_crypt_sha_reset(handle); + + if (sha->algorithm == MZ_HASH_SHA1) + sha->error = CC_SHA1_Init(&sha->ctx1); + else if (sha->algorithm == MZ_HASH_SHA256) + sha->error = CC_SHA256_Init(&sha->ctx256); + else + return MZ_PARAM_ERROR; + + if (!sha->error) + return MZ_HASH_ERROR; + + sha->initialized = 1; + return MZ_OK; +} + +int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) +{ + mz_crypt_sha *sha = (mz_crypt_sha *)handle; + + if (sha == NULL || buf == NULL || !sha->initialized) + return MZ_PARAM_ERROR; + + if (sha->algorithm == MZ_HASH_SHA1) + sha->error = CC_SHA1_Update(&sha->ctx1, buf, size); + else + sha->error = CC_SHA256_Update(&sha->ctx256, buf, size); + + if (!sha->error) + return MZ_HASH_ERROR; + + return size; +} + +int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) +{ + mz_crypt_sha *sha = (mz_crypt_sha *)handle; + + if (sha == NULL || digest == NULL || !sha->initialized) + return MZ_PARAM_ERROR; + + if (sha->algorithm == MZ_HASH_SHA1) + { + if (digest_size < MZ_HASH_SHA1_SIZE) + return MZ_BUF_ERROR; + sha->error = CC_SHA1_Final(digest, &sha->ctx1); + } + else + { + if (digest_size < MZ_HASH_SHA256_SIZE) + return MZ_BUF_ERROR; + sha->error = CC_SHA256_Final(digest, &sha->ctx256); + } + + if (!sha->error) + return MZ_HASH_ERROR; + + return MZ_OK; +} + +void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) +{ + mz_crypt_sha *sha = (mz_crypt_sha *)handle; + sha->algorithm = algorithm; +} + +void *mz_crypt_sha_create(void **handle) +{ + mz_crypt_sha *sha = NULL; + + sha = (mz_crypt_sha *)MZ_ALLOC(sizeof(mz_crypt_sha)); + if (sha != NULL) + { + memset(sha, 0, sizeof(mz_crypt_sha)); + sha->algorithm = MZ_HASH_SHA256; + } + if (handle != NULL) + *handle = sha; + + return sha; +} + +void mz_crypt_sha_delete(void **handle) +{ + mz_crypt_sha *sha = NULL; + if (handle == NULL) + return; + sha = (mz_crypt_sha *)*handle; + if (sha != NULL) + { + mz_crypt_sha_reset(*handle); + MZ_FREE(sha); + } + *handle = NULL; +} + +/***************************************************************************/ + +typedef struct mz_crypt_aes_s { + CCCryptorRef crypt; + int32_t mode; + int32_t error; +} mz_crypt_aes; + +/***************************************************************************/ + +void mz_crypt_aes_reset(void *handle) +{ + mz_crypt_aes *aes = (mz_crypt_aes *)handle; + + if (aes->crypt != NULL) + CCCryptorRelease(aes->crypt); + aes->crypt = NULL; +} + +int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) +{ + mz_crypt_aes *aes = (mz_crypt_aes *)handle; + size_t data_moved = 0; + + if (aes == NULL || buf == NULL) + return MZ_PARAM_ERROR; + if (size != MZ_AES_BLOCK_SIZE) + return MZ_PARAM_ERROR; + + aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved); + + if (aes->error != kCCSuccess) + return MZ_HASH_ERROR; + + return size; +} + +int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) +{ + mz_crypt_aes *aes = (mz_crypt_aes *)handle; + size_t data_moved = 0; + + if (aes == NULL || buf == NULL) + return MZ_PARAM_ERROR; + if (size != MZ_AES_BLOCK_SIZE) + return MZ_PARAM_ERROR; + + aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved); + + if (aes->error != kCCSuccess) + return MZ_HASH_ERROR; + + return size; +} + +int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) +{ + mz_crypt_aes *aes = (mz_crypt_aes *)handle; + + + if (aes == NULL || key == NULL || key_length == 0) + return MZ_PARAM_ERROR; + + mz_crypt_aes_reset(handle); + + aes->error = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionECBMode, + key, key_length, NULL, &aes->crypt); + + if (aes->error != kCCSuccess) + return MZ_HASH_ERROR; + + return MZ_OK; +} + +int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) +{ + mz_crypt_aes *aes = (mz_crypt_aes *)handle; + + + if (aes == NULL || key == NULL || key_length == 0) + return MZ_PARAM_ERROR; + + mz_crypt_aes_reset(handle); + + aes->error = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionECBMode, + key, key_length, NULL, &aes->crypt); + + if (aes->error != kCCSuccess) + return MZ_HASH_ERROR; + + return MZ_OK; +} + +void mz_crypt_aes_set_mode(void *handle, int32_t mode) +{ + mz_crypt_aes *aes = (mz_crypt_aes *)handle; + aes->mode = mode; +} + +void *mz_crypt_aes_create(void **handle) +{ + mz_crypt_aes *aes = NULL; + + aes = (mz_crypt_aes *)MZ_ALLOC(sizeof(mz_crypt_aes)); + if (aes != NULL) + memset(aes, 0, sizeof(mz_crypt_aes)); + if (handle != NULL) + *handle = aes; + + return aes; +} + +void mz_crypt_aes_delete(void **handle) +{ + mz_crypt_aes *aes = NULL; + if (handle == NULL) + return; + aes = (mz_crypt_aes *)*handle; + if (aes != NULL) + { + mz_crypt_aes_reset(*handle); + MZ_FREE(aes); + } + *handle = NULL; +} + +/***************************************************************************/ + +typedef struct mz_crypt_hmac_s { + CCHmacContext ctx; + int32_t initialized; + int32_t error; + uint16_t algorithm; +} mz_crypt_hmac; + +/***************************************************************************/ + +static void mz_crypt_hmac_free(void *handle) +{ + mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle; + memset(&hmac->ctx, 0, sizeof(hmac->ctx)); +} + +void mz_crypt_hmac_reset(void *handle) +{ + mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle; + mz_crypt_hmac_free(handle); + hmac->error = 0; +} + +int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) +{ + mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle; + CCHmacAlgorithm algorithm = 0; + + if (hmac == NULL || key == NULL) + return MZ_PARAM_ERROR; + + mz_crypt_hmac_reset(handle); + + if (hmac->algorithm == MZ_HASH_SHA1) + algorithm = kCCHmacAlgSHA1; + else if (hmac->algorithm == MZ_HASH_SHA256) + algorithm = kCCHmacAlgSHA256; + else + return MZ_PARAM_ERROR; + + CCHmacInit(&hmac->ctx, algorithm, key, key_length); + return MZ_OK; +} + +int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) +{ + mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle; + + if (hmac == NULL || buf == NULL) + return MZ_PARAM_ERROR; + + CCHmacUpdate(&hmac->ctx, buf, size); + return MZ_OK; +} + +int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) +{ + mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle; + + if (hmac == NULL || digest == NULL) + return MZ_PARAM_ERROR; + + if (hmac->algorithm == MZ_HASH_SHA1) + { + if (digest_size < MZ_HASH_SHA1_SIZE) + return MZ_BUF_ERROR; + CCHmacFinal(&hmac->ctx, digest); + } + else + { + if (digest_size < MZ_HASH_SHA256_SIZE) + return MZ_BUF_ERROR; + CCHmacFinal(&hmac->ctx, digest); + } + + return MZ_OK; +} + +void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) +{ + mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle; + hmac->algorithm = algorithm; +} + +int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) +{ + mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle; + mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle; + + if (source == NULL || target == NULL) + return MZ_PARAM_ERROR; + + memcpy(&target->ctx, &source->ctx, sizeof(CCHmacContext)); + return MZ_OK; +} + +void *mz_crypt_hmac_create(void **handle) +{ + mz_crypt_hmac *hmac = NULL; + + hmac = (mz_crypt_hmac *)MZ_ALLOC(sizeof(mz_crypt_hmac)); + if (hmac != NULL) + { + memset(hmac, 0, sizeof(mz_crypt_hmac)); + hmac->algorithm = MZ_HASH_SHA256; + } + if (handle != NULL) + *handle = hmac; + + return hmac; +} + +void mz_crypt_hmac_delete(void **handle) +{ + mz_crypt_hmac *hmac = NULL; + if (handle == NULL) + return; + hmac = (mz_crypt_hmac *)*handle; + if (hmac != NULL) + { + mz_crypt_hmac_free(*handle); + MZ_FREE(hmac); + } + *handle = NULL; +} + +/***************************************************************************/ + +#if !defined(MZ_ZIP_NO_SIGNING) +int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size, + const char *cert_pwd, uint8_t **signature, int32_t *signature_size) +{ + CFStringRef password_ref = NULL; + CFDictionaryRef options_dict = NULL; + CFDictionaryRef identity_trust = NULL; + CFDataRef signature_out = NULL; + CFDataRef pkcs12_data = NULL; + CFArrayRef items = 0; + SecIdentityRef identity = NULL; + SecTrustRef trust = NULL; + OSStatus status = noErr; + const void *options_key[2] = { kSecImportExportPassphrase, kSecReturnRef }; + const void *options_values[2] = { 0, kCFBooleanTrue }; + int32_t err = MZ_SIGN_ERROR; + + + if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL) + return MZ_PARAM_ERROR; + + *signature = NULL; + *signature_size = 0; + + password_ref = CFStringCreateWithCString(0, cert_pwd, kCFStringEncodingUTF8); + options_values[0] = password_ref; + + options_dict = CFDictionaryCreate(0, options_key, options_values, 2, 0, 0); + if (options_dict) + pkcs12_data = CFDataCreate(0, cert_data, cert_data_size); + if (pkcs12_data) + status = SecPKCS12Import(pkcs12_data, options_dict, &items); + if (status == noErr) + identity_trust = CFArrayGetValueAtIndex(items, 0); + if (identity_trust) + identity = (SecIdentityRef)CFDictionaryGetValue(identity_trust, kSecImportItemIdentity); + if (identity) + trust = (SecTrustRef)CFDictionaryGetValue(identity_trust, kSecImportItemTrust); + if (trust) + { + status = CMSEncodeContent(identity, NULL, NULL, FALSE, 0, message, message_size, &signature_out); + + if (status == errSecSuccess) + { + *signature_size = CFDataGetLength(signature_out); + *signature = (uint8_t *)MZ_ALLOC(*signature_size); + + memcpy(*signature, CFDataGetBytePtr(signature_out), *signature_size); + + err = MZ_OK; + } + } + + if (signature_out) + CFRelease(signature_out); + if (items) + CFRelease(items); + if (pkcs12_data) + CFRelease(pkcs12_data); + if (options_dict) + CFRelease(options_dict); + if (password_ref) + CFRelease(password_ref); + + return err; +} + +int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) +{ + CMSDecoderRef decoder = NULL; + CMSSignerStatus signer_status = 0; + CFDataRef message_out = NULL; + SecPolicyRef trust_policy = NULL; + OSStatus status = noErr; + OSStatus verify_status = noErr; + size_t signer_count = 0; + size_t i = 0; + int32_t err = MZ_SIGN_ERROR; + + if (message == NULL || signature == NULL) + return MZ_PARAM_ERROR; + + status = CMSDecoderCreate(&decoder); + if (status == errSecSuccess) + status = CMSDecoderUpdateMessage(decoder, signature, signature_size); + if (status == errSecSuccess) + status = CMSDecoderFinalizeMessage(decoder); + if (status == errSecSuccess) + trust_policy = SecPolicyCreateBasicX509(); + + if (status == errSecSuccess && trust_policy) + { + CMSDecoderGetNumSigners(decoder, &signer_count); + if (signer_count > 0) + err = MZ_OK; + for (i = 0; i < signer_count; i += 1) + { + status = CMSDecoderCopySignerStatus(decoder, i, trust_policy, TRUE, &signer_status, NULL, &verify_status); + if (status != errSecSuccess || verify_status != 0 || signer_status != kCMSSignerValid) + { + err = MZ_SIGN_ERROR; + break; + } + } + } + + if (err == MZ_OK) + { + status = CMSDecoderCopyContent(decoder, &message_out); + if ((status != errSecSuccess) || + (CFDataGetLength(message_out) != message_size) || + (memcmp(message, CFDataGetBytePtr(message_out), message_size) != 0)) + err = MZ_SIGN_ERROR; + } + + if (trust_policy) + CFRelease(trust_policy); + if (decoder) + CFRelease(decoder); + + return err; +} + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c.meta new file mode 100644 index 0000000..8124659 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_crypt_apple.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: f53e955c2726c4d568b7cf3d122430ca +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c new file mode 100755 index 0000000..5906adb --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c @@ -0,0 +1,403 @@ +/* mz_os.c -- System functions + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 1998-2010 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "mz.h" +#include "mz_crypt.h" +#include "mz_os.h" +#include "mz_strm.h" +#include "mz_strm_os.h" + +#include /* tolower */ + +/***************************************************************************/ + +int32_t mz_path_combine(char *path, const char *join, int32_t max_path) +{ + int32_t path_len = 0; + + if (path == NULL || join == NULL || max_path == 0) + return MZ_PARAM_ERROR; + + path_len = (int32_t)strlen(path); + + if (path_len == 0) + { + strncpy(path, join, max_path - 1); + path[max_path - 1] = 0; + } + else + { + mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM); + strncat(path, join, max_path - path_len); + } + + return MZ_OK; +} + +int32_t mz_path_append_slash(char *path, int32_t max_path, char slash) +{ + int32_t path_len = (int32_t)strlen(path); + if ((path_len + 2) >= max_path) + return MZ_BUF_ERROR; + if (path[path_len - 1] != '\\' && path[path_len - 1] != '/') + { + path[path_len] = slash; + path[path_len + 1] = 0; + } + return MZ_OK; +} + +int32_t mz_path_remove_slash(char *path) +{ + int32_t path_len = (int32_t)strlen(path); + while (path_len > 0) + { + if (path[path_len - 1] == '\\' || path[path_len - 1] == '/') + path[path_len - 1] = 0; + else + break; + + path_len -= 1; + } + return MZ_OK; +} + +int32_t mz_path_has_slash(const char *path) +{ + int32_t path_len = (int32_t)strlen(path); + if (path[path_len - 1] != '\\' && path[path_len - 1] != '/') + return MZ_EXIST_ERROR; + return MZ_OK; +} + +int32_t mz_path_convert_slashes(char *path, char slash) +{ + int32_t i = 0; + + for (i = 0; i < (int32_t)strlen(path); i += 1) + { + if (path[i] == '\\' || path[i] == '/') + path[i] = slash; + } + return MZ_OK; +} + +int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case) +{ + while (*path != 0) + { + switch (*wildcard) + { + case '*': + + if (*(wildcard + 1) == 0) + return MZ_OK; + + while (*path != 0) + { + if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK) + return MZ_OK; + + path += 1; + } + + return MZ_EXIST_ERROR; + + default: + /* Ignore differences in path slashes on platforms */ + if ((*path == '\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\')) + break; + + if (ignore_case) + { + if (tolower(*path) != tolower(*wildcard)) + return MZ_EXIST_ERROR; + } + else + { + if (*path != *wildcard) + return MZ_EXIST_ERROR; + } + + break; + } + + path += 1; + wildcard += 1; + } + + if ((*wildcard != 0) && (*wildcard != '*')) + return MZ_EXIST_ERROR; + + return MZ_OK; +} + +int32_t mz_path_resolve(const char *path, char *output, int32_t max_output) +{ + const char *source = path; + const char *check = output; + char *target = output; + + if (max_output <= 0) + return MZ_PARAM_ERROR; + + while (*source != 0 && max_output > 1) + { + check = source; + if ((*check == '\\') || (*check == '/')) + check += 1; + + if ((source == path) || (check != source)) + { + /* Skip double paths */ + if ((*check == '\\') || (*check == '/')) + { + source += 1; + continue; + } + if ((*check != 0) && (*check == '.')) + { + check += 1; + + /* Remove current directory . if at end of string */ + if ((*check == 0) && (source != path)) + { + /* Copy last slash */ + *target = *source; + target += 1; + max_output -= 1; + source += (check - source); + continue; + } + + /* Remove current directory . if not at end of string */ + if ((*check == 0) || (*check == '\\' || *check == '/')) + { + /* Only proceed if .\ is not entire string */ + if (check[1] != 0 || (path != source)) + { + source += (check - source); + continue; + } + } + + /* Go to parent directory .. */ + if ((*check != 0) || (*check == '.')) + { + check += 1; + if ((*check == 0) || (*check == '\\' || *check == '/')) + { + source += (check - source); + + /* Search backwards for previous slash */ + if (target != output) + { + target -= 1; + do + { + if ((*target == '\\') || (*target == '/')) + break; + + target -= 1; + max_output += 1; + } + while (target > output); + } + + if ((target == output) && (*source != 0)) + source += 1; + if ((*target == '\\' || *target == '/') && (*source == 0)) + target += 1; + + *target = 0; + continue; + } + } + } + } + + *target = *source; + + source += 1; + target += 1; + max_output -= 1; + } + + *target = 0; + + if (*path == 0) + return MZ_INTERNAL_ERROR; + + return MZ_OK; +} + +int32_t mz_path_remove_filename(char *path) +{ + char *path_ptr = NULL; + + if (path == NULL) + return MZ_PARAM_ERROR; + + path_ptr = path + strlen(path) - 1; + + while (path_ptr > path) + { + if ((*path_ptr == '/') || (*path_ptr == '\\')) + { + *path_ptr = 0; + break; + } + + path_ptr -= 1; + } + + if (path_ptr == path) + *path_ptr = 0; + + return MZ_OK; +} + +int32_t mz_path_remove_extension(char *path) +{ + char *path_ptr = NULL; + + if (path == NULL) + return MZ_PARAM_ERROR; + + path_ptr = path + strlen(path) - 1; + + while (path_ptr > path) + { + if ((*path_ptr == '/') || (*path_ptr == '\\')) + break; + if (*path_ptr == '.') + { + *path_ptr = 0; + break; + } + + path_ptr -= 1; + } + + if (path_ptr == path) + *path_ptr = 0; + + return MZ_OK; +} + +int32_t mz_path_get_filename(const char *path, const char **filename) +{ + const char *match = NULL; + + if (path == NULL || filename == NULL) + return MZ_PARAM_ERROR; + + *filename = NULL; + + for (match = path; *match != 0; match += 1) + { + if ((*match == '\\') || (*match == '/')) + *filename = match + 1; + } + + if (*filename == NULL) + return MZ_EXIST_ERROR; + + return MZ_OK; +} + +int32_t mz_dir_make(const char *path) +{ + int32_t err = MZ_OK; + int16_t len = 0; + char *current_dir = NULL; + char *match = NULL; + char hold = 0; + + + len = (int16_t)strlen(path); + if (len <= 0) + return 0; + + current_dir = (char *)MZ_ALLOC((uint16_t)len + 1); + if (current_dir == NULL) + return MZ_MEM_ERROR; + + strcpy(current_dir, path); + mz_path_remove_slash(current_dir); + + err = mz_os_make_dir(current_dir); + if (err != MZ_OK) + { + match = current_dir + 1; + while (1) + { + while (*match != 0 && *match != '\\' && *match != '/') + match += 1; + hold = *match; + *match = 0; + + err = mz_os_make_dir(current_dir); + if (err != MZ_OK) + break; + if (hold == 0) + break; + + *match = hold; + match += 1; + } + } + + MZ_FREE(current_dir); + return err; +} + +int32_t mz_file_get_crc(const char *path, uint32_t *result_crc) +{ + void *stream = NULL; + uint32_t crc32 = 0; + int32_t read = 0; + int32_t err = MZ_OK; + uint8_t buf[16384]; + + mz_stream_os_create(&stream); + + err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ); + + if (err == MZ_OK) + { + do + { + read = mz_stream_os_read(stream, buf, sizeof(buf)); + + if (read < 0) + { + err = read; + break; + } + + crc32 = mz_crypt_crc32_update(crc32, buf, read); + } + while ((err == MZ_OK) && (read > 0)); + + mz_stream_os_close(stream); + } + + *result_crc = crc32; + + mz_stream_os_delete(&stream); + + return err; +} + +/***************************************************************************/ diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c.meta new file mode 100644 index 0000000..4fba428 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: a47571b2619984b49890665d1e9b32ac +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h new file mode 100755 index 0000000..c2620f9 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h @@ -0,0 +1,174 @@ +/* mz_os.h -- System functions + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_OS_H +#define MZ_OS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +#if defined(__APPLE__) +# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_OSX_DARWIN) +#elif defined(__unix__) +# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_UNIX) +#elif defined(_WIN32) +# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_WINDOWS_NTFS) +#endif + +#ifdef HAVE_LZMA +# define MZ_VERSION_MADEBY_ZIP_VERSION (63) +#elif HAVE_WZAES +# define MZ_VERSION_MADEBY_ZIP_VERSION (51) +#elif HAVE_BZIP2 +# define MZ_VERSION_MADEBY_ZIP_VERSION (46) +#else +# define MZ_VERSION_MADEBY_ZIP_VERSION (45) +#endif + +#define MZ_VERSION_MADEBY ((MZ_VERSION_MADEBY_HOST_SYSTEM << 8) | \ + (MZ_VERSION_MADEBY_ZIP_VERSION)) + +#define MZ_PATH_SLASH_UNIX ('/') +#if defined(_WIN32) +# define MZ_PATH_SLASH_PLATFORM ('\\') +#else +# define MZ_PATH_SLASH_PLATFORM (MZ_PATH_SLASH_UNIX) +#endif + +/***************************************************************************/ + +#if defined(_WIN32) +struct dirent { + char d_name[256]; +}; +typedef void* DIR; +#else +#include +#endif + +/***************************************************************************/ +/* Shared functions */ + +int32_t mz_path_combine(char *path, const char *join, int32_t max_path); +/* Combines two paths */ + +int32_t mz_path_append_slash(char *path, int32_t max_path, char slash); +/* Appends a path slash on to the end of the path */ + +int32_t mz_path_remove_slash(char *path); +/* Removes a path slash from the end of the path */ + +int32_t mz_path_has_slash(const char *path); +/* Returns whether or not the path ends with slash */ + +int32_t mz_path_convert_slashes(char *path, char slash); +/* Converts the slashes in a path */ + +int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case); +/* Compare two paths with wildcard */ + +int32_t mz_path_resolve(const char *path, char *target, int32_t max_target); +/* Resolves path */ + +int32_t mz_path_remove_filename(char *path); +/* Remove the filename from a path */ + +int32_t mz_path_remove_extension(char *path); +/* Remove the extension from a path */ + +int32_t mz_path_get_filename(const char *path, const char **filename); +/* Get the filename from a path */ + +int32_t mz_dir_make(const char *path); +/* Creates a directory recursively */ + +int32_t mz_file_get_crc(const char *path, uint32_t *result_crc); +/* Gets the crc32 hash of a file */ + +/***************************************************************************/ +/* Platform specific functions */ + +wchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding); +/* Create unicode string from a utf8 string */ + +void mz_os_unicode_string_delete(wchar_t **string); +/* Delete a unicode string that was created */ + +uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding); +/* Create a utf8 string from a string with another encoding */ + +void mz_os_utf8_string_delete(uint8_t **string); +/* Delete a utf8 string that was created */ + +int32_t mz_os_rand(uint8_t *buf, int32_t size); +/* Random number generator (not cryptographically secure) */ + +int32_t mz_os_rename(const char *source_path, const char *target_path); +/* Rename a file */ + +int32_t mz_os_unlink(const char *path); +/* Delete an existing file */ + +int32_t mz_os_file_exists(const char *path); +/* Check to see if a file exists */ + +int64_t mz_os_get_file_size(const char *path); +/* Gets the length of a file */ + +int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date); +/* Gets a file's modified, access, and creation dates if supported */ + +int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date); +/* Sets a file's modified, access, and creation dates if supported */ + +int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes); +/* Gets a file's attributes */ + +int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes); +/* Sets a file's attributes */ + +int32_t mz_os_make_dir(const char *path); +/* Recursively creates a directory */ + +DIR* mz_os_open_dir(const char *path); +/* Opens a directory for listing */ +struct +dirent* mz_os_read_dir(DIR *dir); +/* Reads a directory listing entry */ + +int32_t mz_os_close_dir(DIR *dir); +/* Closes a directory that has been opened for listing */ + +int32_t mz_os_is_dir(const char *path); +/* Checks to see if path is a directory */ + +int32_t mz_os_is_symlink(const char *path); +/* Checks to see if path is a symbolic link */ + +int32_t mz_os_make_symlink(const char *path, const char *target_path); +/* Creates a symbolic link pointing to a target */ + +int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path); +/* Gets the target path for a symbolic link */ + +uint64_t mz_os_ms_time(void); +/* Gets the time in milliseconds */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h.meta new file mode 100644 index 0000000..486e454 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 4191254adcd0a4307904b9a924c057f3 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c new file mode 100755 index 0000000..11085fd --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c @@ -0,0 +1,329 @@ +/* mz_os_posix.c -- System functions for posix + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "mz.h" +#include "mz_strm.h" +#include "mz_os.h" + +#include /* rename */ +#include +#include + +#include +#include + +#if defined(__APPLE__) || defined(__unix__) +# include +# include +#endif +#if defined(__APPLE__) +# include +# include +#endif + +/***************************************************************************/ + +uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding) +{ + iconv_t cd; + const char *from_encoding = NULL; + size_t result = 0; + size_t string_length = 0; + size_t string_utf8_size = 0; + uint8_t *string_utf8 = NULL; + uint8_t *string_utf8_ptr = NULL; + + if (string == NULL) + return NULL; + + if (encoding == MZ_ENCODING_CODEPAGE_437) + from_encoding = "CP437"; + else if (encoding == MZ_ENCODING_CODEPAGE_932) + from_encoding = "CP932"; + else if (encoding == MZ_ENCODING_CODEPAGE_936) + from_encoding = "CP936"; + else if (encoding == MZ_ENCODING_CODEPAGE_950) + from_encoding = "CP950"; + else if (encoding == MZ_ENCODING_UTF8) + from_encoding = "UTF-8"; + else + return NULL; + + cd = iconv_open("UTF-8", from_encoding); + if (cd == (iconv_t)-1) + return NULL; + + string_length = strlen(string); + string_utf8_size = string_length * 2; + string_utf8 = (uint8_t *)MZ_ALLOC((int32_t)(string_utf8_size + 1)); + string_utf8_ptr = string_utf8; + + if (string_utf8) + { + memset(string_utf8, 0, string_utf8_size + 1); + + result = iconv(cd, (char **)&string, &string_length, + (char **)&string_utf8_ptr, &string_utf8_size); + } + + iconv_close(cd); + + if (result == (size_t)-1) + { + MZ_FREE(string_utf8); + string_utf8 = NULL; + } + + return string_utf8; +} + +void mz_os_utf8_string_delete(uint8_t **string) +{ + if (string != NULL) + { + MZ_FREE(*string); + *string = NULL; + } +} + +/***************************************************************************/ + +int32_t mz_os_rand(uint8_t *buf, int32_t size) +{ + static unsigned calls = 0; + int32_t i = 0; + + /* Ensure different random header each time */ + if (++calls == 1) + { + #define PI_SEED 3141592654UL + srand((unsigned)(time(NULL) ^ PI_SEED)); + } + + while (i < size) + buf[i++] = (rand() >> 7) & 0xff; + + return size; +} + +int32_t mz_os_rename(const char *source_path, const char *target_path) +{ + if (rename(source_path, target_path) == -1) + return MZ_EXIST_ERROR; + + return MZ_OK; +} + +int32_t mz_os_unlink(const char *path) +{ + if (unlink(path) == -1) + return MZ_EXIST_ERROR; + + return MZ_OK; +} + +int32_t mz_os_file_exists(const char *path) +{ + struct stat path_stat; + + memset(&path_stat, 0, sizeof(path_stat)); + if (stat(path, &path_stat) == 0) + return MZ_OK; + return MZ_EXIST_ERROR; +} + +int64_t mz_os_get_file_size(const char *path) +{ + struct stat path_stat; + + memset(&path_stat, 0, sizeof(path_stat)); + if (stat(path, &path_stat) == 0) + { + /* Stat returns size taken up by directory entry, so return 0 */ + if (S_ISDIR(path_stat.st_mode)) + return 0; + + return path_stat.st_size; + } + + return 0; +} + +int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date) +{ + struct stat path_stat; + char *name = NULL; + size_t len = 0; + int32_t err = MZ_INTERNAL_ERROR; + + memset(&path_stat, 0, sizeof(path_stat)); + + if (strcmp(path, "-") != 0) + { + /* Not all systems allow stat'ing a file with / appended */ + len = strlen(path); + name = (char *)malloc(len + 1); + strncpy(name, path, len + 1); + mz_path_remove_slash(name); + + if (stat(name, &path_stat) == 0) + { + if (modified_date != NULL) + *modified_date = path_stat.st_mtime; + if (accessed_date != NULL) + *accessed_date = path_stat.st_atime; + /* Creation date not supported */ + if (creation_date != NULL) + *creation_date = 0; + + err = MZ_OK; + } + + free(name); + } + + return err; +} + +int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date) +{ + struct utimbuf ut; + + ut.actime = accessed_date; + ut.modtime = modified_date; + + /* Creation date not supported */ + MZ_UNUSED(creation_date); + + if (utime(path, &ut) != 0) + return MZ_INTERNAL_ERROR; + + return MZ_OK; +} + +int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes) +{ + struct stat path_stat; + int32_t err = MZ_OK; + + memset(&path_stat, 0, sizeof(path_stat)); + if (lstat(path, &path_stat) == -1) + err = MZ_INTERNAL_ERROR; + *attributes = path_stat.st_mode; + return err; +} + +int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes) +{ + int32_t err = MZ_OK; + + if (chmod(path, (mode_t)attributes) == -1) + err = MZ_INTERNAL_ERROR; + + return err; +} + +int32_t mz_os_make_dir(const char *path) +{ + int32_t err = 0; + + err = mkdir(path, 0755); + + if (err != 0 && errno != EEXIST) + return MZ_INTERNAL_ERROR; + + return MZ_OK; +} + +DIR* mz_os_open_dir(const char *path) +{ + return opendir(path); +} + +struct dirent* mz_os_read_dir(DIR *dir) +{ + if (dir == NULL) + return NULL; + return readdir(dir); +} + +int32_t mz_os_close_dir(DIR *dir) +{ + if (dir == NULL) + return MZ_PARAM_ERROR; + if (closedir(dir) == -1) + return MZ_INTERNAL_ERROR; + return MZ_OK; +} + +int32_t mz_os_is_dir(const char *path) +{ + struct stat path_stat; + + memset(&path_stat, 0, sizeof(path_stat)); + stat(path, &path_stat); + if (S_ISDIR(path_stat.st_mode)) + return MZ_OK; + + return MZ_EXIST_ERROR; +} + +int32_t mz_os_is_symlink(const char *path) +{ + struct stat path_stat; + + memset(&path_stat, 0, sizeof(path_stat)); + lstat(path, &path_stat); + if (S_ISLNK(path_stat.st_mode)) + return MZ_OK; + + return MZ_EXIST_ERROR; +} + +int32_t mz_os_make_symlink(const char *path, const char *target_path) +{ + if (symlink(target_path, path) != 0) + return MZ_INTERNAL_ERROR; + return MZ_OK; +} + +int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path) +{ + size_t length = 0; + + length = (size_t)readlink(path, target_path, max_target_path - 1); + if (length == (size_t)-1) + return MZ_EXIST_ERROR; + + target_path[length] = 0; + return MZ_OK; +} + +uint64_t mz_os_ms_time(void) +{ + struct timespec ts; + +#if defined(__APPLE__) + clock_serv_t cclock; + mach_timespec_t mts; + + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + + ts.tv_sec = mts.tv_sec; + ts.tv_nsec = mts.tv_nsec; +#else + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif + + return ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000); +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c.meta new file mode 100644 index 0000000..dd7dbb1 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_os_posix.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: db4a1da49f9c44c37bea0b87d0465112 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c new file mode 100755 index 0000000..77c00ab --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c @@ -0,0 +1,623 @@ +/* mz_strm.c -- Stream interface + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "mz.h" +#include "mz_strm.h" + +/***************************************************************************/ + +#define MZ_STREAM_FIND_SIZE (1024) + +/***************************************************************************/ + +int32_t mz_stream_open(void *stream, const char *path, int32_t mode) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->open == NULL) + return MZ_STREAM_ERROR; + return strm->vtbl->open(strm, path, mode); +} + +int32_t mz_stream_is_open(void *stream) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->is_open == NULL) + return MZ_STREAM_ERROR; + return strm->vtbl->is_open(strm); +} + +int32_t mz_stream_read(void *stream, void *buf, int32_t size) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->read == NULL) + return MZ_PARAM_ERROR; + if (mz_stream_is_open(stream) != MZ_OK) + return MZ_STREAM_ERROR; + return strm->vtbl->read(strm, buf, size); +} + +static int32_t mz_stream_read_value(void *stream, uint64_t *value, int32_t len) +{ + uint8_t buf[8]; + int32_t n = 0; + int32_t i = 0; + + *value = 0; + if (mz_stream_read(stream, buf, len) == len) + { + for (n = 0; n < len; n += 1, i += 8) + *value += ((uint64_t)buf[n]) << i; + } + else if (mz_stream_error(stream)) + return MZ_STREAM_ERROR; + else + return MZ_END_OF_STREAM; + + return MZ_OK; +} + +int32_t mz_stream_read_uint8(void *stream, uint8_t *value) +{ + int32_t err = MZ_OK; + uint64_t value64 = 0; + + *value = 0; + err = mz_stream_read_value(stream, &value64, sizeof(uint8_t)); + if (err == MZ_OK) + *value = (uint8_t)value64; + return err; +} + +int32_t mz_stream_read_uint16(void *stream, uint16_t *value) +{ + int32_t err = MZ_OK; + uint64_t value64 = 0; + + *value = 0; + err = mz_stream_read_value(stream, &value64, sizeof(uint16_t)); + if (err == MZ_OK) + *value = (uint16_t)value64; + return err; +} + +int32_t mz_stream_read_uint32(void *stream, uint32_t *value) +{ + int32_t err = MZ_OK; + uint64_t value64 = 0; + + *value = 0; + err = mz_stream_read_value(stream, &value64, sizeof(uint32_t)); + if (err == MZ_OK) + *value = (uint32_t)value64; + return err; +} + +int32_t mz_stream_read_int64(void *stream, int64_t *value) +{ + return mz_stream_read_value(stream, (uint64_t *)value, sizeof(uint64_t)); +} + +int32_t mz_stream_read_uint64(void *stream, uint64_t *value) +{ + return mz_stream_read_value(stream, value, sizeof(uint64_t)); +} + +int32_t mz_stream_write(void *stream, const void *buf, int32_t size) +{ + mz_stream *strm = (mz_stream *)stream; + if (size == 0) + return size; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->write == NULL) + return MZ_PARAM_ERROR; + if (mz_stream_is_open(stream) != MZ_OK) + return MZ_STREAM_ERROR; + return strm->vtbl->write(strm, buf, size); +} + +static int32_t mz_stream_write_value(void *stream, uint64_t value, int32_t len) +{ + uint8_t buf[8]; + int32_t n = 0; + + for (n = 0; n < len; n += 1) + { + buf[n] = (uint8_t)(value & 0xff); + value >>= 8; + } + + if (value != 0) + { + /* Data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < len; n += 1) + buf[n] = 0xff; + } + + if (mz_stream_write(stream, buf, len) != len) + return MZ_STREAM_ERROR; + + return MZ_OK; +} + +int32_t mz_stream_write_uint8(void *stream, uint8_t value) +{ + return mz_stream_write_value(stream, value, sizeof(uint8_t)); +} + +int32_t mz_stream_write_uint16(void *stream, uint16_t value) +{ + return mz_stream_write_value(stream, value, sizeof(uint16_t)); +} + +int32_t mz_stream_write_uint32(void *stream, uint32_t value) +{ + return mz_stream_write_value(stream, value, sizeof(uint32_t)); +} + +int32_t mz_stream_write_int64(void *stream, int64_t value) +{ + return mz_stream_write_value(stream, (uint64_t)value, sizeof(uint64_t)); +} + +int32_t mz_stream_write_uint64(void *stream, uint64_t value) +{ + return mz_stream_write_value(stream, value, sizeof(uint64_t)); +} + +int32_t mz_stream_copy(void *target, void *source, int32_t len) +{ + return mz_stream_copy_stream(target, NULL, source, NULL, len); +} + +int32_t mz_stream_copy_to_end(void *target, void *source) +{ + return mz_stream_copy_stream_to_end(target, NULL, source, NULL); +} + +int32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source, + mz_stream_read_cb read_cb, int32_t len) +{ + uint8_t buf[16384]; + int32_t bytes_to_copy = 0; + int32_t read = 0; + int32_t written = 0; + + if (write_cb == NULL) + write_cb = mz_stream_write; + if (read_cb == NULL) + read_cb = mz_stream_read; + + while (len > 0) + { + bytes_to_copy = len; + if (bytes_to_copy > (int32_t)sizeof(buf)) + bytes_to_copy = sizeof(buf); + read = read_cb(source, buf, bytes_to_copy); + if (read <= 0) + return MZ_STREAM_ERROR; + written = write_cb(target, buf, read); + if (written != read) + return MZ_STREAM_ERROR; + len -= read; + } + + return MZ_OK; +} + +int32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source, + mz_stream_read_cb read_cb) +{ + uint8_t buf[16384]; + int32_t read = 0; + int32_t written = 0; + + if (write_cb == NULL) + write_cb = mz_stream_write; + if (read_cb == NULL) + read_cb = mz_stream_read; + + read = read_cb(source, buf, sizeof(buf)); + while (read > 0) + { + written = write_cb(target, buf, read); + if (written != read) + return MZ_STREAM_ERROR; + read = read_cb(source, buf, sizeof(buf)); + } + + if (read < 0) + return MZ_STREAM_ERROR; + + return MZ_OK; +} + +int64_t mz_stream_tell(void *stream) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->tell == NULL) + return MZ_PARAM_ERROR; + if (mz_stream_is_open(stream) != MZ_OK) + return MZ_STREAM_ERROR; + return strm->vtbl->tell(strm); +} + +int32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->seek == NULL) + return MZ_PARAM_ERROR; + if (mz_stream_is_open(stream) != MZ_OK) + return MZ_STREAM_ERROR; + if (origin == MZ_SEEK_SET && offset < 0) + return MZ_SEEK_ERROR; + return strm->vtbl->seek(strm, offset, origin); +} + +int32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position) +{ + uint8_t buf[MZ_STREAM_FIND_SIZE]; + int32_t buf_pos = 0; + int32_t read_size = sizeof(buf); + int32_t read = 0; + int64_t read_pos = 0; + int64_t start_pos = 0; + int64_t disk_pos = 0; + int32_t i = 0; + uint8_t first = 1; + int32_t err = MZ_OK; + + if (stream == NULL || find == NULL || position == NULL) + return MZ_PARAM_ERROR; + if (find_size < 0 || find_size >= (int32_t)sizeof(buf)) + return MZ_PARAM_ERROR; + + *position = -1; + + start_pos = mz_stream_tell(stream); + + while (read_pos < max_seek) + { + if (read_size > (int32_t)(max_seek - read_pos - buf_pos)) + read_size = (int32_t)(max_seek - read_pos - buf_pos); + + read = mz_stream_read(stream, buf + buf_pos, read_size); + if ((read < 0) || (read + buf_pos < find_size)) + break; + + for (i = 0; i <= read + buf_pos - find_size; i += 1) + { + if (memcmp(&buf[i], find, find_size) != 0) + continue; + + disk_pos = mz_stream_tell(stream); + + /* Seek to position on disk where the data was found */ + err = mz_stream_seek(stream, disk_pos - ((int64_t)read + buf_pos - i), MZ_SEEK_SET); + if (err != MZ_OK) + return MZ_EXIST_ERROR; + + *position = start_pos + read_pos + i; + return MZ_OK; + } + + if (first) + { + read -= find_size; + read_size -= find_size; + buf_pos = find_size; + first = 0; + } + + memmove(buf, buf + read, find_size); + read_pos += read; + } + + return MZ_EXIST_ERROR; +} + +int32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position) +{ + uint8_t buf[MZ_STREAM_FIND_SIZE]; + int32_t buf_pos = 0; + int32_t read_size = MZ_STREAM_FIND_SIZE; + int64_t read_pos = 0; + int32_t read = 0; + int64_t start_pos = 0; + int64_t disk_pos = 0; + uint8_t first = 1; + int32_t i = 0; + int32_t err = MZ_OK; + + if (stream == NULL || find == NULL || position == NULL) + return MZ_PARAM_ERROR; + if (find_size < 0 || find_size >= (int32_t)sizeof(buf)) + return MZ_PARAM_ERROR; + + *position = -1; + + start_pos = mz_stream_tell(stream); + + while (read_pos < max_seek) + { + if (read_size > (int32_t)(max_seek - read_pos)) + read_size = (int32_t)(max_seek - read_pos); + + if (mz_stream_seek(stream, start_pos - (read_pos + read_size), MZ_SEEK_SET) != MZ_OK) + break; + read = mz_stream_read(stream, buf, read_size); + if ((read < 0) || (read + buf_pos < find_size)) + break; + if (read + buf_pos < MZ_STREAM_FIND_SIZE) + memmove(buf + MZ_STREAM_FIND_SIZE - (read + buf_pos), buf, read); + + for (i = find_size; i <= (read + buf_pos); i += 1) + { + if (memcmp(&buf[MZ_STREAM_FIND_SIZE - i], find, find_size) != 0) + continue; + + disk_pos = mz_stream_tell(stream); + + /* Seek to position on disk where the data was found */ + err = mz_stream_seek(stream, disk_pos + buf_pos - i, MZ_SEEK_SET); + if (err != MZ_OK) + return MZ_EXIST_ERROR; + + *position = start_pos - (read_pos - buf_pos + i); + return MZ_OK; + } + + if (first) + { + read -= find_size; + read_size -= find_size; + buf_pos = find_size; + first = 0; + } + + if (read == 0) + break; + + memmove(buf + read_size, buf, find_size); + read_pos += read; + } + + return MZ_EXIST_ERROR; +} + +int32_t mz_stream_close(void *stream) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->close == NULL) + return MZ_PARAM_ERROR; + if (mz_stream_is_open(stream) != MZ_OK) + return MZ_STREAM_ERROR; + return strm->vtbl->close(strm); +} + +int32_t mz_stream_error(void *stream) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->error == NULL) + return MZ_PARAM_ERROR; + return strm->vtbl->error(strm); +} + +int32_t mz_stream_set_base(void *stream, void *base) +{ + mz_stream *strm = (mz_stream *)stream; + strm->base = (mz_stream *)base; + return MZ_OK; +} + +void* mz_stream_get_interface(void *stream) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL) + return NULL; + return (void *)strm->vtbl; +} + +int32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->get_prop_int64 == NULL) + return MZ_PARAM_ERROR; + return strm->vtbl->get_prop_int64(stream, prop, value); +} + +int32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value) +{ + mz_stream *strm = (mz_stream *)stream; + if (strm == NULL || strm->vtbl == NULL || strm->vtbl->set_prop_int64 == NULL) + return MZ_PARAM_ERROR; + return strm->vtbl->set_prop_int64(stream, prop, value); +} + +void *mz_stream_create(void **stream, mz_stream_vtbl *vtbl) +{ + if (stream == NULL) + return NULL; + if (vtbl == NULL || vtbl->create == NULL) + return NULL; + return vtbl->create(stream); +} + +void mz_stream_delete(void **stream) +{ + mz_stream *strm = NULL; + if (stream == NULL) + return; + strm = (mz_stream *)*stream; + if (strm != NULL && strm->vtbl != NULL && strm->vtbl->destroy != NULL) + strm->vtbl->destroy(stream); + *stream = NULL; +} + +/***************************************************************************/ + +typedef struct mz_stream_raw_s { + mz_stream stream; + int64_t total_in; + int64_t total_out; + int64_t max_total_in; +} mz_stream_raw; + +/***************************************************************************/ + +int32_t mz_stream_raw_open(void *stream, const char *path, int32_t mode) +{ + MZ_UNUSED(stream); + MZ_UNUSED(path); + MZ_UNUSED(mode); + + return MZ_OK; +} + +int32_t mz_stream_raw_is_open(void *stream) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + return mz_stream_is_open(raw->stream.base); +} + +int32_t mz_stream_raw_read(void *stream, void *buf, int32_t size) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + int32_t bytes_to_read = size; + int32_t read = 0; + + if (raw->max_total_in > 0) + { + if ((int64_t)bytes_to_read > (raw->max_total_in - raw->total_in)) + bytes_to_read = (int32_t)(raw->max_total_in - raw->total_in); + } + + read = mz_stream_read(raw->stream.base, buf, bytes_to_read); + + if (read > 0) + { + raw->total_in += read; + raw->total_out += read; + } + + return read; +} + +int32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + int32_t written = 0; + + written = mz_stream_write(raw->stream.base, buf, size); + + if (written > 0) + { + raw->total_out += written; + raw->total_in += written; + } + + return written; +} + +int64_t mz_stream_raw_tell(void *stream) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + return mz_stream_tell(raw->stream.base); +} + +int32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + return mz_stream_seek(raw->stream.base, offset, origin); +} + +int32_t mz_stream_raw_close(void *stream) +{ + MZ_UNUSED(stream); + return MZ_OK; +} + +int32_t mz_stream_raw_error(void *stream) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + return mz_stream_error(raw->stream.base); +} + +int32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN: + *value = raw->total_in; + return MZ_OK; + case MZ_STREAM_PROP_TOTAL_OUT: + *value = raw->total_out; + return MZ_OK; + } + return MZ_EXIST_ERROR; +} + +int32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value) +{ + mz_stream_raw *raw = (mz_stream_raw *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN_MAX: + raw->max_total_in = value; + return MZ_OK; + } + return MZ_EXIST_ERROR; +} + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_raw_vtbl = { + mz_stream_raw_open, + mz_stream_raw_is_open, + mz_stream_raw_read, + mz_stream_raw_write, + mz_stream_raw_tell, + mz_stream_raw_seek, + mz_stream_raw_close, + mz_stream_raw_error, + mz_stream_raw_create, + mz_stream_raw_delete, + mz_stream_raw_get_prop_int64, + mz_stream_raw_set_prop_int64 +}; + +/***************************************************************************/ + +void *mz_stream_raw_create(void **stream) +{ + mz_stream_raw *raw = NULL; + + raw = (mz_stream_raw *)MZ_ALLOC(sizeof(mz_stream_raw)); + if (raw != NULL) + { + memset(raw, 0, sizeof(mz_stream_raw)); + raw->stream.vtbl = &mz_stream_raw_vtbl; + } + if (stream != NULL) + *stream = raw; + + return raw; +} + +void mz_stream_raw_delete(void **stream) +{ + mz_stream_raw *raw = NULL; + if (stream == NULL) + return; + raw = (mz_stream_raw *)*stream; + if (raw != NULL) + MZ_FREE(raw); + *stream = NULL; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c.meta new file mode 100644 index 0000000..4c6899b --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: b56953bb832e349238b17569477b517a +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h new file mode 100755 index 0000000..ea48120 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h @@ -0,0 +1,134 @@ +/* mz_strm.h -- Stream interface + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_H +#define MZ_STREAM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +#define MZ_STREAM_PROP_TOTAL_IN (1) +#define MZ_STREAM_PROP_TOTAL_IN_MAX (2) +#define MZ_STREAM_PROP_TOTAL_OUT (3) +#define MZ_STREAM_PROP_TOTAL_OUT_MAX (4) +#define MZ_STREAM_PROP_HEADER_SIZE (5) +#define MZ_STREAM_PROP_FOOTER_SIZE (6) +#define MZ_STREAM_PROP_DISK_SIZE (7) +#define MZ_STREAM_PROP_DISK_NUMBER (8) +#define MZ_STREAM_PROP_COMPRESS_LEVEL (9) +#define MZ_STREAM_PROP_COMPRESS_ALGORITHM (10) +#define MZ_STREAM_PROP_COMPRESS_WINDOW (11) + +/***************************************************************************/ + +typedef int32_t (*mz_stream_open_cb) (void *stream, const char *path, int32_t mode); +typedef int32_t (*mz_stream_is_open_cb) (void *stream); +typedef int32_t (*mz_stream_read_cb) (void *stream, void *buf, int32_t size); +typedef int32_t (*mz_stream_write_cb) (void *stream, const void *buf, int32_t size); +typedef int64_t (*mz_stream_tell_cb) (void *stream); +typedef int32_t (*mz_stream_seek_cb) (void *stream, int64_t offset, int32_t origin); +typedef int32_t (*mz_stream_close_cb) (void *stream); +typedef int32_t (*mz_stream_error_cb) (void *stream); +typedef void* (*mz_stream_create_cb) (void **stream); +typedef void (*mz_stream_destroy_cb) (void **stream); + +typedef int32_t (*mz_stream_get_prop_int64_cb) (void *stream, int32_t prop, int64_t *value); +typedef int32_t (*mz_stream_set_prop_int64_cb) (void *stream, int32_t prop, int64_t value); + +typedef int32_t (*mz_stream_find_cb) (void *stream, const void *find, int32_t find_size, + int64_t max_seek, int64_t *position); + +/***************************************************************************/ + +typedef struct mz_stream_vtbl_s +{ + mz_stream_open_cb open; + mz_stream_is_open_cb is_open; + mz_stream_read_cb read; + mz_stream_write_cb write; + mz_stream_tell_cb tell; + mz_stream_seek_cb seek; + mz_stream_close_cb close; + mz_stream_error_cb error; + mz_stream_create_cb create; + mz_stream_destroy_cb destroy; + + mz_stream_get_prop_int64_cb get_prop_int64; + mz_stream_set_prop_int64_cb set_prop_int64; +} mz_stream_vtbl; + +typedef struct mz_stream_s { + mz_stream_vtbl *vtbl; + struct mz_stream_s *base; +} mz_stream; + +/***************************************************************************/ + +int32_t mz_stream_open(void *stream, const char *path, int32_t mode); +int32_t mz_stream_is_open(void *stream); +int32_t mz_stream_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_read_uint8(void *stream, uint8_t *value); +int32_t mz_stream_read_uint16(void *stream, uint16_t *value); +int32_t mz_stream_read_uint32(void *stream, uint32_t *value); +int32_t mz_stream_read_int64(void *stream, int64_t *value); +int32_t mz_stream_read_uint64(void *stream, uint64_t *value); +int32_t mz_stream_write(void *stream, const void *buf, int32_t size); +int32_t mz_stream_write_uint8(void *stream, uint8_t value); +int32_t mz_stream_write_uint16(void *stream, uint16_t value); +int32_t mz_stream_write_uint32(void *stream, uint32_t value); +int32_t mz_stream_write_int64(void *stream, int64_t value); +int32_t mz_stream_write_uint64(void *stream, uint64_t value); +int32_t mz_stream_copy(void *target, void *source, int32_t len); +int32_t mz_stream_copy_to_end(void *target, void *source); +int32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb, int32_t len); +int32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb); +int64_t mz_stream_tell(void *stream); +int32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position); +int32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position); +int32_t mz_stream_close(void *stream); +int32_t mz_stream_error(void *stream); + +int32_t mz_stream_set_base(void *stream, void *base); +void* mz_stream_get_interface(void *stream); +int32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value); +int32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value); + +void* mz_stream_create(void **stream, mz_stream_vtbl *vtbl); +void mz_stream_delete(void **stream); + +/***************************************************************************/ + +int32_t mz_stream_raw_open(void *stream, const char *filename, int32_t mode); +int32_t mz_stream_raw_is_open(void *stream); +int32_t mz_stream_raw_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_raw_tell(void *stream); +int32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_raw_close(void *stream); +int32_t mz_stream_raw_error(void *stream); + +int32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value); +int32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value); + +void* mz_stream_raw_create(void **stream); +void mz_stream_raw_delete(void **stream); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h.meta new file mode 100644 index 0000000..9cf7715 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 27781d6259ee6461484e5fbedd7e4405 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c new file mode 100755 index 0000000..ffd199b --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c @@ -0,0 +1,416 @@ +/* mz_strm_buf.c -- Stream for buffering reads/writes + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + This version of ioapi is designed to buffer IO. + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "mz.h" +#include "mz_strm.h" +#include "mz_strm_buf.h" + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_buffered_vtbl = { + mz_stream_buffered_open, + mz_stream_buffered_is_open, + mz_stream_buffered_read, + mz_stream_buffered_write, + mz_stream_buffered_tell, + mz_stream_buffered_seek, + mz_stream_buffered_close, + mz_stream_buffered_error, + mz_stream_buffered_create, + mz_stream_buffered_delete, + NULL, + NULL +}; + +/***************************************************************************/ + +typedef struct mz_stream_buffered_s { + mz_stream stream; + int32_t error; + char readbuf[INT16_MAX]; + int32_t readbuf_len; + int32_t readbuf_pos; + int32_t readbuf_hits; + int32_t readbuf_misses; + char writebuf[INT16_MAX]; + int32_t writebuf_len; + int32_t writebuf_pos; + int32_t writebuf_hits; + int32_t writebuf_misses; + int64_t position; +} mz_stream_buffered; + +/***************************************************************************/ + +#if 0 +# define mz_stream_buffered_print printf +#else +# define mz_stream_buffered_print(fmt,...) +#endif + +/***************************************************************************/ + +static int32_t mz_stream_buffered_reset(void *stream) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + + buffered->readbuf_len = 0; + buffered->readbuf_pos = 0; + buffered->writebuf_len = 0; + buffered->writebuf_pos = 0; + buffered->position = 0; + + return MZ_OK; +} + +int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + mz_stream_buffered_print("Buffered - Open (mode %"PRId32")\n", mode); + mz_stream_buffered_reset(buffered); + return mz_stream_open(buffered->stream.base, path, mode); +} + +int32_t mz_stream_buffered_is_open(void *stream) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + return mz_stream_is_open(buffered->stream.base); +} + +static int32_t mz_stream_buffered_flush(void *stream, int32_t *written) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + int32_t total_bytes_written = 0; + int32_t bytes_to_write = buffered->writebuf_len; + int32_t bytes_left_to_write = buffered->writebuf_len; + int32_t bytes_written = 0; + + *written = 0; + + while (bytes_left_to_write > 0) + { + bytes_written = mz_stream_write(buffered->stream.base, + buffered->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write); + + if (bytes_written != bytes_left_to_write) + return MZ_WRITE_ERROR; + + buffered->writebuf_misses += 1; + + mz_stream_buffered_print("Buffered - Write flush (%"PRId32":%"PRId32" len %"PRId32")\n", + bytes_to_write, bytes_left_to_write, buffered->writebuf_len); + + total_bytes_written += bytes_written; + bytes_left_to_write -= bytes_written; + buffered->position += bytes_written; + } + + buffered->writebuf_len = 0; + buffered->writebuf_pos = 0; + + *written = total_bytes_written; + return MZ_OK; +} + +int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + int32_t buf_len = 0; + int32_t bytes_to_read = 0; + int32_t bytes_to_copy = 0; + int32_t bytes_left_to_read = size; + int32_t bytes_read = 0; + + mz_stream_buffered_print("Buffered - Read (size %"PRId32" pos %"PRId64")\n", size, buffered->position); + + if (buffered->writebuf_len > 0) + { + mz_stream_buffered_print("Buffered - Switch from write to read, not yet supported (pos %"PRId64")\n", + buffered->position); + } + + while (bytes_left_to_read > 0) + { + if ((buffered->readbuf_len == 0) || (buffered->readbuf_pos == buffered->readbuf_len)) + { + if (buffered->readbuf_len == sizeof(buffered->readbuf)) + { + buffered->readbuf_pos = 0; + buffered->readbuf_len = 0; + } + + bytes_to_read = (int32_t)sizeof(buffered->readbuf) - (buffered->readbuf_len - buffered->readbuf_pos); + bytes_read = mz_stream_read(buffered->stream.base, buffered->readbuf + buffered->readbuf_pos, bytes_to_read); + if (bytes_read < 0) + return bytes_read; + + buffered->readbuf_misses += 1; + buffered->readbuf_len += bytes_read; + buffered->position += bytes_read; + + mz_stream_buffered_print("Buffered - Filled (read %"PRId32"/%"PRId32" buf %"PRId32":%"PRId32" pos %"PRId64")\n", + bytes_read, bytes_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position); + + if (bytes_read == 0) + break; + } + + if ((buffered->readbuf_len - buffered->readbuf_pos) > 0) + { + bytes_to_copy = buffered->readbuf_len - buffered->readbuf_pos; + if (bytes_to_copy > bytes_left_to_read) + bytes_to_copy = bytes_left_to_read; + + memcpy((char *)buf + buf_len, buffered->readbuf + buffered->readbuf_pos, bytes_to_copy); + + buf_len += bytes_to_copy; + bytes_left_to_read -= bytes_to_copy; + + buffered->readbuf_hits += 1; + buffered->readbuf_pos += bytes_to_copy; + + mz_stream_buffered_print("Buffered - Emptied (copied %"PRId32" remaining %"PRId32" buf %"PRId32":%"PRId32" pos %"PRId64")\n", + bytes_to_copy, bytes_left_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position); + } + } + + return size - bytes_left_to_read; +} + +int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + int32_t bytes_to_write = size; + int32_t bytes_left_to_write = size; + int32_t bytes_to_copy = 0; + int32_t bytes_used = 0; + int32_t bytes_flushed = 0; + int32_t err = MZ_OK; + + + mz_stream_buffered_print("Buffered - Write (size %"PRId32" len %"PRId32" pos %"PRId64")\n", + size, buffered->writebuf_len, buffered->position); + + if (buffered->readbuf_len > 0) + { + buffered->position -= buffered->readbuf_len; + buffered->position += buffered->readbuf_pos; + + buffered->readbuf_len = 0; + buffered->readbuf_pos = 0; + + mz_stream_buffered_print("Buffered - Switch from read to write (pos %"PRId64")\n", buffered->position); + + err = mz_stream_seek(buffered->stream.base, buffered->position, MZ_SEEK_SET); + if (err != MZ_OK) + return err; + } + + while (bytes_left_to_write > 0) + { + bytes_used = buffered->writebuf_len; + if (bytes_used > buffered->writebuf_pos) + bytes_used = buffered->writebuf_pos; + bytes_to_copy = (int32_t)sizeof(buffered->writebuf) - bytes_used; + if (bytes_to_copy > bytes_left_to_write) + bytes_to_copy = bytes_left_to_write; + + if (bytes_to_copy == 0) + { + err = mz_stream_buffered_flush(stream, &bytes_flushed); + if (err != MZ_OK) + return err; + if (bytes_flushed == 0) + return 0; + + continue; + } + + memcpy(buffered->writebuf + buffered->writebuf_pos, + (const char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy); + + mz_stream_buffered_print("Buffered - Write copy (remaining %"PRId32" write %"PRId32":%"PRId32" len %"PRId32")\n", + bytes_to_copy, bytes_to_write, bytes_left_to_write, buffered->writebuf_len); + + bytes_left_to_write -= bytes_to_copy; + + buffered->writebuf_pos += bytes_to_copy; + buffered->writebuf_hits += 1; + if (buffered->writebuf_pos > buffered->writebuf_len) + buffered->writebuf_len += buffered->writebuf_pos - buffered->writebuf_len; + } + + return size - bytes_left_to_write; +} + +int64_t mz_stream_buffered_tell(void *stream) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + int64_t position = mz_stream_tell(buffered->stream.base); + + buffered->position = position; + + mz_stream_buffered_print("Buffered - Tell (pos %"PRId64" readpos %"PRId32" writepos %"PRId32")\n", + buffered->position, buffered->readbuf_pos, buffered->writebuf_pos); + + if (buffered->readbuf_len > 0) + position -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos); + if (buffered->writebuf_len > 0) + position += buffered->writebuf_pos; + return position; +} + +int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + int32_t bytes_flushed = 0; + int32_t err = MZ_OK; + + mz_stream_buffered_print("Buffered - Seek (origin %"PRId32" offset %"PRId64" pos %"PRId64")\n", + origin, offset, buffered->position); + + switch (origin) + { + case MZ_SEEK_SET: + + if (buffered->writebuf_len > 0) + { + if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len)) + { + buffered->writebuf_pos = (int32_t)(offset - buffered->position); + return MZ_OK; + } + } + + if ((buffered->readbuf_len > 0) && (offset < buffered->position) && + (offset >= buffered->position - buffered->readbuf_len)) + { + buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len)); + return MZ_OK; + } + + err = mz_stream_buffered_flush(stream, &bytes_flushed); + if (err != MZ_OK) + return err; + + buffered->position = offset; + break; + + case MZ_SEEK_CUR: + + if (buffered->readbuf_len > 0) + { + if (offset <= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos)) + { + buffered->readbuf_pos += (uint32_t)offset; + return MZ_OK; + } + offset -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos); + buffered->position += offset; + } + if (buffered->writebuf_len > 0) + { + if (offset <= ((int64_t)buffered->writebuf_len - buffered->writebuf_pos)) + { + buffered->writebuf_pos += (uint32_t)offset; + return MZ_OK; + } + /* offset -= (buffered->writebuf_len - buffered->writebuf_pos); */ + } + + err = mz_stream_buffered_flush(stream, &bytes_flushed); + if (err != MZ_OK) + return err; + + break; + + case MZ_SEEK_END: + + if (buffered->writebuf_len > 0) + { + buffered->writebuf_pos = buffered->writebuf_len; + return MZ_OK; + } + break; + } + + buffered->readbuf_len = 0; + buffered->readbuf_pos = 0; + buffered->writebuf_len = 0; + buffered->writebuf_pos = 0; + + return mz_stream_seek(buffered->stream.base, offset, origin); +} + +int32_t mz_stream_buffered_close(void *stream) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + int32_t bytes_flushed = 0; + + mz_stream_buffered_flush(stream, &bytes_flushed); + mz_stream_buffered_print("Buffered - Close (flushed %"PRId32")\n", bytes_flushed); + + if (buffered->readbuf_hits + buffered->readbuf_misses > 0) + { + mz_stream_buffered_print("Buffered - Read efficiency %.02f%%\n", + (buffered->readbuf_hits / ((float)buffered->readbuf_hits + buffered->readbuf_misses)) * 100); + } + + if (buffered->writebuf_hits + buffered->writebuf_misses > 0) + { + mz_stream_buffered_print("Buffered - Write efficiency %.02f%%\n", + (buffered->writebuf_hits / ((float)buffered->writebuf_hits + buffered->writebuf_misses)) * 100); + } + + mz_stream_buffered_reset(buffered); + + return mz_stream_close(buffered->stream.base); +} + +int32_t mz_stream_buffered_error(void *stream) +{ + mz_stream_buffered *buffered = (mz_stream_buffered *)stream; + return mz_stream_error(buffered->stream.base); +} + +void *mz_stream_buffered_create(void **stream) +{ + mz_stream_buffered *buffered = NULL; + + buffered = (mz_stream_buffered *)MZ_ALLOC(sizeof(mz_stream_buffered)); + if (buffered != NULL) + { + memset(buffered, 0, sizeof(mz_stream_buffered)); + buffered->stream.vtbl = &mz_stream_buffered_vtbl; + } + if (stream != NULL) + *stream = buffered; + + return buffered; +} + +void mz_stream_buffered_delete(void **stream) +{ + mz_stream_buffered *buffered = NULL; + if (stream == NULL) + return; + buffered = (mz_stream_buffered *)*stream; + if (buffered != NULL) + MZ_FREE(buffered); + *stream = NULL; +} + +void *mz_stream_buffered_get_interface(void) +{ + return (void *)&mz_stream_buffered_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c.meta new file mode 100644 index 0000000..834316e --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: d390efeb31534481ab0fbfc03e394917 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h new file mode 100755 index 0000000..c2a265d --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h @@ -0,0 +1,43 @@ +/* mz_strm_buf.h -- Stream for buffering reads/writes + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + This version of ioapi is designed to buffer IO. + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_BUFFERED_H +#define MZ_STREAM_BUFFERED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode); +int32_t mz_stream_buffered_is_open(void *stream); +int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_buffered_tell(void *stream); +int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_buffered_close(void *stream); +int32_t mz_stream_buffered_error(void *stream); + +void* mz_stream_buffered_create(void **stream); +void mz_stream_buffered_delete(void **stream); + +void* mz_stream_buffered_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h.meta new file mode 100644 index 0000000..bc83f11 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_buf.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: b511e03feb2f344db8f5ae1a76de5e69 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c new file mode 100755 index 0000000..216026f --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c @@ -0,0 +1,303 @@ +/* mz_strm_mem.c -- Stream for memory access + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + This interface is designed to access memory rather than files. + We do use a region of memory to put data in to and take it out of. + + Based on Unzip ioapi.c version 0.22, May 19th, 2003 + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 2003 Justin Fletcher + Copyright (C) 1998-2003 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_strm.h" +#include "mz_strm_mem.h" + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_mem_vtbl = { + mz_stream_mem_open, + mz_stream_mem_is_open, + mz_stream_mem_read, + mz_stream_mem_write, + mz_stream_mem_tell, + mz_stream_mem_seek, + mz_stream_mem_close, + mz_stream_mem_error, + mz_stream_mem_create, + mz_stream_mem_delete, + NULL, + NULL +}; + +/***************************************************************************/ + +typedef struct mz_stream_mem_s { + mz_stream stream; + int32_t mode; + uint8_t *buffer; /* Memory buffer pointer */ + int32_t size; /* Size of the memory buffer */ + int32_t limit; /* Furthest we've written */ + int32_t position; /* Current position in the memory */ + int32_t grow_size; /* Size to grow when full */ +} mz_stream_mem; + +/***************************************************************************/ + +static int32_t mz_stream_mem_set_size(void *stream, int32_t size) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + int32_t new_size = size; + uint8_t *new_buf = NULL; + + + new_buf = (uint8_t *)MZ_ALLOC((uint32_t)new_size); + if (new_buf == NULL) + return MZ_BUF_ERROR; + + if (mem->buffer) + { + memcpy(new_buf, mem->buffer, mem->size); + MZ_FREE(mem->buffer); + } + + mem->buffer = new_buf; + mem->size = new_size; + return MZ_OK; +} + +int32_t mz_stream_mem_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + int32_t err = MZ_OK; + + MZ_UNUSED(path); + + mem->mode = mode; + mem->limit = 0; + mem->position = 0; + + if (mem->mode & MZ_OPEN_MODE_CREATE) + err = mz_stream_mem_set_size(stream, mem->grow_size); + else + mem->limit = mem->size; + + return err; +} + +int32_t mz_stream_mem_is_open(void *stream) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + if (mem->buffer == NULL) + return MZ_OPEN_ERROR; + return MZ_OK; +} + +int32_t mz_stream_mem_read(void *stream, void *buf, int32_t size) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + + if (size > mem->size - mem->position) + size = mem->size - mem->position; + if (mem->position + size > mem->limit) + size = mem->limit - mem->position; + + if (size <= 0) + return 0; + + memcpy(buf, mem->buffer + mem->position, size); + mem->position += size; + + return size; +} + +int32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + int32_t new_size = 0; + int32_t err = MZ_OK; + + if (size == 0) + return size; + + if (size > mem->size - mem->position) + { + if (mem->mode & MZ_OPEN_MODE_CREATE) + { + new_size = mem->size; + if (size < mem->grow_size) + new_size += mem->grow_size; + else + new_size += size; + + err = mz_stream_mem_set_size(stream, new_size); + if (err != MZ_OK) + return err; + } + else + { + size = mem->size - mem->position; + } + } + + memcpy(mem->buffer + mem->position, buf, size); + + mem->position += size; + if (mem->position > mem->limit) + mem->limit = mem->position; + + return size; +} + +int64_t mz_stream_mem_tell(void *stream) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + return mem->position; +} + +int32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + int64_t new_pos = 0; + int32_t err = MZ_OK; + + switch (origin) + { + case MZ_SEEK_CUR: + new_pos = mem->position + offset; + break; + case MZ_SEEK_END: + new_pos = mem->limit + offset; + break; + case MZ_SEEK_SET: + new_pos = offset; + break; + default: + return MZ_SEEK_ERROR; + } + + if (new_pos > mem->size) + { + if ((mem->mode & MZ_OPEN_MODE_CREATE) == 0) + return MZ_SEEK_ERROR; + + err = mz_stream_mem_set_size(stream, (int32_t)new_pos); + if (err != MZ_OK) + return err; + } + else if (new_pos < 0) + { + return MZ_SEEK_ERROR; + } + + mem->position = (int32_t)new_pos; + return MZ_OK; +} + +int32_t mz_stream_mem_close(void *stream) +{ + MZ_UNUSED(stream); + + /* We never return errors */ + return MZ_OK; +} + +int32_t mz_stream_mem_error(void *stream) +{ + MZ_UNUSED(stream); + + /* We never return errors */ + return MZ_OK; +} + +void mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + mem->buffer = (uint8_t *)buf; + mem->size = size; + mem->limit = size; +} + +int32_t mz_stream_mem_get_buffer(void *stream, const void **buf) +{ + return mz_stream_mem_get_buffer_at(stream, 0, buf); +} + +int32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + if (buf == NULL || position < 0 || mem->size < position || mem->buffer == NULL) + return MZ_SEEK_ERROR; + *buf = mem->buffer + position; + return MZ_OK; +} + +int32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + return mz_stream_mem_get_buffer_at(stream, mem->position, buf); +} + +void mz_stream_mem_get_buffer_length(void *stream, int32_t *length) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + *length = mem->limit; +} + +void mz_stream_mem_set_buffer_limit(void *stream, int32_t limit) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + mem->limit = limit; +} + +void mz_stream_mem_set_grow_size(void *stream, int32_t grow_size) +{ + mz_stream_mem *mem = (mz_stream_mem *)stream; + mem->grow_size = grow_size; +} + +void *mz_stream_mem_create(void **stream) +{ + mz_stream_mem *mem = NULL; + + mem = (mz_stream_mem *)MZ_ALLOC(sizeof(mz_stream_mem)); + if (mem != NULL) + { + memset(mem, 0, sizeof(mz_stream_mem)); + mem->stream.vtbl = &mz_stream_mem_vtbl; + mem->grow_size = 4096; + } + if (stream != NULL) + *stream = mem; + + return mem; +} + +void mz_stream_mem_delete(void **stream) +{ + mz_stream_mem *mem = NULL; + if (stream == NULL) + return; + mem = (mz_stream_mem *)*stream; + if (mem != NULL) + { + if ((mem->mode & MZ_OPEN_MODE_CREATE) && (mem->buffer != NULL)) + MZ_FREE(mem->buffer); + MZ_FREE(mem); + } + *stream = NULL; +} + +void *mz_stream_mem_get_interface(void) +{ + return (void *)&mz_stream_mem_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c.meta new file mode 100644 index 0000000..534c9ac --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 98a6069287f3d42eaab3b6820caf8fdf +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h new file mode 100755 index 0000000..f9bc941 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h @@ -0,0 +1,49 @@ +/* mz_strm_mem.h -- Stream for memory access + Version 2.8.7, May 9, 2019 + part of MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_MEM_H +#define MZ_STREAM_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_mem_open(void *stream, const char *filename, int32_t mode); +int32_t mz_stream_mem_is_open(void *stream); +int32_t mz_stream_mem_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_mem_tell(void *stream); +int32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_mem_close(void *stream); +int32_t mz_stream_mem_error(void *stream); + +void mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size); +int32_t mz_stream_mem_get_buffer(void *stream, const void **buf); +int32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf); +int32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf); +void mz_stream_mem_get_buffer_length(void *stream, int32_t *length); +void mz_stream_mem_set_buffer_limit(void *stream, int32_t limit); +void mz_stream_mem_set_grow_size(void *stream, int32_t grow_size); + +void* mz_stream_mem_create(void **stream); +void mz_stream_mem_delete(void **stream); + +void* mz_stream_mem_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h.meta new file mode 100644 index 0000000..dfb1e62 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_mem.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 78434ad3fc0b74719b73650a6ffc1567 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h new file mode 100755 index 0000000..1ef6bd4 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h @@ -0,0 +1,41 @@ +/* mz_sstrm_os.h -- Stream for filesystem access + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_OS_H +#define MZ_STREAM_OS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode); +int32_t mz_stream_os_is_open(void *stream); +int32_t mz_stream_os_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_os_tell(void *stream); +int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_os_close(void *stream); +int32_t mz_stream_os_error(void *stream); + +void* mz_stream_os_create(void **stream); +void mz_stream_os_delete(void **stream); + +void* mz_stream_os_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h.meta new file mode 100644 index 0000000..e963c29 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 14c0f2a728b834a66bc8da401be3366a +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c new file mode 100755 index 0000000..8f492a8 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c @@ -0,0 +1,228 @@ +/* mz_strm_posix.c -- Stream for filesystem access for posix/linux + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + Copyright (C) 1998-2010 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_strm.h" +#include "mz_strm_os.h" + +#include /* fopen, fread.. */ +#include + +/***************************************************************************/ + +#define fopen64 fopen +#ifndef MZ_FILE32_API +# ifndef NO_FSEEKO +# define ftello64 ftello +# define fseeko64 fseeko +# elif defined(_MSC_VER) && (_MSC_VER >= 1400) +# define ftello64 _ftelli64 +# define fseeko64 _fseeki64 +# endif +#endif +#ifndef ftello64 +# define ftello64 ftell +#endif +#ifndef fseeko64 +# define fseeko64 fseek +#endif + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_os_vtbl = { + mz_stream_os_open, + mz_stream_os_is_open, + mz_stream_os_read, + mz_stream_os_write, + mz_stream_os_tell, + mz_stream_os_seek, + mz_stream_os_close, + mz_stream_os_error, + mz_stream_os_create, + mz_stream_os_delete, + NULL, + NULL +}; + +/***************************************************************************/ + +typedef struct mz_stream_posix_s +{ + mz_stream stream; + int32_t error; + FILE *handle; +} mz_stream_posix; + +/***************************************************************************/ + +int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_posix *posix = (mz_stream_posix *)stream; + const char *mode_fopen = NULL; + + if (path == NULL) + return MZ_PARAM_ERROR; + + if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ) + mode_fopen = "rb"; + else if (mode & MZ_OPEN_MODE_APPEND) + mode_fopen = "r+b"; + else if (mode & MZ_OPEN_MODE_CREATE) + mode_fopen = "wb"; + else + return MZ_OPEN_ERROR; + + posix->handle = fopen64(path, mode_fopen); + if (posix->handle == NULL) + { + posix->error = errno; + return MZ_OPEN_ERROR; + } + + if (mode & MZ_OPEN_MODE_APPEND) + return mz_stream_os_seek(stream, 0, MZ_SEEK_END); + + return MZ_OK; +} + +int32_t mz_stream_os_is_open(void *stream) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + if (posix->handle == NULL) + return MZ_OPEN_ERROR; + return MZ_OK; +} + +int32_t mz_stream_os_read(void *stream, void *buf, int32_t size) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + int32_t read = (int32_t)fread(buf, 1, (size_t)size, posix->handle); + if (read < size && ferror(posix->handle)) + { + posix->error = errno; + return MZ_READ_ERROR; + } + return read; +} + +int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + int32_t written = (int32_t)fwrite(buf, 1, (size_t)size, posix->handle); + if (written < size && ferror(posix->handle)) + { + posix->error = errno; + return MZ_WRITE_ERROR; + } + return written; +} + +int64_t mz_stream_os_tell(void *stream) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + int64_t position = ftello64(posix->handle); + if (position == -1) + { + posix->error = errno; + return MZ_TELL_ERROR; + } + return position; +} + +int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + int32_t fseek_origin = 0; + + switch (origin) + { + case MZ_SEEK_CUR: + fseek_origin = SEEK_CUR; + break; + case MZ_SEEK_END: + fseek_origin = SEEK_END; + break; + case MZ_SEEK_SET: + fseek_origin = SEEK_SET; + break; + default: + return MZ_SEEK_ERROR; + } + + if (fseeko64(posix->handle, offset, fseek_origin) != 0) + { + posix->error = errno; + return MZ_SEEK_ERROR; + } + + return MZ_OK; +} + +int32_t mz_stream_os_close(void *stream) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + int32_t closed = 0; + if (posix->handle != NULL) + { + closed = fclose(posix->handle); + posix->handle = NULL; + } + if (closed != 0) + { + posix->error = errno; + return MZ_CLOSE_ERROR; + } + return MZ_OK; +} + +int32_t mz_stream_os_error(void *stream) +{ + mz_stream_posix *posix = (mz_stream_posix*)stream; + return posix->error; +} + +void *mz_stream_os_create(void **stream) +{ + mz_stream_posix *posix = NULL; + + posix = (mz_stream_posix *)MZ_ALLOC(sizeof(mz_stream_posix)); + if (posix != NULL) + { + memset(posix, 0, sizeof(mz_stream_posix)); + posix->stream.vtbl = &mz_stream_os_vtbl; + } + if (stream != NULL) + *stream = posix; + + return posix; +} + +void mz_stream_os_delete(void **stream) +{ + mz_stream_posix *posix = NULL; + if (stream == NULL) + return; + posix = (mz_stream_posix *)*stream; + if (posix != NULL) + MZ_FREE(posix); + *stream = NULL; +} + +void *mz_stream_os_get_interface(void) +{ + return (void *)&mz_stream_os_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c.meta new file mode 100644 index 0000000..3a4e4f1 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_os_posix.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 5c737dbd3f85547d69dfceb0009b33e1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c new file mode 100755 index 0000000..fef2552 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c @@ -0,0 +1,384 @@ +/* mz_strm_pkcrypt.c -- Code for traditional PKWARE encryption + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 1998-2005 Gilles Vollant + Modifications for Info-ZIP crypting + https://www.winimage.com/zLibDll/minizip.html + Copyright (C) 2003 Terry Thorsen + + This code is a modified version of crypting code in Info-ZIP distribution + + Copyright (C) 1990-2000 Info-ZIP. All rights reserved. + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). +*/ + + +#include "mz.h" +#include "mz_crypt.h" +#include "mz_strm.h" +#include "mz_strm_pkcrypt.h" + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_pkcrypt_vtbl = { + mz_stream_pkcrypt_open, + mz_stream_pkcrypt_is_open, + mz_stream_pkcrypt_read, + mz_stream_pkcrypt_write, + mz_stream_pkcrypt_tell, + mz_stream_pkcrypt_seek, + mz_stream_pkcrypt_close, + mz_stream_pkcrypt_error, + mz_stream_pkcrypt_create, + mz_stream_pkcrypt_delete, + mz_stream_pkcrypt_get_prop_int64, + mz_stream_pkcrypt_set_prop_int64 +}; + +/***************************************************************************/ + +typedef struct mz_stream_pkcrypt_s { + mz_stream stream; + int32_t error; + int16_t initialized; + uint8_t buffer[UINT16_MAX]; + int64_t total_in; + int64_t max_total_in; + int64_t total_out; + uint32_t keys[3]; /* keys defining the pseudo-random sequence */ + uint8_t verify1; + uint8_t verify2; + const char *password; +} mz_stream_pkcrypt; + +/***************************************************************************/ + +#define mz_stream_pkcrypt_decode(strm, c) \ + (mz_stream_pkcrypt_update_keys(strm, \ + c ^= mz_stream_pkcrypt_decrypt_byte(strm))) + +#define mz_stream_pkcrypt_encode(strm, c, t) \ + (t = mz_stream_pkcrypt_decrypt_byte(strm), \ + mz_stream_pkcrypt_update_keys(strm, (uint8_t)c), (uint8_t)(t^(c))) + +/***************************************************************************/ + +static uint8_t mz_stream_pkcrypt_decrypt_byte(void *stream) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an */ + /* unpredictable manner on 16-bit systems; not a problem */ + /* with any known compiler so far, though. */ + + temp = pkcrypt->keys[2] | 2; + return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +static uint8_t mz_stream_pkcrypt_update_keys(void *stream, uint8_t c) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + uint8_t buf = c; + + pkcrypt->keys[0] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[0], &buf, 1); + + pkcrypt->keys[1] += pkcrypt->keys[0] & 0xff; + pkcrypt->keys[1] *= 134775813L; + pkcrypt->keys[1] += 1; + + buf = (uint8_t)(pkcrypt->keys[1] >> 24); + pkcrypt->keys[2] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[2], &buf, 1); + + return (uint8_t)c; +} + +static void mz_stream_pkcrypt_init_keys(void *stream, const char *password) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + + pkcrypt->keys[0] = 305419896L; + pkcrypt->keys[1] = 591751049L; + pkcrypt->keys[2] = 878082192L; + + while (*password != 0) + { + mz_stream_pkcrypt_update_keys(stream, (uint8_t)*password); + password += 1; + } +} + +/***************************************************************************/ + +int32_t mz_stream_pkcrypt_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + uint16_t t = 0; + int16_t i = 0; + uint8_t verify1 = 0; + uint8_t verify2 = 0; + uint8_t header[MZ_PKCRYPT_HEADER_SIZE]; + const char *password = path; + + pkcrypt->total_in = 0; + pkcrypt->total_out = 0; + pkcrypt->initialized = 0; + + if (mz_stream_is_open(pkcrypt->stream.base) != MZ_OK) + return MZ_OPEN_ERROR; + + if (password == NULL) + password = pkcrypt->password; + if (password == NULL) + return MZ_PARAM_ERROR; + + mz_stream_pkcrypt_init_keys(stream, password); + + if (mode & MZ_OPEN_MODE_WRITE) + { +#ifdef MZ_ZIP_NO_COMPRESSION + MZ_UNUSED(t); + MZ_UNUSED(i); + + return MZ_SUPPORT_ERROR; +#else + /* First generate RAND_HEAD_LEN - 2 random bytes. */ + mz_crypt_rand(header, MZ_PKCRYPT_HEADER_SIZE - 2); + + /* Encrypt random header (last two bytes is high word of crc) */ + for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++) + header[i] = mz_stream_pkcrypt_encode(stream, header[i], t); + + header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify1, t); + header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify2, t); + + if (mz_stream_write(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header)) + return MZ_WRITE_ERROR; + + pkcrypt->total_out += MZ_PKCRYPT_HEADER_SIZE; +#endif + } + else if (mode & MZ_OPEN_MODE_READ) + { +#ifdef MZ_ZIP_NO_DECOMPRESSION + MZ_UNUSED(t); + MZ_UNUSED(i); + MZ_UNUSED(verify1); + MZ_UNUSED(verify2); + + return MZ_SUPPORT_ERROR; +#else + if (mz_stream_read(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header)) + return MZ_READ_ERROR; + + for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++) + header[i] = mz_stream_pkcrypt_decode(stream, header[i]); + + verify1 = mz_stream_pkcrypt_decode(stream, header[i++]); + verify2 = mz_stream_pkcrypt_decode(stream, header[i++]); + + /* Older versions used 2 byte check, newer versions use 1 byte check. */ + MZ_UNUSED(verify1); + if ((verify2 != 0) && (verify2 != pkcrypt->verify2)) + return MZ_PASSWORD_ERROR; + + pkcrypt->total_in += MZ_PKCRYPT_HEADER_SIZE; +#endif + } + + pkcrypt->initialized = 1; + return MZ_OK; +} + +int32_t mz_stream_pkcrypt_is_open(void *stream) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + if (pkcrypt->initialized == 0) + return MZ_OPEN_ERROR; + return MZ_OK; +} + +int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + uint8_t *buf_ptr = (uint8_t *)buf; + int32_t bytes_to_read = size; + int32_t read = 0; + int32_t i = 0; + + + if ((int64_t)bytes_to_read > (pkcrypt->max_total_in - pkcrypt->total_in)) + bytes_to_read = (int32_t)(pkcrypt->max_total_in - pkcrypt->total_in); + + read = mz_stream_read(pkcrypt->stream.base, buf, bytes_to_read); + + for (i = 0; i < read; i++) + buf_ptr[i] = mz_stream_pkcrypt_decode(stream, buf_ptr[i]); + + if (read > 0) + pkcrypt->total_in += read; + + return read; +} + +int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + const uint8_t *buf_ptr = (const uint8_t *)buf; + int32_t bytes_to_write = sizeof(pkcrypt->buffer); + int32_t total_written = 0; + int32_t written = 0; + int32_t i = 0; + uint16_t t = 0; + + if (size < 0) + return MZ_PARAM_ERROR; + + do + { + if (bytes_to_write > (size - total_written)) + bytes_to_write = (size - total_written); + + for (i = 0; i < bytes_to_write; i += 1) + { + pkcrypt->buffer[i] = mz_stream_pkcrypt_encode(stream, *buf_ptr, t); + buf_ptr += 1; + } + + written = mz_stream_write(pkcrypt->stream.base, pkcrypt->buffer, bytes_to_write); + if (written < 0) + return written; + + total_written += written; + } + while (total_written < size && written > 0); + + pkcrypt->total_out += total_written; + return total_written; +} + +int64_t mz_stream_pkcrypt_tell(void *stream) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + return mz_stream_tell(pkcrypt->stream.base); +} + +int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + return mz_stream_seek(pkcrypt->stream.base, offset, origin); +} + +int32_t mz_stream_pkcrypt_close(void *stream) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + pkcrypt->initialized = 0; + return MZ_OK; +} + +int32_t mz_stream_pkcrypt_error(void *stream) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + return pkcrypt->error; +} + +void mz_stream_pkcrypt_set_password(void *stream, const char *password) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + pkcrypt->password = password; +} + +void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + pkcrypt->verify1 = verify1; + pkcrypt->verify2 = verify2; +} + +void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + *verify1 = pkcrypt->verify1; + *verify2 = pkcrypt->verify2; +} + +int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN: + *value = pkcrypt->total_in; + break; + case MZ_STREAM_PROP_TOTAL_OUT: + *value = pkcrypt->total_out; + break; + case MZ_STREAM_PROP_TOTAL_IN_MAX: + *value = pkcrypt->max_total_in; + break; + case MZ_STREAM_PROP_HEADER_SIZE: + *value = MZ_PKCRYPT_HEADER_SIZE; + break; + case MZ_STREAM_PROP_FOOTER_SIZE: + *value = 0; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value) +{ + mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN_MAX: + pkcrypt->max_total_in = value; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +void *mz_stream_pkcrypt_create(void **stream) +{ + mz_stream_pkcrypt *pkcrypt = NULL; + + pkcrypt = (mz_stream_pkcrypt *)MZ_ALLOC(sizeof(mz_stream_pkcrypt)); + if (pkcrypt != NULL) + { + memset(pkcrypt, 0, sizeof(mz_stream_pkcrypt)); + pkcrypt->stream.vtbl = &mz_stream_pkcrypt_vtbl; + } + + if (stream != NULL) + *stream = pkcrypt; + return pkcrypt; +} + +void mz_stream_pkcrypt_delete(void **stream) +{ + mz_stream_pkcrypt *pkcrypt = NULL; + if (stream == NULL) + return; + pkcrypt = (mz_stream_pkcrypt *)*stream; + if (pkcrypt != NULL) + MZ_FREE(pkcrypt); + *stream = NULL; +} + +void *mz_stream_pkcrypt_get_interface(void) +{ + return (void *)&mz_stream_pkcrypt_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c.meta new file mode 100644 index 0000000..b2e3657 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: af45f83e47dbe4385869af1a069b00d6 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h new file mode 100755 index 0000000..aefc25a --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h @@ -0,0 +1,47 @@ +/* mz_strm_pkcrypt.h -- Code for traditional PKWARE encryption + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_PKCRYPT_H +#define MZ_STREAM_PKCRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_pkcrypt_open(void *stream, const char *filename, int32_t mode); +int32_t mz_stream_pkcrypt_is_open(void *stream); +int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_pkcrypt_tell(void *stream); +int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_pkcrypt_close(void *stream); +int32_t mz_stream_pkcrypt_error(void *stream); + +void mz_stream_pkcrypt_set_password(void *stream, const char *password); +void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2); +void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2); +int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value); +int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value); + +void* mz_stream_pkcrypt_create(void **stream); +void mz_stream_pkcrypt_delete(void **stream); + +void* mz_stream_pkcrypt_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h.meta new file mode 100644 index 0000000..d6066ca --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_pkcrypt.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 0f84aa1d4b0ec4d028fb796d307c2021 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c new file mode 100755 index 0000000..8012d67 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c @@ -0,0 +1,474 @@ +/* mz_strm_split.c -- Stream for split files + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_os.h" +#include "mz_strm.h" +#include "mz_strm_split.h" + +#include /* snprintf */ + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +# define snprintf _snprintf +#endif + +/***************************************************************************/ + +#define MZ_ZIP_MAGIC_DISKHEADER (0x08074b50) + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_split_vtbl = { + mz_stream_split_open, + mz_stream_split_is_open, + mz_stream_split_read, + mz_stream_split_write, + mz_stream_split_tell, + mz_stream_split_seek, + mz_stream_split_close, + mz_stream_split_error, + mz_stream_split_create, + mz_stream_split_delete, + mz_stream_split_get_prop_int64, + mz_stream_split_set_prop_int64 +}; + +/***************************************************************************/ + +typedef struct mz_stream_split_s { + mz_stream stream; + int32_t is_open; + int64_t disk_size; + int64_t total_in; + int64_t total_in_disk; + int64_t total_out; + int64_t total_out_disk; + int32_t mode; + char *path_cd; + uint32_t path_cd_size; + char *path_disk; + uint32_t path_disk_size; + int32_t number_disk; + int32_t current_disk; + int64_t current_disk_size; + int32_t reached_end; +} mz_stream_split; + +/***************************************************************************/ + +#if 0 +# define mz_stream_split_print printf +#else +# define mz_stream_split_print(fmt,...) +#endif + +/***************************************************************************/ + +static int32_t mz_stream_split_open_disk(void *stream, int32_t number_disk) +{ + mz_stream_split *split = (mz_stream_split *)stream; + uint32_t magic = 0; + int32_t i = 0; + int32_t err = MZ_OK; + int16_t disk_part = 0; + + + /* Check if we are reading or writing a disk part or the cd disk */ + if (number_disk >= 0) + { + if ((split->mode & MZ_OPEN_MODE_WRITE) == 0) + disk_part = MZ_OPEN_MODE_READ; + else if (split->disk_size > 0) + disk_part = MZ_OPEN_MODE_WRITE; + } + + /* Construct disk path */ + if (disk_part > 0) + { + for (i = (int32_t)strlen(split->path_disk) - 1; i >= 0; i -= 1) + { + if (split->path_disk[i] != '.') + continue; + snprintf(&split->path_disk[i], split->path_disk_size - (uint32_t)i, + ".z%02"PRId32, number_disk + 1); + break; + } + } + else + { + strncpy(split->path_disk, split->path_cd, split->path_disk_size - 1); + split->path_disk[split->path_disk_size - 1] = 0; + } + + mz_stream_split_print("Split - Goto disk - %s (disk %"PRId32")\n", split->path_disk, number_disk); + + /* If disk part doesn't exist during reading then return MZ_EXIST_ERROR */ + if (disk_part == MZ_OPEN_MODE_READ) + err = mz_os_file_exists(split->path_disk); + + if (err == MZ_OK) + err = mz_stream_open(split->stream.base, split->path_disk, split->mode); + + if (err == MZ_OK) + { + split->total_in_disk = 0; + split->total_out_disk = 0; + split->current_disk = number_disk; + + if (split->mode & MZ_OPEN_MODE_WRITE) + { + if ((split->current_disk == 0) && (split->disk_size > 0)) + { + err = mz_stream_write_uint32(split->stream.base, MZ_ZIP_MAGIC_DISKHEADER); + split->total_out_disk += 4; + split->total_out += split->total_out_disk; + } + } + else if (split->mode & MZ_OPEN_MODE_READ) + { + if (split->current_disk == 0) + { + /* Get the size of the current disk we are on for seeking */ + mz_stream_seek(split->stream.base, 0, MZ_SEEK_END); + split->current_disk_size = mz_stream_tell(split->stream.base); + mz_stream_seek(split->stream.base, 0, MZ_SEEK_SET); + + err = mz_stream_read_uint32(split->stream.base, &magic); + if (magic != MZ_ZIP_MAGIC_DISKHEADER) + err = MZ_FORMAT_ERROR; + } + } + } + + if (err == MZ_OK) + split->is_open = 1; + + return err; +} + +static int32_t mz_stream_split_close_disk(void *stream) +{ + mz_stream_split *split = (mz_stream_split *)stream; + + if (mz_stream_is_open(split->stream.base) != MZ_OK) + return MZ_OK; + + mz_stream_split_print("Split - Close disk\n"); + return mz_stream_close(split->stream.base); +} + +static int32_t mz_stream_split_goto_disk(void *stream, int32_t number_disk) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int32_t err = MZ_OK; + int32_t err_is_open = MZ_OK; + + err_is_open = mz_stream_is_open(split->stream.base); + + if ((split->disk_size == 0) && (split->mode & MZ_OPEN_MODE_WRITE)) + { + if (err_is_open != MZ_OK) + err = mz_stream_split_open_disk(stream, number_disk); + } + else if ((number_disk != split->current_disk) || (err_is_open != MZ_OK)) + { + err = mz_stream_split_close_disk(stream); + if (err == MZ_OK) + { + err = mz_stream_split_open_disk(stream, number_disk); + if (err == MZ_OK) + split->number_disk = number_disk; + } + } + + return err; +} + +int32_t mz_stream_split_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int32_t number_disk = 0; + + split->mode = mode; + + split->path_cd_size = (uint32_t)strlen(path) + 1; + split->path_cd = (char *)MZ_ALLOC(split->path_cd_size); + + if (split->path_cd == NULL) + return MZ_MEM_ERROR; + + strncpy(split->path_cd, path, split->path_cd_size - 1); + split->path_cd[split->path_cd_size - 1] = 0; + + mz_stream_split_print("Split - Open - %s (disk %"PRId32")\n", split->path_cd, number_disk); + + split->path_disk_size = (uint32_t)strlen(path) + 10; + split->path_disk = (char *)MZ_ALLOC(split->path_disk_size); + + if (split->path_disk == NULL) + { + MZ_FREE(split->path_cd); + return MZ_MEM_ERROR; + } + + strncpy(split->path_disk, path, split->path_disk_size - 1); + split->path_disk[split->path_disk_size - 1] = 0; + + if ((mode & MZ_OPEN_MODE_WRITE) && ((mode & MZ_OPEN_MODE_APPEND) == 0)) + { + number_disk = 0; + split->current_disk = -1; + } + else + { + number_disk = -1; + split->current_disk = 0; + } + + return mz_stream_split_goto_disk(stream, number_disk); +} + +int32_t mz_stream_split_is_open(void *stream) +{ + mz_stream_split *split = (mz_stream_split *)stream; + if (split->is_open != 1) + return MZ_OPEN_ERROR; + return MZ_OK; +} + +int32_t mz_stream_split_read(void *stream, void *buf, int32_t size) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int32_t bytes_left = size; + int32_t read = 0; + int32_t err = MZ_OK; + uint8_t *buf_ptr = (uint8_t *)buf; + + err = mz_stream_split_goto_disk(stream, split->number_disk); + if (err != MZ_OK) + return err; + + while (bytes_left > 0) + { + read = mz_stream_read(split->stream.base, buf_ptr, bytes_left); + + mz_stream_split_print("Split - Read disk - %"PRId32"\n", read); + + if (read < 0) + return read; + if (read == 0) + { + if (split->current_disk < 0) /* No more disks to goto */ + break; + err = mz_stream_split_goto_disk(stream, split->current_disk + 1); + if (err == MZ_EXIST_ERROR) + { + split->current_disk = -1; + break; + } + if (err != MZ_OK) + return err; + } + + bytes_left -= read; + buf_ptr += read; + split->total_in += read; + split->total_in_disk += read; + } + return size - bytes_left; +} + +int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int32_t written = 0; + int32_t bytes_left = size; + int32_t bytes_to_write = 0; + int32_t bytes_avail = 0; + int32_t number_disk = -1; + int32_t err = MZ_OK; + const uint8_t *buf_ptr = (const uint8_t *)buf; + + while (bytes_left > 0) + { + bytes_to_write = bytes_left; + + if (split->disk_size > 0) + { + if ((split->total_out_disk == split->disk_size && split->total_out > 0) || + (split->number_disk == -1 && split->number_disk != split->current_disk)) + { + if (split->number_disk != -1) + number_disk = split->current_disk + 1; + + err = mz_stream_split_goto_disk(stream, number_disk); + if (err != MZ_OK) + return err; + } + + if (split->number_disk != -1) + { + bytes_avail = (int32_t)(split->disk_size - split->total_out_disk); + if (bytes_to_write > bytes_avail) + bytes_to_write = bytes_avail; + } + } + + written = mz_stream_write(split->stream.base, buf_ptr, bytes_to_write); + if (written != bytes_to_write) + return MZ_WRITE_ERROR; + + mz_stream_split_print("Split - Write disk - %"PRId32"\n", written); + + bytes_left -= written; + buf_ptr += written; + split->total_out += written; + split->total_out_disk += written; + } + + return size - bytes_left; +} + +int64_t mz_stream_split_tell(void *stream) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int32_t err = MZ_OK; + err = mz_stream_split_goto_disk(stream, split->number_disk); + if (err != MZ_OK) + return err; + return mz_stream_tell(split->stream.base); +} + +int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int64_t disk_left = 0; + int64_t position = 0; + int32_t err = MZ_OK; + + err = mz_stream_split_goto_disk(stream, split->number_disk); + + if (err != MZ_OK) + return err; + + mz_stream_split_print("Split - Seek disk - %"PRId64" (origin %"PRId32")\n", offset, origin); + + if ((origin == MZ_SEEK_CUR) && (split->number_disk != -1)) + { + position = mz_stream_tell(split->stream.base); + disk_left = split->current_disk_size - position; + + while (offset > disk_left) + { + err = mz_stream_split_goto_disk(stream, split->current_disk + 1); + if (err != MZ_OK) + return err; + + offset -= disk_left; + disk_left = split->current_disk_size; + } + } + + return mz_stream_seek(split->stream.base, offset, origin); +} + +int32_t mz_stream_split_close(void *stream) +{ + mz_stream_split *split = (mz_stream_split *)stream; + int32_t err = MZ_OK; + + err = mz_stream_split_close_disk(stream); + split->is_open = 0; + return err; +} + +int32_t mz_stream_split_error(void *stream) +{ + mz_stream_split *split = (mz_stream_split *)stream; + return mz_stream_error(split->stream.base); +} + +int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value) +{ + mz_stream_split *split = (mz_stream_split *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_OUT: + *value = split->total_out; + break; + case MZ_STREAM_PROP_DISK_NUMBER: + *value = split->number_disk; + break; + case MZ_STREAM_PROP_DISK_SIZE: + *value = split->disk_size; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value) +{ + mz_stream_split *split = (mz_stream_split *)stream; + switch (prop) + { + case MZ_STREAM_PROP_DISK_NUMBER: + split->number_disk = (int32_t)value; + break; + case MZ_STREAM_PROP_DISK_SIZE: + split->disk_size = value; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +void *mz_stream_split_create(void **stream) +{ + mz_stream_split *split = NULL; + + split = (mz_stream_split *)MZ_ALLOC(sizeof(mz_stream_split)); + if (split != NULL) + { + memset(split, 0, sizeof(mz_stream_split)); + split->stream.vtbl = &mz_stream_split_vtbl; + } + if (stream != NULL) + *stream = split; + + return split; +} + +void mz_stream_split_delete(void **stream) +{ + mz_stream_split *split = NULL; + if (stream == NULL) + return; + split = (mz_stream_split *)*stream; + if (split != NULL) + { + if (split->path_cd) + MZ_FREE(split->path_cd); + if (split->path_disk) + MZ_FREE(split->path_disk); + + MZ_FREE(split); + } + *stream = NULL; +} + +void *mz_stream_split_get_interface(void) +{ + return (void *)&mz_stream_split_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c.meta new file mode 100644 index 0000000..09df13b --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: a55d8bffe5cd14576ae81072cb66241c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h new file mode 100755 index 0000000..ec4fdd8 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h @@ -0,0 +1,44 @@ +/* mz_strm_split.h -- Stream for split files + Version 2.8.7, May 9, 2019 + part of MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_SPLIT_H +#define MZ_STREAM_SPLIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_split_open(void *stream, const char *filename, int32_t mode); +int32_t mz_stream_split_is_open(void *stream); +int32_t mz_stream_split_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_split_tell(void *stream); +int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_split_close(void *stream); +int32_t mz_stream_split_error(void *stream); + +int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value); +int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value); + +void* mz_stream_split_create(void **stream); +void mz_stream_split_delete(void **stream); + +void* mz_stream_split_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h.meta new file mode 100644 index 0000000..afa87f9 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_split.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 8fe7f7a0a7bce4881a5d1af3eb1c7444 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c new file mode 100755 index 0000000..208265f --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c @@ -0,0 +1,407 @@ +/* mz_strm_wzaes.c -- Stream for WinZip AES encryption + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 1998-2010 Brian Gladman, Worcester, UK + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_crypt.h" +#include "mz_strm.h" +#include "mz_strm_wzaes.h" + +/***************************************************************************/ + +#define MZ_AES_KEYING_ITERATIONS (1000) +#define MZ_AES_SALT_LENGTH(MODE) (4 * (MODE & 3) + 4) +#define MZ_AES_SALT_LENGTH_MAX (16) +#define MZ_AES_PW_LENGTH_MAX (128) +#define MZ_AES_PW_VERIFY_SIZE (2) +#define MZ_AES_AUTHCODE_SIZE (10) + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_wzaes_vtbl = { + mz_stream_wzaes_open, + mz_stream_wzaes_is_open, + mz_stream_wzaes_read, + mz_stream_wzaes_write, + mz_stream_wzaes_tell, + mz_stream_wzaes_seek, + mz_stream_wzaes_close, + mz_stream_wzaes_error, + mz_stream_wzaes_create, + mz_stream_wzaes_delete, + mz_stream_wzaes_get_prop_int64, + mz_stream_wzaes_set_prop_int64 +}; + +/***************************************************************************/ + +typedef struct mz_stream_wzaes_s { + mz_stream stream; + int32_t mode; + int32_t error; + int16_t initialized; + uint8_t buffer[UINT16_MAX]; + int64_t total_in; + int64_t max_total_in; + int64_t total_out; + int16_t encryption_mode; + const char *password; + void *aes; + uint32_t crypt_pos; + uint8_t crypt_block[MZ_AES_BLOCK_SIZE]; + void *hmac; + uint8_t nonce[MZ_AES_BLOCK_SIZE]; +} mz_stream_wzaes; + +/***************************************************************************/ + +/***************************************************************************/ + +int32_t mz_stream_wzaes_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + uint16_t salt_length = 0; + uint16_t password_length = 0; + uint16_t key_length = 0; + uint8_t kbuf[2 * MZ_AES_KEY_LENGTH_MAX + MZ_AES_PW_VERIFY_SIZE]; + uint8_t verify[MZ_AES_PW_VERIFY_SIZE]; + uint8_t verify_expected[MZ_AES_PW_VERIFY_SIZE]; + uint8_t salt_value[MZ_AES_SALT_LENGTH_MAX]; + const char *password = path; + + wzaes->total_in = 0; + wzaes->total_out = 0; + wzaes->initialized = 0; + + if (mz_stream_is_open(wzaes->stream.base) != MZ_OK) + return MZ_OPEN_ERROR; + + if (password == NULL) + password = wzaes->password; + if (password == NULL) + return MZ_PARAM_ERROR; + password_length = (uint16_t)strlen(password); + if (password_length > MZ_AES_PW_LENGTH_MAX) + return MZ_PARAM_ERROR; + + if (wzaes->encryption_mode < 1 || wzaes->encryption_mode > 3) + return MZ_PARAM_ERROR; + + salt_length = MZ_AES_SALT_LENGTH(wzaes->encryption_mode); + + if (mode & MZ_OPEN_MODE_WRITE) + { +#ifdef MZ_ZIP_NO_COMPRESSION + return MZ_SUPPORT_ERROR; +#else + mz_crypt_rand(salt_value, salt_length); +#endif + } + else if (mode & MZ_OPEN_MODE_READ) + { +#ifdef MZ_ZIP_NO_DECOMPRESSION + return MZ_SUPPORT_ERROR; +#else + if (mz_stream_read(wzaes->stream.base, salt_value, salt_length) != salt_length) + return MZ_READ_ERROR; +#endif + } + + key_length = MZ_AES_KEY_LENGTH(wzaes->encryption_mode); + + /* Derive the encryption and authentication keys and the password verifier */ + mz_crypt_pbkdf2((uint8_t *)password, password_length, salt_value, salt_length, + MZ_AES_KEYING_ITERATIONS, kbuf, 2 * key_length + MZ_AES_PW_VERIFY_SIZE); + + /* Initialize the encryption nonce and buffer pos */ + wzaes->crypt_pos = MZ_AES_BLOCK_SIZE; + memset(wzaes->nonce, 0, sizeof(wzaes->nonce)); + + /* Initialize for encryption using key 1 */ + mz_crypt_aes_reset(wzaes->aes); + mz_crypt_aes_set_mode(wzaes->aes, wzaes->encryption_mode); + mz_crypt_aes_set_encrypt_key(wzaes->aes, kbuf, key_length); + + /* Initialize for authentication using key 2 */ + mz_crypt_hmac_reset(wzaes->hmac); + mz_crypt_hmac_set_algorithm(wzaes->hmac, MZ_HASH_SHA1); + mz_crypt_hmac_init(wzaes->hmac, kbuf + key_length, key_length); + + memcpy(verify, kbuf + (2 * key_length), MZ_AES_PW_VERIFY_SIZE); + + if (mode & MZ_OPEN_MODE_WRITE) + { + if (mz_stream_write(wzaes->stream.base, salt_value, salt_length) != salt_length) + return MZ_WRITE_ERROR; + + wzaes->total_out += salt_length; + + if (mz_stream_write(wzaes->stream.base, verify, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE) + return MZ_WRITE_ERROR; + + wzaes->total_out += MZ_AES_PW_VERIFY_SIZE; + } + else if (mode & MZ_OPEN_MODE_READ) + { + wzaes->total_in += salt_length; + + if (mz_stream_read(wzaes->stream.base, verify_expected, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE) + return MZ_READ_ERROR; + + wzaes->total_in += MZ_AES_PW_VERIFY_SIZE; + + if (memcmp(verify_expected, verify, MZ_AES_PW_VERIFY_SIZE) != 0) + return MZ_PASSWORD_ERROR; + } + + wzaes->mode = mode; + wzaes->initialized = 1; + + return MZ_OK; +} + +int32_t mz_stream_wzaes_is_open(void *stream) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + if (wzaes->initialized == 0) + return MZ_OPEN_ERROR; + return MZ_OK; +} + +static int32_t mz_stream_wzaes_encrypt_data(void *stream, uint8_t *buf, int32_t size) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + uint32_t pos = wzaes->crypt_pos; + uint32_t i = 0; + int32_t err = MZ_OK; + + while (i < (uint32_t)size) + { + if (pos == MZ_AES_BLOCK_SIZE) + { + uint32_t j = 0; + + /* Increment encryption nonce */ + while (j < 8 && !++wzaes->nonce[j]) + j += 1; + + /* Encrypt the nonce to form next xor buffer */ + memcpy(wzaes->crypt_block, wzaes->nonce, MZ_AES_BLOCK_SIZE); + mz_crypt_aes_encrypt(wzaes->aes, wzaes->crypt_block, sizeof(wzaes->crypt_block)); + pos = 0; + } + + buf[i++] ^= wzaes->crypt_block[pos++]; + } + + wzaes->crypt_pos = pos; + return err; +} + +int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + int64_t max_total_in = 0; + int32_t bytes_to_read = size; + int32_t read = 0; + + max_total_in = wzaes->max_total_in - MZ_AES_FOOTER_SIZE; + if ((int64_t)bytes_to_read > (max_total_in - wzaes->total_in)) + bytes_to_read = (int32_t)(max_total_in - wzaes->total_in); + + read = mz_stream_read(wzaes->stream.base, buf, bytes_to_read); + + if (read > 0) + { + mz_crypt_hmac_update(wzaes->hmac, (uint8_t *)buf, read); + mz_stream_wzaes_encrypt_data(stream, (uint8_t *)buf, read); + + wzaes->total_in += read; + } + + return read; +} + +int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + const uint8_t *buf_ptr = (const uint8_t *)buf; + int32_t bytes_to_write = sizeof(wzaes->buffer); + int32_t total_written = 0; + int32_t written = 0; + + if (size < 0) + return MZ_PARAM_ERROR; + + do + { + if (bytes_to_write > (size - total_written)) + bytes_to_write = (size - total_written); + + memcpy(wzaes->buffer, buf_ptr, bytes_to_write); + buf_ptr += bytes_to_write; + + mz_stream_wzaes_encrypt_data(stream, (uint8_t *)wzaes->buffer, bytes_to_write); + mz_crypt_hmac_update(wzaes->hmac, wzaes->buffer, bytes_to_write); + + written = mz_stream_write(wzaes->stream.base, wzaes->buffer, bytes_to_write); + if (written < 0) + return written; + + total_written += written; + } + while (total_written < size && written > 0); + + wzaes->total_out += total_written; + return total_written; +} + +int64_t mz_stream_wzaes_tell(void *stream) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + return mz_stream_tell(wzaes->stream.base); +} + +int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + return mz_stream_seek(wzaes->stream.base, offset, origin); +} + +int32_t mz_stream_wzaes_close(void *stream) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + uint8_t expected_hash[MZ_AES_AUTHCODE_SIZE]; + uint8_t computed_hash[MZ_HASH_SHA1_SIZE]; + + mz_crypt_hmac_end(wzaes->hmac, computed_hash, sizeof(computed_hash)); + + if (wzaes->mode & MZ_OPEN_MODE_WRITE) + { + if (mz_stream_write(wzaes->stream.base, computed_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE) + return MZ_WRITE_ERROR; + + wzaes->total_out += MZ_AES_AUTHCODE_SIZE; + } + else if (wzaes->mode & MZ_OPEN_MODE_READ) + { + if (mz_stream_read(wzaes->stream.base, expected_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE) + return MZ_READ_ERROR; + + wzaes->total_in += MZ_AES_AUTHCODE_SIZE; + + /* If entire entry was not read this will fail */ + if (memcmp(computed_hash, expected_hash, MZ_AES_AUTHCODE_SIZE) != 0) + return MZ_CRC_ERROR; + } + + wzaes->initialized = 0; + return MZ_OK; +} + +int32_t mz_stream_wzaes_error(void *stream) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + return wzaes->error; +} + +void mz_stream_wzaes_set_password(void *stream, const char *password) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + wzaes->password = password; +} + +void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + wzaes->encryption_mode = encryption_mode; +} + +int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN: + *value = wzaes->total_in; + break; + case MZ_STREAM_PROP_TOTAL_OUT: + *value = wzaes->total_out; + break; + case MZ_STREAM_PROP_TOTAL_IN_MAX: + *value = wzaes->max_total_in; + break; + case MZ_STREAM_PROP_HEADER_SIZE: + *value = MZ_AES_SALT_LENGTH((int64_t)wzaes->encryption_mode) + MZ_AES_PW_VERIFY_SIZE; + break; + case MZ_STREAM_PROP_FOOTER_SIZE: + *value = MZ_AES_AUTHCODE_SIZE; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value) +{ + mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN_MAX: + wzaes->max_total_in = value; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +void *mz_stream_wzaes_create(void **stream) +{ + mz_stream_wzaes *wzaes = NULL; + + wzaes = (mz_stream_wzaes *)MZ_ALLOC(sizeof(mz_stream_wzaes)); + if (wzaes != NULL) + { + memset(wzaes, 0, sizeof(mz_stream_wzaes)); + wzaes->stream.vtbl = &mz_stream_wzaes_vtbl; + wzaes->encryption_mode = MZ_AES_ENCRYPTION_MODE_256; + + mz_crypt_hmac_create(&wzaes->hmac); + mz_crypt_aes_create(&wzaes->aes); + } + if (stream != NULL) + *stream = wzaes; + + return wzaes; +} + +void mz_stream_wzaes_delete(void **stream) +{ + mz_stream_wzaes *wzaes = NULL; + if (stream == NULL) + return; + wzaes = (mz_stream_wzaes *)*stream; + if (wzaes != NULL) + { + mz_crypt_aes_delete(&wzaes->aes); + mz_crypt_hmac_delete(&wzaes->hmac); + MZ_FREE(wzaes); + } + *stream = NULL; +} + +void *mz_stream_wzaes_get_interface(void) +{ + return (void *)&mz_stream_wzaes_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c.meta new file mode 100644 index 0000000..9beea6d --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 3297f7098cde949129f21df6e62c55cd +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h new file mode 100755 index 0000000..7413b55 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h @@ -0,0 +1,47 @@ +/* mz_strm_wzaes.h -- Stream for WinZIP AES encryption + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_WZAES_SHA1_H +#define MZ_STREAM_WZAES_SHA1_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_wzaes_open(void *stream, const char *filename, int32_t mode); +int32_t mz_stream_wzaes_is_open(void *stream); +int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_wzaes_tell(void *stream); +int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_wzaes_close(void *stream); +int32_t mz_stream_wzaes_error(void *stream); + +void mz_stream_wzaes_set_password(void *stream, const char *password); +void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode); + +int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value); +int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value); + +void* mz_stream_wzaes_create(void **stream); +void mz_stream_wzaes_delete(void **stream); + +void* mz_stream_wzaes_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h.meta new file mode 100644 index 0000000..8f0954f --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_wzaes.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: cd30d6c188cf54a3daed42328ab583b7 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c new file mode 100755 index 0000000..0e325f2 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c @@ -0,0 +1,426 @@ +/* mz_strm_zlib.c -- Stream for zlib inflate/deflate + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_strm.h" +#include "mz_strm_zlib.h" + +#include "zlib.h" +#if defined(ZLIBNG_VERNUM) +# include "zlib-ng.h" +#endif + +/***************************************************************************/ + +#if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT) +# define ZLIB_PREFIX(x) zng_ ## x + typedef zng_stream zlib_stream; +#else +# define ZLIB_PREFIX(x) x + typedef z_stream zlib_stream; +#endif + +#if !defined(DEF_MEM_LEVEL) +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif + +/***************************************************************************/ + +static mz_stream_vtbl mz_stream_zlib_vtbl = { + mz_stream_zlib_open, + mz_stream_zlib_is_open, + mz_stream_zlib_read, + mz_stream_zlib_write, + mz_stream_zlib_tell, + mz_stream_zlib_seek, + mz_stream_zlib_close, + mz_stream_zlib_error, + mz_stream_zlib_create, + mz_stream_zlib_delete, + mz_stream_zlib_get_prop_int64, + mz_stream_zlib_set_prop_int64 +}; + +/***************************************************************************/ + +typedef struct mz_stream_zlib_s { + mz_stream stream; + zlib_stream zstream; + uint8_t buffer[INT16_MAX]; + int32_t buffer_len; + int64_t total_in; + int64_t total_out; + int64_t max_total_in; + int8_t initialized; + int16_t level; + int32_t window_bits; + int32_t mode; + int32_t error; +} mz_stream_zlib; + +/***************************************************************************/ + +int32_t mz_stream_zlib_open(void *stream, const char *path, int32_t mode) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + + MZ_UNUSED(path); + + zlib->zstream.data_type = Z_BINARY; + zlib->zstream.zalloc = Z_NULL; + zlib->zstream.zfree = Z_NULL; + zlib->zstream.opaque = Z_NULL; + zlib->zstream.total_in = 0; + zlib->zstream.total_out = 0; + + zlib->total_in = 0; + zlib->total_out = 0; + + if (mode & MZ_OPEN_MODE_WRITE) + { +#ifdef MZ_ZIP_NO_COMPRESSION + return MZ_SUPPORT_ERROR; +#else + zlib->zstream.next_out = zlib->buffer; + zlib->zstream.avail_out = sizeof(zlib->buffer); + + zlib->error = ZLIB_PREFIX(deflateInit2)(&zlib->zstream, (int8_t)zlib->level, Z_DEFLATED, + zlib->window_bits, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +#endif + } + else if (mode & MZ_OPEN_MODE_READ) + { +#ifdef MZ_ZIP_NO_DECOMPRESSION + return MZ_SUPPORT_ERROR; +#else + zlib->zstream.next_in = zlib->buffer; + zlib->zstream.avail_in = 0; + + zlib->error = ZLIB_PREFIX(inflateInit2)(&zlib->zstream, zlib->window_bits); +#endif + } + + if (zlib->error != Z_OK) + return MZ_OPEN_ERROR; + + zlib->initialized = 1; + zlib->mode = mode; + return MZ_OK; +} + +int32_t mz_stream_zlib_is_open(void *stream) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + if (zlib->initialized != 1) + return MZ_OPEN_ERROR; + return MZ_OK; +} + +int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size) +{ +#ifdef MZ_ZIP_NO_DECOMPRESSION + MZ_UNUSED(stream); + MZ_UNUSED(buf); + MZ_UNUSED(size); + return MZ_SUPPORT_ERROR; +#else + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + uint64_t total_in_before = 0; + uint64_t total_in_after = 0; + uint64_t total_out_before = 0; + uint64_t total_out_after = 0; + uint32_t total_in = 0; + uint32_t total_out = 0; + uint32_t in_bytes = 0; + uint32_t out_bytes = 0; + int32_t bytes_to_read = sizeof(zlib->buffer); + int32_t read = 0; + int32_t err = Z_OK; + + + zlib->zstream.next_out = (Bytef*)buf; + zlib->zstream.avail_out = (uInt)size; + + do + { + if (zlib->zstream.avail_in == 0) + { + if (zlib->max_total_in > 0) + { + if ((int64_t)bytes_to_read > (zlib->max_total_in - zlib->total_in)) + bytes_to_read = (int32_t)(zlib->max_total_in - zlib->total_in); + } + + read = mz_stream_read(zlib->stream.base, zlib->buffer, bytes_to_read); + + if (read < 0) + return read; + if (read == 0) + break; + + zlib->zstream.next_in = zlib->buffer; + zlib->zstream.avail_in = read; + } + + total_in_before = zlib->zstream.avail_in; + total_out_before = zlib->zstream.total_out; + + err = ZLIB_PREFIX(inflate)(&zlib->zstream, Z_SYNC_FLUSH); + if ((err >= Z_OK) && (zlib->zstream.msg != NULL)) + { + zlib->error = Z_DATA_ERROR; + break; + } + + total_in_after = zlib->zstream.avail_in; + total_out_after = zlib->zstream.total_out; + + in_bytes = (uint32_t)(total_in_before - total_in_after); + out_bytes = (uint32_t)(total_out_after - total_out_before); + + total_in += in_bytes; + total_out += out_bytes; + + zlib->total_in += in_bytes; + zlib->total_out += out_bytes; + + if (err == Z_STREAM_END) + break; + if (err != Z_OK) + { + zlib->error = err; + break; + } + } + while (zlib->zstream.avail_out > 0); + + if (zlib->error != 0) + { + /* Zlib errors are compatible with MZ */ + return zlib->error; + } + + return total_out; +#endif +} + +#ifndef MZ_ZIP_NO_COMPRESSION +static int32_t mz_stream_zlib_flush(void *stream) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + if (mz_stream_write(zlib->stream.base, zlib->buffer, zlib->buffer_len) != zlib->buffer_len) + return MZ_WRITE_ERROR; + return MZ_OK; +} + +static int32_t mz_stream_zlib_deflate(void *stream, int flush) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + uint64_t total_out_before = 0; + uint64_t total_out_after = 0; + int32_t out_bytes = 0; + int32_t err = Z_OK; + + + do + { + if (zlib->zstream.avail_out == 0) + { + err = mz_stream_zlib_flush(zlib); + if (err != MZ_OK) + return err; + + zlib->zstream.avail_out = sizeof(zlib->buffer); + zlib->zstream.next_out = zlib->buffer; + + zlib->buffer_len = 0; + } + + total_out_before = zlib->zstream.total_out; + err = ZLIB_PREFIX(deflate)(&zlib->zstream, flush); + total_out_after = zlib->zstream.total_out; + + out_bytes = (uint32_t)(total_out_after - total_out_before); + + zlib->buffer_len += out_bytes; + zlib->total_out += out_bytes; + + if (err == Z_STREAM_END) + break; + if (err != Z_OK) + { + zlib->error = err; + return MZ_DATA_ERROR; + } + } + while ((zlib->zstream.avail_in > 0) || (flush == Z_FINISH && err == Z_OK)); + + return MZ_OK; +} +#endif + +int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + int32_t err = size; + +#ifdef MZ_ZIP_NO_COMPRESSION + MZ_UNUSED(zlib); + MZ_UNUSED(buf); + err = MZ_SUPPORT_ERROR; +#else + zlib->zstream.next_in = (Bytef*)(intptr_t)buf; + zlib->zstream.avail_in = (uInt)size; + + mz_stream_zlib_deflate(stream, Z_NO_FLUSH); + + zlib->total_in += size; +#endif + return err; +} + +int64_t mz_stream_zlib_tell(void *stream) +{ + MZ_UNUSED(stream); + + return MZ_TELL_ERROR; +} + +int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin) +{ + MZ_UNUSED(stream); + MZ_UNUSED(offset); + MZ_UNUSED(origin); + + return MZ_SEEK_ERROR; +} + +int32_t mz_stream_zlib_close(void *stream) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + + + if (zlib->mode & MZ_OPEN_MODE_WRITE) + { +#ifdef MZ_ZIP_NO_COMPRESSION + return MZ_SUPPORT_ERROR; +#else + mz_stream_zlib_deflate(stream, Z_FINISH); + mz_stream_zlib_flush(stream); + + ZLIB_PREFIX(deflateEnd)(&zlib->zstream); +#endif + } + else if (zlib->mode & MZ_OPEN_MODE_READ) + { +#ifdef MZ_ZIP_NO_DECOMPRESSION + return MZ_SUPPORT_ERROR; +#else + ZLIB_PREFIX(inflateEnd)(&zlib->zstream); +#endif + } + + zlib->initialized = 0; + + if (zlib->error != Z_OK) + return MZ_CLOSE_ERROR; + return MZ_OK; +} + +int32_t mz_stream_zlib_error(void *stream) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + return zlib->error; +} + +int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + switch (prop) + { + case MZ_STREAM_PROP_TOTAL_IN: + *value = zlib->total_in; + break; + case MZ_STREAM_PROP_TOTAL_IN_MAX: + *value = zlib->max_total_in; + break; + case MZ_STREAM_PROP_TOTAL_OUT: + *value = zlib->total_out; + break; + case MZ_STREAM_PROP_HEADER_SIZE: + *value = 0; + break; + case MZ_STREAM_PROP_COMPRESS_WINDOW: + *value = zlib->window_bits; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value) +{ + mz_stream_zlib *zlib = (mz_stream_zlib *)stream; + switch (prop) + { + case MZ_STREAM_PROP_COMPRESS_LEVEL: + zlib->level = (int16_t)value; + break; + case MZ_STREAM_PROP_TOTAL_IN_MAX: + zlib->max_total_in = value; + break; + case MZ_STREAM_PROP_COMPRESS_WINDOW: + zlib->window_bits = (int32_t)value; + break; + default: + return MZ_EXIST_ERROR; + } + return MZ_OK; +} + +void *mz_stream_zlib_create(void **stream) +{ + mz_stream_zlib *zlib = NULL; + + zlib = (mz_stream_zlib *)MZ_ALLOC(sizeof(mz_stream_zlib)); + if (zlib != NULL) + { + memset(zlib, 0, sizeof(mz_stream_zlib)); + zlib->stream.vtbl = &mz_stream_zlib_vtbl; + zlib->level = Z_DEFAULT_COMPRESSION; + zlib->window_bits = -MAX_WBITS; + } + if (stream != NULL) + *stream = zlib; + + return zlib; +} + +void mz_stream_zlib_delete(void **stream) +{ + mz_stream_zlib *zlib = NULL; + if (stream == NULL) + return; + zlib = (mz_stream_zlib *)*stream; + if (zlib != NULL) + MZ_FREE(zlib); + *stream = NULL; +} + +void *mz_stream_zlib_get_interface(void) +{ + return (void *)&mz_stream_zlib_vtbl; +} diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c.meta new file mode 100644 index 0000000..ed3fe27 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 03d6d59f0437340b88f287b786910af4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h new file mode 100755 index 0000000..7cc570b --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h @@ -0,0 +1,44 @@ +/* mz_strm_zlib.h -- Stream for zlib inflate/deflate + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_STREAM_ZLIB_H +#define MZ_STREAM_ZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +int32_t mz_stream_zlib_open(void *stream, const char *filename, int32_t mode); +int32_t mz_stream_zlib_is_open(void *stream); +int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size); +int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size); +int64_t mz_stream_zlib_tell(void *stream); +int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin); +int32_t mz_stream_zlib_close(void *stream); +int32_t mz_stream_zlib_error(void *stream); + +int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value); +int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value); + +void* mz_stream_zlib_create(void **stream); +void mz_stream_zlib_delete(void **stream); + +void* mz_stream_zlib_get_interface(void); + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h.meta new file mode 100644 index 0000000..328c922 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_strm_zlib.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: dee0e4836969d4fbcb2a16b45ea530b7 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c new file mode 100755 index 0000000..1375c93 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c @@ -0,0 +1,2771 @@ +/* zip.c -- Zip manipulation + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 2009-2010 Mathias Svensson + Modifications for Zip64 support + http://result42.com + Copyright (C) 2007-2008 Even Rouault + Modifications of Unzip for Zip64 + Copyright (C) 1998-2010 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include "mz.h" +#include "mz_crypt.h" +#include "mz_strm.h" +#ifdef HAVE_BZIP2 +# include "mz_strm_bzip.h" +#endif +#ifdef HAVE_LIBCOMP +# include "mz_strm_libcomp.h" +#endif +#ifdef HAVE_LZMA +# include "mz_strm_lzma.h" +#endif +#include "mz_strm_mem.h" +#ifdef HAVE_PKCRYPT +# include "mz_strm_pkcrypt.h" +#endif +#ifdef HAVE_WZAES +# include "mz_strm_wzaes.h" +#endif +#ifdef HAVE_ZLIB +# include "mz_strm_zlib.h" +#endif + +#include "mz_zip.h" + +#include /* tolower */ +#include /* snprintf */ + +#if defined(_MSC_VER) || defined(__MINGW32__) +# define localtime_r(t1,t2) (localtime_s(t2,t1) == 0 ? t1 : NULL) +#endif +#if defined(_MSC_VER) && (_MSC_VER < 1900) +# define snprintf _snprintf +#endif + +/***************************************************************************/ + +#define MZ_ZIP_MAGIC_LOCALHEADER (0x04034b50) +#define MZ_ZIP_MAGIC_CENTRALHEADER (0x02014b50) +#define MZ_ZIP_MAGIC_ENDHEADER (0x06054b50) +#define MZ_ZIP_MAGIC_ENDHEADERU8 { 0x50, 0x4b, 0x05, 0x06 } +#define MZ_ZIP_MAGIC_ENDHEADER64 (0x06064b50) +#define MZ_ZIP_MAGIC_ENDLOCHEADER64 (0x07064b50) +#define MZ_ZIP_MAGIC_DATADESCRIPTOR (0x08074b50) +#define MZ_ZIP_MAGIC_DATADESCRIPTORU8 { 0x50, 0x4b, 0x07, 0x08 } + +#define MZ_ZIP_SIZE_LD_ITEM (30) +#define MZ_ZIP_SIZE_CD_ITEM (46) +#define MZ_ZIP_SIZE_CD_LOCATOR64 (20) + +#ifndef MZ_ZIP_EOCD_MAX_BACK +#define MZ_ZIP_EOCD_MAX_BACK (1 << 20) +#endif + +/***************************************************************************/ + +typedef struct mz_zip_s +{ + mz_zip_file file_info; + mz_zip_file local_file_info; + + void *stream; /* main stream */ + void *cd_stream; /* pointer to the stream with the cd */ + void *cd_mem_stream; /* memory stream for central directory */ + void *compress_stream; /* compression stream */ + void *crypt_stream; /* encryption stream */ + void *file_info_stream; /* memory stream for storing file info */ + void *local_file_info_stream; /* memory stream for storing local file info */ + + int32_t open_mode; + uint8_t recover; + + uint32_t disk_number_with_cd; /* number of the disk with the central dir */ + int64_t disk_offset_shift; /* correction for zips that have wrong offset start of cd */ + + int64_t cd_start_pos; /* pos of the first file in the central dir stream */ + int64_t cd_current_pos; /* pos of the current file in the central dir */ + int64_t cd_offset; /* offset of start of central directory */ + int64_t cd_size; /* size of the central directory */ + + uint8_t entry_scanned; /* entry header information read ok */ + uint8_t entry_opened; /* entry is open for read/write */ + uint8_t entry_raw; /* entry opened with raw mode */ + uint32_t entry_crc32; /* entry crc32 */ + + uint64_t number_entry; + + uint16_t version_madeby; + char *comment; +} mz_zip; + +/***************************************************************************/ + +#if 0 +# define mz_zip_print printf +#else +# define mz_zip_print(fmt,...) +#endif + +/***************************************************************************/ + +/* Locate the end of central directory */ +static int32_t mz_zip_search_eocd(void *stream, int64_t *central_pos) +{ + int64_t file_size = 0; + int64_t max_back = MZ_ZIP_EOCD_MAX_BACK; + uint8_t find[4] = MZ_ZIP_MAGIC_ENDHEADERU8; + int32_t err = MZ_OK; + + err = mz_stream_seek(stream, 0, MZ_SEEK_END); + if (err != MZ_OK) + return err; + + file_size = mz_stream_tell(stream); + + if (max_back <= 0 || max_back > file_size) + max_back = file_size; + + return mz_stream_find_reverse(stream, (const void *)find, sizeof(find), max_back, central_pos); +} + +/* Locate the end of central directory 64 of a zip file */ +static int32_t mz_zip_search_zip64_eocd(void *stream, const int64_t end_central_offset, int64_t *central_pos) +{ + int64_t offset = 0; + uint32_t value32 = 0; + int32_t err = MZ_OK; + + + *central_pos = 0; + + /* Zip64 end of central directory locator */ + err = mz_stream_seek(stream, end_central_offset - MZ_ZIP_SIZE_CD_LOCATOR64, MZ_SEEK_SET); + /* Read locator signature */ + if (err == MZ_OK) + { + err = mz_stream_read_uint32(stream, &value32); + if (value32 != MZ_ZIP_MAGIC_ENDLOCHEADER64) + err = MZ_FORMAT_ERROR; + } + /* Number of the disk with the start of the zip64 end of central directory */ + if (err == MZ_OK) + err = mz_stream_read_uint32(stream, &value32); + /* Relative offset of the zip64 end of central directory record8 */ + if (err == MZ_OK) + err = mz_stream_read_uint64(stream, (uint64_t *)&offset); + /* Total number of disks */ + if (err == MZ_OK) + err = mz_stream_read_uint32(stream, &value32); + /* Goto end of central directory record */ + if (err == MZ_OK) + err = mz_stream_seek(stream, (int64_t)offset, MZ_SEEK_SET); + /* The signature */ + if (err == MZ_OK) + { + err = mz_stream_read_uint32(stream, &value32); + if (value32 != MZ_ZIP_MAGIC_ENDHEADER64) + err = MZ_FORMAT_ERROR; + } + + if (err == MZ_OK) + *central_pos = offset; + + return err; +} + +/* Get info about the current file in the zip file */ +static int32_t mz_zip_entry_read_header(void *stream, uint8_t local, mz_zip_file *file_info, void *file_extra_stream) +{ + uint64_t ntfs_time = 0; + uint32_t reserved = 0; + uint32_t magic = 0; + uint32_t dos_date = 0; + uint32_t field_pos = 0; + uint16_t field_type = 0; + uint16_t field_length = 0; + uint32_t field_length_read = 0; + uint16_t ntfs_attrib_id = 0; + uint16_t ntfs_attrib_size = 0; + uint16_t linkname_size; + uint16_t value16 = 0; + uint32_t value32 = 0; + int64_t extrafield_pos = 0; + int64_t comment_pos = 0; + int64_t linkname_pos = 0; + int64_t saved_pos = 0; + int32_t err = MZ_OK; + char *linkname = NULL; + + + memset(file_info, 0, sizeof(mz_zip_file)); + + /* Check the magic */ + err = mz_stream_read_uint32(stream, &magic); + if (err == MZ_END_OF_STREAM) + err = MZ_END_OF_LIST; + else if (magic == MZ_ZIP_MAGIC_ENDHEADER || magic == MZ_ZIP_MAGIC_ENDHEADER64) + err = MZ_END_OF_LIST; + else if ((local) && (magic != MZ_ZIP_MAGIC_LOCALHEADER)) + err = MZ_FORMAT_ERROR; + else if ((!local) && (magic != MZ_ZIP_MAGIC_CENTRALHEADER)) + err = MZ_FORMAT_ERROR; + + /* Read header fields */ + if (err == MZ_OK) + { + if (!local) + err = mz_stream_read_uint16(stream, &file_info->version_madeby); + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->version_needed); + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->flag); + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->compression_method); + if (err == MZ_OK) + { + err = mz_stream_read_uint32(stream, &dos_date); + file_info->modified_date = mz_zip_dosdate_to_time_t(dos_date); + } + if (err == MZ_OK) + err = mz_stream_read_uint32(stream, &file_info->crc); + if (err == MZ_OK) + { + err = mz_stream_read_uint32(stream, &value32); + file_info->compressed_size = value32; + } + if (err == MZ_OK) + { + err = mz_stream_read_uint32(stream, &value32); + file_info->uncompressed_size = value32; + } + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->filename_size); + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->extrafield_size); + if (!local) + { + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->comment_size); + if (err == MZ_OK) + { + err = mz_stream_read_uint16(stream, &value16); + file_info->disk_number = value16; + } + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &file_info->internal_fa); + if (err == MZ_OK) + err = mz_stream_read_uint32(stream, &file_info->external_fa); + if (err == MZ_OK) + { + err = mz_stream_read_uint32(stream, &value32); + file_info->disk_offset = value32; + } + } + } + + if (err == MZ_OK) + err = mz_stream_seek(file_extra_stream, 0, MZ_SEEK_SET); + + /* Copy variable length data to memory stream for later retrieval */ + if ((err == MZ_OK) && (file_info->filename_size > 0)) + err = mz_stream_copy(file_extra_stream, stream, file_info->filename_size); + mz_stream_write_uint8(file_extra_stream, 0); + extrafield_pos = mz_stream_tell(file_extra_stream); + + if ((err == MZ_OK) && (file_info->extrafield_size > 0)) + err = mz_stream_copy(file_extra_stream, stream, file_info->extrafield_size); + mz_stream_write_uint8(file_extra_stream, 0); + + comment_pos = mz_stream_tell(file_extra_stream); + if ((err == MZ_OK) && (file_info->comment_size > 0)) + err = mz_stream_copy(file_extra_stream, stream, file_info->comment_size); + mz_stream_write_uint8(file_extra_stream, 0); + + linkname_pos = mz_stream_tell(file_extra_stream); + /* Overwrite if we encounter UNIX1 extra block */ + mz_stream_write_uint8(file_extra_stream, 0); + + if ((err == MZ_OK) && (file_info->extrafield_size > 0)) + { + /* Seek to and parse the extra field */ + err = mz_stream_seek(file_extra_stream, extrafield_pos, MZ_SEEK_SET); + + while ((err == MZ_OK) && (field_pos + 4 <= file_info->extrafield_size)) + { + err = mz_zip_extrafield_read(file_extra_stream, &field_type, &field_length); + if (err != MZ_OK) + break; + field_pos += 4; + + /* Don't allow field length to exceed size of remaining extrafield */ + if (field_length > (file_info->extrafield_size - field_pos)) + field_length = (uint16_t)(file_info->extrafield_size - field_pos); + + /* Read ZIP64 extra field */ + if ((field_type == MZ_ZIP_EXTENSION_ZIP64) && (field_length >= 8)) + { + if ((err == MZ_OK) && (file_info->uncompressed_size == UINT32_MAX)) + { + err = mz_stream_read_int64(file_extra_stream, &file_info->uncompressed_size); + if (file_info->uncompressed_size < 0) + err = MZ_FORMAT_ERROR; + } + if ((err == MZ_OK) && (file_info->compressed_size == UINT32_MAX)) + { + err = mz_stream_read_int64(file_extra_stream, &file_info->compressed_size); + if (file_info->compressed_size < 0) + err = MZ_FORMAT_ERROR; + } + if ((err == MZ_OK) && (file_info->disk_offset == UINT32_MAX)) + { + err = mz_stream_read_int64(file_extra_stream, &file_info->disk_offset); + if (file_info->disk_offset < 0) + err = MZ_FORMAT_ERROR; + } + if ((err == MZ_OK) && (file_info->disk_number == UINT16_MAX)) + err = mz_stream_read_uint32(file_extra_stream, &file_info->disk_number); + } + /* Read NTFS extra field */ + else if ((field_type == MZ_ZIP_EXTENSION_NTFS) && (field_length > 4)) + { + if (err == MZ_OK) + err = mz_stream_read_uint32(file_extra_stream, &reserved); + field_length_read = 4; + + while ((err == MZ_OK) && (field_length_read + 4 <= field_length)) + { + err = mz_stream_read_uint16(file_extra_stream, &ntfs_attrib_id); + if (err == MZ_OK) + err = mz_stream_read_uint16(file_extra_stream, &ntfs_attrib_size); + field_length_read += 4; + + if ((err == MZ_OK) && (ntfs_attrib_id == 0x01) && (ntfs_attrib_size == 24)) + { + err = mz_stream_read_uint64(file_extra_stream, &ntfs_time); + mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->modified_date); + + if (err == MZ_OK) + { + err = mz_stream_read_uint64(file_extra_stream, &ntfs_time); + mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->accessed_date); + } + if (err == MZ_OK) + { + err = mz_stream_read_uint64(file_extra_stream, &ntfs_time); + mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->creation_date); + } + } + else if ((err == MZ_OK) && (field_length_read + ntfs_attrib_size <= field_length)) + { + err = mz_stream_seek(file_extra_stream, ntfs_attrib_size, MZ_SEEK_CUR); + } + + field_length_read += ntfs_attrib_size; + } + } + /* Read UNIX1 extra field */ + else if ((field_type == MZ_ZIP_EXTENSION_UNIX1) && (field_length >= 12)) + { + if (err == MZ_OK) + { + err = mz_stream_read_uint32(file_extra_stream, &value32); + if (err == MZ_OK && file_info->accessed_date == 0) + file_info->accessed_date = value32; + } + if (err == MZ_OK) + { + err = mz_stream_read_uint32(file_extra_stream, &value32); + if (err == MZ_OK && file_info->modified_date == 0) + file_info->modified_date = value32; + } + if (err == MZ_OK) + err = mz_stream_read_uint16(file_extra_stream, &value16); /* User id */ + if (err == MZ_OK) + err = mz_stream_read_uint16(file_extra_stream, &value16); /* Group id */ + + /* Copy linkname to end of file extra stream so we can return null + terminated string */ + linkname_size = field_length - 12; + if ((err == MZ_OK) && (linkname_size > 0)) + { + linkname = (char *)MZ_ALLOC(linkname_size); + if (linkname != NULL) + { + if (mz_stream_read(file_extra_stream, linkname, linkname_size) != linkname_size) + err = MZ_READ_ERROR; + if (err == MZ_OK) + { + saved_pos = mz_stream_tell(file_extra_stream); + + mz_stream_seek(file_extra_stream, linkname_pos, MZ_SEEK_SET); + mz_stream_write(file_extra_stream, linkname, linkname_size); + mz_stream_write_uint8(file_extra_stream, 0); + + mz_stream_seek(file_extra_stream, saved_pos, MZ_SEEK_SET); + } + MZ_FREE(linkname); + } + } + } +#ifdef HAVE_WZAES + /* Read AES extra field */ + else if ((field_type == MZ_ZIP_EXTENSION_AES) && (field_length == 7)) + { + uint8_t value8 = 0; + /* Verify version info */ + err = mz_stream_read_uint16(file_extra_stream, &value16); + /* Support AE-1 and AE-2 */ + if (value16 != 1 && value16 != 2) + err = MZ_FORMAT_ERROR; + file_info->aes_version = value16; + if (err == MZ_OK) + err = mz_stream_read_uint8(file_extra_stream, &value8); + if ((char)value8 != 'A') + err = MZ_FORMAT_ERROR; + if (err == MZ_OK) + err = mz_stream_read_uint8(file_extra_stream, &value8); + if ((char)value8 != 'E') + err = MZ_FORMAT_ERROR; + /* Get AES encryption strength and actual compression method */ + if (err == MZ_OK) + { + err = mz_stream_read_uint8(file_extra_stream, &value8); + file_info->aes_encryption_mode = value8; + } + if (err == MZ_OK) + { + err = mz_stream_read_uint16(file_extra_stream, &value16); + file_info->compression_method = value16; + } + } +#endif + else if (field_length > 0) + { + err = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR); + } + + field_pos += field_length; + } + } + + /* Get pointers to variable length data */ + mz_stream_mem_get_buffer(file_extra_stream, (const void **)&file_info->filename); + mz_stream_mem_get_buffer_at(file_extra_stream, extrafield_pos, (const void **)&file_info->extrafield); + mz_stream_mem_get_buffer_at(file_extra_stream, comment_pos, (const void **)&file_info->comment); + mz_stream_mem_get_buffer_at(file_extra_stream, linkname_pos, (const void **)&file_info->linkname); + + /* Set to empty string just in-case */ + if (file_info->filename == NULL) + file_info->filename = ""; + if (file_info->extrafield == NULL) + file_info->extrafield_size = 0; + if (file_info->comment == NULL) + file_info->comment = ""; + if (file_info->linkname == NULL) + file_info->linkname = ""; + + if (err == MZ_OK) + { + mz_zip_print("Zip - Entry - Read header - %s (local %"PRId8")\n", + file_info->filename, local); + mz_zip_print("Zip - Entry - Read header compress (ucs %"PRId64" cs %"PRId64" crc 0x%08"PRIx32")\n", + file_info->uncompressed_size, file_info->compressed_size, file_info->crc); + if (!local) + { + mz_zip_print("Zip - Entry - Read header disk (disk %"PRIu32" offset %"PRId64")\n", + file_info->disk_number, file_info->disk_offset); + } + mz_zip_print("Zip - Entry - Read header variable (fnl %"PRId32" efs %"PRId32" cms %"PRId32")\n", + file_info->filename_size, file_info->extrafield_size, file_info->comment_size); + } + + return err; +} + +static int32_t mz_zip_entry_read_descriptor(void *stream, uint8_t zip64, uint32_t *crc32, int64_t *compressed_size, int64_t *uncompressed_size) +{ + uint32_t value32 = 0; + int64_t value64 = 0; + int32_t err = MZ_OK; + + + err = mz_stream_read_uint32(stream, &value32); + if (value32 != MZ_ZIP_MAGIC_DATADESCRIPTOR) + err = MZ_FORMAT_ERROR; + if (err == MZ_OK) + err = mz_stream_read_uint32(stream, &value32); + if ((err == MZ_OK) && (crc32 != NULL)) + *crc32 = value32; + if (err == MZ_OK) + { + /* If zip 64 extension is enabled then read as 8 byte */ + if (!zip64) + { + err = mz_stream_read_uint32(stream, &value32); + value64 = value32; + } + else + { + err = mz_stream_read_int64(stream, &value64); + if (value64 < 0) + err = MZ_FORMAT_ERROR; + } + if ((err == MZ_OK) && (compressed_size != NULL)) + *compressed_size = value64; + } + if (err == MZ_OK) + { + if (!zip64) + { + err = mz_stream_read_uint32(stream, &value32); + value64 = value32; + } + else + { + err = mz_stream_read_int64(stream, &value64); + if (value64 < 0) + err = MZ_FORMAT_ERROR; + } + if ((err == MZ_OK) && (uncompressed_size != NULL)) + *uncompressed_size = value64; + } + + return err; +} + +static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_file *file_info) +{ + uint64_t ntfs_time = 0; + uint32_t reserved = 0; + uint32_t dos_date = 0; + uint16_t extrafield_size = 0; + uint16_t field_type = 0; + uint16_t field_length = 0; + uint16_t field_length_zip64 = 0; + uint16_t field_length_ntfs = 0; + uint16_t field_length_aes = 0; + uint16_t field_length_unix1 = 0; + uint16_t filename_size = 0; + uint16_t filename_length = 0; + uint16_t linkname_size = 0; + uint16_t version_needed = 0; + int32_t comment_size = 0; + int32_t err = MZ_OK; + int32_t err_mem = MZ_OK; + uint8_t zip64 = 0; + uint8_t skip_aes = 0; + uint8_t mask = 0; + uint8_t write_end_slash = 0; + const char *filename = NULL; + char masked_name[64]; + void *file_extra_stream = NULL; + + if (file_info == NULL) + return MZ_PARAM_ERROR; + + if ((local) && (file_info->flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO)) + mask = 1; + + /* Calculate extra field sizes */ + if (file_info->uncompressed_size >= UINT32_MAX) + field_length_zip64 += 8; + if (file_info->compressed_size >= UINT32_MAX) + field_length_zip64 += 8; + if (file_info->disk_offset >= UINT32_MAX) + field_length_zip64 += 8; + + if (file_info->zip64 == MZ_ZIP64_AUTO) + { + /* If uncompressed size is unknown, assume zip64 for 64-bit data descriptors */ + zip64 = (local && file_info->uncompressed_size == 0) || (field_length_zip64 > 0); + } + else if (file_info->zip64 == MZ_ZIP64_FORCE) + { + zip64 = 1; + } + else if (file_info->zip64 == MZ_ZIP64_DISABLE) + { + /* Zip64 extension is required to zip file */ + if (field_length_zip64 > 0) + return MZ_PARAM_ERROR; + } + + if (zip64) + { + extrafield_size += 4; + extrafield_size += field_length_zip64; + } + + /* Calculate extra field size and check for duplicates */ + if (file_info->extrafield_size > 0) + { + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_set_buffer(file_extra_stream, (void *)file_info->extrafield, + file_info->extrafield_size); + + do + { + err_mem = mz_stream_read_uint16(file_extra_stream, &field_type); + if (err_mem == MZ_OK) + err_mem = mz_stream_read_uint16(file_extra_stream, &field_length); + if (err_mem != MZ_OK) + break; + + /* Prefer incoming aes extensions over ours */ + if (field_type == MZ_ZIP_EXTENSION_AES) + skip_aes = 1; + + /* Prefer our zip64, ntfs, unix1 extension over incoming */ + if (field_type != MZ_ZIP_EXTENSION_ZIP64 && field_type != MZ_ZIP_EXTENSION_NTFS && + field_type != MZ_ZIP_EXTENSION_UNIX1) + extrafield_size += 4 + field_length; + + if (err_mem == MZ_OK) + err_mem = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR); + } + while (err_mem == MZ_OK); + } + +#ifdef HAVE_WZAES + if (!skip_aes) + { + if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) + { + field_length_aes = 1 + 1 + 1 + 2 + 2; + extrafield_size += 4 + field_length_aes; + } + } +#else + MZ_UNUSED(field_length_aes); + MZ_UNUSED(skip_aes); +#endif + /* NTFS timestamps */ + if ((file_info->modified_date != 0) && + (file_info->accessed_date != 0) && + (file_info->creation_date != 0) && (!mask)) + { + field_length_ntfs = 8 + 8 + 8 + 4 + 2 + 2; + extrafield_size += 4 + field_length_ntfs; + } + + /* Unix1 symbolic links */ + if (file_info->linkname != NULL && *file_info->linkname != 0) + { + linkname_size = (uint16_t)strlen(file_info->linkname); + field_length_unix1 = 12 + linkname_size; + extrafield_size += 4 + field_length_unix1; + } + + if (local) + err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_LOCALHEADER); + else + { + err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_CENTRALHEADER); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, file_info->version_madeby); + } + + /* Calculate version needed to extract */ + if (err == MZ_OK) + { + version_needed = file_info->version_needed; + if (version_needed == 0) + { + version_needed = 20; + if (zip64) + version_needed = 45; +#ifdef HAVE_WZAES + if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) + version_needed = 51; +#endif +#ifdef HAVE_LZMA + if (file_info->compression_method == MZ_COMPRESS_METHOD_LZMA) + version_needed = 63; +#endif + } + err = mz_stream_write_uint16(stream, version_needed); + } + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, file_info->flag); + if (err == MZ_OK) + { +#ifdef HAVE_WZAES + if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) + err = mz_stream_write_uint16(stream, MZ_COMPRESS_METHOD_AES); + else +#endif + err = mz_stream_write_uint16(stream, file_info->compression_method); + } + if (err == MZ_OK) + { + if (file_info->modified_date != 0 && !mask) + dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date); + err = mz_stream_write_uint32(stream, dos_date); + } + + if (err == MZ_OK) + { + if (mask) + err = mz_stream_write_uint32(stream, 0); + else + err = mz_stream_write_uint32(stream, file_info->crc); /* crc */ + } + if (err == MZ_OK) + { + if (file_info->compressed_size >= UINT32_MAX) /* compr size */ + err = mz_stream_write_uint32(stream, UINT32_MAX); + else + err = mz_stream_write_uint32(stream, (uint32_t)file_info->compressed_size); + } + if (err == MZ_OK) + { + if (file_info->uncompressed_size >= UINT32_MAX) /* uncompr size */ + err = mz_stream_write_uint32(stream, UINT32_MAX); + else if (mask) + err = mz_stream_write_uint32(stream, 0); + else + err = mz_stream_write_uint32(stream, (uint32_t)file_info->uncompressed_size); + } + + if (mask) + { + snprintf(masked_name, sizeof(masked_name), "%"PRIx32"_%"PRIx64, + file_info->disk_number, file_info->disk_offset); + filename = masked_name; + } + else + { + filename = file_info->filename; + } + + filename_length = (uint16_t)strlen(filename); + filename_size += filename_length; + + if ((mz_zip_attrib_is_dir(file_info->external_fa, file_info->version_madeby) == MZ_OK) && + ((filename[filename_length - 1] != '/') && (filename[filename_length - 1] != '\\'))) + { + filename_size += 1; + write_end_slash = 1; + } + + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, filename_size); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, extrafield_size); + + if (!local) + { + if (file_info->comment != NULL) + { + comment_size = (int32_t)strlen(file_info->comment); + if (comment_size > UINT16_MAX) + comment_size = UINT16_MAX; + } + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, (uint16_t)comment_size); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, (uint16_t)file_info->disk_number); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, file_info->internal_fa); + if (err == MZ_OK) + err = mz_stream_write_uint32(stream, file_info->external_fa); + if (err == MZ_OK) + { + if (file_info->disk_offset >= UINT32_MAX) + err = mz_stream_write_uint32(stream, UINT32_MAX); + else + err = mz_stream_write_uint32(stream, (uint32_t)file_info->disk_offset); + } + } + + if (err == MZ_OK) + { + if (mz_stream_write(stream, filename, filename_length) != filename_length) + err = MZ_WRITE_ERROR; + + /* Ensure that directories have a slash appended to them for compatibility */ + if (err == MZ_OK && write_end_slash) + err = mz_stream_write_uint8(stream, '/'); + } + + if (file_info->extrafield_size > 0) + { + err_mem = mz_stream_mem_seek(file_extra_stream, 0, MZ_SEEK_SET); + while (err == MZ_OK && err_mem == MZ_OK) + { + err_mem = mz_stream_read_uint16(file_extra_stream, &field_type); + if (err_mem == MZ_OK) + err_mem = mz_stream_read_uint16(file_extra_stream, &field_length); + if (err_mem != MZ_OK) + break; + + /* Prefer our zip 64, ntfs, unix1 extensions over incoming */ + if (field_type == MZ_ZIP_EXTENSION_ZIP64 || field_type == MZ_ZIP_EXTENSION_NTFS || + field_type == MZ_ZIP_EXTENSION_UNIX1) + { + err_mem = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR); + continue; + } + + err = mz_stream_write_uint16(stream, field_type); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, field_length); + if (err == MZ_OK) + err = mz_stream_copy(stream, file_extra_stream, field_length); + } + + mz_stream_mem_delete(&file_extra_stream); + } + + /* Write ZIP64 extra field */ + if ((err == MZ_OK) && (zip64)) + { + err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_ZIP64, field_length_zip64); + if ((err == MZ_OK) && (file_info->uncompressed_size >= UINT32_MAX)) + { + if (mask) + err = mz_stream_write_int64(stream, 0); + else + err = mz_stream_write_int64(stream, file_info->uncompressed_size); + } + if ((err == MZ_OK) && (file_info->compressed_size >= UINT32_MAX)) + err = mz_stream_write_int64(stream, file_info->compressed_size); + if ((err == MZ_OK) && (file_info->disk_offset >= UINT32_MAX)) + err = mz_stream_write_int64(stream, file_info->disk_offset); + } + /* Write NTFS extra field */ + if ((err == MZ_OK) && (field_length_ntfs > 0)) + { + err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_NTFS, field_length_ntfs); + if (err == MZ_OK) + err = mz_stream_write_uint32(stream, reserved); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, 0x01); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, field_length_ntfs - 8); + if (err == MZ_OK) + { + mz_zip_unix_to_ntfs_time(file_info->modified_date, &ntfs_time); + err = mz_stream_write_uint64(stream, ntfs_time); + } + if (err == MZ_OK) + { + mz_zip_unix_to_ntfs_time(file_info->accessed_date, &ntfs_time); + err = mz_stream_write_uint64(stream, ntfs_time); + } + if (err == MZ_OK) + { + mz_zip_unix_to_ntfs_time(file_info->creation_date, &ntfs_time); + err = mz_stream_write_uint64(stream, ntfs_time); + } + } + /* Write UNIX extra block extra field */ + if ((err == MZ_OK) && (field_length_unix1 > 0)) + { + err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_UNIX1, field_length_unix1); + if (err == MZ_OK) + err = mz_stream_write_uint32(stream, (uint32_t)file_info->accessed_date); + if (err == MZ_OK) + err = mz_stream_write_uint32(stream, (uint32_t)file_info->modified_date); + if (err == MZ_OK) /* User id */ + err = mz_stream_write_uint16(stream, 0); + if (err == MZ_OK) /* Group id */ + err = mz_stream_write_uint16(stream, 0); + if (err == MZ_OK && linkname_size > 0) + { + if (mz_stream_write(stream, file_info->linkname, linkname_size) != linkname_size) + err = MZ_WRITE_ERROR; + } + } +#ifdef HAVE_WZAES + /* Write AES extra field */ + if ((err == MZ_OK) && (!skip_aes) && (file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) + { + err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_AES, field_length_aes); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, file_info->aes_version); + if (err == MZ_OK) + err = mz_stream_write_uint8(stream, 'A'); + if (err == MZ_OK) + err = mz_stream_write_uint8(stream, 'E'); + if (err == MZ_OK) + err = mz_stream_write_uint8(stream, file_info->aes_encryption_mode); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, file_info->compression_method); + } +#endif + if ((err == MZ_OK) && (!local) && (file_info->comment != NULL)) + { + if (mz_stream_write(stream, file_info->comment, file_info->comment_size) != file_info->comment_size) + err = MZ_WRITE_ERROR; + } + + return err; +} + +static int32_t mz_zip_entry_write_descriptor(void *stream, uint8_t zip64, uint32_t crc32, int64_t compressed_size, int64_t uncompressed_size) +{ + int32_t err = MZ_OK; + + err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_DATADESCRIPTOR); + if (err == MZ_OK) + err = mz_stream_write_uint32(stream, crc32); + + /* Store data descriptor as 8 bytes if zip 64 extension enabled */ + if (err == MZ_OK) + { + /* Zip 64 extension is enabled when uncompressed size is > UINT32_MAX */ + if (!zip64) + err = mz_stream_write_uint32(stream, (uint32_t)compressed_size); + else + err = mz_stream_write_int64(stream, compressed_size); + } + if (err == MZ_OK) + { + if (!zip64) + err = mz_stream_write_uint32(stream, (uint32_t)uncompressed_size); + else + err = mz_stream_write_int64(stream, uncompressed_size); + } + + return err; +} + +static int32_t mz_zip_read_cd(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + uint64_t number_entry_cd64 = 0; + uint64_t number_entry = 0; + uint64_t number_entry_cd = 0; + int64_t eocd_pos = 0; + int64_t eocd_pos64 = 0; + int64_t value64i = 0; + uint16_t value16 = 0; + uint32_t value32 = 0; + uint64_t value64 = 0; + uint16_t comment_size = 0; + int32_t comment_read = 0; + int32_t err = MZ_OK; + + + if (zip == NULL) + return MZ_PARAM_ERROR; + + /* Read and cache central directory records */ + err = mz_zip_search_eocd(zip->stream, &eocd_pos); + if (err == MZ_OK) + { + /* The signature, already checked */ + err = mz_stream_read_uint32(zip->stream, &value32); + /* Number of this disk */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &value16); + /* Number of the disk with the start of the central directory */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &value16); + zip->disk_number_with_cd = value16; + /* Total number of entries in the central dir on this disk */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &value16); + zip->number_entry = value16; + /* Total number of entries in the central dir */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &value16); + number_entry_cd = value16; + if (number_entry_cd != zip->number_entry) + err = MZ_FORMAT_ERROR; + /* Size of the central directory */ + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &value32); + if (err == MZ_OK) + zip->cd_size = value32; + /* Offset of start of central directory with respect to the starting disk number */ + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &value32); + if (err == MZ_OK) + zip->cd_offset = value32; + /* Zip file global comment length */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &comment_size); + if ((err == MZ_OK) && (comment_size > 0)) + { + zip->comment = (char *)MZ_ALLOC(comment_size + 1); + if (zip->comment != NULL) + { + comment_read = mz_stream_read(zip->stream, zip->comment, comment_size); + /* Don't fail if incorrect comment length read, not critical */ + if (comment_read < 0) + comment_read = 0; + zip->comment[comment_read] = 0; + } + } + + if ((err == MZ_OK) && ((number_entry_cd == UINT16_MAX) || (zip->cd_offset == UINT32_MAX))) + { + /* Format should be Zip64, as the central directory or file size is too large */ + if (mz_zip_search_zip64_eocd(zip->stream, eocd_pos, &eocd_pos64) == MZ_OK) + { + eocd_pos = eocd_pos64; + + err = mz_stream_seek(zip->stream, eocd_pos, MZ_SEEK_SET); + /* The signature, already checked */ + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &value32); + /* Size of zip64 end of central directory record */ + if (err == MZ_OK) + err = mz_stream_read_uint64(zip->stream, &value64); + /* Version made by */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &zip->version_madeby); + /* Version needed to extract */ + if (err == MZ_OK) + err = mz_stream_read_uint16(zip->stream, &value16); + /* Number of this disk */ + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &value32); + /* Number of the disk with the start of the central directory */ + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &zip->disk_number_with_cd); + /* Total number of entries in the central directory on this disk */ + if (err == MZ_OK) + err = mz_stream_read_uint64(zip->stream, &number_entry); + /* Total number of entries in the central directory */ + if (err == MZ_OK) + err = mz_stream_read_uint64(zip->stream, &number_entry_cd64); + if (number_entry == UINT32_MAX) + zip->number_entry = number_entry_cd64; + /* Size of the central directory */ + if (err == MZ_OK) + { + err = mz_stream_read_int64(zip->stream, &zip->cd_size); + if (zip->cd_size < 0) + err = MZ_FORMAT_ERROR; + } + /* Offset of start of central directory with respect to the starting disk number */ + if (err == MZ_OK) + { + err = mz_stream_read_int64(zip->stream, &zip->cd_offset); + if (zip->cd_offset < 0) + err = MZ_FORMAT_ERROR; + } + } + else if ((zip->number_entry == UINT16_MAX) || (number_entry_cd != zip->number_entry) || + (zip->cd_size == UINT16_MAX) || (zip->cd_offset == UINT32_MAX)) + { + err = MZ_FORMAT_ERROR; + } + } + } + + if (err == MZ_OK) + { + mz_zip_print("Zip - Read cd (disk %"PRId32" entries %"PRId64" offset %"PRId64" size %"PRId64")\n", + zip->disk_number_with_cd, zip->number_entry, zip->cd_offset, zip->cd_size); + + /* Verify central directory signature exists at offset */ + err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET); + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &value32); + if (value32 != MZ_ZIP_MAGIC_CENTRALHEADER) + { + /* If not found attempt to seek backward to find it */ + err = mz_stream_seek(zip->stream, eocd_pos - zip->cd_size, MZ_SEEK_SET); + if (err == MZ_OK) + err = mz_stream_read_uint32(zip->stream, &value32); + if (value32 == MZ_ZIP_MAGIC_CENTRALHEADER) + { + /* If found compensate for incorrect locations */ + value64i = zip->cd_offset; + zip->cd_offset = eocd_pos - zip->cd_size; + /* Assume disk has prepended data */ + zip->disk_offset_shift = zip->cd_offset - value64i; + } + } + } + + if (err == MZ_OK) + { + if (eocd_pos < zip->cd_offset) + { + /* End of central dir should always come after central dir */ + err = MZ_FORMAT_ERROR; + } + else if (eocd_pos < zip->cd_offset + zip->cd_size) + { + /* Truncate size of cd if incorrect size or offset provided */ + zip->cd_size = eocd_pos - zip->cd_offset; + } + } + + return err; +} + +static int32_t mz_zip_write_cd(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + int64_t zip64_eocd_pos_inzip = 0; + int64_t disk_number = 0; + int64_t disk_size = 0; + int32_t comment_size = 0; + int32_t err = MZ_OK; + + + if (zip == NULL) + return MZ_PARAM_ERROR; + + if (mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number) == MZ_OK) + zip->disk_number_with_cd = (uint32_t)disk_number; + if (mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_SIZE, &disk_size) == MZ_OK && disk_size > 0) + zip->disk_number_with_cd += 1; + mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1); + + zip->cd_offset = mz_stream_tell(zip->stream); + mz_stream_seek(zip->cd_mem_stream, 0, MZ_SEEK_END); + zip->cd_size = (uint32_t)mz_stream_tell(zip->cd_mem_stream); + mz_stream_seek(zip->cd_mem_stream, 0, MZ_SEEK_SET); + + err = mz_stream_copy(zip->stream, zip->cd_mem_stream, (int32_t)zip->cd_size); + + mz_zip_print("Zip - Write cd (disk %"PRId32" entries %"PRId64" offset %"PRId64" size %"PRId64")\n", + zip->disk_number_with_cd, zip->number_entry, zip->cd_offset, zip->cd_size); + + if (zip->cd_size == 0 && zip->number_entry > 0) + { + // Zip does not contain central directory, open with recovery option + return MZ_FORMAT_ERROR; + } + + /* Write the ZIP64 central directory header */ + if (zip->cd_offset >= UINT32_MAX || zip->number_entry > UINT16_MAX) + { + zip64_eocd_pos_inzip = mz_stream_tell(zip->stream); + + err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDHEADER64); + + /* Size of this 'zip64 end of central directory' */ + if (err == MZ_OK) + err = mz_stream_write_uint64(zip->stream, (uint64_t)44); + /* Version made by */ + if (err == MZ_OK) + err = mz_stream_write_uint16(zip->stream, zip->version_madeby); + /* Version needed */ + if (err == MZ_OK) + err = mz_stream_write_uint16(zip->stream, (uint16_t)45); + /* Number of this disk */ + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd); + /* Number of the disk with the start of the central directory */ + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd); + /* Total number of entries in the central dir on this disk */ + if (err == MZ_OK) + err = mz_stream_write_uint64(zip->stream, zip->number_entry); + /* Total number of entries in the central dir */ + if (err == MZ_OK) + err = mz_stream_write_uint64(zip->stream, zip->number_entry); + /* Size of the central directory */ + if (err == MZ_OK) + err = mz_stream_write_int64(zip->stream, zip->cd_size); + /* Offset of start of central directory with respect to the starting disk number */ + if (err == MZ_OK) + err = mz_stream_write_int64(zip->stream, zip->cd_offset); + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDLOCHEADER64); + + /* Number of the disk with the start of the central directory */ + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd); + /* Relative offset to the end of zip64 central directory */ + if (err == MZ_OK) + err = mz_stream_write_int64(zip->stream, zip64_eocd_pos_inzip); + /* Number of the disk with the start of the central directory */ + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd + 1); + } + + /* Write the central directory header */ + + /* Signature */ + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDHEADER); + /* Number of this disk */ + if (err == MZ_OK) + err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->disk_number_with_cd); + /* Number of the disk with the start of the central directory */ + if (err == MZ_OK) + err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->disk_number_with_cd); + /* Total number of entries in the central dir on this disk */ + if (err == MZ_OK) + { + if (zip->number_entry >= UINT16_MAX) + err = mz_stream_write_uint16(zip->stream, UINT16_MAX); + else + err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->number_entry); + } + /* Total number of entries in the central dir */ + if (err == MZ_OK) + { + if (zip->number_entry >= UINT16_MAX) + err = mz_stream_write_uint16(zip->stream, UINT16_MAX); + else + err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->number_entry); + } + /* Size of the central directory */ + if (err == MZ_OK) + err = mz_stream_write_uint32(zip->stream, (uint32_t)zip->cd_size); + /* Offset of start of central directory with respect to the starting disk number */ + if (err == MZ_OK) + { + if (zip->cd_offset >= UINT32_MAX) + err = mz_stream_write_uint32(zip->stream, UINT32_MAX); + else + err = mz_stream_write_uint32(zip->stream, (uint32_t)zip->cd_offset); + } + + /* Write global comment */ + if (zip->comment != NULL) + { + comment_size = (int32_t)strlen(zip->comment); + if (comment_size > UINT16_MAX) + comment_size = UINT16_MAX; + } + if (err == MZ_OK) + err = mz_stream_write_uint16(zip->stream, (uint16_t)comment_size); + if (err == MZ_OK) + { + if (mz_stream_write(zip->stream, zip->comment, comment_size) != comment_size) + err = MZ_READ_ERROR; + } + return err; +} + +static int32_t mz_zip_recover_cd(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + mz_zip_file local_file_info; + void *local_file_info_stream = NULL; + void *cd_mem_stream = NULL; + uint64_t number_entry = 0; + int64_t descriptor_pos = 0; + int64_t disk_offset = 0; + int64_t disk_number = 0; + int64_t compressed_size = 0; + int64_t uncompressed_size = 0; + uint8_t descriptor_magic[4] = MZ_ZIP_MAGIC_DATADESCRIPTORU8; + uint32_t crc32 = 0; + int32_t disk_number_with_cd = 0; + int32_t err = MZ_OK; + uint8_t zip64 = 0; + + + mz_zip_print("Zip - Recover cd\n"); + + mz_zip_get_cd_mem_stream(handle, &cd_mem_stream); + + /* Determine if we are on a split disk or not */ + mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, 0); + if (mz_stream_tell(zip->stream) < 0) + { + mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1); + mz_stream_seek(zip->stream, 0, MZ_SEEK_SET); + } + else + disk_number_with_cd = 1; + + if (mz_stream_is_open(cd_mem_stream) != MZ_OK) + err = mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE); + + mz_stream_mem_create(&local_file_info_stream); + mz_stream_mem_open(local_file_info_stream, NULL, MZ_OPEN_MODE_CREATE); + + while (err == MZ_OK) + { + memset(&local_file_info, 0, sizeof(local_file_info)); + + /* Get current offset and disk number for central dir record */ + disk_offset = mz_stream_tell(zip->stream); + mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number); + + /* Read local headers */ + err = mz_zip_entry_read_header(zip->stream, 1, &local_file_info, local_file_info_stream); + + local_file_info.disk_offset = disk_offset; + if (disk_number < 0) + disk_number = 0; + local_file_info.disk_number = (uint32_t)disk_number; + + if (err == MZ_OK) + { + if (local_file_info.compressed_size > 0) + { + err = mz_stream_seek(zip->stream, local_file_info.compressed_size, MZ_SEEK_CUR); + } + else if (local_file_info.uncompressed_size > 0) + { + err = mz_stream_find(zip->stream, (const void *)descriptor_magic, sizeof(descriptor_magic), + INT64_MAX, &descriptor_pos); + } + } + + /* Read descriptor if it exists so we can get to the next local header */ + if ((err == MZ_OK) && (local_file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)) + { + if (mz_zip_extrafield_contains(local_file_info.extrafield, + local_file_info.extrafield_size, MZ_ZIP_EXTENSION_ZIP64, NULL) == MZ_OK) + zip64 = 1; + + err = mz_zip_entry_read_descriptor(zip->stream, zip64, &crc32, + &compressed_size, &uncompressed_size); + + if (local_file_info.crc == 0) + local_file_info.crc = crc32; + if (local_file_info.compressed_size == 0) + local_file_info.compressed_size = compressed_size; + if (local_file_info.uncompressed_size == 0) + local_file_info.uncompressed_size = uncompressed_size; + } + + /* Rewrite central dir with local headers and offsets */ + if (err == MZ_OK) + err = mz_zip_entry_write_header(cd_mem_stream, 0, &local_file_info); + + if (err == MZ_OK) + number_entry += 1; + } + + mz_stream_mem_delete(&local_file_info_stream); + + mz_zip_print("Zip - Recover cd complete (cddisk %"PRId32" entries %"PRId64")\n", + disk_number_with_cd, number_entry); + + if (number_entry == 0) + return err; + + /* Set new upper seek boundary for central dir mem stream */ + disk_offset = mz_stream_tell(cd_mem_stream); + mz_stream_mem_set_buffer_limit(cd_mem_stream, (int32_t)disk_offset); + + /* Set new central directory info */ + mz_zip_set_cd_stream(handle, 0, cd_mem_stream); + mz_zip_set_number_entry(handle, number_entry); + mz_zip_set_disk_number_with_cd(handle, disk_number_with_cd); + + return MZ_OK; +} + +void *mz_zip_create(void **handle) +{ + mz_zip *zip = NULL; + + zip = (mz_zip *)MZ_ALLOC(sizeof(mz_zip)); + if (zip != NULL) + memset(zip, 0, sizeof(mz_zip)); + if (handle != NULL) + *handle = zip; + + return zip; +} + +void mz_zip_delete(void **handle) +{ + mz_zip *zip = NULL; + if (handle == NULL) + return; + zip = (mz_zip *)*handle; + if (zip != NULL) + { + MZ_FREE(zip); + } + *handle = NULL; +} + +int32_t mz_zip_open(void *handle, void *stream, int32_t mode) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + + + if (zip == NULL) + return MZ_PARAM_ERROR; + + mz_zip_print("Zip - Open\n"); + + zip->stream = stream; + + mz_stream_mem_create(&zip->cd_mem_stream); + + if (mode & MZ_OPEN_MODE_WRITE) + { + mz_stream_mem_open(zip->cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE); + zip->cd_stream = zip->cd_mem_stream; + } + else + { + zip->cd_stream = stream; + } + + if ((mode & MZ_OPEN_MODE_READ) || (mode & MZ_OPEN_MODE_APPEND)) + { + if ((mode & MZ_OPEN_MODE_CREATE) == 0) + { + err = mz_zip_read_cd(zip); + if (err != MZ_OK) + { + mz_zip_print("Zip - Error detected reading cd (%"PRId32")", err); + if (zip->recover && mz_zip_recover_cd(zip) == MZ_OK) + err = MZ_OK; + } + } + + if ((err == MZ_OK) && (mode & MZ_OPEN_MODE_APPEND)) + { + if (zip->cd_size > 0) + { + /* Store central directory in memory */ + err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET); + if (err == MZ_OK) + err = mz_stream_copy(zip->cd_mem_stream, zip->stream, (int32_t)zip->cd_size); + if (err == MZ_OK) + err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET); + } + else + { + /* If no central directory, append new zip to end of file */ + err = mz_stream_seek(zip->stream, 0, MZ_SEEK_END); + } + + if (zip->disk_number_with_cd > 0) + { + /* Move to last disk to begin appending */ + mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, zip->disk_number_with_cd - 1); + } + } + else + { + zip->cd_start_pos = zip->cd_offset; + } + } + + if (err != MZ_OK) + { + mz_zip_close(zip); + return err; + } + + /* Memory streams used to store variable length file info data */ + mz_stream_mem_create(&zip->file_info_stream); + mz_stream_mem_open(zip->file_info_stream, NULL, MZ_OPEN_MODE_CREATE); + + mz_stream_mem_create(&zip->local_file_info_stream); + mz_stream_mem_open(zip->local_file_info_stream, NULL, MZ_OPEN_MODE_CREATE); + + zip->open_mode = mode; + + return err; +} + +int32_t mz_zip_close(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + mz_zip_print("Zip - Close\n"); + + if (mz_zip_entry_is_open(handle) == MZ_OK) + err = mz_zip_entry_close(handle); + + if ((err == MZ_OK) && (zip->open_mode & MZ_OPEN_MODE_WRITE)) + err = mz_zip_write_cd(handle); + + if (zip->cd_mem_stream != NULL) + { + mz_stream_close(zip->cd_mem_stream); + mz_stream_delete(&zip->cd_mem_stream); + } + + if (zip->file_info_stream != NULL) + { + mz_stream_mem_close(zip->file_info_stream); + mz_stream_mem_delete(&zip->file_info_stream); + } + if (zip->local_file_info_stream != NULL) + { + mz_stream_mem_close(zip->local_file_info_stream); + mz_stream_mem_delete(&zip->local_file_info_stream); + } + + if (zip->comment) + { + MZ_FREE(zip->comment); + zip->comment = NULL; + } + + zip->stream = NULL; + zip->cd_stream = NULL; + + return err; +} + +int32_t mz_zip_get_comment(void *handle, const char **comment) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || comment == NULL) + return MZ_PARAM_ERROR; + if (zip->comment == NULL) + return MZ_EXIST_ERROR; + *comment = zip->comment; + return MZ_OK; +} + +int32_t mz_zip_set_comment(void *handle, const char *comment) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t comment_size = 0; + if (zip == NULL || comment == NULL) + return MZ_PARAM_ERROR; + if (zip->comment != NULL) + MZ_FREE(zip->comment); + comment_size = (int32_t)strlen(comment); + if (comment_size > UINT16_MAX) + return MZ_PARAM_ERROR; + zip->comment = (char *)MZ_ALLOC(comment_size+1); + if (zip->comment == NULL) + return MZ_MEM_ERROR; + memset(zip->comment, 0, comment_size+1); + strncpy(zip->comment, comment, comment_size); + return MZ_OK; +} + +int32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || version_madeby == NULL) + return MZ_PARAM_ERROR; + *version_madeby = zip->version_madeby; + return MZ_OK; +} + +int32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL) + return MZ_PARAM_ERROR; + zip->version_madeby = version_madeby; + return MZ_OK; +} + +int32_t mz_zip_set_recover(void *handle, uint8_t recover) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL) + return MZ_PARAM_ERROR; + zip->recover = recover; + return MZ_OK; +} + +int32_t mz_zip_get_stream(void *handle, void **stream) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || stream == NULL) + return MZ_PARAM_ERROR; + *stream = zip->stream; + if (*stream == NULL) + return MZ_EXIST_ERROR; + return MZ_OK; +} + +int32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || cd_stream == NULL) + return MZ_PARAM_ERROR; + zip->cd_stream = cd_stream; + zip->cd_start_pos = cd_start_pos; + return MZ_OK; +} + +int32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || cd_mem_stream == NULL) + return MZ_PARAM_ERROR; + *cd_mem_stream = zip->cd_mem_stream; + if (*cd_mem_stream == NULL) + return MZ_EXIST_ERROR; + return MZ_OK; +} + +static int32_t mz_zip_entry_close_int(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip->crypt_stream != NULL) + mz_stream_delete(&zip->crypt_stream); + zip->crypt_stream = NULL; + if (zip->compress_stream != NULL) + mz_stream_delete(&zip->compress_stream); + zip->compress_stream = NULL; + + zip->entry_opened = 0; + + return MZ_OK; +} + +static int32_t mz_zip_entry_open_int(void *handle, uint8_t raw, int16_t compress_level, const char *password) +{ + mz_zip *zip = (mz_zip *)handle; + int64_t max_total_in = 0; + int64_t header_size = 0; + int64_t footer_size = 0; + int32_t err = MZ_OK; + uint8_t use_crypt = 0; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + switch (zip->file_info.compression_method) + { + case MZ_COMPRESS_METHOD_STORE: + case MZ_COMPRESS_METHOD_DEFLATE: +#ifdef HAVE_BZIP2 + case MZ_COMPRESS_METHOD_BZIP2: +#endif +#ifdef HAVE_LZMA + case MZ_COMPRESS_METHOD_LZMA: +#endif + err = MZ_OK; + break; + default: + return MZ_SUPPORT_ERROR; + } + +#ifndef HAVE_WZAES + if (zip->file_info.aes_version) + return MZ_SUPPORT_ERROR; +#endif + + zip->entry_raw = raw; + + if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password != NULL)) + { + if (zip->open_mode & MZ_OPEN_MODE_WRITE) + { + /* Encrypt only when we are not trying to write raw and password is supplied. */ + if (!zip->entry_raw) + use_crypt = 1; + } + else if (zip->open_mode & MZ_OPEN_MODE_READ) + { + /* Decrypt only when password is supplied. Don't error when password */ + /* is not supplied as we may want to read the raw encrypted data. */ + use_crypt = 1; + } + } + + if ((err == MZ_OK) && (use_crypt)) + { +#ifdef HAVE_WZAES + if (zip->file_info.aes_version) + { + mz_stream_wzaes_create(&zip->crypt_stream); + mz_stream_wzaes_set_password(zip->crypt_stream, password); + mz_stream_wzaes_set_encryption_mode(zip->crypt_stream, zip->file_info.aes_encryption_mode); + } + else +#endif + { +#ifdef HAVE_PKCRYPT + uint8_t verify1 = 0; + uint8_t verify2 = 0; + + /* Info-ZIP modification to ZipCrypto format: */ + /* If bit 3 of the general purpose bit flag is set, it uses high byte of 16-bit File Time. */ + + if (zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) + { + uint32_t dos_date = 0; + + dos_date = mz_zip_time_t_to_dos_date(zip->file_info.modified_date); + + verify1 = (uint8_t)((dos_date >> 16) & 0xff); + verify2 = (uint8_t)((dos_date >> 8) & 0xff); + } + else + { + verify1 = (uint8_t)((zip->file_info.crc >> 16) & 0xff); + verify2 = (uint8_t)((zip->file_info.crc >> 24) & 0xff); + } + + mz_stream_pkcrypt_create(&zip->crypt_stream); + mz_stream_pkcrypt_set_password(zip->crypt_stream, password); + mz_stream_pkcrypt_set_verify(zip->crypt_stream, verify1, verify2); +#endif + } + } + + if (err == MZ_OK) + { + if (zip->crypt_stream == NULL) + mz_stream_raw_create(&zip->crypt_stream); + + mz_stream_set_base(zip->crypt_stream, zip->stream); + + err = mz_stream_open(zip->crypt_stream, NULL, zip->open_mode); + } + + if (err == MZ_OK) + { + if (zip->entry_raw || zip->file_info.compression_method == MZ_COMPRESS_METHOD_STORE) + mz_stream_raw_create(&zip->compress_stream); +#if defined(HAVE_ZLIB) || defined(HAVE_LIBCOMP) + else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE) + mz_stream_zlib_create(&zip->compress_stream); +#endif +#ifdef HAVE_BZIP2 + else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_BZIP2) + mz_stream_bzip_create(&zip->compress_stream); +#endif +#ifdef HAVE_LZMA + else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA) + mz_stream_lzma_create(&zip->compress_stream); +#endif + else + err = MZ_PARAM_ERROR; + } + + if (err == MZ_OK) + { + if (zip->open_mode & MZ_OPEN_MODE_WRITE) + { + mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_LEVEL, compress_level); + } + else + { +#ifndef HAVE_LIBCOMP + if (zip->entry_raw || zip->file_info.compression_method == MZ_COMPRESS_METHOD_STORE || zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) +#endif + { + max_total_in = zip->file_info.compressed_size; + mz_stream_set_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, max_total_in); + + if (mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_HEADER_SIZE, &header_size) == MZ_OK) + max_total_in -= header_size; + if (mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_FOOTER_SIZE, &footer_size) == MZ_OK) + max_total_in -= footer_size; + + mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, max_total_in); + } + if ((zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA) && (zip->file_info.flag & MZ_ZIP_FLAG_LZMA_EOS_MARKER) == 0) + { + mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, zip->file_info.compressed_size); + mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_OUT_MAX, zip->file_info.uncompressed_size); + } + } + + mz_stream_set_base(zip->compress_stream, zip->crypt_stream); + + err = mz_stream_open(zip->compress_stream, NULL, zip->open_mode); + } + + if (err == MZ_OK) + { + zip->entry_opened = 1; + zip->entry_crc32 = 0; + } + else + { + mz_zip_entry_close_int(handle); + } + + return err; +} + +int32_t mz_zip_entry_is_open(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL) + return MZ_PARAM_ERROR; + if (zip->entry_opened == 0) + return MZ_EXIST_ERROR; + return MZ_OK; +} + +static int32_t mz_zip_seek_to_local_header(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + + + if (zip->file_info.disk_number == zip->disk_number_with_cd) + mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1); + else + mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, zip->file_info.disk_number); + + mz_zip_print("Zip - Entry - Seek local (disk %"PRId32" offset %"PRId64")\n", + zip->file_info.disk_number, zip->file_info.disk_offset); + + /* Guard against seek overflows */ + if ((zip->disk_offset_shift > 0) && + (zip->file_info.disk_offset > (INT64_MAX - zip->disk_offset_shift))) + return MZ_FORMAT_ERROR; + + return mz_stream_seek(zip->stream, zip->file_info.disk_offset + zip->disk_offset_shift, MZ_SEEK_SET); +} + +int32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + int32_t err_shift = MZ_OK; + +#if defined(MZ_ZIP_NO_ENCRYPTION) + if (password != NULL) + return MZ_SUPPORT_ERROR; +#endif + if (zip == NULL) + return MZ_PARAM_ERROR; + if ((zip->open_mode & MZ_OPEN_MODE_READ) == 0) + return MZ_PARAM_ERROR; + if (zip->entry_scanned == 0) + return MZ_PARAM_ERROR; + + mz_zip_print("Zip - Entry - Read open (raw %"PRId32")\n", raw); + + err = mz_zip_seek_to_local_header(handle); + if (err == MZ_OK) + err = mz_zip_entry_read_header(zip->stream, 1, &zip->local_file_info, zip->local_file_info_stream); + + if (err == MZ_FORMAT_ERROR && zip->disk_offset_shift > 0) + { + /* Perhaps we didn't compensated correctly for incorrect cd offset */ + err_shift = mz_stream_seek(zip->stream, zip->file_info.disk_offset, MZ_SEEK_SET); + if (err_shift == MZ_OK) + err_shift = mz_zip_entry_read_header(zip->stream, 1, &zip->local_file_info, zip->local_file_info_stream); + if (err_shift == MZ_OK) + { + zip->disk_offset_shift = 0; + err = err_shift; + } + } + +#ifdef MZ_ZIP_NO_DECOMPRESSION + if (!raw && zip->file_info.compression_method != MZ_COMPRESS_METHOD_STORE) + err = MZ_SUPPORT_ERROR; +#endif + if (err == MZ_OK) + err = mz_zip_entry_open_int(handle, raw, 0, password); + + return err; +} + +int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int16_t compress_level, uint8_t raw, const char *password) +{ + mz_zip *zip = (mz_zip *)handle; + int64_t filename_pos = -1; + int64_t extrafield_pos = 0; + int64_t comment_pos = 0; + int64_t linkname_pos = 0; + int64_t disk_number = 0; + uint8_t is_dir = 0; + int32_t err = MZ_OK; + +#if defined(MZ_ZIP_NO_ENCRYPTION) + if (password != NULL) + return MZ_SUPPORT_ERROR; +#endif + if (zip == NULL || file_info == NULL || file_info->filename == NULL) + return MZ_PARAM_ERROR; + + if (mz_zip_entry_is_open(handle) == MZ_OK) + { + err = mz_zip_entry_close(handle); + if (err != MZ_OK) + return err; + } + + memcpy(&zip->file_info, file_info, sizeof(mz_zip_file)); + + mz_zip_print("Zip - Entry - Write open - %s (level %"PRId16" raw %"PRId8")\n", + zip->file_info.filename, compress_level, raw); + + mz_stream_seek(zip->file_info_stream, 0, MZ_SEEK_SET); + mz_stream_write(zip->file_info_stream, file_info, sizeof(mz_zip_file)); + + /* Copy filename, extrafield, and comment internally */ + filename_pos = mz_stream_tell(zip->file_info_stream); + if (file_info->filename != NULL) + mz_stream_write(zip->file_info_stream, file_info->filename, (int32_t)strlen(file_info->filename)); + mz_stream_write_uint8(zip->file_info_stream, 0); + + extrafield_pos = mz_stream_tell(zip->file_info_stream); + if (file_info->extrafield != NULL) + mz_stream_write(zip->file_info_stream, file_info->extrafield, file_info->extrafield_size); + mz_stream_write_uint8(zip->file_info_stream, 0); + + comment_pos = mz_stream_tell(zip->file_info_stream); + if (file_info->comment != NULL) + mz_stream_write(zip->file_info_stream, file_info->comment, file_info->comment_size); + mz_stream_write_uint8(zip->file_info_stream, 0); + + linkname_pos = mz_stream_tell(zip->file_info_stream); + if (file_info->linkname != NULL) + mz_stream_write(zip->file_info_stream, file_info->linkname, (int32_t)strlen(file_info->linkname)); + mz_stream_write_uint8(zip->file_info_stream, 0); + + mz_stream_mem_get_buffer_at(zip->file_info_stream, filename_pos, (const void **)&zip->file_info.filename); + mz_stream_mem_get_buffer_at(zip->file_info_stream, extrafield_pos, (const void **)&zip->file_info.extrafield); + mz_stream_mem_get_buffer_at(zip->file_info_stream, comment_pos, (const void **)&zip->file_info.comment); + mz_stream_mem_get_buffer_at(zip->file_info_stream, linkname_pos, (const void **)&zip->file_info.linkname); + + if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE) + { + if ((compress_level == 8) || (compress_level == 9)) + zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_MAX; + if (compress_level == 2) + zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_FAST; + if (compress_level == 1) + zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_SUPER_FAST; + } +#ifdef HAVE_LZMA + else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA) + zip->file_info.flag |= MZ_ZIP_FLAG_LZMA_EOS_MARKER; +#endif + + if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK) + is_dir = 1; + + if (!is_dir) + { + zip->file_info.flag |= MZ_ZIP_FLAG_DATA_DESCRIPTOR; + if (password != NULL) + zip->file_info.flag |= MZ_ZIP_FLAG_ENCRYPTED; + } + + mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number); + zip->file_info.disk_number = (uint32_t)disk_number; + + zip->file_info.disk_offset = mz_stream_tell(zip->stream); + zip->file_info.crc = 0; + zip->file_info.compressed_size = 0; + +#ifdef HAVE_WZAES + if (zip->file_info.aes_version && zip->file_info.aes_encryption_mode == 0) + zip->file_info.aes_encryption_mode = MZ_AES_ENCRYPTION_MODE_256; +#endif + + if ((compress_level == 0) || (is_dir)) + zip->file_info.compression_method = MZ_COMPRESS_METHOD_STORE; + +#ifdef MZ_ZIP_NO_COMPRESSION + if (zip->file_info.compression_method != MZ_COMPRESS_METHOD_STORE) + err = MZ_SUPPORT_ERROR; +#endif + if (err == MZ_OK) + err = mz_zip_entry_write_header(zip->stream, 1, &zip->file_info); + if (err == MZ_OK) + err = mz_zip_entry_open_int(handle, raw, compress_level, password); + + return err; +} + +int32_t mz_zip_entry_read(void *handle, void *buf, int32_t len) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t read = 0; + + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + if (UINT_MAX == UINT16_MAX && len > UINT16_MAX) /* zlib limitation */ + return MZ_PARAM_ERROR; + if (len == 0) + return MZ_PARAM_ERROR; + + if (zip->file_info.compressed_size == 0) + return 0; + + /* Read entire entry even if uncompressed_size = 0, otherwise */ + /* aes encryption validation will fail if compressed_size > 0 */ + read = mz_stream_read(zip->compress_stream, buf, len); + if (read > 0) + zip->entry_crc32 = mz_crypt_crc32_update(zip->entry_crc32, buf, read); + + mz_zip_print("Zip - Entry - Read - %"PRId32" (max %"PRId32")\n", read, len); + + return read; +} + +int32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t written = 0; + + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + written = mz_stream_write(zip->compress_stream, buf, len); + if (written > 0) + zip->entry_crc32 = mz_crypt_crc32_update(zip->entry_crc32, buf, written); + + mz_zip_print("Zip - Entry - Write - %"PRId32" (max %"PRId32")\n", written, len); + + return written; +} + +int32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size, + int64_t *uncompressed_size) +{ + mz_zip *zip = (mz_zip *)handle; + int64_t total_in = 0; + int32_t err = MZ_OK; + uint8_t zip64 = 0; + + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + + mz_stream_close(zip->compress_stream); + + mz_zip_print("Zip - Entry - Read Close\n"); + + if (crc32 != NULL) + *crc32 = zip->file_info.crc; + if (compressed_size != NULL) + *compressed_size = zip->file_info.compressed_size; + if (uncompressed_size != NULL) + *uncompressed_size = zip->file_info.uncompressed_size; + + mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN, &total_in); + + if ((zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) && + ((zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO) == 0) && + (crc32 != NULL || compressed_size != NULL || uncompressed_size != NULL)) + { + /* Check to see if data descriptor is zip64 bit format or not */ + if (mz_zip_extrafield_contains(zip->local_file_info.extrafield, + zip->local_file_info.extrafield_size, MZ_ZIP_EXTENSION_ZIP64, NULL) == MZ_OK) + zip64 = 1; + + err = mz_zip_seek_to_local_header(handle); + + /* Seek to end of compressed stream since we might have over-read during compression */ + if (err == MZ_OK) + err = mz_stream_seek(zip->stream, MZ_ZIP_SIZE_LD_ITEM + + (int64_t)zip->local_file_info.filename_size + + (int64_t)zip->local_file_info.extrafield_size + + total_in, MZ_SEEK_CUR); + + /* Read data descriptor */ + if (err == MZ_OK) + err = mz_zip_entry_read_descriptor(zip->stream, zip64, + crc32, compressed_size, uncompressed_size); + } + + /* If entire entry was not read verification will fail */ + if ((err == MZ_OK) && (total_in > 0) && (!zip->entry_raw)) + { +#ifdef HAVE_WZAES + /* AES zip version AE-1 will expect a valid crc as well */ + if (zip->file_info.aes_version <= 0x0001) +#endif + { + if (zip->entry_crc32 != zip->file_info.crc) + { + mz_zip_print("Zip - Entry - Crc failed (actual 0x%08"PRIx32" expected 0x%08"PRIx32")\n", + zip->entry_crc32, zip->file_info.crc); + + err = MZ_CRC_ERROR; + } + } + } + + mz_zip_entry_close_int(handle); + + return err; +} + +int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size, + int64_t uncompressed_size) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + uint8_t zip64 = 0; + + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + + mz_stream_close(zip->compress_stream); + + if (!zip->entry_raw) + crc32 = zip->entry_crc32; + + mz_zip_print("Zip - Entry - Write Close (crc 0x%08"PRIx32" cs %"PRId64" ucs %"PRId64" )\n", + crc32, compressed_size, uncompressed_size); + + /* If sizes are not set, then read them from the compression stream */ + if (compressed_size < 0) + mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size); + if (uncompressed_size < 0) + mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN, &uncompressed_size); + + if (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) + { + mz_stream_set_base(zip->crypt_stream, zip->stream); + err = mz_stream_close(zip->crypt_stream); + + mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size); + } + + if ((err == MZ_OK) && (zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)) + { + /* Determine if we need to write data descriptor in zip64 format, + if local extrafield was saved with zip64 extrafield */ + if (zip->file_info.zip64 == MZ_ZIP64_AUTO) + { + if (zip->file_info.uncompressed_size >= UINT32_MAX) + zip64 = 1; + if (zip->file_info.compressed_size >= UINT32_MAX) + zip64 = 1; + if (zip->file_info.disk_offset >= UINT32_MAX) + zip64 = 1; + else if (zip->file_info.uncompressed_size == 0) + zip64 = 1; + } + else if (zip->file_info.zip64 == MZ_ZIP64_FORCE) + { + zip64 = 1; + } + + if (zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO) + err = mz_zip_entry_write_descriptor(zip->stream, + zip64, 0, compressed_size, 0); + else + err = mz_zip_entry_write_descriptor(zip->stream, + zip64, crc32, compressed_size, uncompressed_size); + } + + /* Write file info to central directory */ + + mz_zip_print("Zip - Entry - Write cd (ucs %"PRId64" cs %"PRId64" crc 0x%08"PRIx32")\n", + uncompressed_size, compressed_size, crc32); + + zip->file_info.crc = crc32; + zip->file_info.compressed_size = compressed_size; + zip->file_info.uncompressed_size = uncompressed_size; + + if (err == MZ_OK) + err = mz_zip_entry_write_header(zip->cd_mem_stream, 0, &zip->file_info); + + zip->number_entry += 1; + + mz_zip_entry_close_int(handle); + + return err; +} + +int32_t mz_zip_entry_is_dir(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t filename_length = 0; + + if (zip == NULL) + return MZ_PARAM_ERROR; + if (zip->entry_scanned == 0) + return MZ_PARAM_ERROR; + if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK) + return MZ_OK; + + filename_length = (int32_t)strlen(zip->file_info.filename); + if (filename_length > 0) + { + if ((zip->file_info.filename[filename_length - 1] == '/') || + (zip->file_info.filename[filename_length - 1] == '\\')) + return MZ_OK; + } + return MZ_EXIST_ERROR; +} + +int32_t mz_zip_entry_is_symlink(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL) + return MZ_PARAM_ERROR; + if (zip->entry_scanned == 0) + return MZ_PARAM_ERROR; + if (mz_zip_attrib_is_symlink(zip->file_info.external_fa, zip->file_info.version_madeby) != MZ_OK) + return MZ_EXIST_ERROR; + if (zip->file_info.linkname == NULL || *zip->file_info.linkname == 0) + return MZ_EXIST_ERROR; + + return MZ_OK; +} + +int32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + if ((zip->open_mode & MZ_OPEN_MODE_WRITE) == 0) + { + if (!zip->entry_scanned) + return MZ_PARAM_ERROR; + } + + *file_info = &zip->file_info; + return MZ_OK; +} + +int32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + *local_file_info = &zip->local_file_info; + return MZ_OK; +} + +int32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + + zip->file_info.extrafield = extrafield; + zip->file_info.extrafield_size = extrafield_size; + return MZ_OK; +} + +int32_t mz_zip_entry_close(void *handle) +{ + return mz_zip_entry_close_raw(handle, UINT64_MAX, 0); +} + +int32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + + if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + + if (zip->open_mode & MZ_OPEN_MODE_WRITE) + err = mz_zip_entry_write_close(handle, crc32, UINT64_MAX, uncompressed_size); + else + err = mz_zip_entry_read_close(handle, NULL, NULL, NULL); + + return err; +} + +static int32_t mz_zip_goto_next_entry_int(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + zip->entry_scanned = 0; + + mz_stream_set_prop_int64(zip->cd_stream, MZ_STREAM_PROP_DISK_NUMBER, -1); + + err = mz_stream_seek(zip->cd_stream, zip->cd_current_pos, MZ_SEEK_SET); + if (err == MZ_OK) + err = mz_zip_entry_read_header(zip->cd_stream, 0, &zip->file_info, zip->file_info_stream); + if (err == MZ_OK) + zip->entry_scanned = 1; + return err; +} + +int32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL) + return MZ_PARAM_ERROR; + zip->number_entry = number_entry; + return MZ_OK; +} + +int32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || number_entry == NULL) + return MZ_PARAM_ERROR; + *number_entry = zip->number_entry; + return MZ_OK; +} + +int32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL) + return MZ_PARAM_ERROR; + zip->disk_number_with_cd = disk_number_with_cd; + return MZ_OK; +} + +int32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd) +{ + mz_zip *zip = (mz_zip *)handle; + if (zip == NULL || disk_number_with_cd == NULL) + return MZ_PARAM_ERROR; + *disk_number_with_cd = zip->disk_number_with_cd; + return MZ_OK; +} + +int64_t mz_zip_get_entry(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + return zip->cd_current_pos; +} + +int32_t mz_zip_goto_entry(void *handle, int64_t cd_pos) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + if (cd_pos < zip->cd_start_pos || cd_pos > zip->cd_start_pos + zip->cd_size) + return MZ_PARAM_ERROR; + + zip->cd_current_pos = cd_pos; + + return mz_zip_goto_next_entry_int(handle); +} + +int32_t mz_zip_goto_first_entry(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + zip->cd_current_pos = zip->cd_start_pos; + + return mz_zip_goto_next_entry_int(handle); +} + +int32_t mz_zip_goto_next_entry(void *handle) +{ + mz_zip *zip = (mz_zip *)handle; + + if (zip == NULL) + return MZ_PARAM_ERROR; + + zip->cd_current_pos += (int64_t)MZ_ZIP_SIZE_CD_ITEM + zip->file_info.filename_size + + zip->file_info.extrafield_size + zip->file_info.comment_size; + + return mz_zip_goto_next_entry_int(handle); +} + +int32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + int32_t result = 0; + + if (zip == NULL || filename == NULL) + return MZ_PARAM_ERROR; + + /* If we are already on the current entry, no need to search */ + if ((zip->entry_scanned) && (zip->file_info.filename != NULL)) + { + result = mz_zip_path_compare(zip->file_info.filename, filename, ignore_case); + if (result == 0) + return MZ_OK; + } + + /* Search all entries starting at the first */ + err = mz_zip_goto_first_entry(handle); + while (err == MZ_OK) + { + result = mz_zip_path_compare(zip->file_info.filename, filename, ignore_case); + if (result == 0) + return MZ_OK; + + err = mz_zip_goto_next_entry(handle); + } + + return err; +} + +int32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + int32_t result = 0; + + /* Search first entry looking for match */ + err = mz_zip_goto_first_entry(handle); + if (err != MZ_OK) + return err; + + result = cb(handle, userdata, &zip->file_info); + if (result == 0) + return MZ_OK; + + return mz_zip_locate_next_entry(handle, userdata, cb); +} + +int32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb) +{ + mz_zip *zip = (mz_zip *)handle; + int32_t err = MZ_OK; + int32_t result = 0; + + /* Search next entries looking for match */ + err = mz_zip_goto_next_entry(handle); + while (err == MZ_OK) + { + result = cb(handle, userdata, &zip->file_info); + if (result == 0) + return MZ_OK; + + err = mz_zip_goto_next_entry(handle); + } + + return err; +} + +/***************************************************************************/ + +int32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby) +{ + uint32_t posix_attrib = 0; + uint8_t system = MZ_HOST_SYSTEM(version_madeby); + int32_t err = MZ_OK; + + err = mz_zip_attrib_convert(system, attrib, MZ_HOST_SYSTEM_UNIX, &posix_attrib); + if (err == MZ_OK) + { + if ((posix_attrib & 0170000) == 0040000) /* S_ISDIR */ + return MZ_OK; + } + + return MZ_EXIST_ERROR; +} + +int32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby) +{ + uint32_t posix_attrib = 0; + uint8_t system = MZ_HOST_SYSTEM(version_madeby); + int32_t err = MZ_OK; + + err = mz_zip_attrib_convert(system, attrib, MZ_HOST_SYSTEM_UNIX, &posix_attrib); + if (err == MZ_OK) + { + if ((posix_attrib & 0170000) == 0120000) /* S_ISLNK */ + return MZ_OK; + } + + return MZ_EXIST_ERROR; +} + +int32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys, uint32_t *target_attrib) +{ + if (target_attrib == NULL) + return MZ_PARAM_ERROR; + + *target_attrib = 0; + + if ((src_sys == MZ_HOST_SYSTEM_MSDOS) || (src_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) + { + if ((target_sys == MZ_HOST_SYSTEM_MSDOS) || (target_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) + { + *target_attrib = src_attrib; + return MZ_OK; + } + if ((target_sys == MZ_HOST_SYSTEM_UNIX) || (target_sys == MZ_HOST_SYSTEM_OSX_DARWIN)) + return mz_zip_attrib_win32_to_posix(src_attrib, target_attrib); + } + else if ((src_sys == MZ_HOST_SYSTEM_UNIX) || (src_sys == MZ_HOST_SYSTEM_OSX_DARWIN)) + { + if ((target_sys == MZ_HOST_SYSTEM_UNIX) || (target_sys == MZ_HOST_SYSTEM_OSX_DARWIN)) + { + /* If high bytes are set, it contains unix specific attributes */ + if ((src_attrib >> 16) != 0) + src_attrib >>= 16; + + *target_attrib = src_attrib; + return MZ_OK; + } + if ((target_sys == MZ_HOST_SYSTEM_MSDOS) || (target_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) + return mz_zip_attrib_posix_to_win32(src_attrib, target_attrib); + } + + return MZ_SUPPORT_ERROR; +} + +int32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib) +{ + if (win32_attrib == NULL) + return MZ_PARAM_ERROR; + + *win32_attrib = 0; + + /* S_IWUSR | S_IWGRP | S_IWOTH | S_IXUSR | S_IXGRP | S_IXOTH */ + if ((posix_attrib & 0000333) == 0 && (posix_attrib & 0000444) != 0) + *win32_attrib |= 0x01; /* FILE_ATTRIBUTE_READONLY */ + /* S_IFLNK */ + if ((posix_attrib & 0170000) == 0120000) + *win32_attrib |= 0x400; /* FILE_ATTRIBUTE_REPARSE_POINT */ + /* S_IFDIR */ + else if ((posix_attrib & 0170000) == 0040000) + *win32_attrib |= 0x10; /* FILE_ATTRIBUTE_DIRECTORY */ + /* S_IFREG */ + else + *win32_attrib |= 0x80; /* FILE_ATTRIBUTE_NORMAL */ + + return MZ_OK; +} + +int32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib) +{ + if (posix_attrib == NULL) + return MZ_PARAM_ERROR; + + *posix_attrib = 0000444; /* S_IRUSR | S_IRGRP | S_IROTH */ + /* FILE_ATTRIBUTE_READONLY */ + if ((win32_attrib & 0x01) == 0) + *posix_attrib |= 0000222; /* S_IWUSR | S_IWGRP | S_IWOTH */ + /* FILE_ATTRIBUTE_REPARSE_POINT */ + if ((win32_attrib & 0x400) == 0x400) + *posix_attrib |= 0120000; /* S_IFLNK */ + /* FILE_ATTRIBUTE_DIRECTORY */ + else if ((win32_attrib & 0x10) == 0x10) + *posix_attrib |= 0040111; /* S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH */ + else + *posix_attrib |= 0100000; /* S_IFREG */ + + return MZ_OK; +} + +/***************************************************************************/ + +int32_t mz_zip_extrafield_find(void *stream, uint16_t type, uint16_t *length) +{ + int32_t err = MZ_OK; + uint16_t field_type = 0; + uint16_t field_length = 0; + + do + { + err = mz_stream_read_uint16(stream, &field_type); + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, &field_length); + if (err != MZ_OK) + break; + + if (type == field_type) + { + if (length != NULL) + *length = field_length; + return MZ_OK; + } + + err = mz_stream_seek(stream, field_length, MZ_SEEK_CUR); + } + while (err == MZ_OK); + + return MZ_EXIST_ERROR; +} + +int32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size, + uint16_t type, uint16_t *length) +{ + void *file_extra_stream = NULL; + int32_t err = MZ_OK; + + if (extrafield == NULL || extrafield_size == 0) + return MZ_PARAM_ERROR; + + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_set_buffer(file_extra_stream, (void *)extrafield, extrafield_size); + + err = mz_zip_extrafield_find(file_extra_stream, type, length); + + mz_stream_mem_delete(&file_extra_stream); + + return err; +} + +int32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length) +{ + int32_t err = MZ_OK; + if (type == NULL || length == NULL) + return MZ_PARAM_ERROR; + err = mz_stream_read_uint16(stream, type); + if (err == MZ_OK) + err = mz_stream_read_uint16(stream, length); + return err; +} + +int32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length) +{ + int32_t err = MZ_OK; + err = mz_stream_write_uint16(stream, type); + if (err == MZ_OK) + err = mz_stream_write_uint16(stream, length); + return err; +} + +/***************************************************************************/ + +static int32_t mz_zip_invalid_date(const struct tm *ptm) +{ +#define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) + return (!datevalue_in_range(0, 127 + 80, ptm->tm_year) || /* 1980-based year, allow 80 extra */ + !datevalue_in_range(0, 11, ptm->tm_mon) || + !datevalue_in_range(1, 31, ptm->tm_mday) || + !datevalue_in_range(0, 23, ptm->tm_hour) || + !datevalue_in_range(0, 59, ptm->tm_min) || + !datevalue_in_range(0, 59, ptm->tm_sec)); +#undef datevalue_in_range +} + +static void mz_zip_dosdate_to_raw_tm(uint64_t dos_date, struct tm *ptm) +{ + uint64_t date = (uint64_t)(dos_date >> 16); + + ptm->tm_mday = (uint16_t)(date & 0x1f); + ptm->tm_mon = (uint16_t)(((date & 0x1E0) / 0x20) - 1); + ptm->tm_year = (uint16_t)(((date & 0x0FE00) / 0x0200) + 80); + ptm->tm_hour = (uint16_t)((dos_date & 0xF800) / 0x800); + ptm->tm_min = (uint16_t)((dos_date & 0x7E0) / 0x20); + ptm->tm_sec = (uint16_t)(2 * (dos_date & 0x1f)); + ptm->tm_isdst = -1; +} + +int32_t mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm) +{ + if (ptm == NULL) + return MZ_PARAM_ERROR; + + mz_zip_dosdate_to_raw_tm(dos_date, ptm); + + if (mz_zip_invalid_date(ptm)) + { + /* Invalid date stored, so don't return it */ + memset(ptm, 0, sizeof(struct tm)); + return MZ_FORMAT_ERROR; + } + return MZ_OK; +} + +time_t mz_zip_dosdate_to_time_t(uint64_t dos_date) +{ + struct tm ptm; + mz_zip_dosdate_to_raw_tm(dos_date, &ptm); + return mktime(&ptm); +} + +int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm) +{ + struct tm ltm; + if (ptm == NULL) + return MZ_PARAM_ERROR; + if (localtime_r(&unix_time, <m) == NULL) /* Returns a 1900-based year */ + { + /* Invalid date stored, so don't return it */ + memset(ptm, 0, sizeof(struct tm)); + return MZ_INTERNAL_ERROR; + } + memcpy(ptm, <m, sizeof(struct tm)); + return MZ_OK; +} + +uint32_t mz_zip_time_t_to_dos_date(time_t unix_time) +{ + struct tm ptm; + mz_zip_time_t_to_tm(unix_time, &ptm); + return mz_zip_tm_to_dosdate((const struct tm *)&ptm); +} + +uint32_t mz_zip_tm_to_dosdate(const struct tm *ptm) +{ + struct tm fixed_tm; + + /* Years supported: */ + + /* [00, 79] (assumed to be between 2000 and 2079) */ + /* [80, 207] (assumed to be between 1980 and 2107, typical output of old */ + /* software that does 'year-1900' to get a double digit year) */ + /* [1980, 2107] (due to format limitations, only years 1980-2107 can be stored.) */ + + memcpy(&fixed_tm, ptm, sizeof(struct tm)); + if (fixed_tm.tm_year >= 1980) /* range [1980, 2107] */ + fixed_tm.tm_year -= 1980; + else if (fixed_tm.tm_year >= 80) /* range [80, 207] */ + fixed_tm.tm_year -= 80; + else /* range [00, 79] */ + fixed_tm.tm_year += 20; + + if (mz_zip_invalid_date(&fixed_tm)) + return 0; + + return (((uint32_t)fixed_tm.tm_mday + (32 * ((uint32_t)fixed_tm.tm_mon + 1)) + (512 * (uint32_t)fixed_tm.tm_year)) << 16) | + (((uint32_t)fixed_tm.tm_sec / 2) + (32 * (uint32_t)fixed_tm.tm_min) + (2048 * (uint32_t)fixed_tm.tm_hour)); +} + +int32_t mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time) +{ + *unix_time = (time_t)((ntfs_time - 116444736000000000LL) / 10000000); + return MZ_OK; +} + +int32_t mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time) +{ + *ntfs_time = ((uint64_t)unix_time * 10000000) + 116444736000000000LL; + return MZ_OK; +} + +/***************************************************************************/ + +int32_t mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case) +{ + do + { + if ((*path1 == '\\' && *path2 == '/') || + (*path2 == '\\' && *path1 == '/')) + { + /* Ignore comparison of path slashes */ + } + else if (ignore_case) + { + if (tolower(*path1) != tolower(*path2)) + break; + } + else if (*path1 != *path2) + { + break; + } + + path1 += 1; + path2 += 1; + } + while (*path1 != 0 && *path2 != 0); + + if (ignore_case) + return (int32_t)(tolower(*path1) - tolower(*path2)); + + return (int32_t)(*path1 - *path2); +} + +/***************************************************************************/ diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c.meta new file mode 100644 index 0000000..7f62f51 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 942018742cdcc4941895d55633bd2497 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h new file mode 100755 index 0000000..cbb8160 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h @@ -0,0 +1,248 @@ +/* mz_zip.h -- Zip manipulation + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + Copyright (C) 2009-2010 Mathias Svensson + Modifications for Zip64 support + http://result42.com + Copyright (C) 1998-2010 Gilles Vollant + https://www.winimage.com/zLibDll/minizip.html + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_ZIP_H +#define MZ_ZIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +typedef struct mz_zip_file_s +{ + uint16_t version_madeby; /* version made by */ + uint16_t version_needed; /* version needed to extract */ + uint16_t flag; /* general purpose bit flag */ + uint16_t compression_method; /* compression method */ + time_t modified_date; /* last modified date in unix time */ + time_t accessed_date; /* last accessed date in unix time */ + time_t creation_date; /* creation date in unix time */ + uint32_t crc; /* crc-32 */ + int64_t compressed_size; /* compressed size */ + int64_t uncompressed_size; /* uncompressed size */ + uint16_t filename_size; /* filename length */ + uint16_t extrafield_size; /* extra field length */ + uint16_t comment_size; /* file comment length */ + uint32_t disk_number; /* disk number start */ + int64_t disk_offset; /* relative offset of local header */ + uint16_t internal_fa; /* internal file attributes */ + uint32_t external_fa; /* external file attributes */ + + const char *filename; /* filename utf8 null-terminated string */ + const uint8_t *extrafield; /* extrafield data */ + const char *comment; /* comment utf8 null-terminated string */ + const char *linkname; /* sym-link filename utf8 null-terminated string */ + + uint16_t zip64; /* zip64 extension mode */ + uint16_t aes_version; /* winzip aes extension if not 0 */ + uint8_t aes_encryption_mode; /* winzip aes encryption mode */ + +} mz_zip_file, mz_zip_entry; + +/***************************************************************************/ + +typedef int32_t (*mz_zip_locate_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info); + +/***************************************************************************/ + +void * mz_zip_create(void **handle); +/* Create zip instance for opening */ + +void mz_zip_delete(void **handle); +/* Delete zip object */ + +int32_t mz_zip_open(void *handle, void *stream, int32_t mode); +/* Create a zip file, no delete file in zip functionality */ + +int32_t mz_zip_close(void *handle); +/* Close the zip file */ + +int32_t mz_zip_get_comment(void *handle, const char **comment); +/* Get a pointer to the global comment */ + +int32_t mz_zip_set_comment(void *handle, const char *comment); +/* Set the global comment used for writing zip file */ + +int32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby); +/* Get the version made by */ + +int32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby); +/* Set the version made by used for writing zip file */ + +int32_t mz_zip_set_recover(void *handle, uint8_t recover); +/* Set the ability to recover the central dir by reading local file headers */ + +int32_t mz_zip_get_stream(void *handle, void **stream); +/* Get a pointer to the stream used to open */ + +int32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream); +/* Sets the stream to use for reading the central dir */ + +int32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream); +/* Get a pointer to the stream used to store the central dir in memory */ + +/***************************************************************************/ + +int32_t mz_zip_entry_is_open(void *handle); +/* Check to see if entry is open for read/write */ + +int32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password); +/* Open for reading the current file in the zip file */ + +int32_t mz_zip_entry_read(void *handle, void *buf, int32_t len); +/* Read bytes from the current file in the zip file */ + +int32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size, + int64_t *uncompressed_size); +/* Close the current file for reading and get data descriptor values */ + +int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, + int16_t compress_level, uint8_t raw, const char *password); +/* Open for writing the current file in the zip file */ + +int32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len); +/* Write bytes from the current file in the zip file */ + +int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size, + int64_t uncompressed_size); +/* Close the current file for writing and set data descriptor values */ + +int32_t mz_zip_entry_is_dir(void *handle); +/* Checks to see if the entry is a directory */ + +int32_t mz_zip_entry_is_symlink(void *handle); +/* Checks to see if the entry is a symbolic link */ + +int32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info); +/* Get info about the current file, only valid while current entry is open */ + +int32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info); +/* Get local info about the current file, only valid while current entry is being read */ + +int32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size); +/* Sets or updates the extra field for the entry to be used before writing cd */ + +int32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32); +/* Close the current file in the zip file where raw is compressed data */ + +int32_t mz_zip_entry_close(void *handle); +/* Close the current file in the zip file */ + +/***************************************************************************/ + +int32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry); +/* Sets the total number of entries */ + +int32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry); +/* Get the total number of entries */ + +int32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd); +/* Sets the disk number containing the central directory record */ + +int32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd); +/* Get the disk number containing the central directory record */ + +int64_t mz_zip_get_entry(void *handle); +/* Return offset of the current entry in the zip file */ + +int32_t mz_zip_goto_entry(void *handle, int64_t cd_pos); +/* Go to specified entry in the zip file */ + +int32_t mz_zip_goto_first_entry(void *handle); +/* Go to the first entry in the zip file */ + +int32_t mz_zip_goto_next_entry(void *handle); +/* Go to the next entry in the zip file or MZ_END_OF_LIST if reaching the end */ + +int32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case); +/* Locate the file with the specified name in the zip file or MZ_END_LIST if not found */ + +int32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb); +/* Locate the first matching entry based on a match callback */ + +int32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb); +/* LOcate the next matching entry based on a match callback */ + +/***************************************************************************/ + +int32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby); +/* Checks to see if the attribute is a directory based on platform */ + +int32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby); +/* Checks to see if the attribute is a symbolic link based on platform */ + +int32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys, + uint32_t *target_attrib); +/* Converts file attributes from one host system to another */ + +int32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib); +/* Converts posix file attributes to win32 file attributes */ + +int32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib); +/* Converts win32 file attributes to posix file attributes */ + +/***************************************************************************/ + +int32_t mz_zip_extrafield_find(void *stream, uint16_t type, uint16_t *length); +/* Seeks to extra field by its type and returns its length */ + +int32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size, + uint16_t type, uint16_t *length); +/* Gets whether an extrafield exists and its size */ + +int32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length); +/* Reads an extrafield header from a stream */ + +int32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length); +/* Writes an extrafield header to a stream */ + +/***************************************************************************/ + +int32_t mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm); +/* Convert dos date/time format to struct tm */ + +time_t mz_zip_dosdate_to_time_t(uint64_t dos_date); +/* Convert dos date/time format to time_t */ + +int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm); +/* Convert time_t to time struct */ + +uint32_t mz_zip_time_t_to_dos_date(time_t unix_time); +/* Convert time_t to dos date/time format */ + +uint32_t mz_zip_tm_to_dosdate(const struct tm *ptm); +/* Convert struct tm to dos date/time format */ + +int32_t mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time); +/* Convert ntfs time to unix time */ + +int32_t mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time); +/* Convert unix time to ntfs time */ + +/***************************************************************************/ + +int32_t mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case); +/* Compare two paths without regard to slashes */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* _ZIP_H */ diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h.meta new file mode 100644 index 0000000..c7ba395 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 95567da492cad463fa604585bea9a3db +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c new file mode 100755 index 0000000..85dd75b --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c @@ -0,0 +1,2100 @@ +/* mz_zip_rw.c -- Zip reader/writer + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include "mz.h" +#include "mz_crypt.h" +#include "mz_os.h" +#include "mz_strm.h" +#include "mz_strm_buf.h" +#include "mz_strm_mem.h" +#include "mz_strm_os.h" +#include "mz_strm_split.h" +#include "mz_strm_wzaes.h" +#include "mz_zip.h" + +#include "mz_zip_rw.h" + +/***************************************************************************/ + +#define MZ_DEFAULT_PROGRESS_INTERVAL (1000u) + +#define MZ_ZIP_CD_FILENAME ("__cdcd__") + +/***************************************************************************/ + +typedef struct mz_zip_reader_s { + void *zip_handle; + void *file_stream; + void *buffered_stream; + void *split_stream; + void *mem_stream; + void *hash; + uint16_t hash_algorithm; + uint16_t hash_digest_size; + mz_zip_file *file_info; + const char *pattern; + uint8_t pattern_ignore_case; + const char *password; + void *overwrite_userdata; + mz_zip_reader_overwrite_cb + overwrite_cb; + void *password_userdata; + mz_zip_reader_password_cb + password_cb; + void *progress_userdata; + mz_zip_reader_progress_cb + progress_cb; + uint32_t progress_cb_interval_ms; + void *entry_userdata; + mz_zip_reader_entry_cb + entry_cb; + uint8_t raw; + uint8_t buffer[UINT16_MAX]; + int32_t encoding; + uint8_t sign_required; + uint8_t cd_verified; + uint8_t cd_zipped; + uint8_t entry_verified; +} mz_zip_reader; + +/***************************************************************************/ + +int32_t mz_zip_reader_is_open(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + if (reader == NULL) + return MZ_PARAM_ERROR; + if (reader->zip_handle == NULL) + return MZ_PARAM_ERROR; + return MZ_OK; +} + +int32_t mz_zip_reader_open(void *handle, void *stream) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + reader->cd_verified = 0; + reader->cd_zipped = 0; + + mz_zip_create(&reader->zip_handle); + mz_zip_set_recover(reader->zip_handle, 1); + + err = mz_zip_open(reader->zip_handle, stream, MZ_OPEN_MODE_READ); + + if (err != MZ_OK) + { + mz_zip_reader_close(handle); + return err; + } + + mz_zip_reader_unzip_cd(reader); + return MZ_OK; +} + +int32_t mz_zip_reader_open_file(void *handle, const char *path) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + + mz_zip_reader_close(handle); + + mz_stream_os_create(&reader->file_stream); + mz_stream_buffered_create(&reader->buffered_stream); + mz_stream_split_create(&reader->split_stream); + + mz_stream_set_base(reader->buffered_stream, reader->file_stream); + mz_stream_set_base(reader->split_stream, reader->buffered_stream); + + err = mz_stream_open(reader->split_stream, path, MZ_OPEN_MODE_READ); + if (err == MZ_OK) + err = mz_zip_reader_open(handle, reader->split_stream); + return err; +} + +int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + void *file_stream = NULL; + int64_t file_size = 0; + int32_t err = 0; + + + mz_zip_reader_close(handle); + + mz_stream_os_create(&file_stream); + + err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ); + + if (err != MZ_OK) + { + mz_stream_os_delete(&file_stream); + mz_zip_reader_close(handle); + return err; + } + + mz_stream_os_seek(file_stream, 0, MZ_SEEK_END); + file_size = mz_stream_os_tell(file_stream); + mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET); + + if ((file_size <= 0) || (file_size > UINT32_MAX)) + { + /* Memory size is too large or too small */ + + mz_stream_os_close(file_stream); + mz_stream_os_delete(&file_stream); + mz_zip_reader_close(handle); + return MZ_MEM_ERROR; + } + + mz_stream_mem_create(&reader->mem_stream); + mz_stream_mem_set_grow_size(reader->mem_stream, (int32_t)file_size); + mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE); + + err = mz_stream_copy(reader->mem_stream, file_stream, (int32_t)file_size); + + mz_stream_os_close(file_stream); + mz_stream_os_delete(&file_stream); + + if (err == MZ_OK) + err = mz_zip_reader_open(handle, reader->mem_stream); + if (err != MZ_OK) + mz_zip_reader_close(handle); + + return err; +} + +int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + mz_zip_reader_close(handle); + + mz_stream_mem_create(&reader->mem_stream); + + if (copy) + { + mz_stream_mem_set_grow_size(reader->mem_stream, len); + mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE); + mz_stream_mem_write(reader->mem_stream, buf, len); + mz_stream_mem_seek(reader->mem_stream, 0, MZ_SEEK_SET); + } + else + { + mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_READ); + mz_stream_mem_set_buffer(reader->mem_stream, buf, len); + } + + if (err == MZ_OK) + err = mz_zip_reader_open(handle, reader->mem_stream); + + return err; +} + +int32_t mz_zip_reader_close(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + if (reader->zip_handle != NULL) + { + err = mz_zip_close(reader->zip_handle); + mz_zip_delete(&reader->zip_handle); + } + + if (reader->split_stream != NULL) + { + mz_stream_split_close(reader->split_stream); + mz_stream_split_delete(&reader->split_stream); + } + + if (reader->buffered_stream != NULL) + mz_stream_buffered_delete(&reader->buffered_stream); + + if (reader->file_stream != NULL) + mz_stream_os_delete(&reader->file_stream); + + if (reader->mem_stream != NULL) + { + mz_stream_mem_close(reader->mem_stream); + mz_stream_mem_delete(&reader->mem_stream); + } + + return err; +} + +/***************************************************************************/ + +int32_t mz_zip_reader_unzip_cd(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + mz_zip_file *cd_info = NULL; + void *cd_mem_stream = NULL; + void *new_cd_stream = NULL; + void *file_extra_stream = NULL; + uint64_t number_entry = 0; + int32_t err = MZ_OK; + + + err = mz_zip_reader_goto_first_entry(handle); + if (err != MZ_OK) + return err; + err = mz_zip_reader_entry_get_info(handle, &cd_info); + if (err != MZ_OK) + return err; + + if (strcmp(cd_info->filename, MZ_ZIP_CD_FILENAME) != 0) + return mz_zip_reader_goto_first_entry(handle); + + err = mz_zip_reader_entry_open(handle); + if (err != MZ_OK) + return err; + + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_set_buffer(file_extra_stream, (void *)cd_info->extrafield, cd_info->extrafield_size); + + err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, NULL); + if (err == MZ_OK) + err = mz_stream_read_uint64(file_extra_stream, &number_entry); + + mz_stream_mem_delete(&file_extra_stream); + + if (err != MZ_OK) + return err; + + mz_zip_get_cd_mem_stream(reader->zip_handle, &cd_mem_stream); + if (mz_stream_mem_is_open(cd_mem_stream) != MZ_OK) + mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE); + + err = mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET); + if (err == MZ_OK) + err = mz_stream_copy_stream(cd_mem_stream, NULL, handle, mz_zip_reader_entry_read, + (int32_t)cd_info->uncompressed_size); + + if (err == MZ_OK) + { + reader->cd_zipped = 1; + + mz_zip_set_cd_stream(reader->zip_handle, 0, cd_mem_stream); + mz_zip_set_number_entry(reader->zip_handle, number_entry); + + err = mz_zip_reader_goto_first_entry(handle); + } + + reader->cd_verified = reader->entry_verified; + + mz_stream_mem_delete(&new_cd_stream); + return err; +} + +/***************************************************************************/ + +static int32_t mz_zip_reader_locate_entry_cb(void *handle, void *userdata, mz_zip_file *file_info) +{ + mz_zip_reader *reader = (mz_zip_reader *)userdata; + int32_t result = 0; + MZ_UNUSED(handle); + result = mz_path_compare_wc(file_info->filename, reader->pattern, reader->pattern_ignore_case); + return result; +} + +int32_t mz_zip_reader_goto_first_entry(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + if (mz_zip_reader_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + + if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK) + mz_zip_reader_entry_close(handle); + + if (reader->pattern == NULL) + err = mz_zip_goto_first_entry(reader->zip_handle); + else + err = mz_zip_locate_first_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb); + + reader->file_info = NULL; + if (err == MZ_OK) + err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info); + + return err; +} + +int32_t mz_zip_reader_goto_next_entry(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + if (mz_zip_reader_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + + if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK) + mz_zip_reader_entry_close(handle); + + if (reader->pattern == NULL) + err = mz_zip_goto_next_entry(reader->zip_handle); + else + err = mz_zip_locate_next_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb); + + reader->file_info = NULL; + if (err == MZ_OK) + err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info); + + return err; +} + +int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + + if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK) + mz_zip_reader_entry_close(handle); + + err = mz_zip_locate_entry(reader->zip_handle, filename, ignore_case); + + reader->file_info = NULL; + if (err == MZ_OK) + err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info); + + return err; +} + +/***************************************************************************/ + +int32_t mz_zip_reader_entry_open(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + const char *password = NULL; + char password_buf[120]; + + + reader->entry_verified = 0; + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (reader->file_info == NULL) + return MZ_PARAM_ERROR; + + /* If the entry isn't open for reading, open it */ + if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK) + return MZ_OK; + + password = reader->password; + + /* Check if we need a password and ask for it if we need to */ + if ((reader->file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) && + (reader->password_cb != NULL)) + { + reader->password_cb(handle, reader->password_userdata, reader->file_info, + password_buf, sizeof(password_buf)); + + password = password_buf; + } + + err = mz_zip_entry_read_open(reader->zip_handle, reader->raw, password); +#ifndef MZ_ZIP_NO_ENCRYPTION + if (err != MZ_OK) + return err; + + if (mz_zip_reader_entry_get_first_hash(handle, &reader->hash_algorithm, &reader->hash_digest_size) == MZ_OK) + { + mz_crypt_sha_create(&reader->hash); + if (reader->hash_algorithm == MZ_HASH_SHA1) + mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA1); + else if (reader->hash_algorithm == MZ_HASH_SHA256) + mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA256); + else + err = MZ_SUPPORT_ERROR; + + if (err == MZ_OK) + mz_crypt_sha_begin(reader->hash); +#ifndef MZ_ZIP_NO_SIGNING + if (err == MZ_OK) + { + if (mz_zip_reader_entry_has_sign(handle) == MZ_OK) + { + err = mz_zip_reader_entry_sign_verify(handle); + if (err == MZ_OK) + reader->entry_verified = 1; + } + else if (reader->sign_required && !reader->cd_verified) + err = MZ_SIGN_ERROR; + } +#endif + } + else if (reader->sign_required && !reader->cd_verified) + err = MZ_SIGN_ERROR; +#endif + + return err; +} + +int32_t mz_zip_reader_entry_close(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + int32_t err_close = MZ_OK; +#ifndef MZ_ZIP_NO_ENCRYPTION + int32_t err_hash = MZ_OK; + uint8_t computed_hash[MZ_HASH_MAX_SIZE]; + uint8_t expected_hash[MZ_HASH_MAX_SIZE]; + + if (reader->hash != NULL) + { + mz_crypt_sha_end(reader->hash, computed_hash, sizeof(computed_hash)); + mz_crypt_sha_delete(&reader->hash); + + err_hash = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, expected_hash, + reader->hash_digest_size); + + if (err_hash == MZ_OK) + { + /* Verify expected hash against computed hash */ + if (memcmp(computed_hash, expected_hash, reader->hash_digest_size) != 0) + err = MZ_CRC_ERROR; + } + } +#endif + + err_close = mz_zip_entry_close(reader->zip_handle); + if (err == MZ_OK) + err = err_close; + return err; +} + +int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t read = 0; + read = mz_zip_entry_read(reader->zip_handle, buf, len); +#ifndef MZ_ZIP_NO_ENCRYPTION + if ((read > 0) && (reader->hash != NULL)) + mz_crypt_sha_update(reader->hash, buf, read); +#endif + return read; +} + +int32_t mz_zip_reader_entry_has_sign(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + + if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK) + return MZ_PARAM_ERROR; + + return mz_zip_extrafield_contains(reader->file_info->extrafield, + reader->file_info->extrafield_size, MZ_ZIP_EXTENSION_SIGN, NULL); +} + +#if !defined(MZ_ZIP_NO_ENCRYPTION) && !defined(MZ_ZIP_NO_SIGNING) +int32_t mz_zip_reader_entry_sign_verify(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + void *file_extra_stream = NULL; + int32_t err = MZ_OK; + uint8_t *signature = NULL; + uint16_t signature_size = 0; + uint8_t hash[MZ_HASH_MAX_SIZE]; + + if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK) + return MZ_PARAM_ERROR; + + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield, + reader->file_info->extrafield_size); + + err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_SIGN, &signature_size); + if ((err == MZ_OK) && (signature_size > 0)) + { + signature = (uint8_t *)MZ_ALLOC(signature_size); + if (mz_stream_read(file_extra_stream, signature, signature_size) != signature_size) + err = MZ_READ_ERROR; + } + + mz_stream_mem_delete(&file_extra_stream); + + if (err == MZ_OK) + { + /* Get most secure hash to verify signature against */ + err = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, hash, reader->hash_digest_size); + } + + if (err == MZ_OK) + { + /* Verify the pkcs signature */ + err = mz_crypt_sign_verify(hash, reader->hash_digest_size, signature, signature_size); + } + + if (signature != NULL) + MZ_FREE(signature); + + return err; +} +#endif + +int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + void *file_extra_stream = NULL; + int32_t err = MZ_OK; + int32_t return_err = MZ_EXIST_ERROR; + uint16_t cur_algorithm = 0; + uint16_t cur_digest_size = 0; + + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield, + reader->file_info->extrafield_size); + + do + { + err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, NULL); + if (err != MZ_OK) + break; + + err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm); + if (err == MZ_OK) + err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size); + if ((err == MZ_OK) && (cur_algorithm == algorithm) && (cur_digest_size <= digest_size) && + (cur_digest_size <= MZ_HASH_MAX_SIZE)) + { + /* Read hash digest */ + if (mz_stream_read(file_extra_stream, digest, digest_size) == cur_digest_size) + return_err = MZ_OK; + break; + } + else + { + err = mz_stream_seek(file_extra_stream, cur_digest_size, MZ_SEEK_CUR); + } + } + while (err == MZ_OK); + + mz_stream_mem_delete(&file_extra_stream); + + return return_err; +} + +int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + void *file_extra_stream = NULL; + int32_t err = MZ_OK; + uint16_t cur_algorithm = 0; + uint16_t cur_digest_size = 0; + + if (reader == NULL || algorithm == NULL) + return MZ_PARAM_ERROR; + + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield, + reader->file_info->extrafield_size); + + err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, NULL); + if (err == MZ_OK) + err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm); + if (err == MZ_OK) + err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size); + + if (algorithm != NULL) + *algorithm = cur_algorithm; + if (digest_size != NULL) + *digest_size = cur_digest_size; + + mz_stream_mem_delete(&file_extra_stream); + + return err; +} + +int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + if (file_info == NULL || mz_zip_reader_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + *file_info = reader->file_info; + if (*file_info == NULL) + return MZ_EXIST_ERROR; + return err; +} + +int32_t mz_zip_reader_entry_is_dir(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + if (mz_zip_reader_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + return mz_zip_entry_is_dir(reader->zip_handle); +} + +int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + int32_t read = 0; + int32_t written = 0; + + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (reader->file_info == NULL) + return MZ_PARAM_ERROR; + if (write_cb == NULL) + return MZ_PARAM_ERROR; + + /* If the entry isn't open for reading, open it */ + if (mz_zip_entry_is_open(reader->zip_handle) != MZ_OK) + err = mz_zip_reader_entry_open(handle); + + if (err != MZ_OK) + return err; + + /* Unzip entry in zip file */ + read = mz_zip_reader_entry_read(handle, reader->buffer, sizeof(reader->buffer)); + + if (read == 0) + { + /* If we are done close the entry */ + err = mz_zip_reader_entry_close(handle); + if (err != MZ_OK) + return err; + + return MZ_END_OF_STREAM; + } + + if (read > 0) + { + /* Write the data to the specified stream */ + written = write_cb(stream, reader->buffer, read); + if (written != read) + return MZ_WRITE_ERROR; + } + + return read; +} + +int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + uint64_t current_time = 0; + uint64_t update_time = 0; + int64_t current_pos = 0; + int64_t update_pos = 0; + int32_t err = MZ_OK; + int32_t written = 0; + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (reader->file_info == NULL) + return MZ_PARAM_ERROR; + + /* Update the progress at the beginning */ + if (reader->progress_cb != NULL) + reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos); + + /* Write data to stream until done */ + while (err == MZ_OK) + { + written = mz_zip_reader_entry_save_process(handle, stream, write_cb); + if (written == MZ_END_OF_STREAM) + break; + if (written > 0) + current_pos += written; + if (written < 0) + err = written; + + /* Update progress if enough time have passed */ + current_time = mz_os_ms_time(); + if ((current_time - update_time) > reader->progress_cb_interval_ms) + { + if (reader->progress_cb != NULL) + reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos); + + update_pos = current_pos; + update_time = current_time; + } + } + + /* Update the progress at the end */ + if (reader->progress_cb != NULL && update_pos != current_pos) + reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos); + + return err; +} + +int32_t mz_zip_reader_entry_save_file(void *handle, const char *path) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + void *stream = NULL; + uint32_t target_attrib = 0; + int32_t err_attrib = 0; + int32_t err = MZ_OK; + int32_t err_cb = MZ_OK; + char pathwfs[512]; + char directory[512]; + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (reader->file_info == NULL || path == NULL) + return MZ_PARAM_ERROR; + + /* Convert to forward slashes for unix which doesn't like backslashes */ + strncpy(pathwfs, path, sizeof(pathwfs) - 1); + pathwfs[sizeof(pathwfs) - 1] = 0; + mz_path_convert_slashes(pathwfs, MZ_PATH_SLASH_UNIX); + + if (reader->entry_cb != NULL) + reader->entry_cb(handle, reader->entry_userdata, reader->file_info, pathwfs); + + strncpy(directory, pathwfs, sizeof(directory) - 1); + directory[sizeof(directory) - 1] = 0; + mz_path_remove_filename(directory); + + /* If it is a directory entry then create a directory instead of writing file */ + if ((mz_zip_entry_is_dir(reader->zip_handle) == MZ_OK) && + (mz_zip_entry_is_symlink(reader->zip_handle) != MZ_OK)) + { + err = mz_dir_make(directory); + return err; + } + + /* Check if file exists and ask if we want to overwrite */ + if ((mz_os_file_exists(pathwfs) == MZ_OK) && (reader->overwrite_cb != NULL)) + { + err_cb = reader->overwrite_cb(handle, reader->overwrite_userdata, reader->file_info, pathwfs); + if (err_cb != MZ_OK) + return err; + /* We want to overwrite the file so we delete the existing one */ + mz_os_unlink(pathwfs); + } + + /* If symbolic link then properly construct destination path and link path */ + if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) + { + mz_path_remove_slash(pathwfs); + mz_path_remove_filename(directory); + } + + /* Create the output directory if it doesn't already exist */ + if (mz_os_is_dir(directory) != MZ_OK) + { + err = mz_dir_make(directory); + if (err != MZ_OK) + return err; + } + + /* If it is a symbolic link then create symbolic link instead of writing file */ + if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) + { + mz_os_make_symlink(pathwfs, reader->file_info->linkname); + /* Don't check return value because we aren't validating symbolic link target */ + return err; + } + + /* Create the file on disk so we can save to it */ + mz_stream_os_create(&stream); + err = mz_stream_os_open(stream, pathwfs, MZ_OPEN_MODE_CREATE); + + if (err == MZ_OK) + err = mz_zip_reader_entry_save(handle, stream, mz_stream_write); + + mz_stream_close(stream); + mz_stream_delete(&stream); + + if (err == MZ_OK) + { + /* Set the time of the file that has been created */ + mz_os_set_file_date(pathwfs, reader->file_info->modified_date, + reader->file_info->accessed_date, reader->file_info->creation_date); + } + + if (err == MZ_OK) + { + /* Set file attributes for the correct system */ + err_attrib = mz_zip_attrib_convert(MZ_HOST_SYSTEM(reader->file_info->version_madeby), + reader->file_info->external_fa, MZ_VERSION_MADEBY_HOST_SYSTEM, &target_attrib); + + if (err_attrib == MZ_OK) + mz_os_set_file_attribs(pathwfs, target_attrib); + } + + return err; +} + +int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + void *mem_stream = NULL; + int32_t err = MZ_OK; + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (reader->file_info == NULL) + return MZ_PARAM_ERROR; + if (reader->file_info->uncompressed_size > INT32_MAX) + return MZ_PARAM_ERROR; + if (len != (int32_t)reader->file_info->uncompressed_size) + return MZ_PARAM_ERROR; + + /* Create a memory stream backed by our buffer and save to it */ + mz_stream_mem_create(&mem_stream); + mz_stream_mem_set_buffer(mem_stream, buf, len); + + err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ); + if (err == MZ_OK) + err = mz_zip_reader_entry_save(handle, mem_stream, mz_stream_mem_write); + + mz_stream_mem_delete(&mem_stream); + return err; +} + +int32_t mz_zip_reader_entry_save_buffer_length(void *handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (reader->file_info == NULL) + return MZ_PARAM_ERROR; + if (reader->file_info->uncompressed_size > INT32_MAX) + return MZ_PARAM_ERROR; + + /* Get the maximum size required for the save buffer */ + return (int32_t)reader->file_info->uncompressed_size; +} + +/***************************************************************************/ + +int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + int32_t err = MZ_OK; + uint8_t *utf8_string = NULL; + char path[512]; + char utf8_name[256]; + char resolved_name[256]; + + err = mz_zip_reader_goto_first_entry(handle); + + if (err == MZ_END_OF_LIST) + return err; + + while (err == MZ_OK) + { + /* Construct output path */ + path[0] = 0; + + strncpy(utf8_name, reader->file_info->filename, sizeof(utf8_name) - 1); + utf8_name[sizeof(utf8_name) - 1] = 0; + + if ((reader->encoding > 0) && (reader->file_info->flag & MZ_ZIP_FLAG_UTF8) == 0) + { + utf8_string = mz_os_utf8_string_create(reader->file_info->filename, reader->encoding); + if (utf8_string) + { + strncpy(utf8_name, (char *)utf8_string, sizeof(utf8_name) - 1); + utf8_name[sizeof(utf8_name) - 1] = 0; + mz_os_utf8_string_delete(&utf8_string); + } + } + + err = mz_path_resolve(utf8_name, resolved_name, sizeof(resolved_name)); + if (err != MZ_OK) + break; + + if (destination_dir != NULL) + mz_path_combine(path, destination_dir, sizeof(path)); + + mz_path_combine(path, resolved_name, sizeof(path)); + + /* Save file to disk */ + err = mz_zip_reader_entry_save_file(handle, path); + + if (err == MZ_OK) + err = mz_zip_reader_goto_next_entry(handle); + } + + if (err == MZ_END_OF_LIST) + return MZ_OK; + + return err; +} + +/***************************************************************************/ + +void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->pattern = pattern; + reader->pattern_ignore_case = ignore_case; +} + +void mz_zip_reader_set_password(void *handle, const char *password) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->password = password; +} + +void mz_zip_reader_set_raw(void *handle, uint8_t raw) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->raw = raw; +} + +int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + if (raw == NULL) + return MZ_PARAM_ERROR; + *raw = reader->raw; + return MZ_OK; +} + +int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + if (zip_cd == NULL) + return MZ_PARAM_ERROR; + *zip_cd = reader->cd_zipped; + return MZ_OK; +} + +int32_t mz_zip_reader_get_comment(void *handle, const char **comment) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (comment == NULL) + return MZ_PARAM_ERROR; + return mz_zip_get_comment(reader->zip_handle, comment); +} + +void mz_zip_reader_set_encoding(void *handle, int32_t encoding) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->encoding = encoding; +} + +void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->sign_required = sign_required; +} + +void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->overwrite_cb = cb; + reader->overwrite_userdata = userdata; +} + +void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->password_cb = cb; + reader->password_userdata = userdata; +} + +void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->progress_cb = cb; + reader->progress_userdata = userdata; +} + +void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->progress_cb_interval_ms = milliseconds; +} + +void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + reader->entry_cb = cb; + reader->entry_userdata = userdata; +} + +int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle) +{ + mz_zip_reader *reader = (mz_zip_reader *)handle; + if (zip_handle == NULL) + return MZ_PARAM_ERROR; + *zip_handle = reader->zip_handle; + if (*zip_handle == NULL) + return MZ_EXIST_ERROR; + return MZ_OK; +} + +/***************************************************************************/ + +void *mz_zip_reader_create(void **handle) +{ + mz_zip_reader *reader = NULL; + + reader = (mz_zip_reader *)MZ_ALLOC(sizeof(mz_zip_reader)); + if (reader != NULL) + { + memset(reader, 0, sizeof(mz_zip_reader)); + reader->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL; + *handle = reader; + } + + return reader; +} + +void mz_zip_reader_delete(void **handle) +{ + mz_zip_reader *reader = NULL; + if (handle == NULL) + return; + reader = (mz_zip_reader *)*handle; + if (reader != NULL) + { + mz_zip_reader_close(reader); + MZ_FREE(reader); + } + *handle = NULL; +} + +/***************************************************************************/ + +typedef struct mz_zip_writer_s { + void *zip_handle; + void *file_stream; + void *buffered_stream; + void *split_stream; + void *sha256; + void *mem_stream; + void *file_extra_stream; + mz_zip_file file_info; + void *overwrite_userdata; + mz_zip_writer_overwrite_cb + overwrite_cb; + void *password_userdata; + mz_zip_writer_password_cb + password_cb; + void *progress_userdata; + mz_zip_writer_progress_cb + progress_cb; + uint32_t progress_cb_interval_ms; + void *entry_userdata; + mz_zip_writer_entry_cb + entry_cb; + const char *password; + const char *comment; + uint8_t *cert_data; + int32_t cert_data_size; + const char *cert_pwd; + uint16_t compress_method; + int16_t compress_level; + uint8_t follow_links; + uint8_t store_links; + uint8_t zip_cd; + uint8_t aes; + uint8_t raw; + uint8_t buffer[UINT16_MAX]; +} mz_zip_writer; + +/***************************************************************************/ + +int32_t mz_zip_writer_is_open(void *handle) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + if (writer == NULL) + return MZ_PARAM_ERROR; + if (writer->zip_handle == NULL) + return MZ_PARAM_ERROR; + return MZ_OK; +} + +static int32_t mz_zip_writer_open_int(void *handle, void *stream, int32_t mode) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t err = MZ_OK; + + mz_zip_create(&writer->zip_handle); + err = mz_zip_open(writer->zip_handle, stream, mode); + + if (err != MZ_OK) + { + mz_zip_writer_close(handle); + return err; + } + + return MZ_OK; +} + +int32_t mz_zip_writer_open(void *handle, void *stream) +{ + return mz_zip_writer_open_int(handle, stream, MZ_OPEN_MODE_WRITE); +} + +int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t mode = MZ_OPEN_MODE_READWRITE; + int32_t err = MZ_OK; + int32_t err_cb = 0; + char directory[320]; + + mz_zip_writer_close(handle); + + if (mz_os_file_exists(path) != MZ_OK) + { + /* If the file doesn't exist, we don't append file */ + mode |= MZ_OPEN_MODE_CREATE; + + /* Create destination directory if it doesn't already exist */ + if (strchr(path, '/') != NULL || strrchr(path, '\\') != NULL) + { + strncpy(directory, path, sizeof(directory)); + mz_path_remove_filename(directory); + if (mz_os_file_exists(directory) != MZ_OK) + mz_dir_make(directory); + } + } + else if (append) + { + mode |= MZ_OPEN_MODE_APPEND; + } + else + { + if (writer->overwrite_cb != NULL) + err_cb = writer->overwrite_cb(handle, writer->overwrite_userdata, path); + + if (err_cb == MZ_INTERNAL_ERROR) + return err; + + if (err_cb == MZ_OK) + mode |= MZ_OPEN_MODE_CREATE; + else + mode |= MZ_OPEN_MODE_APPEND; + } + + mz_stream_os_create(&writer->file_stream); + mz_stream_buffered_create(&writer->buffered_stream); + mz_stream_split_create(&writer->split_stream); + + mz_stream_set_base(writer->buffered_stream, writer->file_stream); + mz_stream_set_base(writer->split_stream, writer->buffered_stream); + + mz_stream_split_set_prop_int64(writer->split_stream, MZ_STREAM_PROP_DISK_SIZE, disk_size); + + err = mz_stream_open(writer->split_stream, path, mode); + if (err == MZ_OK) + err = mz_zip_writer_open_int(handle, writer->split_stream, mode); + + return err; +} + +int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + void *file_stream = NULL; + int64_t file_size = 0; + int32_t err = 0; + + + mz_zip_writer_close(handle); + + mz_stream_os_create(&file_stream); + + err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ); + + if (err != MZ_OK) + { + mz_stream_os_delete(&file_stream); + mz_zip_writer_close(handle); + return err; + } + + mz_stream_os_seek(file_stream, 0, MZ_SEEK_END); + file_size = mz_stream_os_tell(file_stream); + mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET); + + if ((file_size <= 0) || (file_size > UINT32_MAX)) + { + /* Memory size is too large or too small */ + + mz_stream_os_close(file_stream); + mz_stream_os_delete(&file_stream); + mz_zip_writer_close(handle); + return MZ_MEM_ERROR; + } + + mz_stream_mem_create(&writer->mem_stream); + mz_stream_mem_set_grow_size(writer->mem_stream, (int32_t)file_size); + mz_stream_mem_open(writer->mem_stream, NULL, MZ_OPEN_MODE_CREATE); + + err = mz_stream_copy(writer->mem_stream, file_stream, (int32_t)file_size); + + mz_stream_os_close(file_stream); + mz_stream_os_delete(&file_stream); + + if (err == MZ_OK) + err = mz_zip_writer_open(handle, writer->mem_stream); + if (err != MZ_OK) + mz_zip_writer_close(handle); + + return err; +} + +int32_t mz_zip_writer_close(void *handle) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t err = MZ_OK; + + + if (writer->zip_handle != NULL) + { + mz_zip_set_version_madeby(writer->zip_handle, MZ_VERSION_MADEBY); + if (writer->comment) + mz_zip_set_comment(writer->zip_handle, writer->comment); + if (writer->zip_cd) + mz_zip_writer_zip_cd(writer); + + err = mz_zip_close(writer->zip_handle); + mz_zip_delete(&writer->zip_handle); + } + + if (writer->split_stream != NULL) + { + mz_stream_split_close(writer->split_stream); + mz_stream_split_delete(&writer->split_stream); + } + + if (writer->buffered_stream != NULL) + mz_stream_buffered_delete(&writer->buffered_stream); + + if (writer->file_stream != NULL) + mz_stream_os_delete(&writer->file_stream); + + if (writer->mem_stream != NULL) + { + mz_stream_mem_close(writer->mem_stream); + mz_stream_mem_delete(&writer->mem_stream); + } + + return err; +} + +/***************************************************************************/ + +int32_t mz_zip_writer_zip_cd(void *handle) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + mz_zip_file cd_file; + uint64_t number_entry = 0; + int64_t cd_mem_length = 0; + int32_t err = MZ_OK; + int32_t extrafield_size = 0; + void *file_extra_stream = NULL; + void *cd_mem_stream = NULL; + + + memset(&cd_file, 0, sizeof(cd_file)); + + mz_zip_get_number_entry(writer->zip_handle, &number_entry); + mz_zip_get_cd_mem_stream(writer->zip_handle, &cd_mem_stream); + mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END); + cd_mem_length = (uint32_t)mz_stream_tell(cd_mem_stream); + mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET); + + cd_file.filename = MZ_ZIP_CD_FILENAME; + cd_file.modified_date = time(NULL); + cd_file.version_madeby = MZ_VERSION_MADEBY; + cd_file.compression_method = writer->compress_method; + cd_file.uncompressed_size = (int32_t)cd_mem_length; + cd_file.flag = MZ_ZIP_FLAG_UTF8; + + if (writer->password != NULL) + cd_file.flag |= MZ_ZIP_FLAG_ENCRYPTED; + + mz_stream_mem_create(&file_extra_stream); + mz_stream_mem_open(file_extra_stream, NULL, MZ_OPEN_MODE_CREATE); + + mz_zip_extrafield_write(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, 8); + + mz_stream_write_uint64(file_extra_stream, number_entry); + + mz_stream_mem_get_buffer(file_extra_stream, (const void **)&cd_file.extrafield); + mz_stream_mem_get_buffer_length(file_extra_stream, &extrafield_size); + cd_file.extrafield_size = (uint16_t)extrafield_size; + + err = mz_zip_writer_entry_open(handle, &cd_file); + if (err == MZ_OK) + { + mz_stream_copy_stream(handle, mz_zip_writer_entry_write, cd_mem_stream, + NULL, (int32_t)cd_mem_length); + + mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET); + mz_stream_mem_set_buffer_limit(cd_mem_stream, 0); + + err = mz_zip_writer_entry_close(writer); + } + + mz_stream_mem_delete(&file_extra_stream); + + return err; +} + +/***************************************************************************/ + +int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t err = MZ_OK; + const char *password = NULL; + char password_buf[120]; + + /* Copy file info to access data upon close */ + memcpy(&writer->file_info, file_info, sizeof(mz_zip_file)); + + if (writer->entry_cb != NULL) + writer->entry_cb(handle, writer->entry_userdata, &writer->file_info); + + password = writer->password; + + /* Check if we need a password and ask for it if we need to */ + if ((writer->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) && + (writer->password_cb != NULL)) + { + writer->password_cb(handle, writer->password_userdata, &writer->file_info, + password_buf, sizeof(password_buf)); + password = password_buf; + } + +#ifndef MZ_ZIP_NO_ENCRYPTION + if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) + { + /* Start calculating sha256 */ + mz_crypt_sha_create(&writer->sha256); + mz_crypt_sha_set_algorithm(writer->sha256, MZ_HASH_SHA256); + mz_crypt_sha_begin(writer->sha256); + } +#endif + + /* Open entry in zip */ + err = mz_zip_entry_write_open(writer->zip_handle, &writer->file_info, writer->compress_level, + writer->raw, password); + + return err; +} + +int32_t mz_zip_writer_entry_close(void *handle) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t err = MZ_OK; +#ifndef MZ_ZIP_NO_ENCRYPTION + const uint8_t *extrafield = NULL; + int32_t extrafield_size = 0; + int16_t field_length_hash = 0; + uint8_t sha256[MZ_HASH_SHA256_SIZE]; + + + if (writer->sha256 != NULL) + { + mz_crypt_sha_end(writer->sha256, sha256, sizeof(sha256)); + mz_crypt_sha_delete(&writer->sha256); + + /* Copy extrafield so we can append our own fields before close */ + mz_stream_mem_create(&writer->file_extra_stream); + mz_stream_mem_open(writer->file_extra_stream, NULL, MZ_OPEN_MODE_CREATE); + + /* Write sha256 hash to extrafield */ + field_length_hash = 4 + MZ_HASH_SHA256_SIZE; + err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_HASH, field_length_hash); + if (err == MZ_OK) + err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256); + if (err == MZ_OK) + err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256_SIZE); + if (err == MZ_OK) + { + if (mz_stream_write(writer->file_extra_stream, sha256, sizeof(sha256)) != MZ_HASH_SHA256_SIZE) + err = MZ_WRITE_ERROR; + } + +#ifndef MZ_ZIP_NO_SIGNING + if ((err == MZ_OK) && (writer->cert_data != NULL) && (writer->cert_data_size > 0)) + { + /* Sign entry if not zipping cd or if it is cd being zipped */ + if (!writer->zip_cd || strcmp(writer->file_info.filename, MZ_ZIP_CD_FILENAME) == 0) + { + err = mz_zip_writer_entry_sign(handle, sha256, sizeof(sha256), + writer->cert_data, writer->cert_data_size, writer->cert_pwd); + } + } +#endif + + if ((writer->file_info.extrafield != NULL) && (writer->file_info.extrafield_size > 0)) + mz_stream_mem_write(writer->file_extra_stream, writer->file_info.extrafield, + writer->file_info.extrafield_size); + + /* Update extra field for central directory after adding extra fields */ + mz_stream_mem_get_buffer(writer->file_extra_stream, (const void **)&extrafield); + mz_stream_mem_get_buffer_length(writer->file_extra_stream, &extrafield_size); + + mz_zip_entry_set_extrafield(writer->zip_handle, extrafield, (uint16_t)extrafield_size); + } +#endif + + if (err == MZ_OK) + { + if (writer->raw) + err = mz_zip_entry_close_raw(writer->zip_handle, writer->file_info.uncompressed_size, + writer->file_info.crc); + else + err = mz_zip_entry_close(writer->zip_handle); + } + + return err; +} + +int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t written = 0; + written = mz_zip_entry_write(writer->zip_handle, buf, len); +#ifndef MZ_ZIP_NO_ENCRYPTION + if ((written > 0) && (writer->sha256 != NULL)) + mz_crypt_sha_update(writer->sha256, buf, written); +#endif + return written; +} + +#if !defined(MZ_ZIP_NO_ENCRYPTION) && !defined(MZ_ZIP_NO_SIGNING) +int32_t mz_zip_writer_entry_sign(void *handle, uint8_t *message, int32_t message_size, + uint8_t *cert_data, int32_t cert_data_size, const char *cert_pwd) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t err = MZ_OK; + int32_t signature_size = 0; + uint8_t *signature = NULL; + + + if (writer == NULL || cert_data == NULL || cert_data_size <= 0) + return MZ_PARAM_ERROR; + if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK) + return MZ_PARAM_ERROR; + + /* Sign message with certificate */ + err = mz_crypt_sign(message, message_size, cert_data, cert_data_size, cert_pwd, + &signature, &signature_size); + + if ((err == MZ_OK) && (signature != NULL)) + { + /* Write signature zip extra field */ + err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_SIGN, + (uint16_t)signature_size); + + if (err == MZ_OK) + { + if (mz_stream_write(writer->file_extra_stream, signature, signature_size) != signature_size) + err = MZ_WRITE_ERROR; + } + + MZ_FREE(signature); + } + + return err; +} +#endif + +/***************************************************************************/ + +int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t read = 0; + int32_t written = 0; + int32_t err = MZ_OK; + + if (mz_zip_writer_is_open(writer) != MZ_OK) + return MZ_PARAM_ERROR; + /* If the entry isn't open for writing, open it */ + if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK) + return MZ_PARAM_ERROR; + if (read_cb == NULL) + return MZ_PARAM_ERROR; + + read = read_cb(stream, writer->buffer, sizeof(writer->buffer)); + if (read == 0) + return MZ_END_OF_STREAM; + if (read < 0) + { + err = read; + return err; + } + + written = mz_zip_writer_entry_write(handle, writer->buffer, read); + if (written != read) + return MZ_WRITE_ERROR; + + return written; +} + +int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + uint64_t current_time = 0; + uint64_t update_time = 0; + int64_t current_pos = 0; + int64_t update_pos = 0; + int32_t err = MZ_OK; + int32_t written = 0; + + /* Update the progress at the beginning */ + if (writer->progress_cb != NULL) + writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos); + + /* Write data to stream until done */ + while (err == MZ_OK) + { + written = mz_zip_writer_add_process(handle, stream, read_cb); + if (written == MZ_END_OF_STREAM) + break; + if (written > 0) + current_pos += written; + if (written < 0) + err = written; + + /* Update progress if enough time have passed */ + current_time = mz_os_ms_time(); + if ((current_time - update_time) > writer->progress_cb_interval_ms) + { + if (writer->progress_cb != NULL) + writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos); + + update_pos = current_pos; + update_time = current_time; + } + } + + /* Update the progress at the end */ + if (writer->progress_cb != NULL && update_pos != current_pos) + writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos); + + return err; +} + +int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + int32_t err = MZ_OK; + + + if (mz_zip_writer_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + if (file_info == NULL) + return MZ_PARAM_ERROR; + + /* Add to zip */ + err = mz_zip_writer_entry_open(handle, file_info); + if (err != MZ_OK) + return err; + + if (stream != NULL) + { + if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) + { + err = mz_zip_writer_add(handle, stream, read_cb); + if (err != MZ_OK) + return err; + } + } + + err = mz_zip_writer_entry_close(handle); + + return err; +} + +int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info) +{ + void *mem_stream = NULL; + int32_t err = MZ_OK; + + if (mz_zip_writer_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + if (buf == NULL) + return MZ_PARAM_ERROR; + + /* Create a memory stream backed by our buffer and add from it */ + mz_stream_mem_create(&mem_stream); + mz_stream_mem_set_buffer(mem_stream, buf, len); + + err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ); + if (err == MZ_OK) + err = mz_zip_writer_add_info(handle, mem_stream, mz_stream_mem_read, file_info); + + mz_stream_mem_delete(&mem_stream); + return err; +} + +int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + mz_zip_file file_info; + uint32_t target_attrib = 0; + uint32_t src_attrib = 0; + int32_t err = MZ_OK; + uint8_t src_sys = 0; + void *stream = NULL; + char link_path[1024]; + const char *filename = filename_in_zip; + + + if (mz_zip_writer_is_open(handle) != MZ_OK) + return MZ_PARAM_ERROR; + if (path == NULL) + return MZ_PARAM_ERROR; + + if (filename == NULL) + { + err = mz_path_get_filename(path, &filename); + if (err != MZ_OK) + return err; + } + + memset(&file_info, 0, sizeof(file_info)); + + /* The path name saved, should not include a leading slash. */ + /* If it did, windows/xp and dynazip couldn't read the zip file. */ + + while (filename[0] == '\\' || filename[0] == '/') + filename += 1; + + /* Get information about the file on disk so we can store it in zip */ + + file_info.version_madeby = MZ_VERSION_MADEBY; + file_info.compression_method = writer->compress_method; + file_info.filename = filename; + file_info.uncompressed_size = mz_os_get_file_size(path); + file_info.flag = MZ_ZIP_FLAG_UTF8; + + if (writer->zip_cd) + file_info.flag |= MZ_ZIP_FLAG_MASK_LOCAL_INFO; + if (writer->aes) + file_info.aes_version = MZ_AES_VERSION; + + mz_os_get_file_date(path, &file_info.modified_date, &file_info.accessed_date, + &file_info.creation_date); + mz_os_get_file_attribs(path, &src_attrib); + + src_sys = MZ_HOST_SYSTEM(file_info.version_madeby); + + if ((src_sys != MZ_HOST_SYSTEM_MSDOS) && (src_sys != MZ_HOST_SYSTEM_WINDOWS_NTFS)) + { + /* High bytes are OS specific attributes, low byte is always DOS attributes */ + if (mz_zip_attrib_convert(src_sys, src_attrib, MZ_HOST_SYSTEM_MSDOS, &target_attrib) == MZ_OK) + file_info.external_fa = target_attrib; + file_info.external_fa |= (src_attrib << 16); + } + else + { + file_info.external_fa = src_attrib; + } + + if (writer->store_links && mz_os_is_symlink(path) == MZ_OK) + { + err = mz_os_read_symlink(path, link_path, sizeof(link_path)); + if (err == MZ_OK) + file_info.linkname = link_path; + } + + if (mz_os_is_dir(path) != MZ_OK) + { + mz_stream_os_create(&stream); + err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ); + } + + if (err == MZ_OK) + err = mz_zip_writer_add_info(handle, stream, mz_stream_read, &file_info); + + if (stream != NULL) + { + mz_stream_close(stream); + mz_stream_delete(&stream); + } + + return err; +} + +int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, + uint8_t include_path, uint8_t recursive) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + DIR *dir = NULL; + struct dirent *entry = NULL; + int32_t err = MZ_OK; + int16_t is_dir = 0; + const char *filename = NULL; + const char *filenameinzip = path; + char *wildcard_ptr = NULL; + char full_path[1024]; + char path_dir[1024]; + + + if (strrchr(path, '*') != NULL) + { + strncpy(path_dir, path, sizeof(path_dir) - 1); + path_dir[sizeof(path_dir) - 1] = 0; + mz_path_remove_filename(path_dir); + wildcard_ptr = path_dir + strlen(path_dir) + 1; + root_path = path = path_dir; + } + else + { + if (mz_os_is_dir(path) == MZ_OK) + is_dir = 1; + + /* Construct the filename that our file will be stored in the zip as */ + if (root_path == NULL) + root_path = path; + + /* Should the file be stored with any path info at all? */ + if (!include_path) + { + if (!is_dir && root_path == path) + { + if (mz_path_get_filename(filenameinzip, &filename) == MZ_OK) + filenameinzip = filename; + } + else + { + filenameinzip += strlen(root_path); + } + } + + if (!writer->store_links && !writer->follow_links) + { + if (mz_os_is_symlink(path) == MZ_OK) + return err; + } + + if (*filenameinzip != 0) + err = mz_zip_writer_add_file(handle, path, filenameinzip); + + if (!is_dir) + return err; + + if (writer->store_links) + { + if (mz_os_is_symlink(path) == MZ_OK) + return err; + } + } + + dir = mz_os_open_dir(path); + + if (dir == NULL) + return MZ_EXIST_ERROR; + + while ((entry = mz_os_read_dir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + full_path[0] = 0; + mz_path_combine(full_path, path, sizeof(full_path)); + mz_path_combine(full_path, entry->d_name, sizeof(full_path)); + + if (!recursive && mz_os_is_dir(full_path) == MZ_OK) + continue; + + if ((wildcard_ptr != NULL) && (mz_path_compare_wc(entry->d_name, wildcard_ptr, 1) != MZ_OK)) + continue; + + err = mz_zip_writer_add_path(handle, full_path, root_path, include_path, recursive); + if (err != MZ_OK) + return err; + } + + mz_os_close_dir(dir); + return MZ_OK; +} + +int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + mz_zip_file *file_info = NULL; + int64_t compressed_size = 0; + int64_t uncompressed_size = 0; + uint32_t crc32 = 0; + int32_t err = MZ_OK; + uint8_t original_raw = 0; + void *reader_zip_handle = NULL; + void *writer_zip_handle = NULL; + + + if (mz_zip_reader_is_open(reader) != MZ_OK) + return MZ_PARAM_ERROR; + if (mz_zip_writer_is_open(writer) != MZ_OK) + return MZ_PARAM_ERROR; + + err = mz_zip_reader_entry_get_info(reader, &file_info); + + if (err != MZ_OK) + return err; + + mz_zip_reader_get_zip_handle(reader, &reader_zip_handle); + mz_zip_writer_get_zip_handle(writer, &writer_zip_handle); + + /* Open entry for raw reading */ + err = mz_zip_entry_read_open(reader_zip_handle, 1, NULL); + + if (err == MZ_OK) + { + /* Write entry raw, save original raw value */ + original_raw = writer->raw; + writer->raw = 1; + + err = mz_zip_writer_entry_open(writer, file_info); + + if ((err == MZ_OK) && + (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK)) + { + err = mz_zip_writer_add(writer, reader_zip_handle, mz_zip_entry_read); + } + + if ((err == MZ_OK) && (file_info->flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)) + { + err = mz_zip_entry_read_close(reader_zip_handle, &crc32, &compressed_size, &uncompressed_size); + if (err == MZ_OK) + err = mz_zip_entry_write_close(writer_zip_handle, crc32, compressed_size, uncompressed_size); + } + + if (mz_zip_entry_is_open(reader_zip_handle) == MZ_OK) + mz_zip_entry_close(reader_zip_handle); + + if (mz_zip_entry_is_open(writer_zip_handle) == MZ_OK) + mz_zip_entry_close(writer_zip_handle); + + writer->raw = original_raw; + } + + return err; +} + +/***************************************************************************/ + +void mz_zip_writer_set_password(void *handle, const char *password) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->password = password; +} + +void mz_zip_writer_set_comment(void *handle, const char *comment) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->comment = comment; +} + +void mz_zip_writer_set_raw(void *handle, uint8_t raw) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->raw = raw; +} + +int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + if (raw == NULL) + return MZ_PARAM_ERROR; + *raw = writer->raw; + return MZ_OK; +} + +void mz_zip_writer_set_aes(void *handle, uint8_t aes) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->aes = aes; +} + +void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->compress_method = compress_method; +} + +void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->compress_level = compress_level; +} + +void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->follow_links = follow_links; +} + +void mz_zip_writer_set_store_links(void *handle, uint8_t store_links) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->store_links = store_links; +} + +void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->zip_cd = zip_cd; +} + +int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + void *cert_stream = NULL; + uint8_t *cert_data = NULL; + int32_t cert_data_size = 0; + int32_t err = MZ_OK; + + if (cert_path == NULL) + return MZ_PARAM_ERROR; + + cert_data_size = (int32_t)mz_os_get_file_size(cert_path); + + if (cert_data_size == 0) + return MZ_PARAM_ERROR; + + if (writer->cert_data != NULL) + { + MZ_FREE(writer->cert_data); + writer->cert_data = NULL; + } + + cert_data = (uint8_t *)MZ_ALLOC(cert_data_size); + + /* Read pkcs12 certificate from disk */ + mz_stream_os_create(&cert_stream); + err = mz_stream_os_open(cert_stream, cert_path, MZ_OPEN_MODE_READ); + if (err == MZ_OK) + { + if (mz_stream_os_read(cert_stream, cert_data, cert_data_size) != cert_data_size) + err = MZ_READ_ERROR; + mz_stream_os_close(cert_stream); + } + mz_stream_os_delete(&cert_stream); + + if (err == MZ_OK) + { + writer->cert_data = cert_data; + writer->cert_data_size = cert_data_size; + writer->cert_pwd = cert_pwd; + } + else + { + MZ_FREE(cert_data); + } + + return err; +} + +void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->overwrite_cb = cb; + writer->overwrite_userdata = userdata; +} + +void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->password_cb = cb; + writer->password_userdata = userdata; +} + +void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->progress_cb = cb; + writer->progress_userdata = userdata; +} + +void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->progress_cb_interval_ms = milliseconds; +} + +void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + writer->entry_cb = cb; + writer->entry_userdata = userdata; +} + +int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle) +{ + mz_zip_writer *writer = (mz_zip_writer *)handle; + if (zip_handle == NULL) + return MZ_PARAM_ERROR; + *zip_handle = writer->zip_handle; + if (*zip_handle == NULL) + return MZ_EXIST_ERROR; + return MZ_OK; +} + +/***************************************************************************/ + +void *mz_zip_writer_create(void **handle) +{ + mz_zip_writer *writer = NULL; + + writer = (mz_zip_writer *)MZ_ALLOC(sizeof(mz_zip_writer)); + if (writer != NULL) + { + memset(writer, 0, sizeof(mz_zip_writer)); +#if defined(HAVE_WZAES) + writer->aes = 1; +#endif +#if defined(HAVE_ZLIB) || defined(HAVE_LIBCOMP) + writer->compress_method = MZ_COMPRESS_METHOD_DEFLATE; +#elif defined(HAVE_BZIP2) + writer->compress_method = MZ_COMPRESS_METHOD_BZIP2; +#elif defined(HAVE_LZMA) + writer->compress_method = MZ_COMPRESS_METHOD_LZMA; +#else + writer->compress_method = MZ_COMPRESS_METHOD_STORE; +#endif + writer->compress_level = MZ_COMPRESS_LEVEL_BEST; + writer->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL; + + *handle = writer; + } + + return writer; +} + +void mz_zip_writer_delete(void **handle) +{ + mz_zip_writer *writer = NULL; + if (handle == NULL) + return; + writer = (mz_zip_writer *)*handle; + if (writer != NULL) + { + mz_zip_writer_close(writer); + + if (writer->cert_data != NULL) + MZ_FREE(writer->cert_data); + + writer->cert_data = NULL; + writer->cert_data_size = 0; + + MZ_FREE(writer); + } + *handle = NULL; +} + +/***************************************************************************/ diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c.meta new file mode 100644 index 0000000..f1b7165 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.c.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: e8b65135bcd76463f96d92c2ac0b96f8 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h new file mode 100755 index 0000000..1eb8370 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h @@ -0,0 +1,292 @@ +/* mz_zip_rw.h -- Zip reader/writer + Version 2.8.7, May 9, 2019 + part of the MiniZip project + + Copyright (C) 2010-2019 Nathan Moinvaziri + https://github.com/nmoinvaz/minizip + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef MZ_ZIP_RW_H +#define MZ_ZIP_RW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +typedef int32_t (*mz_zip_reader_overwrite_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path); +typedef int32_t (*mz_zip_reader_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password); +typedef int32_t (*mz_zip_reader_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position); +typedef int32_t (*mz_zip_reader_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path); + +/***************************************************************************/ + +int32_t mz_zip_reader_is_open(void *handle); +/* Checks to see if the zip file is open */ + +int32_t mz_zip_reader_open(void *handle, void *stream); +/* Opens zip file from stream */ + +int32_t mz_zip_reader_open_file(void *handle, const char *path); +/* Opens zip file from a file path */ + +int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path); +/* Opens zip file from a file path into memory for faster access */ + +int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy); +/* Opens zip file from memory buffer */ + +int32_t mz_zip_reader_close(void *handle); +/* Closes the zip file */ + +/***************************************************************************/ + +int32_t mz_zip_reader_unzip_cd(void *handle); +/* Unzip the central directory */ + +/***************************************************************************/ + +int32_t mz_zip_reader_goto_first_entry(void *handle); +/* Goto the first entry in the zip file that matches the pattern */ + +int32_t mz_zip_reader_goto_next_entry(void *handle); +/* Goto the next entry in the zip file that matches the pattern */ + +int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case); +/* Locates an entry by filename */ + +int32_t mz_zip_reader_entry_open(void *handle); +/* Opens an entry for reading */ + +int32_t mz_zip_reader_entry_close(void *handle); +/* Closes an entry */ + +int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len); +/* Reads and entry after being opened */ + +int32_t mz_zip_reader_entry_has_sign(void *handle); +/* Checks to see if the entry has a signature */ + +int32_t mz_zip_reader_entry_sign_verify(void *handle); +/* Verifies a signature stored with the entry */ + +int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size); +/* Gets a hash algorithm from the entry's extra field */ + +int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size); +/* Gets the most secure hash algorithm from the entry's extra field */ + +int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info); +/* Gets the current entry file info */ + +int32_t mz_zip_reader_entry_is_dir(void *handle); +/* Gets the current entry is a directory */ + +int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb); +/* Save the current entry to a steam */ + +int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb); +/* Saves a portion of the current entry to a stream callback */ + +int32_t mz_zip_reader_entry_save_file(void *handle, const char *path); +/* Save the current entry to a file */ + +int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len); +/* Save the current entry to a memory buffer */ + +int32_t mz_zip_reader_entry_save_buffer_length(void *handle); +/* Gets the length of the buffer required to save */ + +/***************************************************************************/ + +int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir); +/* Save all files into a directory */ + +/***************************************************************************/ + +void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case); +/* Sets the match pattern for entries in the zip file, if null all entries are matched */ + +void mz_zip_reader_set_password(void *handle, const char *password); +/* Sets the password required for extraction */ + +void mz_zip_reader_set_raw(void *handle, uint8_t raw); +/* Sets whether or not it should save the entry raw */ + +int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw); +/* Gets whether or not it should save the entry raw */ + +int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd); +/* Gets whether or not the archive has zipped cd */ + +int32_t mz_zip_reader_get_comment(void *handle, const char **comment); +/* Gets the comment for the central directory */ + +void mz_zip_reader_set_encoding(void *handle, int32_t encoding); +/* Sets whether or not it should support cp437 in zip file names */ + +void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required); +/* Sets whether or not it a signature is required */ + +void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb); +/* Callback for what to do when a file is being overwritten */ + +void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb); +/* Callback for when a password is required and hasn't been set */ + +void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb); +/* Callback for extraction progress */ + +void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds); +/* Let at least milliseconds pass between calls to progress callback */ + +void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb); +/* Callback for zip file entries */ + +int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle); +/* Gets the underlying zip instance handle */ + +void* mz_zip_reader_create(void **handle); +/* Create new instance of zip reader */ + +void mz_zip_reader_delete(void **handle); +/* Delete instance of zip reader */ + +/***************************************************************************/ + +typedef int32_t (*mz_zip_writer_overwrite_cb)(void *handle, void *userdata, const char *path); +typedef int32_t (*mz_zip_writer_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password); +typedef int32_t (*mz_zip_writer_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position); +typedef int32_t (*mz_zip_writer_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info); + +/***************************************************************************/ + +int32_t mz_zip_writer_is_open(void *handle); +/* Checks to see if the zip file is open */ + +int32_t mz_zip_writer_open(void *handle, void *stream); +/* Opens zip file from stream */ + +int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append); +/* Opens zip file from a file path */ + +int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path); +/* Opens zip file from a file path into memory for faster access */ + +int32_t mz_zip_writer_close(void *handle); +/* Closes the zip file */ + +/***************************************************************************/ + +int32_t mz_zip_writer_zip_cd(void *handle); +/* Zip the central directory */ + +/***************************************************************************/ + +int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info); +/* Opens an entry in the zip file for writing */ + +int32_t mz_zip_writer_entry_close(void *handle); +/* Closes entry in zip file */ + +int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len); +/* Writes data into entry for zip */ + +int32_t mz_zip_writer_entry_sign(void *handle, uint8_t *message, int32_t message_size, + uint8_t *cert_data, int32_t cert_data_size, const char *cert_pwd); +/* Signs uncompressed content of entry, call before closing */ + +/***************************************************************************/ + +int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb); +/* Writes all data to the currently open entry in the zip */ + +int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb); +/* Writes a portion of data to the currently open entry in the zip */ + +int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info); +/* Adds an entry to the zip based on the info */ + +int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info); +/* Adds an entry to the zip with a memory buffer */ + +int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip); +/* Adds an entry to the zip from a file */ + +int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, uint8_t include_path, + uint8_t recursive); +/* Enumerates a directory or pattern and adds entries to the zip */ + +int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader); +/* Adds an entry from a zip reader instance */ + +/***************************************************************************/ + +void mz_zip_writer_set_password(void *handle, const char *password); +/* Password to use for encrypting files in the zip */ + +void mz_zip_writer_set_comment(void *handle, const char *comment); +/* Comment to use for the archive */ + +void mz_zip_writer_set_raw(void *handle, uint8_t raw); +/* Sets whether or not we should write the entry raw */ + +int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw); +/* Gets whether or not we should write the entry raw */ + +void mz_zip_writer_set_aes(void *handle, uint8_t aes); +/* Use aes encryption when adding files in zip */ + +void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method); +/* Sets the compression method when adding files in zip */ + +void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level); +/* Sets the compression level when adding files in zip */ + +void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links); +/* Follow symbolic links when traversing directories and files to add */ + +void mz_zip_writer_set_store_links(void *handle, uint8_t store_links); +/* Store symbolic links in zip file */ + +void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd); +/* Sets additional flags to be set when adding files in zip */ + +int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd); +/* Sets the certificate and timestamp url to use for signing when adding files in zip */ + +void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb); +/* Callback for what to do when zip file already exists */ + +void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb); +/* Callback for ask if a password is required for adding */ + +void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb); +/* Callback for compression progress */ + +void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds); +/* Let at least milliseconds pass between calls to progress callback */ + +void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb); +/* Callback for zip file entries */ + +int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle); +/* Gets the underlying zip handle */ + +void* mz_zip_writer_create(void **handle); +/* Create new instance of zip writer */ + +void mz_zip_writer_delete(void **handle); +/* Delete instance of zip writer */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h.meta b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h.meta new file mode 100644 index 0000000..ef6c3d7 --- /dev/null +++ b/Assets/Plugins/iOS/SSZipArchive/minizip/mz_zip_rw.h.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 4cdf450461c3245fcbce373414c70254 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/iOS/UnityZipFile.mm b/Assets/Plugins/iOS/UnityZipFile.mm index 6e02cc1..4f70aa6 100644 --- a/Assets/Plugins/iOS/UnityZipFile.mm +++ b/Assets/Plugins/iOS/UnityZipFile.mm @@ -3,37 +3,38 @@ // Unity-iPhone // // Created by 山村 達彦 on 2013/12/29. -// +// Modified by Ruman on 2019/06/07 // #import "ZipArchive.h" static NSMutableArray* list = nil; -extern "C"{ - - - void zip(const char*file) { - NSString *zipPath =[NSString stringWithUTF8String:file]; +extern "C" +{ + void zip(const char*file) + { + // todo + // NSString *zipPath =[NSString stringWithUTF8String:file]; - ZipArchive* zip = [[ZipArchive alloc] init]; + // ZipArchive* zip = [[ZipArchive alloc] init]; - [zip CreateZipFile2:zipPath]; + // [zip CreateZipFile2:zipPath]; - for(int i=0; i Date: Fri, 7 Jun 2019 23:04:34 +0900 Subject: [PATCH 03/18] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d5faebd..db994c4 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,14 @@ string[] files = new string[]{ Application.temporaryCachePath + "/dir/args.txt"} ZipUtil.Zip (exportZip, files); ``` +#TODO +- [ ] iOS zip +- [ ] support async zip/unzip +- [ ] inform result +- [ ] support password +- [ ] submit assetstore +- [ ] Directry support #License -This software is released under the MIT License, see LICENSE. \ No newline at end of file +This software is released under the MIT License, see LICENSE. From b61fa3ccf05f16efbab56fdba9ebf38e9c4c0eda Mon Sep 17 00:00:00 2001 From: Ruman Kim Date: Fri, 7 Jun 2019 23:06:48 +0900 Subject: [PATCH 04/18] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index db994c4..f609581 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ ZipUtil.Zip (exportZip, files); #TODO - [ ] iOS zip - [ ] support async zip/unzip +- [ ] inform progress while async job - [ ] inform result - [ ] support password - [ ] submit assetstore From 63184648783c9719a229cc0349e8f0560a275a6d Mon Sep 17 00:00:00 2001 From: Ruman Kim Date: Fri, 7 Jun 2019 23:17:50 +0900 Subject: [PATCH 05/18] Upload logo file --- logo.jpg | Bin 0 -> 46478 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 logo.jpg diff --git a/logo.jpg b/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c198d5891c07b76a08453cd1c09817d67264336b GIT binary patch literal 46478 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 literal 0 HcmV?d00001 From 0b0c9c3ba4d8a617e63fd3a494cb2e97364052b5 Mon Sep 17 00:00:00 2001 From: Ruman Kim Date: Fri, 7 Jun 2019 23:18:22 +0900 Subject: [PATCH 06/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f609581..5431fd0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ UniZip UniZip is zipper for unity3d. -![unity zip](https://dl.dropboxusercontent.com/u/56297224/Images/unityzip%20rogo.jpg) +![unity zip](https://github.com/rumaniel/UnityZip/blob/master/logo.jpg) #supported From dfefacef879fc1b6ad79915285e630413299ff5e Mon Sep 17 00:00:00 2001 From: Ruman Kim Date: Sat, 8 Jun 2019 14:58:16 +0900 Subject: [PATCH 07/18] Update README.md --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 5431fd0..845fad5 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,6 @@ UniZip is zipper for unity3d. - Android. - Mac.and probably windows. -#iOS how to - -1. build project. -2. add file "PluginsCode>iOS>ZipArchive" to xcode project. -3. enjoy. - #example -unzip From 971e033817054f45f768bd349b73871c050cec70 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 17:42:32 +0900 Subject: [PATCH 08/18] Works on iOS --- Assets/Plugins/iOS/UnityZipFile.mm | 52 ++++++++++++------------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/Assets/Plugins/iOS/UnityZipFile.mm b/Assets/Plugins/iOS/UnityZipFile.mm index 4f70aa6..ff949d2 100644 --- a/Assets/Plugins/iOS/UnityZipFile.mm +++ b/Assets/Plugins/iOS/UnityZipFile.mm @@ -13,55 +13,43 @@ { void zip(const char*file) { - // todo - // NSString *zipPath =[NSString stringWithUTF8String:file]; - - // ZipArchive* zip = [[ZipArchive alloc] init]; - - - // [zip CreateZipFile2:zipPath]; - - // for(int i=0; i Date: Sat, 8 Jun 2019 21:19:51 +0900 Subject: [PATCH 09/18] Update jar to java file --- Assets/Plugins/Android/zipper.jar | Bin 2715 -> 0 bytes Assets/Plugins/Android/zipper.java | 114 ++++++++++++++++++ .../{zipper.jar.meta => zipper.java.meta} | 2 +- 3 files changed, 115 insertions(+), 1 deletion(-) delete mode 100644 Assets/Plugins/Android/zipper.jar create mode 100644 Assets/Plugins/Android/zipper.java rename Assets/Plugins/Android/{zipper.jar.meta => zipper.java.meta} (93%) diff --git a/Assets/Plugins/Android/zipper.jar b/Assets/Plugins/Android/zipper.jar deleted file mode 100644 index d728387aea424de8c46bc034e39f3f6b669854d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2715 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 diff --git a/Assets/Plugins/Android/zipper.java b/Assets/Plugins/Android/zipper.java new file mode 100644 index 0000000..b350294 --- /dev/null +++ b/Assets/Plugins/Android/zipper.java @@ -0,0 +1,114 @@ +package com.tsw; + +import android.util.Log; + +import java.io.File; +import java.io.*; +import java.util.zip.*; + +/** + * Created by yamamuratatsuhiko on 2013/12/29. + */ +public class zipper { + /** + * Unzip a zip file. Will overwrite existing files. + * + * @param zipFile Full path of the zip file you'd like to unzip. + * @param location Full path of the directory you'd like to unzip to (will be created if it doesn't exist). + * @throws java.io.IOException + */ + + static int BUFFER_SIZE = 512; + static String TAG = "unity"; + + /*** + * + * @param files + * @param zipFile + * @throws IOException + */ + public static void zip(String zipFile, String[] files) throws IOException { + BufferedInputStream origin = null; + ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile))); + try { + byte data[] = new byte[BUFFER_SIZE]; + + for (int i = 0; i < files.length; i++) { + FileInputStream fi = new FileInputStream(files[i]); + origin = new BufferedInputStream(fi, BUFFER_SIZE); + try { + ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1)); + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) { + out.write(data, 0, count); + } + } + finally { + origin.close(); + } + } + } + finally { + out.close(); + } + } + + public static void unzip(String zipFile, String location) throws IOException { + int size; + byte[] buffer = new byte[BUFFER_SIZE]; + + try { + if ( !location.endsWith("/") ) { + location += "/"; + } + File f = new File(location); + if(!f.isDirectory()) { + f.mkdirs(); + } + ZipInputStream zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile), BUFFER_SIZE)); + try { + ZipEntry ze = null; + while ((ze = zin.getNextEntry()) != null) { + String path = location + ze.getName(); + File unzipFile = new File(path); + + if (ze.isDirectory()) { + if(!unzipFile.isDirectory()) { + unzipFile.mkdirs(); + } + } else { + // check for and create parent directories if they don't exist + File parentDir = unzipFile.getParentFile(); + if ( null != parentDir ) { + if ( !parentDir.isDirectory() ) { + parentDir.mkdirs(); + } + } + + // unzip the file + FileOutputStream out = new FileOutputStream(unzipFile, false); + BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE); + try { + while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) { + fout.write(buffer, 0, size); + } + + zin.closeEntry(); + } + finally { + fout.flush(); + fout.close(); + } + } + } + } + finally { + zin.close(); + } + } + catch (Exception e) { + Log.e(TAG, "Unzip exception", e); + } + } +} diff --git a/Assets/Plugins/Android/zipper.jar.meta b/Assets/Plugins/Android/zipper.java.meta similarity index 93% rename from Assets/Plugins/Android/zipper.jar.meta rename to Assets/Plugins/Android/zipper.java.meta index b1b4208..d0095d9 100644 --- a/Assets/Plugins/Android/zipper.jar.meta +++ b/Assets/Plugins/Android/zipper.java.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d92153e6d88864707b56d9e4fabc1209 +guid: b35ebb883a53f4d808345aa1b867388a PluginImporter: externalObjects: {} serializedVersion: 2 From 29abd25ea1cc5a5b2117829189c5e29a85ac5dc4 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 21:20:19 +0900 Subject: [PATCH 10/18] Remove unused PluginCode folder --- PluginsCode/Android/zipper.java | 114 -- PluginsCode/iOS/ZipArchive/AUTHORS.txt | 21 - PluginsCode/iOS/ZipArchive/ZipArchive.h | 48 - PluginsCode/iOS/ZipArchive/ZipArchive.mm | 337 ---- PluginsCode/iOS/ZipArchive/minizip/crypt.h | 132 -- PluginsCode/iOS/ZipArchive/minizip/ioapi.c | 177 -- PluginsCode/iOS/ZipArchive/minizip/ioapi.h | 75 - PluginsCode/iOS/ZipArchive/minizip/mztools.c | 281 --- PluginsCode/iOS/ZipArchive/minizip/mztools.h | 31 - PluginsCode/iOS/ZipArchive/minizip/unzip.c | 1598 ------------------ PluginsCode/iOS/ZipArchive/minizip/unzip.h | 354 ---- PluginsCode/iOS/ZipArchive/minizip/zip.c | 1219 ------------- PluginsCode/iOS/ZipArchive/minizip/zip.h | 235 --- 13 files changed, 4622 deletions(-) delete mode 100644 PluginsCode/Android/zipper.java delete mode 100644 PluginsCode/iOS/ZipArchive/AUTHORS.txt delete mode 100644 PluginsCode/iOS/ZipArchive/ZipArchive.h delete mode 100644 PluginsCode/iOS/ZipArchive/ZipArchive.mm delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/crypt.h delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/ioapi.c delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/ioapi.h delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/mztools.c delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/mztools.h delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/unzip.c delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/unzip.h delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/zip.c delete mode 100644 PluginsCode/iOS/ZipArchive/minizip/zip.h diff --git a/PluginsCode/Android/zipper.java b/PluginsCode/Android/zipper.java deleted file mode 100644 index b350294..0000000 --- a/PluginsCode/Android/zipper.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.tsw; - -import android.util.Log; - -import java.io.File; -import java.io.*; -import java.util.zip.*; - -/** - * Created by yamamuratatsuhiko on 2013/12/29. - */ -public class zipper { - /** - * Unzip a zip file. Will overwrite existing files. - * - * @param zipFile Full path of the zip file you'd like to unzip. - * @param location Full path of the directory you'd like to unzip to (will be created if it doesn't exist). - * @throws java.io.IOException - */ - - static int BUFFER_SIZE = 512; - static String TAG = "unity"; - - /*** - * - * @param files - * @param zipFile - * @throws IOException - */ - public static void zip(String zipFile, String[] files) throws IOException { - BufferedInputStream origin = null; - ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile))); - try { - byte data[] = new byte[BUFFER_SIZE]; - - for (int i = 0; i < files.length; i++) { - FileInputStream fi = new FileInputStream(files[i]); - origin = new BufferedInputStream(fi, BUFFER_SIZE); - try { - ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1)); - out.putNextEntry(entry); - int count; - while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) { - out.write(data, 0, count); - } - } - finally { - origin.close(); - } - } - } - finally { - out.close(); - } - } - - public static void unzip(String zipFile, String location) throws IOException { - int size; - byte[] buffer = new byte[BUFFER_SIZE]; - - try { - if ( !location.endsWith("/") ) { - location += "/"; - } - File f = new File(location); - if(!f.isDirectory()) { - f.mkdirs(); - } - ZipInputStream zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile), BUFFER_SIZE)); - try { - ZipEntry ze = null; - while ((ze = zin.getNextEntry()) != null) { - String path = location + ze.getName(); - File unzipFile = new File(path); - - if (ze.isDirectory()) { - if(!unzipFile.isDirectory()) { - unzipFile.mkdirs(); - } - } else { - // check for and create parent directories if they don't exist - File parentDir = unzipFile.getParentFile(); - if ( null != parentDir ) { - if ( !parentDir.isDirectory() ) { - parentDir.mkdirs(); - } - } - - // unzip the file - FileOutputStream out = new FileOutputStream(unzipFile, false); - BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE); - try { - while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) { - fout.write(buffer, 0, size); - } - - zin.closeEntry(); - } - finally { - fout.flush(); - fout.close(); - } - } - } - } - finally { - zin.close(); - } - } - catch (Exception e) { - Log.e(TAG, "Unzip exception", e); - } - } -} diff --git a/PluginsCode/iOS/ZipArchive/AUTHORS.txt b/PluginsCode/iOS/ZipArchive/AUTHORS.txt deleted file mode 100644 index e0de027..0000000 --- a/PluginsCode/iOS/ZipArchive/AUTHORS.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 08 aish. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/PluginsCode/iOS/ZipArchive/ZipArchive.h b/PluginsCode/iOS/ZipArchive/ZipArchive.h deleted file mode 100644 index 9ace9b2..0000000 --- a/PluginsCode/iOS/ZipArchive/ZipArchive.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// ZipArchive.h -// -// -// Created by aish on 08-9-11. -// acsolu@gmail.com -// Copyright 2008 Inc. All rights reserved. -// -// History: -// 09-11-2008 version 1.0 release -// 10-18-2009 version 1.1 support password protected zip files -// 10-21-2009 version 1.2 fix date bug - -#import - -#include "minizip/zip.h" -#include "minizip/unzip.h" - - -@protocol ZipArchiveDelegate -@optional --(void) ErrorMessage:(NSString*) msg; --(BOOL) OverWriteOperation:(NSString*) file; - -@end - - -@interface ZipArchive : NSObject { -@private - zipFile _zipFile; - unzFile _unzFile; - - NSString* _password; - id _delegate; -} - -@property (nonatomic, retain) id delegate; - --(BOOL) CreateZipFile2:(NSString*) zipFile; --(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password; --(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname; --(BOOL) CloseZipFile2; - --(BOOL) UnzipOpenFile:(NSString*) zipFile; --(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password; --(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite; --(BOOL) UnzipCloseFile; -@end diff --git a/PluginsCode/iOS/ZipArchive/ZipArchive.mm b/PluginsCode/iOS/ZipArchive/ZipArchive.mm deleted file mode 100644 index 868abe5..0000000 --- a/PluginsCode/iOS/ZipArchive/ZipArchive.mm +++ /dev/null @@ -1,337 +0,0 @@ -// -// ZipArchive.mm -// -// -// Created by aish on 08-9-11. -// acsolu@gmail.com -// Copyright 2008 Inc. All rights reserved. -// - -#import "ZipArchive.h" -#import "zlib.h" -#import "zconf.h" - - - -@interface ZipArchive (Private) - --(void) OutputErrorMessage:(NSString*) msg; --(BOOL) OverWrite:(NSString*) file; --(NSDate*) Date1980; -@end - - - -@implementation ZipArchive -@synthesize delegate = _delegate; - --(id) init -{ - if( self=[super init] ) - { - _zipFile = NULL ; - } - return self; -} - --(void) dealloc -{ - [self CloseZipFile2]; - [super dealloc]; -} - --(BOOL) CreateZipFile2:(NSString*) zipFile -{ - _zipFile = zipOpen( (const char*)[zipFile UTF8String], 0 ); - if( !_zipFile ) - return NO; - return YES; -} - --(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password -{ - _password = password; - return [self CreateZipFile2:zipFile]; -} - --(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname; -{ - if( !_zipFile ) - return NO; -// tm_zip filetime; - time_t current; - time( ¤t ); - - zip_fileinfo zipInfo = {0}; -// zipInfo.dosDate = (unsigned long) current; - - NSDictionary* attr = [[NSFileManager defaultManager] fileAttributesAtPath:file traverseLink:YES]; - if( attr ) - { - NSDate* fileDate = (NSDate*)[attr objectForKey:NSFileModificationDate]; - if( fileDate ) - { - // some application does use dosDate, but tmz_date instead - // zipInfo.dosDate = [fileDate timeIntervalSinceDate:[self Date1980] ]; - NSCalendar* currCalendar = [NSCalendar currentCalendar]; - uint flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | - NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ; - NSDateComponents* dc = [currCalendar components:flags fromDate:fileDate]; - zipInfo.tmz_date.tm_sec = [dc second]; - zipInfo.tmz_date.tm_min = [dc minute]; - zipInfo.tmz_date.tm_hour = [dc hour]; - zipInfo.tmz_date.tm_mday = [dc day]; - zipInfo.tmz_date.tm_mon = [dc month] - 1; - zipInfo.tmz_date.tm_year = [dc year]; - } - } - - int ret ; - NSData* data = nil; - if( [_password length] == 0 ) - { - ret = zipOpenNewFileInZip( _zipFile, - (const char*) [newname UTF8String], - &zipInfo, - NULL,0, - NULL,0, - NULL,//comment - Z_DEFLATED, - Z_DEFAULT_COMPRESSION ); - } - else - { - data = [ NSData dataWithContentsOfFile:file]; - uLong crcValue = crc32( 0L,NULL, 0L ); - crcValue = crc32( crcValue, (const Bytef*)[data bytes], [data length] ); - ret = zipOpenNewFileInZip3( _zipFile, - (const char*) [newname UTF8String], - &zipInfo, - NULL,0, - NULL,0, - NULL,//comment - Z_DEFLATED, - Z_DEFAULT_COMPRESSION, - 0, - 15, - 8, - Z_DEFAULT_STRATEGY, - [_password cStringUsingEncoding:NSASCIIStringEncoding], - crcValue ); - } - if( ret!=Z_OK ) - { - return NO; - } - if( data==nil ) - { - data = [ NSData dataWithContentsOfFile:file]; - } - unsigned int dataLen = [data length]; - ret = zipWriteInFileInZip( _zipFile, (const void*)[data bytes], dataLen); - if( ret!=Z_OK ) - { - return NO; - } - ret = zipCloseFileInZip( _zipFile ); - if( ret!=Z_OK ) - return NO; - return YES; -} - --(BOOL) CloseZipFile2 -{ - _password = nil; - if( _zipFile==NULL ) - return NO; - BOOL ret = zipClose( _zipFile,NULL )==Z_OK?YES:NO; - _zipFile = NULL; - return ret; -} - --(BOOL) UnzipOpenFile:(NSString*) zipFile -{ - _unzFile = unzOpen( (const char*)[zipFile UTF8String] ); - if( _unzFile ) - { - unz_global_info globalInfo = {0}; - if( unzGetGlobalInfo(_unzFile, &globalInfo )==UNZ_OK ) - { - NSLog([NSString stringWithFormat:@"%d entries in the zip file",globalInfo.number_entry] ); - } - } - return _unzFile!=NULL; -} - --(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password -{ - _password = password; - return [self UnzipOpenFile:zipFile]; -} - --(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite -{ - BOOL success = YES; - int ret = unzGoToFirstFile( _unzFile ); - unsigned char buffer[4096] = {0}; - NSFileManager* fman = [NSFileManager defaultManager]; - if( ret!=UNZ_OK ) - { - [self OutputErrorMessage:@"Failed"]; - } - - do{ - if( [_password length]==0 ) - ret = unzOpenCurrentFile( _unzFile ); - else - ret = unzOpenCurrentFilePassword( _unzFile, [_password cStringUsingEncoding:NSASCIIStringEncoding] ); - if( ret!=UNZ_OK ) - { - [self OutputErrorMessage:@"Error occurs"]; - success = NO; - break; - } - // reading data and write to file - int read ; - unz_file_info fileInfo ={0}; - ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); - if( ret!=UNZ_OK ) - { - [self OutputErrorMessage:@"Error occurs while getting file info"]; - success = NO; - unzCloseCurrentFile( _unzFile ); - break; - } - char* filename = (char*) malloc( fileInfo.size_filename +1 ); - unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0); - filename[fileInfo.size_filename] = '\0'; - - // check if it contains directory - NSString * strPath = [NSString stringWithCString:filename]; - BOOL isDirectory = NO; - if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\') - isDirectory = YES; - free( filename ); - if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound ) - {// contains a path - strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; - } - NSString* fullPath = [path stringByAppendingPathComponent:strPath]; - - if( isDirectory ) - [fman createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil]; - else - [fman createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil]; - if( [fman fileExistsAtPath:fullPath] && !isDirectory && !overwrite ) - { - if( ![self OverWrite:fullPath] ) - { - unzCloseCurrentFile( _unzFile ); - ret = unzGoToNextFile( _unzFile ); - continue; - } - } - FILE* fp = fopen( (const char*)[fullPath UTF8String], "wb"); - while( fp ) - { - read=unzReadCurrentFile(_unzFile, buffer, 4096); - if( read > 0 ) - { - fwrite(buffer, read, 1, fp ); - } - else if( read<0 ) - { - [self OutputErrorMessage:@"Failed to reading zip file"]; - break; - } - else - break; - } - if( fp ) - { - fclose( fp ); - // set the orignal datetime property - NSDate* orgDate = nil; - - //{{ thanks to brad.eaton for the solution - NSDateComponents *dc = [[NSDateComponents alloc] init]; - - dc.second = fileInfo.tmu_date.tm_sec; - dc.minute = fileInfo.tmu_date.tm_min; - dc.hour = fileInfo.tmu_date.tm_hour; - dc.day = fileInfo.tmu_date.tm_mday; - dc.month = fileInfo.tmu_date.tm_mon+1; - dc.year = fileInfo.tmu_date.tm_year; - - NSCalendar *gregorian = [[NSCalendar alloc] - initWithCalendarIdentifier:NSGregorianCalendar]; - - orgDate = [gregorian dateFromComponents:dc] ; - [dc release]; - [gregorian release]; - //}} - - - NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES]; - if( attr ) - { - // [attr setValue:orgDate forKey:NSFileCreationDate]; - if( ![[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:fullPath error:nil] ) - { - // cann't set attributes - NSLog(@"Failed to set attributes"); - } - - } - - - - } - unzCloseCurrentFile( _unzFile ); - ret = unzGoToNextFile( _unzFile ); - }while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE ); - return success; -} - --(BOOL) UnzipCloseFile -{ - _password = nil; - if( _unzFile ) - return unzClose( _unzFile )==UNZ_OK; - return YES; -} - -#pragma mark wrapper for delegate --(void) OutputErrorMessage:(NSString*) msg -{ - if( _delegate && [_delegate respondsToSelector:@selector(ErrorMessage)] ) - [_delegate ErrorMessage:msg]; -} - --(BOOL) OverWrite:(NSString*) file -{ - if( _delegate && [_delegate respondsToSelector:@selector(OverWriteOperation)] ) - return [_delegate OverWriteOperation:file]; - return YES; -} - -#pragma mark get NSDate object for 1980-01-01 --(NSDate*) Date1980 -{ - NSDateComponents *comps = [[NSDateComponents alloc] init]; - [comps setDay:1]; - [comps setMonth:1]; - [comps setYear:1980]; - NSCalendar *gregorian = [[NSCalendar alloc] - initWithCalendarIdentifier:NSGregorianCalendar]; - NSDate *date = [gregorian dateFromComponents:comps]; - - [comps release]; - [gregorian release]; - return date; -} - - -@end - - diff --git a/PluginsCode/iOS/ZipArchive/minizip/crypt.h b/PluginsCode/iOS/ZipArchive/minizip/crypt.h deleted file mode 100644 index f14a628..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/crypt.h +++ /dev/null @@ -1,132 +0,0 @@ -/* crypt.h -- base code for crypt/uncrypt ZIPfile - - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This code is a modified version of crypting code in Infozip distribution - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - - If you don't need crypting in your application, just define symbols - NOCRYPT and NOUNCRYPT. - - This code support the "Traditional PKWARE Encryption". - - The new AES encryption added on Zip format by Winzip (see the page - http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong - Encryption is not supported. -*/ - -#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) - -/*********************************************************************** - * Return the next byte in the pseudo-random sequence - */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) -{ - unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an - * unpredictable manner on 16-bit systems; not a problem - * with any known compiler so far, though */ - - temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*********************************************************************** - * Update the encryption keys with the next byte of plain text - */ -static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) -{ - (*(pkeys+0)) = CRC32((*(pkeys+0)), c); - (*(pkeys+1)) += (*(pkeys+0)) & 0xff; - (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; - { - register int keyshift = (int)((*(pkeys+1)) >> 24); - (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); - } - return c; -} - - -/*********************************************************************** - * Initialize the encryption keys and the random header according to - * the given password. - */ -static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) -{ - *(pkeys+0) = 305419896L; - *(pkeys+1) = 591751049L; - *(pkeys+2) = 878082192L; - while (*passwd != '\0') { - update_keys(pkeys,pcrc_32_tab,(int)*passwd); - passwd++; - } -} - -#define zdecode(pkeys,pcrc_32_tab,c) \ - (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) - -#define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) - -#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED - -#define RAND_HEAD_LEN 12 - /* "last resort" source for second part of crypt seed pattern */ -# ifndef ZCR_SEED2 -# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ -# endif - -static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) - const char *passwd; /* password string */ - unsigned char *buf; /* where to write header */ - int bufSize; - unsigned long* pkeys; - const unsigned long* pcrc_32_tab; - unsigned long crcForCrypting; -{ - int n; /* index in random header */ - int t; /* temporary */ - int c; /* random byte */ - unsigned char header[RAND_HEAD_LEN-2]; /* random header */ - static unsigned calls = 0; /* ensure different random header each time */ - - if (bufSize> 7) & 0xff; - header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); - } - /* Encrypt random header (last two bytes is high word of crc) */ - init_keys(passwd, pkeys, pcrc_32_tab); - for (n = 0; n < RAND_HEAD_LEN-2; n++) - { - buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); - } - buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); - buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); - return n; -} - -#endif diff --git a/PluginsCode/iOS/ZipArchive/minizip/ioapi.c b/PluginsCode/iOS/ZipArchive/minizip/ioapi.c deleted file mode 100644 index 7f20c18..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/ioapi.c +++ /dev/null @@ -1,177 +0,0 @@ -/* ioapi.c -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant -*/ - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" - - - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -voidpf ZCALLBACK fopen_file_func OF(( - voidpf opaque, - const char* filename, - int mode)); - -uLong ZCALLBACK fread_file_func OF(( - voidpf opaque, - voidpf stream, - void* buf, - uLong size)); - -uLong ZCALLBACK fwrite_file_func OF(( - voidpf opaque, - voidpf stream, - const void* buf, - uLong size)); - -long ZCALLBACK ftell_file_func OF(( - voidpf opaque, - voidpf stream)); - -long ZCALLBACK fseek_file_func OF(( - voidpf opaque, - voidpf stream, - uLong offset, - int origin)); - -int ZCALLBACK fclose_file_func OF(( - voidpf opaque, - voidpf stream)); - -int ZCALLBACK ferror_file_func OF(( - voidpf opaque, - voidpf stream)); - - -voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) - voidpf opaque; - const char* filename; - int mode; -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename!=NULL) && (mode_fopen != NULL)) - file = fopen(filename, mode_fopen); - return file; -} - - -uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) - voidpf opaque; - voidpf stream; - void* buf; - uLong size; -{ - uLong ret; - ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); - return ret; -} - - -uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) - voidpf opaque; - voidpf stream; - const void* buf; - uLong size; -{ - uLong ret; - ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); - return ret; -} - -long ZCALLBACK ftell_file_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - long ret; - ret = ftell((FILE *)stream); - return ret; -} - -long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) - voidpf opaque; - voidpf stream; - uLong offset; - int origin; -{ - int fseek_origin=0; - long ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END : - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - fseek_origin = SEEK_SET; - break; - default: return -1; - } - ret = 0; - fseek((FILE *)stream, offset, fseek_origin); - return ret; -} - -int ZCALLBACK fclose_file_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - int ret; - ret = fclose((FILE *)stream); - return ret; -} - -int ZCALLBACK ferror_file_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - int ret; - ret = ferror((FILE *)stream); - return ret; -} - -void fill_fopen_filefunc (pzlib_filefunc_def) - zlib_filefunc_def* pzlib_filefunc_def; -{ - pzlib_filefunc_def->zopen_file = fopen_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell_file = ftell_file_func; - pzlib_filefunc_def->zseek_file = fseek_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} diff --git a/PluginsCode/iOS/ZipArchive/minizip/ioapi.h b/PluginsCode/iOS/ZipArchive/minizip/ioapi.h deleted file mode 100644 index e73a3b2..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/ioapi.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant -*/ - -#ifndef _ZLIBIOAPI_H -#define _ZLIBIOAPI_H - - -#define ZLIB_FILEFUNC_SEEK_CUR (1) -#define ZLIB_FILEFUNC_SEEK_END (2) -#define ZLIB_FILEFUNC_SEEK_SET (0) - -#define ZLIB_FILEFUNC_MODE_READ (1) -#define ZLIB_FILEFUNC_MODE_WRITE (2) -#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) - -#define ZLIB_FILEFUNC_MODE_EXISTING (4) -#define ZLIB_FILEFUNC_MODE_CREATE (8) - - -#ifndef ZCALLBACK - -#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) -#define ZCALLBACK CALLBACK -#else -#define ZCALLBACK -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); - -typedef struct zlib_filefunc_def_s -{ - open_file_func zopen_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell_file_func ztell_file; - seek_file_func zseek_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc_def; - - - -void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); - -#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) -#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) -#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) -#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) -#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) -#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/PluginsCode/iOS/ZipArchive/minizip/mztools.c b/PluginsCode/iOS/ZipArchive/minizip/mztools.c deleted file mode 100644 index bc5c798..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/mztools.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - Additional tools for Minizip - Code: Xavier Roche '2004 - License: Same as ZLIB (www.gzip.org) -*/ - -/* Code */ -#include -#include -#include -#include "zlib.h" -#include "unzip.h" - -#define READ_8(adr) ((unsigned char)*(adr)) -#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) -#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) - -#define WRITE_8(buff, n) do { \ - *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ -} while(0) -#define WRITE_16(buff, n) do { \ - WRITE_8((unsigned char*)(buff), n); \ - WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ -} while(0) -#define WRITE_32(buff, n) do { \ - WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ - WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ -} while(0) - -extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) -const char* file; -const char* fileOut; -const char* fileOutTmp; -uLong* nRecovered; -uLong* bytesRecovered; -{ - int err = Z_OK; - FILE* fpZip = fopen(file, "rb"); - FILE* fpOut = fopen(fileOut, "wb"); - FILE* fpOutCD = fopen(fileOutTmp, "wb"); - if (fpZip != NULL && fpOut != NULL) { - int entries = 0; - uLong totalBytes = 0; - char header[30]; - char filename[256]; - char extra[1024]; - int offset = 0; - int offsetCD = 0; - while ( fread(header, 1, 30, fpZip) == 30 ) { - int currentOffset = offset; - - /* File entry */ - if (READ_32(header) == 0x04034b50) { - unsigned int version = READ_16(header + 4); - unsigned int gpflag = READ_16(header + 6); - unsigned int method = READ_16(header + 8); - unsigned int filetime = READ_16(header + 10); - unsigned int filedate = READ_16(header + 12); - unsigned int crc = READ_32(header + 14); /* crc */ - unsigned int cpsize = READ_32(header + 18); /* compressed size */ - unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ - unsigned int fnsize = READ_16(header + 26); /* file name length */ - unsigned int extsize = READ_16(header + 28); /* extra field length */ - filename[0] = extra[0] = '\0'; - - /* Header */ - if (fwrite(header, 1, 30, fpOut) == 30) { - offset += 30; - } else { - err = Z_ERRNO; - break; - } - - /* Filename */ - if (fnsize > 0) { - if (fread(filename, 1, fnsize, fpZip) == fnsize) { - if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { - offset += fnsize; - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_STREAM_ERROR; - break; - } - - /* Extra field */ - if (extsize > 0) { - if (fread(extra, 1, extsize, fpZip) == extsize) { - if (fwrite(extra, 1, extsize, fpOut) == extsize) { - offset += extsize; - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_ERRNO; - break; - } - } - - /* Data */ - { - int dataSize = cpsize; - if (dataSize == 0) { - dataSize = uncpsize; - } - if (dataSize > 0) { - char* data = malloc(dataSize); - if (data != NULL) { - if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { - if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { - offset += dataSize; - totalBytes += dataSize; - } else { - err = Z_ERRNO; - } - } else { - err = Z_ERRNO; - } - free(data); - if (err != Z_OK) { - break; - } - } else { - err = Z_MEM_ERROR; - break; - } - } - } - - /* Central directory entry */ - { - char header[46]; - char* comment = ""; - int comsize = (int) strlen(comment); - WRITE_32(header, 0x02014b50); - WRITE_16(header + 4, version); - WRITE_16(header + 6, version); - WRITE_16(header + 8, gpflag); - WRITE_16(header + 10, method); - WRITE_16(header + 12, filetime); - WRITE_16(header + 14, filedate); - WRITE_32(header + 16, crc); - WRITE_32(header + 20, cpsize); - WRITE_32(header + 24, uncpsize); - WRITE_16(header + 28, fnsize); - WRITE_16(header + 30, extsize); - WRITE_16(header + 32, comsize); - WRITE_16(header + 34, 0); /* disk # */ - WRITE_16(header + 36, 0); /* int attrb */ - WRITE_32(header + 38, 0); /* ext attrb */ - WRITE_32(header + 42, currentOffset); - /* Header */ - if (fwrite(header, 1, 46, fpOutCD) == 46) { - offsetCD += 46; - - /* Filename */ - if (fnsize > 0) { - if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { - offsetCD += fnsize; - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_STREAM_ERROR; - break; - } - - /* Extra field */ - if (extsize > 0) { - if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { - offsetCD += extsize; - } else { - err = Z_ERRNO; - break; - } - } - - /* Comment field */ - if (comsize > 0) { - if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { - offsetCD += comsize; - } else { - err = Z_ERRNO; - break; - } - } - - - } else { - err = Z_ERRNO; - break; - } - } - - /* Success */ - entries++; - - } else { - break; - } - } - - /* Final central directory */ - { - int entriesZip = entries; - char header[22]; - char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; - int comsize = (int) strlen(comment); - if (entriesZip > 0xffff) { - entriesZip = 0xffff; - } - WRITE_32(header, 0x06054b50); - WRITE_16(header + 4, 0); /* disk # */ - WRITE_16(header + 6, 0); /* disk # */ - WRITE_16(header + 8, entriesZip); /* hack */ - WRITE_16(header + 10, entriesZip); /* hack */ - WRITE_32(header + 12, offsetCD); /* size of CD */ - WRITE_32(header + 16, offset); /* offset to CD */ - WRITE_16(header + 20, comsize); /* comment */ - - /* Header */ - if (fwrite(header, 1, 22, fpOutCD) == 22) { - - /* Comment field */ - if (comsize > 0) { - if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { - err = Z_ERRNO; - } - } - - } else { - err = Z_ERRNO; - } - } - - /* Final merge (file + central directory) */ - fclose(fpOutCD); - if (err == Z_OK) { - fpOutCD = fopen(fileOutTmp, "rb"); - if (fpOutCD != NULL) { - int nRead; - char buffer[8192]; - while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { - if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { - err = Z_ERRNO; - break; - } - } - fclose(fpOutCD); - } - } - - /* Close */ - fclose(fpZip); - fclose(fpOut); - - /* Wipe temporary file */ - (void)remove(fileOutTmp); - - /* Number of recovered entries */ - if (err == Z_OK) { - if (nRecovered != NULL) { - *nRecovered = entries; - } - if (bytesRecovered != NULL) { - *bytesRecovered = totalBytes; - } - } - } else { - err = Z_STREAM_ERROR; - } - return err; -} diff --git a/PluginsCode/iOS/ZipArchive/minizip/mztools.h b/PluginsCode/iOS/ZipArchive/minizip/mztools.h deleted file mode 100644 index 82d1597..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/mztools.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Additional tools for Minizip - Code: Xavier Roche '2004 - License: Same as ZLIB (www.gzip.org) -*/ - -#ifndef _zip_tools_H -#define _zip_tools_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#include "unzip.h" - -/* Repair a ZIP file (missing central directory) - file: file to recover - fileOut: output file after recovery - fileOutTmp: temporary file name used for recovery -*/ -extern int ZEXPORT unzRepair(const char* file, - const char* fileOut, - const char* fileOutTmp, - uLong* nRecovered, - uLong* bytesRecovered); - -#endif diff --git a/PluginsCode/iOS/ZipArchive/minizip/unzip.c b/PluginsCode/iOS/ZipArchive/minizip/unzip.c deleted file mode 100644 index 3a70629..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/unzip.c +++ /dev/null @@ -1,1598 +0,0 @@ -/* unzip.c -- IO for uncompress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Read unzip.h for more info -*/ - -/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of -compatibility with older software. The following is from the original crypt.c. Code -woven in by Terry Thorsen 1/2003. -*/ -/* - Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - - See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. - If, for some reason, all these files are missing, the Info-ZIP license - also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html -*/ -/* - crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - */ - -/* - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - */ - - -#include -#include -#include -#include "zlib.h" -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - - -#ifndef CASESENSITIVITYDEFAULT_NO -# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) -# define CASESENSITIVITYDEFAULT_NO -# endif -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (16384) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - - - -const char unz_copyright[] = - " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info_internal_s -{ - uLong offset_curfile;/* relative offset of local header 4 bytes */ -} unz_file_info_internal; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct -{ - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - - uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - uLong stream_initialised; /* flag set if stream structure is initialised*/ - - uLong offset_local_extrafield;/* offset of the local extra field */ - uInt size_local_extrafield;/* size of the local extra field */ - uLong pos_local_extrafield; /* position in the local extra field in read*/ - - uLong crc32; /* crc32 of all data uncompressed */ - uLong crc32_wait; /* crc32 we must obtain after decompress all */ - uLong rest_read_compressed; /* number of byte to be decompressed */ - uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - uLong compression_method; /* compression method (0==store) */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - int raw; -} file_in_zip_read_info_s; - - -/* unz_s contain internal information about the zipfile -*/ -typedef struct -{ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - unz_global_info gi; /* public global information */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - uLong num_file; /* number of the current file in the zipfile*/ - uLong pos_in_central_dir; /* pos of the current file in the central dir*/ - uLong current_file_ok; /* flag about the usability of the current file*/ - uLong central_pos; /* position of the beginning of the central dir*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info cur_file_info; /* public info about the current file in zip*/ - unz_file_info_internal cur_file_info_internal; /* private info about it*/ - file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ - int encrypted; -# ifndef NOUNCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; -# endif -} unz_s; - - -#ifndef NOUNCRYPT -#include "crypt.h" -#endif - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - - -local int unzlocal_getByte OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - int *pi; -{ - unsigned char c; - int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ZERROR(*pzlib_filefunc_def,filestream)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unzlocal_getShort OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unzlocal_getLong OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - - -/* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (fileName1,fileName2) - const char* fileName1; - const char* fileName2; -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) - const char* fileName1; - const char* fileName2; - int iCaseSensitivity; -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong unzlocal_SearchCentralDir OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream)); - -local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer - "zlib/zlib114.zip". - If the zipfile cannot be opened (file doesn't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) - const char *path; - zlib_filefunc_def* pzlib_filefunc_def; -{ - unz_s us; - unz_s *s; - uLong central_pos,uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - if (unz_copyright[0]!=' ') - return NULL; - - if (pzlib_filefunc_def==NULL) - fill_fopen_filefunc(&us.z_filefunc); - else - us.z_filefunc = *pzlib_filefunc_def; - - us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, - path, - ZLIB_FILEFUNC_MODE_READ | - ZLIB_FILEFUNC_MODE_EXISTING); - if (us.filestream==NULL) - return NULL; - - central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); - if (central_pos==0) - err=UNZ_ERRNO; - - if (ZSEEK(us.z_filefunc, us.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - ZCLOSE(s->z_filefunc, s->filestream); - TRYFREE(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) - unzFile file; - unz_global_info *pglobal_info; -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) - uLong ulDosDate; - tm_unz* ptm; -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unzlocal_GetCurrentFileInfoInternal (file, - pfile_info, - pfile_info_internal, - szFileName, fileNameBufferSize, - extraField, extraFieldBufferSize, - szComment, commentBufferSize) - unzFile file; - unz_file_info *pfile_info; - unz_file_info_internal *pfile_info_internal; - char *szFileName; - uLong fileNameBufferSize; - void *extraField; - uLong extraFieldBufferSize; - char *szComment; - uLong commentBufferSize; -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - long lSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (ZSEEK(s->z_filefunc, s->filestream, - s->pos_in_central_dir+s->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - lSeek += file_info.size_file_extra - uSizeRead; - } - else - lSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; - } - else - lSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int ZEXPORT unzGetCurrentFileInfo (file, - pfile_info, - szFileName, fileNameBufferSize, - extraField, extraFieldBufferSize, - szComment, commentBufferSize) - unzFile file; - unz_file_info *pfile_info; - char *szFileName; - uLong fileNameBufferSize; - void *extraField; - uLong extraFieldBufferSize; - char *szComment; - uLong commentBufferSize; -{ - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int ZEXPORT unzGoToFirstFile (file) - unzFile file; -{ - int err=UNZ_OK; - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int ZEXPORT unzGoToNextFile (file) - unzFile file; -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) - unzFile file; - const char *szFileName; - int iCaseSensitivity; -{ - unz_s* s; - int err; - - /* We remember the 'current' position in the file so that we can jump - * back there if we fail. - */ - unz_file_info cur_file_infoSaved; - unz_file_info_internal cur_file_info_internalSaved; - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - /* Save the current state */ - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - cur_file_infoSaved = s->cur_file_info; - cur_file_info_internalSaved = s->cur_file_info_internal; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - err = unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (err == UNZ_OK) - { - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - } - - /* We failed, so restore the state of the 'current file' to where we - * were. - */ - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - s->cur_file_info = cur_file_infoSaved; - s->cur_file_info_internal = cur_file_info_internalSaved; - return err; -} - - -/* -/////////////////////////////////////////// -// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) -// I need random access -// -// Further optimization could be realized by adding an ability -// to cache the directory in memory. The goal being a single -// comprehensive file read to put the file I need in a memory. -*/ - -/* -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; // offset in file - uLong num_of_file; // # of file -} unz_file_pos; -*/ - -extern int ZEXPORT unzGetFilePos(file, file_pos) - unzFile file; - unz_file_pos* file_pos; -{ - unz_s* s; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - file_pos->pos_in_zip_directory = s->pos_in_central_dir; - file_pos->num_of_file = s->num_file; - - return UNZ_OK; -} - -extern int ZEXPORT unzGoToFilePos(file, file_pos) - unzFile file; - unz_file_pos* file_pos; -{ - unz_s* s; - int err; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - /* jump to the right spot */ - s->pos_in_central_dir = file_pos->pos_in_zip_directory; - s->num_file = file_pos->num_of_file; - - /* set the current file */ - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - /* return results */ - s->current_file_ok = (err == UNZ_OK); - return err; -} - -/* -// Unzip Helper Functions - should be here? -/////////////////////////////////////////// -*/ - -/* - Read the local header of the current zipfile - Check the coherency of the local header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in local header - (filename and size of extra field data) -*/ -local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, - poffset_local_extrafield, - psize_local_extrafield) - unz_s* s; - uInt* piSizeVar; - uLong *poffset_local_extrafield; - uInt *psize_local_extrafield; -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) - unzFile file; - int* method; - int* level; - int raw; - const char* password; -{ - int err=UNZ_OK; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; /* offset of the local extra field */ - uInt size_local_extrafield; /* size of the local extra field */ -# ifndef NOUNCRYPT - char source[12]; -# else - if (password != NULL) - return UNZ_PARAMERROR; -# endif - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*) - ALLOC(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - pfile_in_zip_read_info->raw=raw; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - TRYFREE(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if (method!=NULL) - *method = (int)s->cur_file_info.compression_method; - - if (level!=NULL) - { - *level = 6; - switch (s->cur_file_info.flag & 0x06) - { - case 6 : *level = 1; break; - case 4 : *level = 2; break; - case 2 : *level = 9; break; - } - } - - if ((s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = - s->cur_file_info.compression_method; - pfile_in_zip_read_info->filestream=s->filestream; - pfile_in_zip_read_info->z_filefunc=s->z_filefunc; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if ((s->cur_file_info.compression_method==Z_DEFLATED) && - (!raw)) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - pfile_in_zip_read_info->stream.next_in = (voidpf)0; - pfile_in_zip_read_info->stream.avail_in = 0; - - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - else - { - TRYFREE(pfile_in_zip_read_info); - return err; - } - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = - s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = - s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - s->pfile_in_zip_read = pfile_in_zip_read_info; - -# ifndef NOUNCRYPT - if (password != NULL) - { - int i; - s->pcrc_32_tab = get_crc_table(); - init_keys(password,s->keys,s->pcrc_32_tab); - if (ZSEEK(s->z_filefunc, s->filestream, - s->pfile_in_zip_read->pos_in_zipfile + - s->pfile_in_zip_read->byte_before_the_zipfile, - SEEK_SET)!=0) - return UNZ_INTERNALERROR; - if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) - return UNZ_INTERNALERROR; - - for (i = 0; i<12; i++) - zdecode(s->keys,s->pcrc_32_tab,source[i]); - - s->pfile_in_zip_read->pos_in_zipfile+=12; - s->encrypted=1; - } -# endif - - - return UNZ_OK; -} - -extern int ZEXPORT unzOpenCurrentFile (file) - unzFile file; -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); -} - -extern int ZEXPORT unzOpenCurrentFilePassword (file, password) - unzFile file; - const char* password; -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, password); -} - -extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) - unzFile file; - int* method; - int* level; - int raw; -{ - return unzOpenCurrentFile3(file, method, level, raw, NULL); -} - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int ZEXPORT unzReadCurrentFile (file, buf, len) - unzFile file; - voidp buf; - unsigned len; -{ - int err=UNZ_OK; - uInt iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->read_buffer == NULL)) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && - (!(pfile_in_zip_read_info->raw))) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - if ((len>pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in) && - (pfile_in_zip_read_info->raw)) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (ZSEEK(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - if (ZREAD(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->read_buffer, - uReadThis)!=uReadThis) - return UNZ_ERRNO; - - -# ifndef NOUNCRYPT - if(s->encrypted) - { - uInt i; - for(i=0;iread_buffer[i] = - zdecode(s->keys,s->pcrc_32_tab, - pfile_in_zip_read_info->read_buffer[i]); - } -# endif - - - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) - { - uInt uDoCopy,i ; - - if ((pfile_in_zip_read_info->stream.avail_in == 0) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - return (iRead==0) ? UNZ_EOF : iRead; - - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else - { - uLong uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err=inflate(&pfile_in_zip_read_info->stream,flush); - - if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) - err = Z_DATA_ERROR; - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern z_off_t ZEXPORT unztell (file) - unzFile file; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int ZEXPORT unzeof (file) - unzFile file; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) - unzFile file; - voidp buf; - unsigned len; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (ZSEEK(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (ZREAD(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - buf,read_now)!=read_now) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int ZEXPORT unzCloseCurrentFile (file) - unzFile file; -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && - (!pfile_in_zip_read_info->raw)) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - TRYFREE(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) - unzFile file; - char *szComment; - uLong uSizeBuf; -{ - int err=UNZ_OK; - unz_s* s; - uLong uReadThis ; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - -/* Additions by RX '2004 */ -extern uLong ZEXPORT unzGetOffset (file) - unzFile file; -{ - unz_s* s; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return 0; - if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) - if (s->num_file==s->gi.number_entry) - return 0; - return s->pos_in_central_dir; -} - -extern int ZEXPORT unzSetOffset (file, pos) - unzFile file; - uLong pos; -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - s->pos_in_central_dir = pos; - s->num_file = s->gi.number_entry; /* hack */ - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} diff --git a/PluginsCode/iOS/ZipArchive/minizip/unzip.h b/PluginsCode/iOS/ZipArchive/minizip/unzip.h deleted file mode 100644 index c3206a0..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/unzip.h +++ /dev/null @@ -1,354 +0,0 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - - Multi volume ZipFile (span) are not supported. - Encryption compatible with pkzip 2.04g only supported - Old compressions used by old PKZip 1.x are not supported - - - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -*/ - -/* for more info about .ZIP format, see - http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip - http://www.info-zip.org/pub/infozip/doc/ - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip -*/ - -#ifndef _unz_H -#define _unz_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef voidp unzFile; -#endif - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -/* tm_unz contain date/time info */ -typedef struct tm_unz_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info_s -{ - uLong number_entry; /* total number of entries in - the central dir on this disk */ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - - -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_info_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - uLong compressed_size; /* compressed size 4 bytes */ - uLong uncompressed_size; /* uncompressed size 4 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; -} unz_file_info; - -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - - -extern unzFile ZEXPORT unzOpen OF((const char *path)); -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer - "zlib/zlib113.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ - -extern unzFile ZEXPORT unzOpen2 OF((const char *path, - zlib_filefunc_def* pzlib_filefunc_def)); -/* - Open a Zip file, like unzOpen, but provide a set of file low level API - for read/write the zip file (see ioapi.h) -*/ - -extern int ZEXPORT unzClose OF((unzFile file)); -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -/* ****************************************** */ -/* Ryan supplied functions */ -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; /* offset in zip file directory */ - uLong num_of_file; /* # of file */ -} unz_file_pos; - -extern int ZEXPORT unzGetFilePos( - unzFile file, - unz_file_pos* file_pos); - -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos); - -/* ****************************************** */ - -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - -/***************************************************************************/ -/* for reading the content of the current zipfile, you can open it, read data - from it, and close it (you can close it before reading all the file) - */ - -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); -/* - Open for reading data the current file in the zipfile. - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, - const char* password)); -/* - Open for reading data the current file in the zipfile. - password is a crypting password - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, - int* method, - int* level, - int raw)); -/* - Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 - *method will receive method of compression, *level will receive level of - compression - note : you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL -*/ - -extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, - int* method, - int* level, - int raw, - const char* password)); -/* - Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 - *method will receive method of compression, *level will receive level of - compression - note : you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL -*/ - - -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); -/* - Close the file in zip opened with unzOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ - -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read bytes from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ - -extern z_off_t ZEXPORT unztell OF((unzFile file)); -/* - Give the current position in uncompressed data -*/ - -extern int ZEXPORT unzeof OF((unzFile file)); -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ - -/***************************************************************************/ - -/* Get the current file offset */ -extern uLong ZEXPORT unzGetOffset (unzFile file); - -/* Set the current file offset */ -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); - - - -#ifdef __cplusplus -} -#endif - -#endif /* _unz_H */ diff --git a/PluginsCode/iOS/ZipArchive/minizip/zip.c b/PluginsCode/iOS/ZipArchive/minizip/zip.c deleted file mode 100644 index 400e2ba..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/zip.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* zip.c -- IO on .zip files using zlib - Version 1.01e, February 12th, 2005 - - 27 Dec 2004 Rolf Kalbermatter - Modification to zipOpen2 to support globalComment retrieval. - - Copyright (C) 1998-2005 Gilles Vollant - - Read zip.h for more info -*/ - - -#include -#include -#include -#include -#include "zlib.h" -#include "zip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x0) /* platform depedent */ -#endif - -#ifndef Z_BUFSIZE -#define Z_BUFSIZE (16384) -#endif - -#ifndef Z_MAXFILENAMEINZIP -#define Z_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -/* -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) -*/ - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef DEF_MEM_LEVEL -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -#endif -const char zip_copyright[] = - " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - - -#define SIZEDATA_INDATABLOCK (4096-(4*4)) - -#define LOCALHEADERMAGIC (0x04034b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) - -#define FLAG_LOCALHEADER_OFFSET (0x06) -#define CRC_LOCALHEADER_OFFSET (0x0e) - -#define SIZECENTRALHEADER (0x2e) /* 46 */ - -typedef struct linkedlist_datablock_internal_s -{ - struct linkedlist_datablock_internal_s* next_datablock; - uLong avail_in_this_block; - uLong filled_in_this_block; - uLong unused; /* for future use and alignement */ - unsigned char data[SIZEDATA_INDATABLOCK]; -} linkedlist_datablock_internal; - -typedef struct linkedlist_data_s -{ - linkedlist_datablock_internal* first_block; - linkedlist_datablock_internal* last_block; -} linkedlist_data; - - -typedef struct -{ - z_stream stream; /* zLib stream structure for inflate */ - int stream_initialised; /* 1 is stream is initialised */ - uInt pos_in_buffered_data; /* last written byte in buffered_data */ - - uLong pos_local_header; /* offset of the local header of the file - currenty writing */ - char* central_header; /* central header data for the current file */ - uLong size_centralheader; /* size of the central header for cur file */ - uLong flag; /* flag of the file currently writing */ - - int method; /* compression method of file currenty wr.*/ - int raw; /* 1 for directly writing raw data */ - Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ - uLong dosDate; - uLong crc32; - int encrypt; -#ifndef NOCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; - int crypt_header_size; -#endif -} curfile_info; - -typedef struct -{ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - linkedlist_data central_dir;/* datablock with central dir in construction*/ - int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ - curfile_info ci; /* info on the file curretly writing */ - - uLong begin_pos; /* position of the beginning of the zipfile */ - uLong add_position_when_writting_offset; - uLong number_entry; -#ifndef NO_ADDFILEINEXISTINGZIP - char *globalcomment; -#endif -} zip_internal; - - - -#ifndef NOCRYPT -#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED -#include "crypt.h" -#endif - -local linkedlist_datablock_internal* allocate_new_datablock() -{ - linkedlist_datablock_internal* ldi; - ldi = (linkedlist_datablock_internal*) - ALLOC(sizeof(linkedlist_datablock_internal)); - if (ldi!=NULL) - { - ldi->next_datablock = NULL ; - ldi->filled_in_this_block = 0 ; - ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; - } - return ldi; -} - -local void free_datablock(ldi) - linkedlist_datablock_internal* ldi; -{ - while (ldi!=NULL) - { - linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); - ldi = ldinext; - } -} - -local void init_linkedlist(ll) - linkedlist_data* ll; -{ - ll->first_block = ll->last_block = NULL; -} - -local void free_linkedlist(ll) - linkedlist_data* ll; -{ - free_datablock(ll->first_block); - ll->first_block = ll->last_block = NULL; -} - - -local int add_data_in_datablock(ll,buf,len) - linkedlist_data* ll; - const void* buf; - uLong len; -{ - linkedlist_datablock_internal* ldi; - const unsigned char* from_copy; - - if (ll==NULL) - return ZIP_INTERNALERROR; - - if (ll->last_block == NULL) - { - ll->first_block = ll->last_block = allocate_new_datablock(); - if (ll->first_block == NULL) - return ZIP_INTERNALERROR; - } - - ldi = ll->last_block; - from_copy = (unsigned char*)buf; - - while (len>0) - { - uInt copy_this; - uInt i; - unsigned char* to_copy; - - if (ldi->avail_in_this_block==0) - { - ldi->next_datablock = allocate_new_datablock(); - if (ldi->next_datablock == NULL) - return ZIP_INTERNALERROR; - ldi = ldi->next_datablock ; - ll->last_block = ldi; - } - - if (ldi->avail_in_this_block < len) - copy_this = (uInt)ldi->avail_in_this_block; - else - copy_this = (uInt)len; - - to_copy = &(ldi->data[ldi->filled_in_this_block]); - - for (i=0;ifilled_in_this_block += copy_this; - ldi->avail_in_this_block -= copy_this; - from_copy += copy_this ; - len -= copy_this; - } - return ZIP_OK; -} - - - -/****************************************************************************/ - -#ifndef NO_ADDFILEINEXISTINGZIP -/* =========================================================================== - Inputs a long in LSB order to the given file - nbByte == 1, 2 or 4 (byte, short or long) -*/ - -local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, uLong x, int nbByte)); -local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong x; - int nbByte; -{ - unsigned char buf[4]; - int n; - for (n = 0; n < nbByte; n++) - { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - if (x != 0) - { /* data overflow - hack for ZIP64 (X Roche) */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } - - if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) - return ZIP_ERRNO; - else - return ZIP_OK; -} - -local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); -local void ziplocal_putValue_inmemory (dest, x, nbByte) - void* dest; - uLong x; - int nbByte; -{ - unsigned char* buf=(unsigned char*)dest; - int n; - for (n = 0; n < nbByte; n++) { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - - if (x != 0) - { /* data overflow - hack for ZIP64 */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } -} - -/****************************************************************************/ - - -local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) - const tm_zip* ptm; - uLong dosDate; -{ - uLong year = (uLong)ptm->tm_year; - if (year>1980) - year-=1980; - else if (year>80) - year-=80; - return - (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | - ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); -} - - -/****************************************************************************/ - -local int ziplocal_getByte OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - int *pi; -{ - unsigned char c; - int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return ZIP_OK; - } - else - { - if (ZERROR(*pzlib_filefunc_def,filestream)) - return ZIP_ERRNO; - else - return ZIP_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int ziplocal_getShort OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int ziplocal_getLong OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong ziplocal_SearchCentralDir OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream)); - -local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} -#endif /* !NO_ADDFILEINEXISTINGZIP*/ - -/************************************************************/ -extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def) - const char *pathname; - int append; - zipcharpc* globalcomment; - zlib_filefunc_def* pzlib_filefunc_def; -{ - zip_internal ziinit; - zip_internal* zi; - int err=ZIP_OK; - - - if (pzlib_filefunc_def==NULL) - fill_fopen_filefunc(&ziinit.z_filefunc); - else - ziinit.z_filefunc = *pzlib_filefunc_def; - - ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) - (ziinit.z_filefunc.opaque, - pathname, - (append == APPEND_STATUS_CREATE) ? - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); - - if (ziinit.filestream == NULL) - return NULL; - ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); - ziinit.in_opened_file_inzip = 0; - ziinit.ci.stream_initialised = 0; - ziinit.number_entry = 0; - ziinit.add_position_when_writting_offset = 0; - init_linkedlist(&(ziinit.central_dir)); - - - zi = (zip_internal*)ALLOC(sizeof(zip_internal)); - if (zi==NULL) - { - ZCLOSE(ziinit.z_filefunc,ziinit.filestream); - return NULL; - } - - /* now we add file in a zipfile */ -# ifndef NO_ADDFILEINEXISTINGZIP - ziinit.globalcomment = NULL; - if (append == APPEND_STATUS_ADDINZIP) - { - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory */ - uLong central_pos,uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry; - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - uLong size_comment; - - central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); - if (central_pos==0) - err=ZIP_ERRNO; - - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((number_entry_CD!=number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* zipfile global comment length */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((central_pos0) - { - ziinit.globalcomment = ALLOC(size_comment+1); - if (ziinit.globalcomment) - { - size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); - ziinit.globalcomment[size_comment]=0; - } - } - - byte_before_the_zipfile = central_pos - - (offset_central_dir+size_central_dir); - ziinit.add_position_when_writting_offset = byte_before_the_zipfile; - - { - uLong size_central_dir_to_read = size_central_dir; - size_t buf_size = SIZEDATA_INDATABLOCK; - void* buf_read = (void*)ALLOC(buf_size); - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - offset_central_dir + byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - while ((size_central_dir_to_read>0) && (err==ZIP_OK)) - { - uLong read_this = SIZEDATA_INDATABLOCK; - if (read_this > size_central_dir_to_read) - read_this = size_central_dir_to_read; - if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) - err=ZIP_ERRNO; - - if (err==ZIP_OK) - err = add_data_in_datablock(&ziinit.central_dir,buf_read, - (uLong)read_this); - size_central_dir_to_read-=read_this; - } - TRYFREE(buf_read); - } - ziinit.begin_pos = byte_before_the_zipfile; - ziinit.number_entry = number_entry_CD; - - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - } - - if (globalcomment) - { - *globalcomment = ziinit.globalcomment; - } -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - - if (err != ZIP_OK) - { -# ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - TRYFREE(zi); - return NULL; - } - else - { - *zi = ziinit; - return (zipFile)zi; - } -} - -extern zipFile ZEXPORT zipOpen (pathname, append) - const char *pathname; - int append; -{ - return zipOpen2(pathname,append,NULL,NULL); -} - -extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; - int raw; - int windowBits; - int memLevel; - int strategy; - const char* password; - uLong crcForCrypting; -{ - zip_internal* zi; - uInt size_filename; - uInt size_comment; - uInt i; - int err = ZIP_OK; - -# ifdef NOCRYPT - if (password != NULL) - return ZIP_PARAMERROR; -# endif - - if (file == NULL) - return ZIP_PARAMERROR; - if ((method!=0) && (method!=Z_DEFLATED)) - return ZIP_PARAMERROR; - - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - if (err != ZIP_OK) - return err; - } - - - if (filename==NULL) - filename="-"; - - if (comment==NULL) - size_comment = 0; - else - size_comment = (uInt)strlen(comment); - - size_filename = (uInt)strlen(filename); - - if (zipfi == NULL) - zi->ci.dosDate = 0; - else - { - if (zipfi->dosDate != 0) - zi->ci.dosDate = zipfi->dosDate; - else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); - } - - zi->ci.flag = 0; - if ((level==8) || (level==9)) - zi->ci.flag |= 2; - if ((level==2)) - zi->ci.flag |= 4; - if ((level==1)) - zi->ci.flag |= 6; - if (password != NULL) - zi->ci.flag |= 1; - - zi->ci.crc32 = 0; - zi->ci.method = method; - zi->ci.encrypt = 0; - zi->ci.stream_initialised = 0; - zi->ci.pos_in_buffered_data = 0; - zi->ci.raw = raw; - zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; - zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + - size_extrafield_global + size_comment; - zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); - - ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); - /* version info */ - ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); - ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); - ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); - ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); - ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); - ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ - ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ - ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ - ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); - ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); - ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); - ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ - - if (zipfi==NULL) - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); - else - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); - - if (zipfi==NULL) - ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); - else - ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); - - ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); - - for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = - *(((const char*)extrafield_global)+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ - size_extrafield_global+i) = *(comment+i); - if (zi->ci.central_header == NULL) - return ZIP_INTERNALERROR; - - /* write the local header */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); - - if ((err==ZIP_OK) && (size_filename>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) - err = ZIP_ERRNO; - - if ((err==ZIP_OK) && (size_extrafield_local>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) - !=size_extrafield_local) - err = ZIP_ERRNO; - - zi->ci.stream.avail_in = (uInt)0; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - zi->ci.stream.total_in = 0; - zi->ci.stream.total_out = 0; - - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - zi->ci.stream.zalloc = (alloc_func)0; - zi->ci.stream.zfree = (free_func)0; - zi->ci.stream.opaque = (voidpf)0; - - if (windowBits>0) - windowBits = -windowBits; - - err = deflateInit2(&zi->ci.stream, level, - Z_DEFLATED, windowBits, memLevel, strategy); - - if (err==Z_OK) - zi->ci.stream_initialised = 1; - } -# ifndef NOCRYPT - zi->ci.crypt_header_size = 0; - if ((err==Z_OK) && (password != NULL)) - { - unsigned char bufHead[RAND_HEAD_LEN]; - unsigned int sizeHead; - zi->ci.encrypt = 1; - zi->ci.pcrc_32_tab = get_crc_table(); - /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ - - sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); - zi->ci.crypt_header_size = sizeHead; - - if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) - err = ZIP_ERRNO; - } -# endif - - if (err==Z_OK) - zi->in_opened_file_inzip = 1; - return err; -} - -extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; - int raw; -{ - return zipOpenNewFileInZip3 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; -{ - return zipOpenNewFileInZip2 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0); -} - -local int zipFlushWriteBuffer(zi) - zip_internal* zi; -{ - int err=ZIP_OK; - - if (zi->ci.encrypt != 0) - { -#ifndef NOCRYPT - uInt i; - int t; - for (i=0;ici.pos_in_buffered_data;i++) - zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, - zi->ci.buffered_data[i],t); -#endif - } - if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) - !=zi->ci.pos_in_buffered_data) - err = ZIP_ERRNO; - zi->ci.pos_in_buffered_data = 0; - return err; -} - -extern int ZEXPORT zipWriteInFileInZip (file, buf, len) - zipFile file; - const void* buf; - unsigned len; -{ - zip_internal* zi; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - - zi->ci.stream.next_in = (void*)buf; - zi->ci.stream.avail_in = len; - zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); - - while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) - { - if (zi->ci.stream.avail_out == 0) - { - if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - - - if(err != ZIP_OK) - break; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_NO_FLUSH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - - } - else - { - uInt copy_this,i; - if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) - copy_this = zi->ci.stream.avail_in; - else - copy_this = zi->ci.stream.avail_out; - for (i=0;ici.stream.next_out)+i) = - *(((const char*)zi->ci.stream.next_in)+i); - { - zi->ci.stream.avail_in -= copy_this; - zi->ci.stream.avail_out-= copy_this; - zi->ci.stream.next_in+= copy_this; - zi->ci.stream.next_out+= copy_this; - zi->ci.stream.total_in+= copy_this; - zi->ci.stream.total_out+= copy_this; - zi->ci.pos_in_buffered_data += copy_this; - } - } - } - - return err; -} - -extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) - zipFile file; - uLong uncompressed_size; - uLong crc32; -{ - zip_internal* zi; - uLong compressed_size; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - zi->ci.stream.avail_in = 0; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - while (err==ZIP_OK) - { - uLong uTotalOutBefore; - if (zi->ci.stream.avail_out == 0) - { - if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_FINISH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - - if (err==Z_STREAM_END) - err=ZIP_OK; /* this is normal */ - - if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) - if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) - err = ZIP_ERRNO; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - err=deflateEnd(&zi->ci.stream); - zi->ci.stream_initialised = 0; - } - - if (!zi->ci.raw) - { - crc32 = (uLong)zi->ci.crc32; - uncompressed_size = (uLong)zi->ci.stream.total_in; - } - compressed_size = (uLong)zi->ci.stream.total_out; -# ifndef NOCRYPT - compressed_size += zi->ci.crypt_header_size; -# endif - - ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ - ziplocal_putValue_inmemory(zi->ci.central_header+20, - compressed_size,4); /*compr size*/ - if (zi->ci.stream.data_type == Z_ASCII) - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); - ziplocal_putValue_inmemory(zi->ci.central_header+24, - uncompressed_size,4); /*uncompr size*/ - - if (err==ZIP_OK) - err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, - (uLong)zi->ci.size_centralheader); - free(zi->ci.central_header); - - if (err==ZIP_OK) - { - long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); - if (ZSEEK(zi->z_filefunc,zi->filestream, - zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if (err==ZIP_OK) /* compressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - - if (ZSEEK(zi->z_filefunc,zi->filestream, - cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - } - - zi->number_entry ++; - zi->in_opened_file_inzip = 0; - - return err; -} - -extern int ZEXPORT zipCloseFileInZip (file) - zipFile file; -{ - return zipCloseFileInZipRaw (file,0,0); -} - -extern int ZEXPORT zipClose (file, global_comment) - zipFile file; - const char* global_comment; -{ - zip_internal* zi; - int err = 0; - uLong size_centraldir = 0; - uLong centraldir_pos_inzip; - uInt size_global_comment; - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - } - -#ifndef NO_ADDFILEINEXISTINGZIP - if (global_comment==NULL) - global_comment = zi->globalcomment; -#endif - if (global_comment==NULL) - size_global_comment = 0; - else - size_global_comment = (uInt)strlen(global_comment); - - centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); - if (err==ZIP_OK) - { - linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; - while (ldi!=NULL) - { - if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream, - ldi->data,ldi->filled_in_this_block) - !=ldi->filled_in_this_block ) - err = ZIP_ERRNO; - - size_centraldir += ldi->filled_in_this_block; - ldi = ldi->next_datablock; - } - } - free_datablock(zi->central_dir.first_block); - - if (err==ZIP_OK) /* Magic End */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* number of this disk */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - - if (err==ZIP_OK) /* total number of entries in the central dir */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - - if (err==ZIP_OK) /* size of the central directory */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the - starting disk number */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, - (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); - - if (err==ZIP_OK) /* zipfile comment length */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); - - if ((err==ZIP_OK) && (size_global_comment>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream, - global_comment,size_global_comment) != size_global_comment) - err = ZIP_ERRNO; - - if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) - if (err == ZIP_OK) - err = ZIP_ERRNO; - -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); -#endif - TRYFREE(zi); - - return err; -} diff --git a/PluginsCode/iOS/ZipArchive/minizip/zip.h b/PluginsCode/iOS/ZipArchive/minizip/zip.h deleted file mode 100644 index cd38b67..0000000 --- a/PluginsCode/iOS/ZipArchive/minizip/zip.h +++ /dev/null @@ -1,235 +0,0 @@ -/* zip.h -- IO for compress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This unzip package allow creates .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Multi volume ZipFile (span) are not supported. - Encryption compatible with pkzip 2.04g only supported - Old compressions used by old PKZip 1.x are not supported - - For uncompress .zip file, look at unzip.h - - - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.html for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -*/ - -/* for more info about .ZIP format, see - http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip - http://www.info-zip.org/pub/infozip/doc/ - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip -*/ - -#ifndef _zip_H -#define _zip_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagzipFile__ { int unused; } zipFile__; -typedef zipFile__ *zipFile; -#else -typedef voidp zipFile; -#endif - -#define ZIP_OK (0) -#define ZIP_EOF (0) -#define ZIP_ERRNO (Z_ERRNO) -#define ZIP_PARAMERROR (-102) -#define ZIP_BADZIPFILE (-103) -#define ZIP_INTERNALERROR (-104) - -#ifndef DEF_MEM_LEVEL -# if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -# else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -# endif -#endif -/* default memLevel */ - -/* tm_zip contain date/time info */ -typedef struct tm_zip_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_zip; - -typedef struct -{ - tm_zip tmz_date; /* date in understandable format */ - uLong dosDate; /* if dos_date == 0, tmu_date is used */ -/* uLong flag; */ /* general purpose bit flag 2 bytes */ - - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ -} zip_fileinfo; - -typedef const char* zipcharpc; - - -#define APPEND_STATUS_CREATE (0) -#define APPEND_STATUS_CREATEAFTER (1) -#define APPEND_STATUS_ADDINZIP (2) - -extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); -/* - Create a zipfile. - pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on - an Unix computer "zlib/zlib113.zip". - if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip - will be created at the end of the file. - (useful if the file contain a self extractor code) - if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will - add files in existing zip (be sure you don't add file that doesn't exist) - If the zipfile cannot be opened, the return value is NULL. - Else, the return value is a zipFile Handle, usable with other function - of this zip package. -*/ - -/* Note : there is no delete function into a zipfile. - If you want delete file into a zipfile, you must open a zipfile, and create another - Of couse, you can use RAW reading and writing to copy the file you did not want delte -*/ - -extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, - int append, - zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); - -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level)); -/* - Open a file in the ZIP for writing. - filename : the filename in zip (if NULL, '-' without quote will be used - *zipfi contain supplemental information - if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local - contains the extrafield data the the local header - if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global - contains the extrafield data the the local header - if comment != NULL, comment contain the comment string - method contain the compression method (0 for store, Z_DEFLATED for deflate) - level contain the level of compression (can be Z_DEFAULT_COMPRESSION) -*/ - - -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw)); - -/* - Same than zipOpenNewFileInZip, except if raw=1, we write raw file - */ - -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCtypting)); - -/* - Same than zipOpenNewFileInZip2, except - windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 - password : crypting password (NULL for no crypting) - crcForCtypting : crc of file to compress (needed for crypting) - */ - - -extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, - const void* buf, - unsigned len)); -/* - Write data in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); -/* - Close the current file in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, - uLong uncompressed_size, - uLong crc32)); -/* - Close the current file in the zipfile, for fiel opened with - parameter raw=1 in zipOpenNewFileInZip2 - uncompressed_size and crc32 are value for the uncompressed size -*/ - -extern int ZEXPORT zipClose OF((zipFile file, - const char* global_comment)); -/* - Close the zipfile -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _zip_H */ From b4b37757ce027952cc8e92eb0b5d211879a41012 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 21:20:42 +0900 Subject: [PATCH 11/18] Update Readme --- README.md | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 845fad5..12e580a 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,53 @@ -UniZip +# UniZip ======== UniZip is zipper for unity3d. ![unity zip](https://github.com/rumaniel/UnityZip/blob/master/logo.jpg) -#supported +## Getting Started + +Copy all itmes from Assets folder to your Unity3d Assets folder. + +## supported - iOS. - Android. -- Mac.and probably windows. +- Standalone(Includes Mac and Windows) -#example +## example --unzip +### unzip -``` +```C# string zipfilePath = Application.temporaryCachePath + "/args.zip" string exportLocation = Application.temporaryCachePath + "/dir" -ZipUtil.Unzip ( zipfilePath, exportLocation); +ZipUtil.Unzip(zipfilePath, exportLocation); ``` --zip +### zip -``` +```C# string exportZip = Application.temporaryCachePath + "/dir/args.zip"; -string[] files = new string[]{ Application.temporaryCachePath + "/dir/args.txt"} +string[] files = new string[] { Application.temporaryCachePath + "/dir/args.txt" } ZipUtil.Zip (exportZip, files); ``` -#TODO -- [ ] iOS zip -- [ ] support async zip/unzip -- [ ] inform progress while async job -- [ ] inform result -- [ ] support password -- [ ] submit assetstore -- [ ] Directry support - -#License - -This software is released under the MIT License, see LICENSE. +## TODO + +- [ ] Support async zip/unzip +- [ ] Inform progress while async job +- [ ] Inform result +- [ ] Support password +- [ ] Submit assetstore +- [ ] Directory support + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details + +## Acknowledgments + +* It's inspired of [SSZipArchive](https://github.com/ZipArchive/ZipArchive). + From 92c354a2574782ddf7c11807c3dd0d4718378a14 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 21:22:43 +0900 Subject: [PATCH 12/18] Update Readme Fix mistypo --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 12e580a..b0915e5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # UniZip -======== UniZip is zipper for unity3d. @@ -20,8 +19,8 @@ Copy all itmes from Assets folder to your Unity3d Assets folder. ### unzip ```C# -string zipfilePath = Application.temporaryCachePath + "/args.zip" -string exportLocation = Application.temporaryCachePath + "/dir" +string zipfilePath = Application.temporaryCachePath + "/args.zip"; +string exportLocation = Application.temporaryCachePath + "/dir"; ZipUtil.Unzip(zipfilePath, exportLocation); ``` @@ -34,6 +33,7 @@ string[] files = new string[] { Application.temporaryCachePath + "/dir/args.txt" ZipUtil.Zip (exportZip, files); ``` + ## TODO - [ ] Support async zip/unzip From 2f0a07b9560383d48613e204ecd2915e0a943650 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 21:27:49 +0900 Subject: [PATCH 13/18] Update Readme Fix mistype --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b0915e5..11c56dc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ UniZip is zipper for unity3d. ## Getting Started -Copy all itmes from Assets folder to your Unity3d Assets folder. +Copy all items from the Assets folder to your Unity3d Assets folder. ## supported From 886332748b6dfd3c5a208ffda8787a58c628050a Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 21:44:54 +0900 Subject: [PATCH 14/18] Update zip method on c# --- Assets/Plugins/Zip.cs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Assets/Plugins/Zip.cs b/Assets/Plugins/Zip.cs index 0e60fba..26cd30f 100644 --- a/Assets/Plugins/Zip.cs +++ b/Assets/Plugins/Zip.cs @@ -55,6 +55,46 @@ public static void Zip (string zipFileName, params string[] files) string path = Path.GetDirectoryName(zipFileName); Directory.CreateDirectory (path); + if (files.Length > 0) + { + if (File.Exists(files[0])) + { + // Get the first file in the list so we can get the root directory + string strRootDirectory = Path.GetDirectoryName(files[0]); + + // Set up a temporary directory to save the files to (that we will eventually zip up) + DirectoryInfo dirTemp = Directory.CreateDirectory(strRootDirectory + "/" + DateTime.Now.ToString("yyyyMMddhhmmss")); + + // Copy all files to the temporary directory + foreach (string strFilePath in files) + { + if (!File.Exists(strFilePath)) + { + throw new Exception(string.Format("File {0} does not exist", strFilePath)); + } + string strDestinationFilePath = Path.Combine(dirTemp.FullName, Path.GetFileName(strFilePath)); + File.Copy(strFilePath, strDestinationFilePath); + } + + // Create the zip file using the temporary directory + if (!zipFileName.EndsWith(".zip")) { zipFileName += ".zip"; } + string strZipPath = Path.Combine(strRootDirectory, zipFileName); + if (File.Exists(strZipPath)) { File.Delete(strZipPath); } + ZipFile.CreateFromDirectory(dirTemp.FullName, strZipPath, System.IO.Compression.CompressionLevel.Fastest, false); + + // Delete the temporary directory + dirTemp.Delete(true); + } + else + { + throw new Exception(string.Format("File {0} does not exist", files[0])); + } + } + else + { + throw new Exception("You must specify at least one file to zip."); + } + // todo // System.IO.Compression.ZipFile.ExtractToDirectory(srcPath, destPath); From a60a5ad8c8453a9e8ed79f162dbc3a76840280b4 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 21:50:09 +0900 Subject: [PATCH 15/18] Remove unused codes on Zip.cs --- Assets/Plugins/Zip.cs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Assets/Plugins/Zip.cs b/Assets/Plugins/Zip.cs index 26cd30f..c9f8404 100644 --- a/Assets/Plugins/Zip.cs +++ b/Assets/Plugins/Zip.cs @@ -49,12 +49,10 @@ public static void Unzip (string zipFilePath, string location) #endif } +// https://stackoverflow.com/a/46119361/2655055 public static void Zip (string zipFileName, params string[] files) { #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX - string path = Path.GetDirectoryName(zipFileName); - Directory.CreateDirectory (path); - if (files.Length > 0) { if (File.Exists(files[0])) @@ -94,17 +92,6 @@ public static void Zip (string zipFileName, params string[] files) { throw new Exception("You must specify at least one file to zip."); } - - // todo - // System.IO.Compression.ZipFile.ExtractToDirectory(srcPath, destPath); - - - // using (ZipFile zip = new ZipFile()) { - // foreach (string file in files) { - // zip.AddFile(file, ""); - // } - // zip.Save (zipFileName); - // } #elif UNITY_ANDROID using (AndroidJavaClass zipper = new AndroidJavaClass ("com.tsw.zipper")) { { From fb055ba3b062542d177b68db154a58435176a4f8 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 8 Jun 2019 22:21:56 +0900 Subject: [PATCH 16/18] Add Examples --- Assets/Example.meta | 8 + Assets/Example/Resources.meta | 8 + Assets/Example/Resources/args.txt | 151 ++++ Assets/Example/Resources/args.txt.meta | 7 + Assets/Example/Scene.meta | 8 + Assets/Example/Scene/Test.unity | 873 ++++++++++++++++++++++ Assets/Example/Scene/Test.unity.meta | 7 + Assets/Example/Scripts.meta | 8 + Assets/Example/Scripts/TestScript.cs | 23 + Assets/Example/Scripts/TestScript.cs.meta | 11 + README.md | 8 +- 11 files changed, 1108 insertions(+), 4 deletions(-) create mode 100644 Assets/Example.meta create mode 100644 Assets/Example/Resources.meta create mode 100644 Assets/Example/Resources/args.txt create mode 100644 Assets/Example/Resources/args.txt.meta create mode 100644 Assets/Example/Scene.meta create mode 100644 Assets/Example/Scene/Test.unity create mode 100644 Assets/Example/Scene/Test.unity.meta create mode 100644 Assets/Example/Scripts.meta create mode 100644 Assets/Example/Scripts/TestScript.cs create mode 100644 Assets/Example/Scripts/TestScript.cs.meta diff --git a/Assets/Example.meta b/Assets/Example.meta new file mode 100644 index 0000000..fc21e11 --- /dev/null +++ b/Assets/Example.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9777a06e8a55a4a0f9b5e63be789a390 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Resources.meta b/Assets/Example/Resources.meta new file mode 100644 index 0000000..89685b2 --- /dev/null +++ b/Assets/Example/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61275dc97e3a44d3baa79be9e5296193 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Resources/args.txt b/Assets/Example/Resources/args.txt new file mode 100644 index 0000000..fe1fba5 --- /dev/null +++ b/Assets/Example/Resources/args.txt @@ -0,0 +1,151 @@ + ,` + ,:::::::::,` + :::::::::::::::::,` + .::::::::::::::::::::::::::.` + :::::::::::::::::::::::::::::::::::,` + `:::::::::::::::::::::::::::::::::::::::::::. + ,:::::::::::::::::::::::::::::::::::::::::::::::::::,` + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,. + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.` + `::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,` + `::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.` + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,` + ,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,. + `,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,` + `,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,. + ,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.` + .::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,` + .,,,,,,,,,:,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.` + .,,,,,,,,,,,,,,,,::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,` + ,,,,,,,,,,,,,,,,,,,,,,,,,,::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::'; + `:,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::''''; + .::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+'''''; + ::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;+'''''''; + :::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::;+'''''''''; + `::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::'+'''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::+''''''''''''''; + ,:::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::+''''''''''''''''; + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::;+''''''''''''''''''; + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::'+''''''''''''''''''''; + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,,,,,,,,,,,,,,:,,:,,::::::::'+;'''''''''''''''''''''; + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:++;'''''''''''''''''''''''; + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,:,,,,,,,:::,,,,,,,,,,,,,,,,,,,,::;;;''''''''''''''''''''''''; + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,,,,,,,,,,::;;;;;'''''''''''''''''''''''''; + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::,,::;;;;;;;'''''''''''''''''''''''''; + ,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,,,,,,:,,,:;;;;;;;;;;;'''''''''''''''''''''''''; + .:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,::;;;;;;;;;;;;;'''''''''''''''''''''''''; + .:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,:,::;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+;;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::'';;;;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+;;;'';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .:::::::::::::::::::::::::::::::::::::::::::,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+';;;''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,:::::::::::::::::::::::::::::::::::::::::::::::::,,,,,:::,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::'+;;;'''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,:::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++;;;'''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::++;;;'''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::++;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::+';;;;''''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::+';;;;''''''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,:::::::::::::::::::::::+;;;;;;;;'''''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,::::::::::::::,+;;;;;;;;;;;''''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,,,::,,,,+:;;;;;;;;;;;;''''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,,,,,,,,';;;;;;;;;;;;;;;''''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,,,,,,,.,;;;;;;;;;;;;;;;;;;;;'';'';;''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + .:::: :::::: `:::::: ::::::::::::::::` ::::::::: :::::: ::: :::::: `:,,,,:;;;;;;;;. ''';;;;;; `;;;;;;'': '''''''''; + .:::: :::::: `:::::: ::::::::::::::: ::::::::: :::::: ::: :::::: :::,,;;;;;;;;;. ;'';;;;;; `;;;;;''', ''''''''; + ,:::: :::::: `:::::: ,:::::::::::::: ::::::::: :::::: ::: :::::: :::,,:;;;;;;;;. ''';;;;;; `;;;''''', '''''''; + ,:::: :::::: `:::::: :::::::::::::: ::::::::: :::::: ::: :::::: :::,,:;;;;;;;;. ''';;;;;; `;''''''', :''''''; + ,:::: :::::: `:::::: `::::::::::::: ::::::::: :::::: ::: :::::: :::,,;;;;;;;;;. ''';;;;;; `'''''''', ''''''; + ,:::: :::::: `:::::: ::::::::::::: ::::::::: :::::: ::: :::::: :::,,:;;;;;;;;. ''';;;;;; `'''''''', ;'''''; + ,:::: :::::: `:::::: `:::::::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;;;';' ''';;;;;; `'''''''', :'''' ,'''''; + ,:::: :::::: `:::::: :::::::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;'''': ,''';;;;'' `'''''''', :'''', '''''; + ,:::: :::::: `:::::: ::::::::::: ::::::::: :::::::::::. ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;''''` ;''';;'''' `'''''''', :''''' '''''; + ,:::: :::::: `:::::: ,:::::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;'''' '''''''''' `'''''''', :''''' '''''; + ,:::: :::::: `:::::: :::::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,;;;;;;;;;;;;;;;;;''; `'''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: .::::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,;;;;;;;;;;;;;;;;;''. ;'''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: ::::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,;;;;;;;;;;;;;;;;;;' ''''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: :::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,;;;;;;;;;;;;;;;;;'; `''''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: :::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;;': ,''''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: ::::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;;; ;''''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: ,:::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,:;;;;;;;;;;;;;;;;; '''''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: :::::: ::::::::: :::::::::::, ,:::::::: :::::: :::,,;;;;;;;;;;;;;;;;'; .'''''''''''' `'''''''', :'''''` '''''; + ,:::: :::::: `:::::: `::::: ::::::::: :::::::::::, ,:::::::: :::::: `:::,,:;;;;;;;;;;;;;;''. ;'''''''''''' `'''''''', :''''' '''''; + ,:::: :::::: `:::::: ::::: ::::::::: :::::::::::, ,::::::::` ,::::, `:::,,:;;;;;;;;;;;;;;;; ''''''''''''' `'''''''', :''''' '''''; + ,:::: :::::: `:::::: `:::: ::::::::: :::::::::::, ,::::::::` `:::: .:::,,;;;;;;;;;;;;;;;;; `''''''''''''' `'''''''', :'''': '''''; + ,:::: :::::: `:::::: :::: ::::::::: :::::::::::, ,::::::::, :::: ,:::,,:;;;;;;;;;;;;;;;, :''''''''''''' `'''''''', :'''' `'''''; + ,:::: :::::: `:::::: ::: ::::::::: :::::::::::, ,::::::::: ,. ::::,,:;;;;;;;;;;;;;;;` ;''''''''''''' `'''''''', :;;; :'''''; + ,:::: :::::: `:::::: . ,:: ::::::::: :::::::::::, ,::::::::: ::::,,;;;;;;;;;;;;;;;; '''''''''''''' `'''''''', ''''''; + ,:::: :::::: `:::::: ., :: ::::::::: :::::::::::, ,:::::::::. .::::,,:;;;;;;;;;;;;;;: ,'''''''''''''' `'''''''', `''''''; + ,:::: :::::: `:::::: .: `: ::::::::: :::::::::::, ,:::::::::: :::::,,:;;;;;;;;;;;;;;` ;'''''''''''''' `'''''''', '''''''; + ,:::: :::::: `:::::: .:: : ::::::::: :::::::::::, ,::::::::::: ::::::,,;;;;;;;;;;;;;;; ''''''''''''''' `'''''''', ,'''''''; + ,:::: :::::: `:::::: .::` ` ::::::::: :::::::::::, ,:::::::::::: :::::::,,:;;;;;;;;;;;;;; `''''''''''''''' `'''''''', ,''''''''; + ,:::: :::::: `:::::: .::: ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;;;;;;. ;''''''''''''''' `'''''''', ,;;;;;;''''''''''; + ,:::: :::::: `:::::: .:::. ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;;;;;; '''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .:::: ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;;;;;; '''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .::::, ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;;;;;: :'''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .:::::` ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;;;;; ;'''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .:::::: ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;;;;; ';''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .::::::` ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;;;; .;;''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;;;. ;';''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .:::::::. ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;;; ;';''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .:::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;;; `';;''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .::::::::, ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;;, :';;''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;; ;'';''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .:::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;; ;;''''''''''''''''' `'''''''', :''''''''''''''''; + ,:::: :::::: `:::::: .::::::::::` ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;: ,;'''''''''''''''''' `'''''''', :''''''''''''''''; + ,::::` ,::::. .:::::: .::::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;;` ;';''''''''''''''''' `'''''''', :''''''''''''''''; + ,::::. `:::: ,:::::: .:::::::::::. ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;; ;';;'''''''''''''''' `'''''''', :''''''''''''''''; + ,::::: ,::. ::::::: .:::::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;; .;;;''';;';;''''''''' `'''''''', :''''''''''''''''; + ,::::: ::::::: .::::::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;. ` ` ```''''''''' `'''''''', :''''''''''''''''; + ,:::::` .::::::: .:::::::::::::` ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;. ''''''''' `'''''''', :''''''''''''''''; + ,:::::: :::::::: .:::::::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;. ''''''''' `'''''''', :''''''''''''''''; + ,::::::` .:::::::: .::::::::::::::` ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;. ;'''''''' `'''''''', :''''''''''''''''; + ,::::::: ::::::::: .::::::::::::::: ::::::::: :::::::::::. ,:::::::::::::: :::::::::,,:;;;;;;;;. ''''''''' `'''''''', :''''''''''''''''; + ,::::::::` .:::::::::: .:::::::::::::::. ::::::::: :::::::::::, ,:::::::::::::: :::::::::,,:;;;;;;;;. ''''''''' `;''';;'': :''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;;;;;;';;''''''''';;'';''';;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;''''''''''''''''''''''';;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;'''''''''''''''''''';;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;'''''''''''''''''';;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;'''''''''''''''';;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;'''''''''''''';;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''''''; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;''''''''''''''''''''''''+` + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;''''''''''''''''''''''+. + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''''''` + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''''''+; + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;''''''''''''''''' + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''''': + ,;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;'''''''''''': + ,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''''''''''';;;;;;;;;;;;;;;;;;''''';'''+, + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;''''';;''''';;;;;;;;;;;;;;;;;;'''''''+` + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;''''';;''''';;;;;;;;;;;;;;;;;;'''''+` + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;''''';;''''';;;;;;;;;;;;;;;;;;'''' + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;''''';;''''';;;;;;;;;;;;;;;;;'': + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''';;;''''';;;;;;;;;;;;;;;;'; + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''';;;''''';;;;;;;;;;;;;''. + :;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;'''';;;''''';;;;;;;;;;;;', + :;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;''';;'''''';;;;;;;;;;'` + ,''';;;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;''';;'''''';;;;;;;'' + .:'';;;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;''';;'''''';;;;;;'` + `,'';;;;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;;;;;;'''''';;;'' + .;'';;;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,,:;;;;;;;;;;;;;;;;;;;;;;;''';'''': + `:''';;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;;;;;;;;;;'';''': + .;'';;;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;;;;;;;;;;''''. + `:'';;;;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;;;;;;;;'''', + ,''';;;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;;;;;;;''+` + `:'';;;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;;;;'''' + `,'';;;;;:::::::::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;;;''' + .;'';;;;:::::::::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;;;''; + `:'';;;;:::::::::::::::::::::::::::::::::::::,:;;;;;;;;;;;;'', + .;';;;;;:::::::::::::::::::::::::::::::,:;;;;;;;;;;'', + `:''';;;:::::::::::::::::::::::::,:;;;;;;;;''` + ,;';;;;;:::::::::::::::::::,:;;;;;;''. + `:'';;;;:::::::::::::,:;;;;''` + ,'';;;;;::::::,:;;'; + .:'';;;;::;'' + `,'': \ No newline at end of file diff --git a/Assets/Example/Resources/args.txt.meta b/Assets/Example/Resources/args.txt.meta new file mode 100644 index 0000000..5fad3e3 --- /dev/null +++ b/Assets/Example/Resources/args.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: be24da54cd68a4cea9ab2f5294b8ab93 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Scene.meta b/Assets/Example/Scene.meta new file mode 100644 index 0000000..4a5046b --- /dev/null +++ b/Assets/Example/Scene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a8b1d95a6b7e4f6ca548d5088480465 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Scene/Test.unity b/Assets/Example/Scene/Test.unity new file mode 100644 index 0000000..686a394 --- /dev/null +++ b/Assets/Example/Scene/Test.unity @@ -0,0 +1,873 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.49641287, b: 0.5748173, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &216987548 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 216987549} + - component: {fileID: 216987551} + - component: {fileID: 216987550} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &216987549 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216987548} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1192040340} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &216987550 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216987548} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Zip +--- !u!222 &216987551 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 216987548} + m_CullTransparentMesh: 0 +--- !u!1 &521549963 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 521549965} + - component: {fileID: 521549964} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &521549964 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 521549963} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &521549965 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 521549963} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1192040339 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1192040340} + - component: {fileID: 1192040344} + - component: {fileID: 1192040343} + - component: {fileID: 1192040342} + - component: {fileID: 1192040341} + m_Layer: 5 + m_Name: Zip Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1192040340 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192040339} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 216987549} + m_Father: {fileID: 2053988060} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1192040341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192040339} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f68d0afd9c6384e7ca232dfc239a4874, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &1192040342 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192040339} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1192040343} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1192040341} + m_MethodName: Zip + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &1192040343 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192040339} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 +--- !u!222 &1192040344 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192040339} + m_CullTransparentMesh: 0 +--- !u!1 &1442672018 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1442672021} + - component: {fileID: 1442672020} + - component: {fileID: 1442672019} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1442672019 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442672018} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1442672020 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442672018} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1442672021 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442672018} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1668100727 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1668100730} + - component: {fileID: 1668100729} + - component: {fileID: 1668100728} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1668100728 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1668100727} + m_Enabled: 1 +--- !u!20 &1668100729 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1668100727} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1668100730 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1668100727} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1991436030 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1991436031} + - component: {fileID: 1991436035} + - component: {fileID: 1991436034} + - component: {fileID: 1991436033} + - component: {fileID: 1991436032} + m_Layer: 5 + m_Name: Unzip Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1991436031 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991436030} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2073010230} + m_Father: {fileID: 2053988060} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -30} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1991436032 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991436030} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f68d0afd9c6384e7ca232dfc239a4874, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &1991436033 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991436030} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1991436034} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1991436032} + m_MethodName: Unzip + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &1991436034 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991436030} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 +--- !u!222 &1991436035 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1991436030} + m_CullTransparentMesh: 0 +--- !u!1 &2053988056 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2053988060} + - component: {fileID: 2053988059} + - component: {fileID: 2053988058} + - component: {fileID: 2053988057} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2053988057 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2053988056} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1301386320, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &2053988058 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2053988056} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &2053988059 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2053988056} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &2053988060 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2053988056} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1192040340} + - {fileID: 1991436031} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &2073010229 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2073010230} + - component: {fileID: 2073010232} + - component: {fileID: 2073010231} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2073010230 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2073010229} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1991436031} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2073010231 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2073010229} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Unzip +--- !u!222 &2073010232 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2073010229} + m_CullTransparentMesh: 0 diff --git a/Assets/Example/Scene/Test.unity.meta b/Assets/Example/Scene/Test.unity.meta new file mode 100644 index 0000000..66ea5e5 --- /dev/null +++ b/Assets/Example/Scene/Test.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5834819e028f043e4b78efa3cc61d9c6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Scripts.meta b/Assets/Example/Scripts.meta new file mode 100644 index 0000000..6dc56e2 --- /dev/null +++ b/Assets/Example/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58f3620d1e83142c18985f3825503d5a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Scripts/TestScript.cs b/Assets/Example/Scripts/TestScript.cs new file mode 100644 index 0000000..9e69271 --- /dev/null +++ b/Assets/Example/Scripts/TestScript.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class TestScript : MonoBehaviour +{ + public void Zip() + { + string exportZip = Application.temporaryCachePath + "/args.zip"; + string[] files = new string[] { Application.dataPath + "/Example/Resources/args.txt" }; + + ZipUtil.Zip(exportZip, files); + } + + public void Unzip() + { + string zipfilePath = Application.temporaryCachePath + "/args.zip"; + string exportLocation = Application.temporaryCachePath + "/dir"; + + ZipUtil.Unzip(zipfilePath, exportLocation); + } + +} diff --git a/Assets/Example/Scripts/TestScript.cs.meta b/Assets/Example/Scripts/TestScript.cs.meta new file mode 100644 index 0000000..e462090 --- /dev/null +++ b/Assets/Example/Scripts/TestScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f68d0afd9c6384e7ca232dfc239a4874 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index 11c56dc..f310501 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ UniZip is zipper for unity3d. ## Getting Started -Copy all items from the Assets folder to your Unity3d Assets folder. +Copy all items from the Assets/Plugins folder to your Unity3d Assets/Plugins folder. ## supported @@ -28,10 +28,10 @@ ZipUtil.Unzip(zipfilePath, exportLocation); ### zip ```C# -string exportZip = Application.temporaryCachePath + "/dir/args.zip"; -string[] files = new string[] { Application.temporaryCachePath + "/dir/args.txt" } +string exportZip = Application.temporaryCachePath + "/args.zip"; +string[] files = new string[] { Application.dataPath + "/Example/Resources/args.txt" }; -ZipUtil.Zip (exportZip, files); +ZipUtil.Zip(exportZip, files); ``` ## TODO From 895dd7e17d7421842f1b7113974750703b733edb Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Fri, 12 Jul 2019 21:03:52 +0900 Subject: [PATCH 17/18] Update readme add Suport unityhub distribution --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f310501..f59e65b 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ ZipUtil.Zip(exportZip, files); - [ ] Support password - [ ] Submit assetstore - [ ] Directory support +- [ ] Support unityhub distribution ## License From 362bf124cdf5f66d73febc50b06b88282b329df4 Mon Sep 17 00:00:00 2001 From: Rumaniel Date: Sat, 13 Jul 2019 00:30:41 +0900 Subject: [PATCH 18/18] Match code style --- Assets/Plugins/Zip.cs | 49 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/Assets/Plugins/Zip.cs b/Assets/Plugins/Zip.cs index c9f8404..1d48651 100644 --- a/Assets/Plugins/Zip.cs +++ b/Assets/Plugins/Zip.cs @@ -9,17 +9,17 @@ public class ZipUtil { #if UNITY_IPHONE [DllImport("__Internal")] - private static extern void unzip (string zipFilePath, string location); + private static extern void unzip(string zipFilePath, string location); [DllImport("__Internal")] - private static extern void zip (string zipFilePath); + private static extern void zip(string zipFilePath); [DllImport("__Internal")] - private static extern void addZipFile (string addFile); + private static extern void addZipFile(string addFile); #endif - public static void Unzip (string zipFilePath, string location) + public static void Unzip(string zipFilePath, string location) { #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX if (!location.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) @@ -41,16 +41,17 @@ public static void Unzip (string zipFilePath, string location) } #elif UNITY_ANDROID - using (AndroidJavaClass zipper = new AndroidJavaClass ("com.tsw.zipper")) { - zipper.CallStatic ("unzip", zipFilePath, location); + using (AndroidJavaClass zipper = new AndroidJavaClass("com.tsw.zipper")) + { + zipper.CallStatic("unzip", zipFilePath, location); } #elif UNITY_IPHONE - unzip (zipFilePath, location); + unzip(zipFilePath, location); #endif } // https://stackoverflow.com/a/46119361/2655055 - public static void Zip (string zipFileName, params string[] files) + public static void Zip(string zipFileName, params string[] files) { #if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX if (files.Length > 0) @@ -67,42 +68,44 @@ public static void Zip (string zipFileName, params string[] files) foreach (string strFilePath in files) { if (!File.Exists(strFilePath)) - { throw new Exception(string.Format("File {0} does not exist", strFilePath)); - } + string strDestinationFilePath = Path.Combine(dirTemp.FullName, Path.GetFileName(strFilePath)); + File.Copy(strFilePath, strDestinationFilePath); } // Create the zip file using the temporary directory - if (!zipFileName.EndsWith(".zip")) { zipFileName += ".zip"; } + if (!zipFileName.EndsWith(".zip")) + zipFileName += ".zip"; + string strZipPath = Path.Combine(strRootDirectory, zipFileName); - if (File.Exists(strZipPath)) { File.Delete(strZipPath); } + + if (File.Exists(strZipPath)) + File.Delete(strZipPath); + ZipFile.CreateFromDirectory(dirTemp.FullName, strZipPath, System.IO.Compression.CompressionLevel.Fastest, false); // Delete the temporary directory dirTemp.Delete(true); } else - { throw new Exception(string.Format("File {0} does not exist", files[0])); - } } else - { throw new Exception("You must specify at least one file to zip."); - } #elif UNITY_ANDROID - using (AndroidJavaClass zipper = new AndroidJavaClass ("com.tsw.zipper")) { - { - zipper.CallStatic ("zip", zipFileName, files); - } + using (AndroidJavaClass zipper = new AndroidJavaClass("com.tsw.zipper")) + { + zipper.CallStatic("zip", zipFileName, files); } #elif UNITY_IPHONE - foreach (string file in files) { - addZipFile (file); + foreach (string file in files) + { + addZipFile(file); } - zip (zipFileName); + + zip(zipFileName); #endif } }