# 帳票設計書 5-難読化ログ

## 概要

本ドキュメントは、StaxRipにおける難読化ログ出力機能の設計書である。処理ログからファイルパス等の個人情報を隠蔽（難読化）し、バグレポートやサポート依頼時に安全に共有できる形式で出力する機能について記述する。

### 本帳票の処理概要

難読化ログ機能は、通常の処理ログに含まれるファイルパス（特にディレクトリ名やファイル名）を汎用的な文字列に置換することで、ユーザーのプライバシーを保護しつつ、技術的なデバッグ情報は維持した状態で出力する機能である。

**業務上の目的・背景**：エンコードエラーの調査やバグレポートの際、処理ログの共有が必要となることが多い。しかし、ログにはファイルパス（ユーザー名を含むホームディレクトリなど）が含まれており、そのまま公開するとプライバシーリスクがある。難読化ログは、技術情報を維持しつつ個人情報を隠すことで、安全なログ共有を可能にする。

**帳票の利用シーン**：バグレポート作成時、フォーラムでのサポート依頼時、開発者への問題報告時。

**主要な出力内容**：
1. システム環境情報（難読化なし）
2. 設定情報（難読化なし）
3. 処理ログ（ファイルパスのみ難読化）
4. エラー情報（ファイルパスのみ難読化）

**帳票の出力タイミング**：LogForm画面で「Save Obfuscated As...」メニュー選択時にユーザー操作で出力。

**帳票の利用者**：エンドユーザー（バグレポート作成者）、テクニカルサポート担当者、開発者。

## 帳票種別

ログ出力（難読化テキストログ）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| 11 | LogForm | ログ表示フォーム | コンテキストメニュー「Save Obfuscated As...」(Ctrl+Alt+S) |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキストファイル (.log) |
| 用紙サイズ | - |
| 向き | - |
| ファイル名 | Source.log（デフォルト、ユーザー変更可） |
| 出力方法 | ファイル保存（UTF-8） |
| 文字コード | UTF-8 |

### 難読化ルール

| 項目 | 元の値 | 難読化後 |
|-----|-------|---------|
| ディレクトリ名 | 各フォルダ名 | "x" |
| ファイル名（拡張子なし） | SourceFile.Base | "Source" |
| ボリューム区切り | : (例: C:) | 維持 |
| パス区切り | \ または / | 維持 |
| 拡張子 | .mkv, .mp4 等 | 維持 |

**例**:
- 元: `C:\Users\JohnDoe\Videos\MyMovie\Movie2024.mkv`
- 難読化後: `C:\x\x\x\x\Source.mkv`

## 帳票レイアウト

### レイアウト概要

難読化ログは、通常の処理ログと同じ構造を持つが、ファイルパス部分のみが難読化される。

```
┌─────────────────────────────────────┐
│  ---------- Section Name ---------- │
│                                     │
│  Content lines...                   │
│  (パスは難読化済み)                 │
│                                     │
│  Start:    HH:MM:SS                 │
│  End:      HH:MM:SS                 │
│  Duration: HH:MM:SS                 │
│                                     │
│  ---------- Section Name ---------- │
│  ...                                │
└─────────────────────────────────────┘
```

### ヘッダー部

通常ログと同様。難読化対象外。

### 明細部

| No | 項目名 | 説明 | 難読化 |
|----|-------|------|--------|
| 1 | システム環境情報 | OS, CPU等 | 対象外 |
| 2 | 設定情報 | エンコーダー設定等 | 対象外 |
| 3 | 処理内容 | コマンドライン、出力等 | パス部分のみ難読化 |
| 4 | エラーメッセージ | スタックトレース等 | パス部分のみ難読化 |

### フッター部

通常ログと同様。難読化対象外。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ログ内容存在 | rtb.Text が空でない | Yes |
| SourceFile存在 | p.SourceFile が空でない | Yes（難読化対象がない場合は元ログをそのまま出力） |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | 時系列（書き込み順） | 昇順 |

### 改ページ条件

改ページなし（連続テキスト）

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

### 参照テーブル一覧

本機能はデータベースを使用しない。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| - | - | - |

### 外部データソース

| ソース | 用途 | 取得方法 |
|--------|------|---------|
| Project | ソースファイルパス取得 | p.SourceFile |
| LogForm.rtb | 元ログテキスト取得 | rtb.Text |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| - | - | - | 文字列置換処理のみ |

### 難読化処理仕様

#### ステップ1: ディレクトリ+ベース名の置換

```
toReplace = sourcePath.DirAndBase()
replaceBy = Regex.Replace(toReplace, "[^{VolumeSeparator}\{DirectorySeparator}]+(?=\{DirectorySeparator})", folderReplacement)
replaceBy = Regex.Replace(replaceBy, "(?<=\{DirectorySeparator})[^\{DirectorySeparator}]+$", fileReplacement)
ret = ret.Replace(toReplace, replaceBy)
```

**正規表現解説**:
- `[^:\]+(?=\)`: パス区切りの直前にあるフォルダ名部分をマッチ
- `(?<=\)[^\]+$`: パス区切りの後の最後のファイル名部分をマッチ

#### ステップ2: ベース名のみの置換

```
toReplace = sourcePath.Base()
replaceBy = fileReplacement
ret = ret.Replace(toReplace, replaceBy)
```

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Save Obfuscated As...選択] --> B[SaveFileDialog表示]
    B --> C{ユーザー確認}
    C -->|キャンセル| Z[処理終了]
    C -->|OK| D[g.ObfuscateLogFile呼び出し]
    D --> E{SourceFile有効?}
    E -->|No| F[元テキストをそのまま返却]
    E -->|Yes| G[DirAndBase()取得]
    G --> H[正規表現でフォルダ名置換]
    H --> I[正規表現でファイル名置換]
    I --> J[文字列置換実行]
    J --> K[Base()取得]
    K --> L[ファイル名のみの置換実行]
    L --> M[WriteFileUTF8出力]
    F --> M
    M --> N[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ログ空 | text が空または空白 | - | 空文字を返却 |
| SourceFile空 | p.SourceFile が空 | - | 元テキストをそのまま返却 |
| ファイル保存失敗 | ファイルアクセスエラー | 例外メッセージ | 例外表示 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数KB〜数百KB |
| 目標出力時間 | 瞬時 |
| 同時出力数上限 | 1（UI操作） |

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

- **目的**: ファイルパスに含まれる個人情報（ユーザー名、プロジェクト名等）の保護
- **制限事項**:
  - ログ内の他の個人情報（メタデータ内のタイトル等）は難読化されない
  - システム環境情報（GPU名、CPU名等）は難読化されない
- **推奨事項**: 難読化後も内容を確認してから共有すること

## 備考

- デフォルトのファイル名は "Source" + 元ログの拡張子
- folderReplacement のデフォルト値は "x"
- fileReplacement のデフォルト値は "Source"
- 拡張子は置換されないため、ファイル形式の情報は保持される

---

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

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

### 推奨読解順序

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

難読化処理に関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Project.vb | `Source/General/Project.vb` | SourceFileプロパティでファイルパス管理を確認 |
| 1-2 | LogBuilder.vb | `Source/General/LogBuilder.vb` | GetPathメソッドでログファイルパス取得を確認 |

**読解のコツ**: 難読化処理はSourceFileのパスを基準に行われる。DirAndBase()とBase()拡張メソッドがパス分解に使用される。

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

難読化ログ出力のUI呼び出しを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LogForm.vb | `Source/Forms/LogForm.vb` | Line 43-53で「Save Obfuscated As...」メニュー処理を確認 |

**主要処理フロー**:
1. **Line 43**: コンテキストメニューに「Save Obfuscated As...」追加
2. **Line 44-52**: Lambda式でSaveFileDialog表示とファイル保存
3. **Line 46**: デフォルトファイル名を "Source" + 拡張子に設定
4. **Line 50**: g.ObfuscateLogFile呼び出し + WriteFileUTF8

#### Step 3: 難読化処理を理解する

難読化アルゴリズムの詳細を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | GlobalClass.vb | `Source/General/GlobalClass.vb` | ObfuscateLogFile（Line 1122-1139）で難読化処理を確認 |

**主要処理フロー**:
- **Line 1122**: 関数シグネチャ - オプション引数でfolderReplacement, fileReplacement指定可能
- **Line 1123-1125**: 空チェック・SourceFile存在チェック
- **Line 1128-1132**: ステップ1 - DirAndBase()部分の難読化
  - **Line 1129**: toReplace = sourcePath.DirAndBase()
  - **Line 1130**: 正規表現でフォルダ名を"x"に置換
  - **Line 1131**: 正規表現でファイル名を"Source"に置換
  - **Line 1132**: 文字列置換実行
- **Line 1134-1136**: ステップ2 - Base()のみの難読化
  - **Line 1134**: toReplace = sourcePath.Base()
  - **Line 1135**: replaceBy = fileReplacement
  - **Line 1136**: 文字列置換実行
- **Line 1138**: 難読化済みテキスト返却

#### Step 4: 正規表現パターンを理解する

難読化に使用される正規表現を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | GlobalClass.vb | `Source/General/GlobalClass.vb` | Line 1130-1131の正規表現パターンを確認 |

**正規表現解説**:

1. **フォルダ名置換** (Line 1130):
   ```
   [^{VolumeSeparator}\{DirectorySeparator}]+(?=\{DirectorySeparator})
   ```
   - `[^:\]+`: コロンとバックスラッシュ以外の1文字以上
   - `(?=\)`: バックスラッシュが続く位置（先読み）
   - 結果: `C:\Users\John\Videos` → `C:\x\x\x`

2. **ファイル名置換** (Line 1131):
   ```
   (?<=\{DirectorySeparator})[^\{DirectorySeparator}]+$
   ```
   - `(?<=\)`: バックスラッシュの直後の位置（後読み）
   - `[^\]+$`: バックスラッシュ以外の末尾まで
   - 結果: `C:\x\x\x\Movie2024` → `C:\x\x\x\Source`

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

```
LogForm コンテキストメニュー
    │
    └─ "Save Obfuscated As..." (Lambda)
           │
           ├─ SaveFileDialog表示
           │      └─ FileName = "Source" + p.Log.GetPath.ExtFull
           │
           ├─ g.ObfuscateLogFile(rtb.Text.FixBreak, p)
           │      │
           │      ├─ 空チェック / SourceFileチェック
           │      │
           │      ├─ ステップ1: DirAndBase難読化
           │      │      ├─ sourcePath.DirAndBase() 取得
           │      │      ├─ Regex.Replace (フォルダ名 → "x")
           │      │      ├─ Regex.Replace (ファイル名 → "Source")
           │      │      └─ ret.Replace(toReplace, replaceBy)
           │      │
           │      └─ ステップ2: Base難読化
           │             ├─ sourcePath.Base() 取得
           │             └─ ret.Replace(toReplace, fileReplacement)
           │
           └─ WriteFileUTF8(dialog.FileName)
```

### データフロー図

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

rtb.Text ────────────▶ FixBreak() ────────────────▶ 正規化テキスト
     │                       │
     │                       ▼
p.SourceFile ─────────▶ ObfuscateLogFile()
                              │
                              ├─ DirAndBase() 取得
                              │      │
                              │      ├─ Regex.Replace (フォルダ)
                              │      └─ Regex.Replace (ファイル)
                              │
                              ├─ Base() 取得
                              │      └─ String.Replace
                              │
                              ▼
                         難読化済みテキスト
                              │
                              ▼
                         WriteFileUTF8() ──────────▶ 難読化ログファイル
                                                   (.log UTF-8)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LogForm.vb | `Source/Forms/LogForm.vb` | ソース | UI・メニュー処理 |
| LogForm.Designer.vb | `Source/Forms/LogForm.Designer.vb` | ソース | デザイナー生成コード |
| GlobalClass.vb | `Source/General/GlobalClass.vb` | ソース | ObfuscateLogFile関数 |
| Project.vb | `Source/General/Project.vb` | ソース | SourceFileプロパティ |
| LogBuilder.vb | `Source/General/LogBuilder.vb` | ソース | GetPathメソッド |
| General.vb | `Source/General/General.vb` | ソース | 拡張メソッド（DirAndBase, Base, FixBreak, WriteFileUTF8等） |
