# 帳票設計書 16-プロジェクトZIP

## 概要

本ドキュメントは、Godot Engineにおけるプロジェクトファイル一式のZIPパッケージ化機能に関する設計書である。プロジェクトディレクトリ全体をZIP形式で圧縮し、バックアップやプロジェクト共有に使用できるファイルを生成する。

### 本帳票の処理概要

本機能は、Godot Engineのプロジェクトディレクトリ内のすべてのファイルとフォルダを再帰的に走査し、ZIP形式でアーカイブする。プロジェクトデータディレクトリ（.godot等）は自動的に除外され、ファイル名にはプロジェクト名と日時が含まれる安全な命名規則が適用される。

**業務上の目的・背景**：ゲーム開発プロジェクトのバックアップ、チームメンバーへのプロジェクト共有、教育用サンプルの配布、コンペティション提出用パッケージの作成など、プロジェクト全体を単一ファイルにまとめる需要は高い。ZIP形式は広く普及しており、ほぼすべてのプラットフォームで展開可能である。プロジェクトデータディレクトリを除外することで、不要なキャッシュやビルド成果物を含まないクリーンなアーカイブを作成できる。

**帳票の利用シーン**：プロジェクトのバックアップ作成、チームメンバーへのプロジェクト共有、GitHubリリースへの添付、教育用サンプルの配布、バグレポート時のプロジェクト添付、コンテスト・ジャムへの提出など。

**主要な出力内容**：
1. プロジェクト内のすべてのソースファイル（.gd、.tscn、.tres等）
2. アセットファイル（画像、音声、3Dモデル等）
3. 設定ファイル（project.godot等）
4. ディレクトリ構造の保持

**帳票の出力タイミング**：エディタの「Project > Export > Export Project as ZIP」メニューから実行した際、または対応するAPIを呼び出した際に出力される。

**帳票の利用者**：ゲーム開発者、プロジェクトマネージャー、教育者、学習者

## 帳票種別

アーカイブ出力 / ZIPファイル出力

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | エディタ | Project > Export | Export Project as ZIP |
| - | C++ API | ProjectZIPPacker::pack_project_zip() | 直接呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | ZIP（.zip） |
| 用紙サイズ | N/A（アーカイブ出力） |
| 向き | N/A |
| ファイル名 | {project_name_safe}_{datetime_safe}.zip |
| 出力方法 | ファイル保存 |
| 文字コード | UTF-8（ファイル名エンコーディング） |

### ZIP固有設定

| 項目 | 内容 |
|-----|------|
| 圧縮方式 | DEFLATE（Z_DEFLATED） |
| 圧縮レベル | Z_DEFAULT_COMPRESSION |
| バージョン | 2.0（Unix互換、0x0314） |
| 言語エンコーディング | UTF-8（ビット11設定） |
| 除外対象 | プロジェクトデータディレクトリ（.godot等） |

## 帳票レイアウト

### レイアウト概要

ZIP形式は標準的なPKZIPフォーマットに従う。

```
project_name_2024-01-23_143000.zip
├── project.godot          (プロジェクト設定)
├── icon.svg               (アイコン)
├── scenes/
│   ├── main.tscn         (メインシーン)
│   └── player.tscn       (プレイヤーシーン)
├── scripts/
│   ├── main.gd           (メインスクリプト)
│   └── player.gd         (プレイヤースクリプト)
├── assets/
│   ├── sprites/          (スプライト)
│   └── sounds/           (サウンド)
└── ...

※ .godot/ ディレクトリは除外される
```

### ZIPファイル構造

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Local File Header | 各ファイルのヘッダー | ファイルメタデータ | バイナリ |
| 2 | File Data | 圧縮されたファイルデータ | FileAccess::get_buffer | DEFLATE圧縮 |
| 3 | Central Directory | ファイル一覧インデックス | 全エントリ情報 | バイナリ |
| 4 | End of Central Directory | 終端レコード | - | バイナリ |

### ファイルエントリヘッダー

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | パス | プロジェクトルートからの相対パス | trim_prefix(base_path) | UTF-8文字列 |
| 2 | 圧縮方式 | DEFLATE | 固定値 | 8 |
| 3 | CRC-32 | データ整合性チェック | zlib計算 | 32bit |
| 4 | 圧縮サイズ | 圧縮後のバイト数 | zlib計算 | 32bit |
| 5 | 非圧縮サイズ | 元のバイト数 | FileAccess::get_length | 32bit |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 出力パス | 書き込み可能なパス | Yes |
| プロジェクトパス | 有効なプロジェクトディレクトリ | Yes |

### 除外条件

| 条件名 | 説明 |
|-------|------|
| プロジェクトデータディレクトリ | project_data_dir_name（デフォルト: .godot） |
| カレントディレクトリ参照 | "." と ".." |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | N/A（ディレクトリ走査順） | - |

### 改ページ条件

N/A（アーカイブ出力）

## データベース参照仕様

### プロジェクト設定参照

| 設定キー | 用途 | デフォルト値 |
|---------|------|-------------|
| application/config/name | ZIPファイル名のプロジェクト名部分 | - |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| プロジェクト名（安全） | project_name.to_lower().replace_char(' ', '_') | - | 空白をアンダースコアに |
| 日時（安全） | datetime.replace_char(' ', '_') | - | 空白をアンダースコアに |
| 出力ファイル名 | "{project_name_safe}_{datetime_safe}.zip" | - | OS::get_safe_dir_nameで安全化 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[pack_project_zip 呼び出し] --> B[出力パス設定]
    B --> C[zipOpen2 でZIPファイル作成]
    C --> D[_zip_recursive 開始]
    D --> E[DirAccess::open でディレクトリオープン]
    E --> F[list_dir_begin]
    F --> G{次のエントリ?}
    G -->|Yes| H{除外対象?}
    H -->|Yes| G
    H -->|No| I{ディレクトリ?}
    I -->|Yes| J[ディレクトリエントリ追加]
    J --> K[_zip_recursive 再帰呼び出し]
    K --> G
    I -->|No| L[_zip_file 呼び出し]
    L --> M[FileAccess::open でファイル読み込み]
    M --> N[zipOpenNewFileInZip4]
    N --> O[zipWriteInFileInZip]
    O --> P[zipCloseFileInZip]
    P --> G
    G -->|No| Q[zipClose]
    Q --> R[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ディレクトリオープン失敗 | DirAccess::open 失敗 | "Unable to open directory for zipping: {path}" | パスを確認 |
| ファイルオープン失敗 | FileAccess::open 失敗 | "Unable to open file for zipping: {path}" | ファイル権限を確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定ファイル数 | 無制限（プロジェクトサイズ依存） |
| 目標出力時間 | プロジェクトサイズと圧縮率に依存 |
| 同時出力数上限 | 1（シングルインスタンス） |
| メモリ使用量 | ファイルサイズ分のバッファを使用 |

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

- 出力パスはユーザー指定のため、パストラバーサル攻撃に注意が必要
- ZIPファイルにはプロジェクト内のすべてのファイルが含まれるため、機密情報の除外を考慮
- 大規模プロジェクトではディスク容量枯渇に注意
- ファイル名のサニタイズによりWindows互換性を確保

## 備考

- zlib/minizip ライブラリを使用してZIP生成
- ディレクトリエントリは末尾にスラッシュを付加して記録
- Unix互換のバージョン番号（0x0314）を使用し、ファイルパーミッション保存に対応
- UTF-8ファイル名エンコーディング（ビット11）により国際化対応
- プロジェクトデータディレクトリ（.godot）は自動除外される

---

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

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

### 推奨読解順序

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

まず、ProjectZIPPacker クラスの構造とzlib/minizip APIを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | project_zip_packer.h | `editor/export/project_zip_packer.h` | ProjectZIPPacker クラスの静的メソッド宣言 |
| 1-2 | zip_io.h | `core/io/zip_io.h` | zipio_create_io とZIP関連の型定義 |

**読解のコツ**: ProjectZIPPacker は静的メソッドのみのユーティリティクラス。minizip ライブラリの zipFile 型と関連関数を使用。

#### Step 2: エントリーポイントを理解する

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | project_zip_packer.cpp | `editor/export/project_zip_packer.cpp` | pack_project_zip 関数（行52-62） |
| 2-2 | project_zip_packer.cpp | `editor/export/project_zip_packer.cpp` | get_project_zip_safe_name 関数（行39-50） |

**主要処理フロー**:
1. **行52-54**: zipio_create_io でI/Oハンドラ作成
2. **行56-57**: リソースパスとベースパスの設定
3. **行59**: zipOpen2 でZIPファイル作成
4. **行60**: _zip_recursive で再帰的にファイル追加
5. **行61**: zipClose でZIPファイル完了

#### Step 3: 再帰ディレクトリ走査を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | project_zip_packer.cpp | `editor/export/project_zip_packer.cpp` | _zip_recursive 関数（行98-138） |

**主要処理フロー**:
- **行99-103**: DirAccess でディレクトリオープン
- **行104-106**: list_dir_begin とプロジェクトデータディレクトリ名取得
- **行107-136**: ディレクトリ内エントリのループ処理
- **行109-110**: "."、".."、プロジェクトデータディレクトリの除外
- **行111-131**: ディレクトリの場合はエントリ追加して再帰呼び出し
- **行133-134**: ファイルの場合は _zip_file 呼び出し

#### Step 4: ファイル追加処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | project_zip_packer.cpp | `editor/export/project_zip_packer.cpp` | _zip_file 関数（行64-96） |

**主要処理フロー**:
- **行65-73**: FileAccess でファイル読み込み、バッファに格納
- **行75**: ベースパスからのトリムで相対パス取得
- **行76-93**: zipOpenNewFileInZip4 でZIPエントリヘッダー書き込み
- **行94**: zipWriteInFileInZip でファイルデータ書き込み
- **行95**: zipCloseFileInZip でエントリ完了

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

```
エディタメニュー: Project > Export > Export Project as ZIP
    │
    └─ ProjectZIPPacker::pack_project_zip(path)
           │
           ├─ zipio_create_io() - I/Oハンドラ作成
           │
           ├─ zipOpen2() - ZIPファイル作成
           │
           └─ _zip_recursive(resource_path, base_path, zip)
                  │
                  ├─ DirAccess::open() - ディレクトリオープン
                  │
                  ├─ list_dir_begin() / get_next()
                  │
                  ├─ [ディレクトリの場合]
                  │       │
                  │       ├─ zipOpenNewFileInZip4() - ディレクトリエントリ
                  │       │
                  │       └─ _zip_recursive() - 再帰呼び出し
                  │
                  └─ [ファイルの場合]
                          │
                          └─ _zip_file(path, base_path, zip)
                                 │
                                 ├─ FileAccess::open() - ファイル読み込み
                                 │
                                 ├─ zipOpenNewFileInZip4() - ファイルエントリ
                                 │
                                 ├─ zipWriteInFileInZip() - データ書き込み
                                 │
                                 └─ zipCloseFileInZip()
```

### データフロー図

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

プロジェクトディレクトリ
    │
    ├─ project.godot ──────┐
    ├─ scenes/*.tscn ──────┤
    ├─ scripts/*.gd ───────┼──▶ _zip_recursive() ───▶ project_name_datetime.zip
    ├─ assets/* ───────────┤         │
    └─ ... ────────────────┘         ▼
                                 DEFLATE圧縮
                                     │
                              ┌──────┴──────┐
                              ▼             ▼
                         ファイル      ディレクトリ
                         エントリ       エントリ

project.godot設定
    │
    └─ application/config/name ──▶ get_project_zip_safe_name()
                                          │
                                          ▼
                                  ZIPファイル名生成
                                  {name}_{datetime}.zip
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| project_zip_packer.cpp | `editor/export/project_zip_packer.cpp` | ソース | ZIP生成の主実装 |
| project_zip_packer.h | `editor/export/project_zip_packer.h` | ヘッダー | クラス宣言 |
| zip_io.h | `core/io/zip_io.h` | ヘッダー | ZIP I/Oユーティリティ |
| zip_io.cpp | `core/io/zip_io.cpp` | ソース | ZIP I/O実装 |
| file_access.h | `core/io/file_access.h` | ヘッダー | ファイル読み込みAPI |
| dir_access.h | `core/io/dir_access.h` | ヘッダー | ディレクトリ走査API |
| project_settings.h | `core/config/project_settings.h` | ヘッダー | プロジェクト設定取得 |
| time.h | `core/os/time.h` | ヘッダー | 日時取得 |
| os.h | `core/os/os.h` | ヘッダー | OS::get_safe_dir_name |
| minizip (外部) | thirdparty/minizip | ライブラリ | ZIP生成ライブラリ |
