# 機能設計書 119-文字エンコード変換

## 概要

本ドキュメントは、K-Shoot MANIAにおける文字エンコード変換機能の設計を記述する。UTF-8 / Shift-JIS相互変換機能を提供する。

### 本機能の処理概要

Windows APIのMultiByteToWideChar/WideCharToMultiByte関数を利用して、UTF-8とShift-JIS(CP_ACP)の相互変換およびUTF-16からUTF-8への変換を行うモジュールである。

**業務上の目的・背景**：K-Shoot MANIAの譜面ファイル(KSH)はUTF-8またはShift-JISで記述される可能性がある。HSPの標準文字列処理はShift-JISベースであるため、UTF-8テキストを扱う際にはShift-JISへの変換が必要となる。また、IRやファイル出力時にはUTF-8への変換が必要となる場面もある。

**機能の利用シーン**：譜面ファイル読み込み時のエンコード変換、結果画面での曲名・アーティスト名の表示変換、IR連携時のテキストデータ変換などで利用される。

**主要な処理内容**：
1. utf8enc(p1): Shift-JIS文字列をUTF-8に変換する関数
2. sjisenc(p1): UTF-8文字列をShift-JISに変換する関数
3. UTF16toUTF8(utf16, utf8): UTF-16バイナリデータをUTF-8文字列に変換する命令

**関連システム・外部連携**：Windows API (kernel32.dll) の MultiByteToWideChar / WideCharToMultiByte を使用する。

**権限による制御**：権限による制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 補助機能 | 譜面テキストのUTF-8/Shift-JIS正規化処理 |
| 6 | リザルト画面 | 補助機能 | 曲名・アーティスト名のエンコード変換 |

## 機能種別

ユーティリティ / エンコード変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| p1 (utf8enc) | str | Yes | Shift-JIS文字列 | - |
| p1 (sjisenc) | str | Yes | UTF-8文字列 | - |
| utf16 (UTF16toUTF8) | var | Yes | UTF-16バイナリデータ(参照渡し) | - |
| utf8 (UTF16toUTF8) | var | Yes | UTF-8出力先バッファ(参照渡し) | - |

### 入力データソース

- 譜面ファイルから読み込んだテキストデータ
- 楽曲メタデータ(タイトル、アーティスト名等)
- ユーザー入力テキスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| utf8enc戻り値 | str | UTF-8に変換された文字列 |
| sjisenc戻り値 | str | Shift-JISに変換された文字列 |
| utf8 (UTF16toUTF8) | var | UTF-8に変換された文字列(参照渡し出力) |

### 出力先

- 関数の戻り値(utf8enc, sjisenc)
- 参照渡し変数(UTF16toUTF8)

## 処理フロー

### 処理シーケンス

```
■ utf8enc(p1) - Shift-JIS → UTF-8:
1. Shift-JIS文字列をUnicode(UTF-16)に変換
   └─ MultiByteToWideChar(CP_ACP, 0, ...) → バッファサイズ取得
   └─ MultiByteToWideChar(CP_ACP, 0, ...) → 変換実行
2. Unicode(UTF-16)をUTF-8に変換
   └─ WideCharToMultiByte(CP_UTF8, 0, ...) → バッファサイズ取得
   └─ WideCharToMultiByte(CP_UTF8, 0, ...) → 変換実行
3. UTF-8文字列を返す

■ sjisenc(p1) - UTF-8 → Shift-JIS:
1. UTF-8文字列をUnicode(UTF-16)に変換
   └─ MultiByteToWideChar(CP_UTF8, 0, ...) → バッファサイズ取得
   └─ MultiByteToWideChar(CP_UTF8, 0, ...) → 変換実行
2. Unicode(UTF-16)をShift-JIS(CP_ACP)に変換
   └─ WideCharToMultiByte(CP_ACP, 0, ...) → バッファサイズ取得
   └─ WideCharToMultiByte(CP_ACP, 0, ...) → 変換実行
3. Shift-JIS文字列を返す

■ UTF16toUTF8(utf16, utf8):
1. UTF-16データをUTF-8に変換
   └─ WideCharToMultiByte(CP_UTF8, 0, ...) → バッファサイズ取得
   └─ WideCharToMultiByte(CP_UTF8, 0, ...) → 変換実行
2. 結果をutf8変数に格納
```

### フローチャート

```mermaid
flowchart TD
    A[入力文字列] --> B{変換方向}
    B -->|utf8enc| C[SJIS → Unicode]
    C --> D[Unicode → UTF-8]
    D --> E[UTF-8文字列を返す]
    B -->|sjisenc| F[UTF-8 → Unicode]
    F --> G[Unicode → SJIS]
    G --> H[SJIS文字列を返す]
    B -->|UTF16toUTF8| I[UTF-16 → UTF-8]
    I --> J[変数に格納]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-119-01 | 中間Unicode変換 | Shift-JIS⇔UTF-8の変換はUnicode(UTF-16)を中間形式として使用する | 常時 |
| BR-119-02 | CP_ACP使用 | Shift-JISエンコードにはシステムのACPコードページ(CP_ACP=0)を使用 | 常時 |
| BR-119-03 | CP_UTF8使用 | UTF-8エンコードにはCP_UTF8(65001)を使用 | 常時 |
| BR-119-04 | バッファ確保 | 変換先バッファはsdim命令でnSize*2バイトを確保する | 変換時 |
| BR-119-05 | NULL終端 | 変換長-1指定(自動NULL終端検出)を使用する | 常時 |

### 計算ロジック

- バッファサイズ: `nSize = MultiByteToWideChar(..., NULL, 0)` で必要サイズを事前取得
- UTF-16バッファ: `sdim buf16, nSize * 2 + 2` (ワイド文字は2バイト/文字 + NULL終端)
- UTF-8/SJISバッファ: `sdim buf, nSize * 2` (余裕を持って2倍確保)

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

### 操作別データベース影響一覧

データベース操作はない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 変換失敗 | 不正なエンコードの文字列が入力された場合 | MultiByteToWideChar/WideCharToMultiByteのエラーはチェックしていない |

### リトライ仕様

リトライ処理はない。

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

トランザクション管理はない。

## パフォーマンス要件

- 文字列変換はO(n)の時間計算量(nは文字列長)
- 2回のAPI呼び出し(サイズ取得+変換実行)を行うが、高速

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

- バッファオーバーフローの防止: nSize*2のバッファ確保で余裕を持たせている

## 備考

- mod_encode.hspとして third_party ディレクトリに配置
- HSPの無名モジュール(`#module`のみ)として定義
- CP_UTF16(65002)が定義されているが、実際には使用されていない

---

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

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

### 推奨読解順序

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

エンコード変換で使用される定数を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mod_encode.hsp | `third_party/mod_encode.hsp` | **2-3行目**: kernel32.dllのMultiByteToWideChar/WideCharToMultiByte宣言 |
| 1-2 | mod_encode.hsp | `third_party/mod_encode.hsp` | **5-8行目**: 定数定義(NULL, CP_ACP, CP_UTF8, CP_UTF16) |

**読解のコツ**: HSPの`#cfunc`は戻り値を持つ関数宣言。Win32 APIのMultiByteToWideChar/WideCharToMultiByteは文字列変換の標準関数。

#### Step 2: UTF16toUTF8命令を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mod_encode.hsp | `third_party/mod_encode.hsp` | **9-12行目**: UTF16toUTF8命令定義 |

**主要処理フロー**:
1. **10行目**: サイズ取得 `WideCharToMultiByte(CP_UTF8, 0, varptr(utf16), -1, 0, 0, 0, 0)`
2. **11行目**: バッファ確保 `sdim utf8, size*2`
3. **12行目**: 変換実行 `WideCharToMultiByte(CP_UTF8, 0, varptr(utf16), -1, varptr(utf8), size, 0, 0)`

#### Step 3: utf8enc関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mod_encode.hsp | `third_party/mod_encode.hsp` | **14-24行目**: utf8enc関数(SJIS→UTF-8) |

**主要処理フロー**:
1. **17行目**: SJIS→Unicode サイズ取得 `MultiByteToWideChar(CP_ACP, 0, ...)`
2. **18行目**: UTF-16バッファ確保 `sdim buf16, nSize * 2 + 2`
3. **19行目**: SJIS→Unicode 変換実行
4. **21行目**: Unicode→UTF-8 サイズ取得 `WideCharToMultiByte(CP_UTF8, 0, ...)`
5. **22行目**: UTF-8バッファ確保 `sdim buf08, nSize * 2`
6. **23行目**: Unicode→UTF-8 変換実行
7. **24行目**: `return buf08` - UTF-8文字列を返す

#### Step 4: sjisenc関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | mod_encode.hsp | `third_party/mod_encode.hsp` | **27-37行目**: sjisenc関数(UTF-8→SJIS) |

**主要処理フロー**:
1. **30行目**: UTF-8→Unicode サイズ取得 `MultiByteToWideChar(CP_UTF8, 0, ...)`
2. **31行目**: UTF-16バッファ確保
3. **32行目**: UTF-8→Unicode 変換実行
4. **34行目**: Unicode→SJIS サイズ取得 `WideCharToMultiByte(CP_ACP, 0, ...)`
5. **35行目**: SJISバッファ確保
6. **36行目**: Unicode→SJIS 変換実行
7. **37行目**: `return bufSJIS` - SJIS文字列を返す

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

```
呼び出し元(play_chart_load.hsp, result.hsp等)
    |
    +-- utf8enc(sjis_str)
    |       +-- MultiByteToWideChar(CP_ACP → UTF-16)
    |       +-- WideCharToMultiByte(UTF-16 → CP_UTF8)
    |       +-- return utf8_str
    |
    +-- sjisenc(utf8_str)
    |       +-- MultiByteToWideChar(CP_UTF8 → UTF-16)
    |       +-- WideCharToMultiByte(UTF-16 → CP_ACP)
    |       +-- return sjis_str
    |
    +-- UTF16toUTF8(utf16_var, utf8_var)
            +-- WideCharToMultiByte(UTF-16 → CP_UTF8)
```

### データフロー図

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

SJIS文字列 --------> utf8enc ----+
                     SJIS→UTF-16 +--> UTF-16中間 ---> UTF-8文字列
                                 |
UTF-8文字列 -------> sjisenc ----+
                     UTF-8→UTF-16 +--> UTF-16中間 ---> SJIS文字列
                                 |
UTF-16バイナリ ----> UTF16toUTF8 +------------------> UTF-8文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mod_encode.hsp | `third_party/mod_encode.hsp` | ソース | エンコード変換モジュール本体(全38行) |
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | 譜面読み込み時のエンコード変換利用元 |
| result.hsp | `src/scene/result.hsp` | ソース | リザルト画面での曲名エンコード変換利用元 |
