# 機能設計書 77-ZIP圧縮

## 概要

本ドキュメントは、Godotエンジンにおける ZIP圧縮機能の設計を記述する。ZIPアーカイブの読み取り・作成機能を提供する。

### 本機能の処理概要

ZIP圧縮機能は、ZIPアーカイブファイルの読み取り（展開）と作成（圧縮）を行うユーティリティを提供する。zlibライブラリを内部で使用し、標準的なZIP形式との互換性を確保する。

**業務上の目的・背景**：ゲーム開発では、リソースのパッケージング、MOD配布、セーブデータのバックアップなど様々な場面でアーカイブ機能が必要となる。ZIP圧縮機能は、こうしたアーカイブ操作を標準的な方法で実装するための基盤を提供する。

**機能の利用シーン**：
- ゲームリソースのパッケージ化
- MODファイルの読み込み
- エクスポートデータの圧縮保存
- ダウンロードコンテンツの展開
- バックアップファイルの作成

**主要な処理内容**：
1. ZIPアーカイブを開く（open）
2. ファイル一覧の取得（get_files）
3. ファイルの読み取り（read_file）
4. ファイル存在確認（file_exists）
5. 圧縮レベルの取得（get_compression_level）
6. 新規ZIPの作成（start_file, write_file, close_file）
7. 既存ZIPへの追加（APPEND_ADDINZIP）

**関連システム・外部連携**：zlib、FileAccess

**権限による制御**：ファイルシステムアクセス権限に依存

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当画面なし | - | ZIPはアプリケーション全体で使用されるユーティリティ |

## 機能種別

ユーティリティ / ファイル処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | String | Yes | ZIPファイルパス | ファイル存在チェック（読み取り時） |
| append | ZipAppend | No | 追加モード（デフォルト: APPEND_CREATE） | enum値チェック |
| compression_level | int | No | 圧縮レベル（-1〜9） | 範囲チェック |
| case_sensitive | bool | No | 大文字小文字区別（デフォルト: true） | - |
| data | Vector<uint8_t> | Yes | 書き込みデータ | - |

### 入力データソース

- ファイルシステム上のZIPファイル
- スクリプトからのバイトデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| file_list | PackedStringArray | アーカイブ内ファイル一覧 |
| file_data | PackedByteArray | ファイル内容 |
| exists | bool | ファイル存在フラグ |
| compression_level | int | 圧縮レベル |

### 出力先

- スクリプトへの結果返却
- ファイルシステム（ZIPPacker使用時）

## 処理フロー

### 処理シーケンス

```
[ZIPReader]
1. open()でZIPファイルを開く
2. get_files()でファイル一覧を取得
3. read_file()で個別ファイルを読み取り
4. close()でZIPを閉じる

[ZIPPacker]
1. open()で出力ZIPファイルを作成
2. start_file()で書き込みファイルを開始
3. write_file()でデータを書き込み
4. close_file()でファイルを完了
5. close()でZIPを閉じる
```

### フローチャート

```mermaid
flowchart TD
    subgraph ZIPReader
        A1[open] --> B1[get_files]
        B1 --> C1{ファイル選択}
        C1 --> D1[read_file]
        D1 --> E1{続行?}
        E1 -->|Yes| C1
        E1 -->|No| F1[close]
    end

    subgraph ZIPPacker
        A2[open] --> B2[start_file]
        B2 --> C2[write_file]
        C2 --> D2[close_file]
        D2 --> E2{続行?}
        E2 -->|Yes| B2
        E2 -->|No| F2[close]
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-77-01 | オープン状態チェック | open前にAPI呼び出しはエラー | 各メソッド呼び出し時 |
| BR-77-02 | 圧縮レベル範囲 | -1（デフォルト）〜9（最大圧縮） | set_compression_level |
| BR-77-03 | ファイルサイズ制限 | 2GB以上のファイルは読み取り不可 | read_file |
| BR-77-04 | UTF-8エンコーディング | ファイル名はUTF-8でエンコード | start_file（ビット11フラグ設定） |

### 圧縮レベル定数

```
COMPRESSION_DEFAULT = -1  // zlibデフォルト
COMPRESSION_NONE = 0      // 無圧縮
COMPRESSION_FAST = 1      // 高速圧縮
COMPRESSION_BEST = 9      // 最大圧縮
```

### 追加モード定数

```
APPEND_CREATE = 0         // 新規作成
APPEND_CREATEAFTER = 1    // 新規作成（追加可能）
APPEND_ADDINZIP = 2       // 既存ZIPに追加
```

## データベース操作仕様

本機能はデータベース操作を行わない（ファイル処理）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| FAILED | オープンエラー | ZIPファイルを開けない | パスを確認 |
| ERR_FAIL_COND_V_MSG | 状態エラー | 未オープン状態でAPI呼び出し | open()を先に呼ぶ |
| ERR_FAIL_COND_V_MSG | ファイルエラー | ZIPにファイルが存在しない | ファイルパスを確認 |
| ERR_FAIL_COND_V_MSG | サイズエラー | 2GB超のファイル | 分割処理 |

### リトライ仕様

ZIP処理にリトライ機構はない。

## トランザクション仕様

ZIPPackerでの書き込みは、close()まで完了しないため、途中で中断するとファイルが破損する可能性がある。

## パフォーマンス要件

- 圧縮レベルが高いほど処理時間が増加
- 大きなファイルはメモリに全て読み込まれるため注意
- ストリーミング書き込みに対応（write_fileを複数回呼び出し可能）

## セキュリティ考慮事項

- ZIPスリップ攻撃（パストラバーサル）への対策が必要
- 信頼できないZIPファイルの展開時は注意

## 備考

- zlibライブラリを使用
- DEFLATE圧縮アルゴリズムに対応
- ZIP64形式には非対応（4GB以上のアーカイブ）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ZIPReader/ZIPPackerクラスの基本構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | zip_reader.h | `modules/zip/zip_reader.h` | ZIPReader定義 |
| 1-2 | zip_packer.h | `modules/zip/zip_packer.h` | ZIPPacker定義 |

**読解のコツ**: ZIPReaderは読み取り専用、ZIPPackerは書き込み専用のクラスとして分離されている。

#### Step 2: ZIPReader実装を理解する

ZIPファイル読み取り処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | zip_reader.cpp | `modules/zip/zip_reader.cpp` | ZIPReader実装 |

**主要処理フロー**:
1. **36-44行目**: open()でZIPを開く
2. **58-89行目**: get_files()でファイル一覧取得
3. **91-126行目**: read_file()でファイル読み取り
4. **128-141行目**: file_exists()でファイル存在確認
5. **143-160行目**: get_compression_level()で圧縮レベル取得

#### Step 3: ZIPPacker実装を理解する

ZIPファイル作成処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | zip_packer.cpp | `modules/zip/zip_packer.cpp` | ZIPPacker実装 |

**主要処理フロー**:
1. **36-44行目**: open()でZIPを作成
2. **67-103行目**: start_file()で新規ファイル開始
3. **105-109行目**: write_file()でデータ書き込み
4. **111-115行目**: close_file()でファイル完了

### プログラム呼び出し階層図

```
ZIPReader::open()
    │
    └─ unzOpen2() [zlib]
           │
           └─ zipio_create_io() [FileAccessラッパー]

ZIPReader::read_file()
    │
    ├─ godot_unzip_locate_file()
    │
    ├─ unzOpenCurrentFile()
    │
    ├─ unzReadCurrentFile() [繰り返し]
    │
    └─ unzCloseCurrentFile()

ZIPPacker::start_file()
    │
    └─ zipOpenNewFileInZip4() [zlib]

ZIPPacker::write_file()
    │
    └─ zipWriteInFileInZip() [zlib]
```

### データフロー図

```
[入力]               [処理]                      [出力]

ZIPパス ────────────▶ unzOpen2 ─────────────▶ ファイルハンドル
     │                    │
ファイルパス ───────▶ read_file ─────────────▶ PackedByteArray
     │                    │
バイトデータ ───────▶ write_file ────────────▶ ZIPファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| zip_reader.cpp | `modules/zip/zip_reader.cpp` | ソース | ZIPReader実装 |
| zip_reader.h | `modules/zip/zip_reader.h` | ヘッダー | ZIPReader定義 |
| zip_packer.cpp | `modules/zip/zip_packer.cpp` | ソース | ZIPPacker実装 |
| zip_packer.h | `modules/zip/zip_packer.h` | ヘッダー | ZIPPacker定義 |
| zip_io.cpp | `core/io/zip_io.cpp` | ソース | zlibラッパー |
