# 機能設計書 95-IRハッシュ計算

## 概要

本ドキュメントは、K-Shoot MANIAにおけるインターネットランキング(IR)用の譜面一意識別MD5ハッシュ計算機能の設計を記述する。

### 本機能の処理概要

本機能は、KSH譜面ファイルの内容からメタデータ（タイトル、アーティスト、エフェクター等）を除外した正規化データのMD5ハッシュを計算し、譜面を一意に識別するためのハッシュ値を生成する機能である。

**業務上の目的・背景**：インターネットランキング(IR)では、同一の譜面を異なる環境やバージョンで一意に識別する必要がある。メタデータ（タイトルやアーティスト名など）は変更される可能性があるため、ノート配置や拍子変化等の本質的な譜面データのみからハッシュを計算することで、安定した識別子を提供する。

**機能の利用シーン**：
- リザルト画面でのIRスコア送信時に譜面識別子として使用
- 選曲画面のCtrl+IショートカットでIRページURLを構築する際に使用

**主要な処理内容**：
1. KSH譜面ファイルの全行を走査
2. ignoreListに含まれるメタデータ行を除外
3. 残りの行を連結した正規化文字列を生成
4. varmd5関数でMD5ハッシュを計算

**関連システム・外部連携**：IRサーバー(ir.kshootmania.com)への譜面識別子として使用。hspinet.dllのvarmd5関数でMD5計算。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 参照画面 | getChartIRHashによるメタデータ除外の正規化譜面データからのMD5ハッシュ計算 |
| 3 | 曲選択画面 | 参照画面 | Ctrl+IショートカットでIRページURL構築時にハッシュを使用 |
| 6 | リザルト画面 | 参照画面 | ir_send_scoreによるIRサーバーへのスコア送信時に譜面識別子として使用 |

## 機能種別

計算処理 / データ変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| p1 | var(str) | Yes | KSH譜面ファイルの内容文字列（notesel済み） | なし |

### 入力データソース

- 譜面ファイル(.ksh)の全内容をnoteload命令で読み込みnotesel済みの変数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 返値 | str | 32文字の16進数MD5ハッシュ文字列 |

### 出力先

- 返値として呼び出し元に返却
- IRサーバーへのHTTPリクエストパラメータとして使用
- IRページURL(https://ir.kshootmania.com/md5/{hash})として使用

## 処理フロー

### 処理シーケンス

```
1. 入力文字列(p1)と同サイズのバッファ(buf)を確保
   └─ sdim buf, strlen(p1)
2. 除外対象リスト(ignoreList)を定義
   └─ //, title=, artist=, effect=, jacket=, level=, difficulty=, m=, o=, v=, vo= 等32種類
3. noteselで行単位処理を開始
   └─ 各行をnotegetで取得
4. 各行がignoreListのいずれかで開始するかチェック
   └─ StartsWith関数でプレフィックス一致確認
5. 除外対象でない行のみbufに追記(改行付き)
6. bufのMD5ハッシュを計算
   └─ varmd5 ret, buf, strlen(buf)
7. ハッシュ文字列を返却
```

### フローチャート

```mermaid
flowchart TD
    A[KSH譜面内容受け取り] --> B[bufバッファ確保]
    B --> C[ignoreList定義: 32項目]
    C --> D[行ループ開始]
    D --> E{ignoreListのプレフィックス一致?}
    E -->|Yes| F[行をスキップ]
    E -->|No| G[bufに行+改行を追加]
    F --> H{次の行あり?}
    G --> H
    H -->|Yes| D
    H -->|No| I[varmd5でMD5計算]
    I --> J[ハッシュ文字列返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-95-01 | メタデータ除外 | ignoreListに定義された32種類のプレフィックスに一致する行を除外 | 全行に対して適用 |
| BR-95-02 | 除外対象一覧 | //, title=, title_img=, artist=, artist_img=, effect=, illustrator=, jacket=, level=, difficulty=, m=, o=, v=, vo=, mvol=, bg=, layer=, po=, plength=, pfiltergain=, filtertype=, chokkakuautovol=, chokkakuvol=, chokkakuse=, icon=, ver=, fx-l=, fx-r=, #define, information=, ver_compat=, title_translit=, artist_translit= | getChartIRHash関数内 |
| BR-95-03 | 正規化形式 | 除外されなかった行を改行(\n)で連結して正規化文字列を構成 | buf構築時 |
| BR-95-04 | MD5計算 | varmd5関数で32文字の16進数ハッシュを計算 | 正規化文字列完成後 |

### 計算ロジック

- 正規化: 各行がignoreListのいずれにもStartsWithしない場合のみbufに追加
- MD5: `varmd5 ret, buf, strlen(buf)` で計算

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

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

## エラー処理

### エラーケース一覧

特になし。入力データが空の場合も空文字列のMD5が返却される。

### リトライ仕様

特になし。

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

特になし。

## パフォーマンス要件

選曲画面のCtrl+I操作時にリアルタイムで計算されるため、十分高速に動作する必要がある。

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

MD5ハッシュは衝突耐性が低いため、セキュリティ目的ではなく識別目的のみで使用される。

## 備考

- ignoreListは32項目で、譜面のノート配置・BPM変化・拍子変化等の本質的データのみがハッシュに含まれる
- getChartIRHashは#defcfunc(返値あり関数)として定義されている
- StartsWith関数はksmcore.dllで定義(ksmcore.as 12行目)

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ir.hsp | `src/ir.hsp` | ignoreList配列(53行目): 除外対象プレフィックスの32項目定義 |

**読解のコツ**: HSP3のnotesel/noteget命令は、改行区切りの文字列(メモ帳)を行単位で操作する。notemax変数で行数を取得し、noteget命令で各行を読み取る。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ir.hsp | `src/ir.hsp` | getChartIRHash(51-68行目): メイン関数 |

**主要処理フロー**:
1. **52行目**: bufバッファを入力文字列長で確保
2. **53行目**: ignoreListに32種類のプレフィックスを定義
3. **54-66行目**: 行ループで各行のプレフィックスチェックと正規化
4. **67行目**: varmd5でMD5ハッシュを計算
5. **68行目**: ハッシュ文字列を返却

#### Step 3: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.hsp | `src/scene/select.hsp` | Ctrl+IショートカットでのgetChartIRHash呼び出し(308行目) |

**主要処理フロー**:
- **308行目**: `exec "https://ir.kshootmania.com/md5/" + getChartIRHash(buf), 16` でブラウザ起動

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

```
select.hsp (Ctrl+Iショートカット)
    |
    +-- noteload filePath
    |
    +-- getChartIRHash(buf)  ← ir.hsp
    |       +-- ignoreList定義
    |       +-- 行ループ(noteget)
    |       |       └── StartsWith(line, ignoreList.cnt)  ← ksmcore.dll
    |       +-- varmd5(ret, buf, strlen(buf))  ← hspinet.dll
    |       └── return ret
    |
    └── exec "https://ir.kshootmania.com/md5/{hash}", 16
```

### データフロー図

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

KSH譜面全内容 ──────> ignoreListフィルタリング ──────> 正規化文字列(buf)
(notesel済み)              |
                           v
                     varmd5(hspinet.dll) ──────> MD5ハッシュ文字列(32文字)
                           |
                           v
                     IRページURL / IRスコア送信パラメータ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ir.hsp | `src/ir.hsp` | ソース | getChartIRHash関数の実装 |
| ksmcore.as | `src/ksmcore.as` | ソース | StartsWith関数のDLL定義 |
| select.hsp | `src/scene/select.hsp` | ソース | Ctrl+IショートカットでのgetChartIRHash呼び出し元 |
| result.hsp | `src/scene/result.hsp` | ソース | IRスコア送信時のハッシュ利用 |
