# 機能設計書: MemoryStream

## 1. 機能概要

### 1.1 機能名
MemoryStream（メモリストリーム）

### 1.2 機能ID
No.27

### 1.3 機能分類
System.IO - 入出力

### 1.4 概要説明
MemoryStreamは、メモリ上にデータを格納するインメモリストリームを提供するクラスである。.NET FrameworkのMemoryStreamクラスをVB6で実装したもので、バイト配列をバッキングストアとして使用し、ファイルを使用せずにストリーム操作を行える。

### 1.5 主な用途
- 一時的なデータのバッファリング
- バイト配列のストリームラッパー
- テスト用のモックストリーム
- データの中間処理（変換、圧縮等）
- シリアライズ/デシリアライズのバッファ

---

## 2. 機能詳細

### 2.1 提供機能一覧

| No | 機能名 | 説明 |
|----|--------|------|
| 1 | ReadByte | 1バイト読み取り |
| 2 | ReadBlock | 複数バイト読み取り |
| 3 | WriteByte | 1バイト書き込み |
| 4 | WriteBlock | 複数バイト書き込み |
| 5 | SeekPosition | ストリーム内の位置を移動 |
| 6 | Flush | フラッシュ（MemoryStreamでは何もしない） |
| 7 | CloseStream | ストリームを閉じる |
| 8 | SetLength | ストリーム長を設定 |
| 9 | ToArray | 内容をバイト配列として取得 |
| 10 | WriteTo | 別のストリームに内容を書き込み |
| 11 | CopyTo | 別のストリームにコピー |
| 12 | BeginRead | 非同期読み取り開始 |
| 13 | EndRead | 非同期読み取り終了 |
| 14 | BeginWrite | 非同期書き込み開始 |
| 15 | EndWrite | 非同期書き込み終了 |

### 2.2 処理フロー

#### 2.2.1 読み取りフロー（ReadBlock）
```
1. 配列範囲検証（ValidateArrayRange）
   ↓
2. オープン確認（EnsureOpen）
   ↓
3. バッファ確認（EnsureBuffer）
   ↓
4. 位置がLength以上の場合、0を返却
   ↓
5. 要求量がストリーム残量より大きい場合、残量に調整
   ↓
6. CopyMemoryでバッファからデータをコピー
   ↓
7. 位置を更新して読み取りバイト数を返却
```

#### 2.2.2 書き込みフロー（WriteBlock）
```
1. 配列範囲検証（ValidateArrayRange）
   ↓
2. 書き込み可能性チェック（EnsureWritable）
   ↓
3. オープン確認（EnsureOpen）
   ↓
4. バッファ確認（EnsureBuffer）
   ↓
5. 必要に応じて容量拡張（EnsureCapacity）
   ↓
6. CopyMemoryでバッファにデータをコピー
   ↓
7. 位置を更新、Lengthを更新（必要に応じて）
```

### 2.3 データ構造

#### 2.3.1 クラスメンバ変数
```vb
Private mMode           As BufferMode   ' バッファモード
Private mBufferSet      As Boolean      ' バッファ設定済みフラグ
Private mBuffer()       As Byte         ' 内部バッファ
Private mCanWrite       As Boolean      ' 書き込み可能フラグ
Private mPosition       As Long         ' 現在位置
Private mCapacity       As Long         ' 容量
Private mLength         As Long         ' データ長
Private mIsClosed       As Boolean      ' クローズ済みフラグ
Private mExpandable     As Boolean      ' 拡張可能フラグ
Private mIndex          As Long         ' 配列開始インデックス
Private mAsyncPtr       As Long         ' 非同期結果ポインタ
```

#### 2.3.2 定数・列挙型
```vb
Private Const DefaultCapacity As Long = 256     ' デフォルト容量
Private Const MaxStreamLength As Long = 2147483647  ' 最大ストリーム長

' バッファモード
Public Enum BufferMode
    ShareMode       ' 元配列を共有（参照）
    CopyMode        ' 元配列をコピー
    AcquireMode     ' 元配列を取得（元配列はNullに）
End Enum
```

### 2.4 バッファモードの詳細

| モード | 説明 | 拡張可能 | 注意点 |
|--------|------|----------|--------|
| ShareMode | 元配列への参照を保持 | No | 元配列がMemoryStreamより長生きする必要あり |
| CopyMode | 元配列のコピーを作成 | No | 元配列は影響を受けない |
| AcquireMode | 元配列を「盗む」 | Yes | 元配列変数はNothingになる |

### 2.5 実装インターフェース

| インターフェース | 説明 |
|------------------|------|
| IObject | 基本オブジェクト機能（Equals, GetHashCode, ToString） |
| Stream | ストリーム抽象クラス機能 |

---

## 3. インターフェース仕様

### 3.1 パブリックAPI

#### 3.1.1 ReadByte メソッド
```vb
Public Function ReadByte() As Long
```
**戻り値**: 読み取ったバイト値（0-255）、ストリーム終端の場合は-1

#### 3.1.2 ReadBlock メソッド
```vb
Public Function ReadBlock(ByRef Buffer() As Byte, ByVal Offset As Long, ByVal Count As Long) As Long
```
**パラメータ**:
- Buffer: 読み取りデータを格納する配列
- Offset: 配列内の開始インデックス
- Count: 読み取るバイト数

**戻り値**: 実際に読み取ったバイト数

#### 3.1.3 WriteByte メソッド
```vb
Public Sub WriteByte(ByVal Value As Byte)
```
**パラメータ**:
- Value: 書き込むバイト値

#### 3.1.4 WriteBlock メソッド
```vb
Public Sub WriteBlock(ByRef Buffer() As Byte, ByVal Offset As Long, ByVal Count As Long)
```
**パラメータ**:
- Buffer: 書き込みデータを含む配列
- Offset: 配列内の開始インデックス
- Count: 書き込むバイト数

#### 3.1.5 SeekPosition メソッド
```vb
Public Function SeekPosition(ByVal Offset As Currency, ByVal Loc As SeekOrigin) As Currency
```
**パラメータ**:
- Offset: 移動量（バイト）
- Loc: 基準位置（FromBeginning/FromCurrent/FromEnd）

**戻り値**: 新しいストリーム位置

#### 3.1.6 SetLength メソッド
```vb
Public Sub SetLength(ByVal Value As Currency)
```
**パラメータ**:
- Value: 新しいストリーム長

#### 3.1.7 ToArray メソッド
```vb
Public Function ToArray() As Byte()
```
**戻り値**: ストリーム内容のコピー（バイト配列）

**備考**: 閉じられたストリームでも動作する

#### 3.1.8 WriteTo メソッド
```vb
Public Sub WriteTo(ByVal Stream As Stream)
```
**パラメータ**:
- Stream: 書き込み先ストリーム

#### 3.1.9 Capacity プロパティ
```vb
Public Property Get Capacity() As Long
Public Property Let Capacity(ByVal Value As Long)
```
**備考**: 拡張可能でないストリームでは設定時にNotSupportedException

---

## 4. 内部処理詳細

### 4.1 Init サブルーチン
バイト配列からストリームを初期化する。

**処理概要**（820-847行目）:
1. 配列範囲検証
2. インデックスと容量の設定
3. バッファモードに応じた処理
   - ShareMode: SAPtr参照とロック
   - CopyMode: 配列のコピー
   - AcquireMode: SAPtr移動

### 4.2 EnsureBuffer サブルーチン
バッファが設定されていない場合、初期化する。

**処理概要**（853-863行目）:
1. バッファ未設定の場合、初期化
2. 拡張可能な場合、容量確保

### 4.3 EnsureCapacity サブルーチン
必要な容量を確保する。

**処理概要**（877-887行目）:
1. 必要容量が現在容量以下なら終了
2. 新容量 = 現在容量 * 2
3. 必要容量より小さければ調整
4. Capacity設定で配列をReDim

### 4.4 CloseStream サブルーチン
ストリームを閉じる。

**処理概要**（429-438行目）:
1. 既に閉じていれば終了
2. ShareModeの場合、配列のロック解除とポインタクリア
3. mIsClosedフラグを設定

---

## 5. 関連コンポーネント

### 5.1 依存クラス/モジュール

| クラス名 | 用途 |
|----------|------|
| StreamAsyncResult | 非同期操作結果 |
| Stream | 基底インターフェース |

### 5.2 シリアライゼーション
PropertyBagを使用した永続化をサポート（893-919行目）:
- Buffer, CanWrite, Position, Capacity, Length, IsClosed, Indexを保存

---

## 6. エラー処理

### 6.1 例外一覧

| 例外 | 発生条件 |
|------|----------|
| ArgumentNullException | Bufferが未初期化、StreamがNothing |
| ArgumentOutOfRangeException | 負のOffset/Count/Position/Capacity |
| ArgumentException | 無効な配列範囲、無効なSeekOrigin |
| NotSupportedException | 書き込み不可/拡張不可のストリームへの操作 |
| ObjectDisposedException | 閉じられたストリームへの操作 |
| InvalidOperationException | タイムアウト操作（サポートされていない） |

---

## 7. パフォーマンス考慮

### 7.1 計算量

| 操作 | 計算量 |
|------|--------|
| ReadByte/WriteByte | O(1) |
| ReadBlock/WriteBlock | O(n) |
| SeekPosition | O(1) |
| ToArray | O(n) |
| SetLength（拡張時） | O(n) |
| Capacity設定（拡張時） | O(n) |

### 7.2 メモリ使用
- デフォルト容量: 256バイト
- 容量不足時: 現在容量の2倍に拡張
- 最大長: 2^31 - 1 バイト（約2GB）

### 7.3 推奨事項
- 事前にサイズがわかる場合はCapacityを設定
- 大量のデータを扱う場合はShareModeを検討
- ToArrayは新しい配列を作成するため、頻繁な呼び出しは避ける

---

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

### 8.1 推奨読解順序

1. **データ構造の理解**
   - `MemoryStream.cls` 86-96行目: メンバ変数定義
   - 77-81行目: BufferMode列挙型
   - 83-84行目: 定数定義

2. **初期化処理**
   - `Class_Initialize` (814-818行目): デフォルト初期化
   - `Init` (820-847行目): バイト配列からの初期化

3. **基本操作**
   - `ReadByte` (590-600行目): 1バイト読み取り
   - `ReadBlock` (560-573行目): 複数バイト読み取り
   - `WriteByte` (518-529行目): 1バイト書き込み
   - `WriteBlock` (476-493行目): 複数バイト書き込み

4. **内部アルゴリズム**
   - `EnsureBuffer` (853-863行目): バッファ初期化
   - `EnsureCapacity` (877-887行目): 容量拡張
   - `EnsureOpen` (865-869行目): オープン確認
   - `EnsureWritable` (871-875行目): 書き込み可能確認

5. **ユーティリティ**
   - `ToArray` (706-717行目): 配列変換
   - `WriteTo` (741-748行目): 別ストリームへ書き込み

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

```
MemoryStream.Init
  ├── ValidateArrayRange
  ├── MakeArrayRange
  └── [モード別処理]
        ├── ShareMode: SAPtr設定 + SafeArrayLock
        ├── CopyMode: 配列コピー
        └── AcquireMode: SAPtr移動

MemoryStream.WriteBlock
  ├── ValidateArrayRange
  ├── EnsureWritable
  ├── EnsureOpen
  ├── EnsureBuffer
  │     ├── ReDim mBuffer
  │     └── EnsureCapacity
  ├── EnsureCapacity
  │     └── Capacity Let (ReDim Preserve)
  └── CopyMemory

MemoryStream.ReadBlock
  ├── ValidateArrayRange
  ├── EnsureOpen
  ├── EnsureBuffer
  └── CopyMemory
```

### 8.3 データフロー図

```
[ユーザーデータ]
      │
      ↓
[WriteBlock] ──→ [EnsureCapacity] ──→ [ReDim Preserve]
      │                                     │
      └─────────────→ [mBuffer] ←───────────┘
                          │
                          ↓
                    [ReadBlock]
                          │
                          ↓
                  [ユーザーデータ]

[ToArray]
      │
      ↓
[mBuffer] ──→ [CopyMemory] ──→ [新配列]
```

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

| パス | 種別 | 役割 |
|------|------|------|
| Source/CorLib/System.IO/MemoryStream.cls | クラス | メインクラス |
| Source/CorLib/System.IO/Stream.cls | インターフェース | ストリーム基底 |
| Source/CorLib/System.IO/StreamAsyncResult.cls | クラス | 非同期結果 |

### 8.5 読解のコツ
- mIndexは外部配列使用時のオフセット（自己作成バッファでは0）
- ShareModeではSAPtr操作とSafeArrayLock/Unlockに注意
- mExpandableがFalseの場合は容量変更不可
- Flushは何もしない（メモリ上なので不要）
- 非同期操作は実質的に同期操作（メモリアクセスは即座に完了）

---

## 9. 変更履歴

| 日付 | バージョン | 変更内容 |
|------|------------|----------|
| 2015 | 1.0 | 初期実装（Kelly Ethridge） |

---

## 10. 備考

- .NET FrameworkのSystem.IO.MemoryStreamと互換性のあるAPI設計
- Currency型を使用してStream共通インターフェースと互換性を持たせているが、内部はLong（32ビット）で管理
- ShareModeではSafeArrayLockで配列をロックし、ReDim/Eraseを防止
- Persistable=1のため、PropertyBagでシリアライズ可能
- ToArrayは閉じたストリームでも動作する
