# 機能設計書：100-encodings（文字エンコーディング変換）

## 1. 概要

### 本機能の処理概要
encodingsモジュールは、異なる文字エンコーディング間の変換機能を提供する。Unix系システムでは`iconv`ライブラリを使用し、WindowsではWindows APIを使用する。UTF-8、UTF-16、各国語コードページ（Shift_JIS、GB2312、ISO-8859シリーズなど）間の変換をサポートする。

### 関連画面
本機能は標準ライブラリの文字エンコーディング変換ユーティリティであり、特定の画面には関連しない。国際化対応アプリケーションやレガシーシステム連携で使用される。

### 機能種別
ライブラリ機能（文字エンコーディング変換・プラットフォーム抽象化）

## 2. 入力仕様

### 型定義
```nim
type
  EncodingConverter* = ...  # プラットフォーム依存
  EncodingError* = object of ValueError
```

#### プラットフォーム別実装
- **Unix**: `ptr ConverterObj`（iconvハンドル）
- **Windows**: `object { dest, src: CodePage }`

### 主要プロシージャ

| プロシージャ | シグネチャ | 説明 |
|------------|----------|------|
| getCurrentEncoding | `proc(uiApp = false): string` | 現在のエンコーディング取得 |
| open | `proc(destEncoding, srcEncoding: string): EncodingConverter` | コンバータ作成 |
| close | `proc(c: EncodingConverter)` | コンバータ解放 |
| convert | `proc(c: EncodingConverter, s: string): string` | 変換実行 |
| convert | `proc(s: string, destEncoding, srcEncoding: string): string` | ワンショット変換 |

### Windowsコードページマッピング
約150種類のエンコーディング名とWindowsコードページの対応表が定義されている（77-242行目）。

## 3. 出力仕様

### 戻り値

| プロシージャ | 戻り値型 | 説明 |
|------------|---------|------|
| getCurrentEncoding | string | 現在のエンコーディング名（Unixは常に"UTF-8"） |
| open | EncodingConverter | 変換用オブジェクト |
| convert | string | 変換後の文字列 |

### 例外

| 例外型 | 発生条件 |
|-------|---------|
| EncodingError | 不明なエンコーディング名 |
| EncodingError | 変換コンバータ作成失敗 |
| EncodingError | サポートされないエンコーディング（Windows） |
| OSError | 変換中のシステムエラー |

## 4. 処理フロー

### 4.1 変換処理フロー（Unix）

```
[open(destEncoding, srcEncoding)]
    |
    v
[iconvOpen(destEncoding, srcEncoding)]
    |
    +-- [成功] --> EncodingConverter返却
    |
    +-- [失敗: -1] --> EncodingError
    |
    v
[convert(c, s)]
    |
    v
[結果バッファ確保（入力長と同じ）]
    |
    v
[iconv呼び出しループ]
    |
    +-- [E2BIG] --> バッファ拡張して継続
    |
    +-- [EILSEQ/EINVAL] --> 不明文字をスキップ
    |
    +-- [その他エラー] --> raiseOSError
    |
    v
[iconvバッファフラッシュ]
    |
    v
[結果長を調整して返却]
```

### 4.2 変換処理フロー（Windows）

```
[open(destEncoding, srcEncoding)]
    |
    v
[nameToCodePage(destEncoding)]
[nameToCodePage(srcEncoding)]
    |
    +-- [不明: -1] --> EncodingError
    |
    v
[EncodingConverter{dest, src}返却]
    |
    v
[convert(c, s)]
    |
    v
[convertWin(src, dest, s)]
    |
    +-- [空文字列] --> ""返却
    |
    +-- [サポート外コードページ] --> EncodingError
    |
    v
[convertToWideString(src, s)]
    |   multiByteToWideChar
    |
    v
[convertFromWideString(dest, wideString)]
    |   wideCharToMultiByte
    |
    v
[変換結果を返却]
```

## 5. ビジネスルール

### BR-01: プラットフォーム抽象化
Unix系ではiconvライブラリ、WindowsではWindows APIを使用し、同一のインターフェースで文字エンコーディング変換を提供する。

### BR-02: UTF-16経由変換（Windows）
Windowsでは、ソースエンコーディングからまずUTF-16LEに変換し、その後ターゲットエンコーディングに変換する2段階方式を採用。

### BR-03: 不明文字のスキップ（Unix）
Unix版では、変換できない文字（EILSEQ/EINVAL）はスキップして処理を継続する。

### BR-04: 動的バッファ拡張
出力バッファが不足した場合（E2BIG）、自動的にバッファを拡張して変換を継続する。

### BR-05: エンコーディング名の正規化（Windows）
ハイフン/アンダースコアを無視し、大文字小文字を区別しない比較（eqEncodingNames）を使用。

### BR-06: Windowsの変換制限
UTF-16BE（コードページ1201）およびUTF-32（コードページ12000, 12001）はWindowsでサポートされない。

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

本機能はデータベース操作を行わない。

## 7. エラー処理

### エラーパターン

| プラットフォーム | 条件 | エラー |
|---------------|------|-------|
| 共通 | 不明なエンコーディング名 | EncodingError |
| Unix | iconvOpen失敗 | EncodingError |
| Unix | iconv変換エラー | OSError（EILSEQ/EINVAL以外） |
| Windows | サポート外コードページ | EncodingError |
| Windows | API失敗 | OSError |

### エラーリカバリ
- Unix: 不明文字はスキップして継続
- Windows: 変換失敗は例外で中断

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

本機能はトランザクション処理を行わない。

## 9. パフォーマンス要件

### 推奨使用パターン
- **繰り返し変換**: `open` → 複数回`convert` → `close`
- **単発変換**: `convert(s, destEncoding, srcEncoding)`（便利だが非効率）

### バッファ管理
- 初期バッファ: 入力長 + 入力長/4（25%の余裕）
- 動的拡張: 残り入力 * 2 + 5バイト

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

### 入力検証
- 不明文字は変換結果にそのまま残る可能性（Unix）
- 完全な変換保証はない

### リソース管理
- `open`で取得したコンバータは必ず`close`で解放が必要

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

### 11.1 推奨される読み解き順序

1. **モジュールドキュメント**（10-40行目）
   - 機能概要と使用例
   - 再利用可能なコンバータの例

2. **型定義**（46-59行目）
   - プラットフォーム別EncodingConverter
   - EncodingError例外

3. **Windowsコードページ定義**（76-242行目）
   - winEncodings配列
   - 各エンコーディング名とコードページの対応

4. **Windows固有関数**（255-291行目）
   - nameToCodePage: 名前→コードページ変換
   - Windows API宣言

5. **Unix固有関数**（292-329行目）
   - iconv関連の宣言
   - プラットフォーム別ライブラリ

6. **公開API**（331-511行目）
   - getCurrentEncoding
   - open/close
   - convert

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

```
[公開API]
├── getCurrentEncoding(uiApp: bool): string
│   └── [Windows] getACP() / getGetConsoleCP()
│   └── [Unix] "UTF-8"固定
│
├── open(destEncoding, srcEncoding): EncodingConverter
│   ├── [Windows] nameToCodePage × 2
│   └── [Unix] iconvOpen
│
├── close(c: EncodingConverter)
│   └── [Unix] iconvClose
│
└── convert(c, s) / convert(s, dest, src)
    ├── [Windows] convertWin
    │   ├── convertToWideString
    │   │   └── multiByteToWideChar
    │   └── convertFromWideString
    │       └── wideCharToMultiByte
    └── [Unix] iconv (ループ)
```

### 11.3 データフロー図

```
[Unix変換]
  入力文字列(srcEncoding)
       |
       v
  [iconv変換] ←── errno チェック
       |           |
       |     ┌─────┴─────┐
       |     E2BIG      EILSEQ/EINVAL
       |     (拡張)     (スキップ)
       v
  出力文字列(destEncoding)

[Windows変換]
  入力文字列(srcEncoding)
       |
       v
  [MultiByteToWideChar]
       |
       v
  UTF-16LE (中間表現)
       |
       v
  [WideCharToMultiByte]
       |
       v
  出力文字列(destEncoding)
```

### 11.4 関連ファイル一覧

| ファイル | 役割 | 行数 |
|---------|------|------|
| lib/pure/encodings.nim | エンコーディング変換の実装 | 512 |
| lib/pure/os.nim | raiseOSError | - |
| システム: libiconv | Unix版変換エンジン | - |
| システム: kernel32.dll | Windows版変換API | - |

### 11.5 重要な実装詳細

#### eqEncodingNames（63-74行目）
```nim
proc eqEncodingNames(a, b: string): bool =
  # ハイフン/アンダースコアを無視し、大文字小文字を区別しない比較
  while i < a.len and j < b.len:
    if a[i] in {'-', '_'}: inc i
    if b[j] in {'-', '_'}: inc j
    if a[i].toLowerAscii != b[j].toLowerAscii:
      return false
```

「UTF-8」と「utf_8」を同一視するための正規化比較。

#### iconv変換ループ（468-498行目）
```nim
while inLen > 0:
  iconvres = iconv(c, addr src, addr inLen, addr dst, addr outLen)
  if iconvres == high(csize_t):
    var lerr = errno
    if lerr == EILSEQ or lerr == EINVAL:
      # unknown char, skip
      dst[0] = src[0]
      src = cast[cstring](cast[int](src) + 1)
      ...
```

変換できない文字はそのままコピーしてスキップする。

#### Windows UTF-16経由変換（448-452行目）
```nim
let wideString = if int(codePageFrom) == 1200: s
                 else: convertToWideString(codePageFrom, s)
return if int(codePageTo) == 1200: wideString
       else: convertFromWideString(codePageTo, wideString)
```

コードページ1200（UTF-16LE）が入出力の場合は変換をスキップする最適化。

### 11.6 サポートされる主要エンコーディング

| カテゴリ | エンコーディング例 |
|---------|------------------|
| Unicode | UTF-8, UTF-16, UTF-16BE, UTF-32 |
| 西欧 | ISO-8859-1, Windows-1252, IBM437 |
| 日本語 | Shift_JIS, EUC-JP, ISO-2022-JP |
| 中国語 | GB2312, GBK, GB18030, Big5 |
| 韓国語 | EUC-KR, ISO-2022-KR |
| キリル | KOI8-R, KOI8-U, Windows-1251 |
| EBCDIC | IBM037, IBM500等 |
