[Swift]パスワード付きZipファイルを作る。

ZipArchiveを使ってパスワード付きZipファイルを作成します。

https://github.com/ZipArchive/ZipArchive

パスワード付きZipにするとパスワードを正しく入力しても解凍できない問題が発生

元々、以下リンクのZipを使おうと考えてましたが、パスワード付きにすると解凍できないという問題がありました。

https://github.com/marmelroy/Zip

以下issueは上がっているけど、解決されていない状況のようです。

https://github.com/marmelroy/Zip/issues/215

原因は、AES暗号化によるもので、AESが有効の場合は同じライブラリを使って書かれた解凍アプリケーションが必要のようです。

従って、AESを無効にすれば解決しそうですがZipにはそのオプションがないということがわかったのでZipArchiveを使うことにしました。

ZipArchiveでACE無効にする設定

使い方の例はこれ。
ace:falseにすることが肝です。

                            let result = SSZipArchive.createZipFile(
                                    atPath: zipFilePath.path, 
                                    withContentsOfDirectory: raw.path, 
                                    keepParentDirectory: false, 
                                    compressionLevel: 1, 
                                    password: "password", 
                                    aes: false, 
                                    progressHandler: nil)

最初、atPathに圧縮したいフォルダパスを入れていたのでうまくいかなかった。
原因探るために、SSZipArchive.mにブレークはってデバッグしました。
わかったことは、atPathが圧縮先だということでした。

デバッグついでにざっくりソース眺めてみました。
compressionLevelに何を指定すべきなのかよくわからなかったので調べてみると、以下の設定があることが分かりました。これらconstantをswiftから使う方法はないのだろうか。
あと、これコメントが下にあるのなんでだろう。

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

SSZipArchive.hを眺めてみる。ACE無効はディレクトリのみ対応している?

該当箇所はこちら。
引数違いでメソッドが並んでいます。

// 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<NSString *> *)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<NSString *> *)paths withPassword:(nullable NSString *)password;
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;
+ (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;
//suport symlink compress --file
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password keepSymlinks:(BOOL)keeplinks;
//suport symlink compress --directory
+ (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
               keepSymlinks:(BOOL)keeplinks;

元ファイルの指定方法は大きく分けて二つあるようだ。

withFilesAtPaths:(NSArray<NSString *> *)paths
withContentsOfDirectory:(NSString *)directoryPath

Zipの元になるものが、
・複数ファイル
・ディレクトリ
という分類みたい。

ソースを見ていると、複数ファイルを引数にとるメソッドにはACEの設定ができるものがなかった。

つまり、ACE無効にしたい場合は、ディレクトリを引数にとるパターンのものしか使えない。