# 機能設計書 24-文字エンコード自動判定

## 概要

本ドキュメントは、UTF-8 / Shift-JIS の自動判定とBOM処理を行い、適切にテキストを読み込む機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：KSH譜面ファイルは歴史的にShift-JISで作成されてきたが、国際化対応に伴いUTF-8でも作成されるようになった。両エンコードの譜面ファイルが混在する環境で正しく日本語・多言語テキストを表示するため、自動判定機能が必要となった。

**機能の利用シーン**：譜面ファイル読み込み時（loadKSHChartFile）、コースファイル読み込み時、選曲画面でのファイル情報読み込み時、IRスコア送信時の文字列エンコードなど、テキストデータを扱う全ての場面で利用される。

**主要な処理内容**：
1. UTF-8 BOM（Byte Order Mark: 0xEF 0xBB 0xBF）の検出による自動判定
2. BOM検出時はBOMバイト列を削除し、UTF-8として処理
3. BOM非検出時はShift-JISとして処理
4. _utf8_マクロによる条件付きUTF-8→Shift-JIS変換（isutf8=0の場合のみ変換）
5. _sjis_マクロによる条件付きShift-JIS→UTF-8→Shift-JIS変換（isutf8=1の場合のみ変換）

**関連システム・外部連携**：mod_encode.hsp（third_party）のUTF-8/Shift-JIS変換関数と連携する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | 譜面ファイル読み込み時のエンコード自動判定 |
| 4 | プレイ前処理画面 | 参照画面 | コースファイルのエンコード判定 |
| 3 | 曲選択画面 | 参照画面 | 楽曲情報読み込み時のエンコード判定 |

## 機能種別

データ変換 / エンコード処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| buf | var | Yes | 読み込まれたファイルデータ | - |

### 入力データソース

ファイルシステムから読み込まれたテキストデータ（.ksh, .kcoファイル等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isutf8 | int | UTF-8判定フラグ（1=UTF-8, 0=Shift-JIS） |
| buf | var | BOM除去後のテキストデータ |

### 出力先

ゲーム内部変数

## 処理フロー

### 処理シーケンス

```
1. ファイルデータの先頭3バイトを取得
   └─ lpeek(buf, 0) & 0x00FFFFFF
2. BOM判定
   ├─ 値が0xBFBBEFの場合: isutf8=1, DeleteUTF8BOMを実行
   └─ それ以外: isutf8=0のまま
3. テキスト変換（以降の処理で使用）
   ├─ _utf8_マクロ: isutf8=0なら utf8enc(文字列) を適用
   └─ _sjis_マクロ: isutf8=1なら sjisenc(文字列) を適用
```

### フローチャート

```mermaid
flowchart TD
    A[ファイルデータ読み込み] --> B[先頭3バイト取得]
    B --> C{0xBFBBEF?}
    C -->|Yes| D[isutf8=1]
    D --> E[DeleteUTF8BOM実行]
    C -->|No| F[isutf8=0]
    E --> G[テキスト処理]
    F --> G
    G --> H{文字列使用時}
    H --> I{isutf8=0?}
    I -->|Yes: UTF-8変換必要| J[utf8enc適用]
    I -->|No: 既にUTF-8| K[そのまま使用]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | BOM判定 | 先頭3バイトが0xEF,0xBB,0xBF（リトルエンディアンで0xBFBBEF）ならUTF-8 | ファイル読み込み時 |
| BR-24-02 | BOM除去 | BOM検出時は先頭3バイトを削除 | isutf8=1の場合 |
| BR-24-03 | デフォルトShift-JIS | BOM非検出時はShift-JISとして処理 | isutf8=0の場合 |
| BR-24-04 | 条件付き変換 | _utf8_/_sjis_マクロでisutf8フラグに応じた変換を行う | テキスト表示時 |

### 計算ロジック

BOM判定: `(lpeek(buf, 0) & 0x00FFFFFF) == 0xBFBBEF`
- lpeekは先頭4バイトをリトルエンディアンで取得
- 0x00FFFFFFでマスクして下位3バイトのみ比較
- UTF-8 BOMのバイト列 0xEF 0xBB 0xBF はリトルエンディアンで0xBFBBEFとなる

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

本機能ではデータベース操作は発生しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 判定不能 | BOMなしUTF-8ファイルの場合 | Shift-JISとして扱われ、文字化けが発生する可能性がある |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

BOM判定は先頭3バイトのみの比較で即時完了する。

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

特になし。

## 備考

- BOMなしUTF-8ファイルはShift-JISとして誤認される制限がある。KSHフォーマット仕様ではUTF-8の場合はBOM付きで保存することが推奨されている。
- ir.hspのutf8enc_auto関数（134-141行目）でも同様のBOM判定ロジックが実装されている。

---

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

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

### 推奨読解順序

#### Step 1: BOM判定の基本ロジック

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | loadKSHChartFile内のBOM判定処理 |

**主要処理フロー**:
1. **262行目**: isutf8=0でデフォルトShift-JIS
2. **263行目**: lpeek(buf, 0) & 0x00FFFFFFで先頭3バイト取得
3. **264行目**: 0xBFBBEFとの比較でUTF-8 BOM判定
4. **265行目**: DeleteUTF8BOMでBOM削除

#### Step 2: utf8enc_auto関数

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ir.hsp | `src/ir.hsp` | utf8enc_auto関数（BOM有無で分岐するヘルパー） |

**主要処理フロー**:
- **134-141行目**: BOMあり→BOM削除してそのまま返す、BOMなし→utf8encで変換

#### Step 3: コースファイルでの使用例

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | course_result.hsp | `src/scene/course_result.hsp` | コース結果画面でのisutf8判定 |

**主要処理フロー**:
- **87-90行目**: コースファイル読み込み時のBOM判定とDeleteUTF8BOM

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

```
loadKSHChartFile (play_chart_load.hsp)
    |
    +-- lpeek(buf, 0) & 0x00FFFFFF   (BOM判定)
    +-- DeleteUTF8BOM buf             (BOM削除)
    |
parseKSHChartParamLines
    +-- _utf8_ csongtitle            (条件付きUTF-8変換)
    +-- _sjis_ bgname                (条件付きShift-JIS変換)

utf8enc_auto (ir.hsp)
    +-- lpeek判定
    +-- DeleteUTF8BOM / utf8enc
```

### データフロー図

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

テキストデータ -----> BOM判定(先頭3バイト) -----> isutf8フラグ
                                                     |
                      BOM削除(isutf8=1時) -------> クリーンテキスト
                                                     |
                      _utf8_/_sjis_マクロ -------> 表示用文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | 譜面読み込み時のBOM判定（262-266行目） |
| ir.hsp | `src/ir.hsp` | ソース | utf8enc_auto関数（134-141行目） |
| course_result.hsp | `src/scene/course_result.hsp` | ソース | コース結果画面でのBOM判定（87-90行目） |
| select.hsp | `src/scene/select.hsp` | ソース | 選曲画面でのBOM判定（2869-2870行目, 3184-3186行目） |
