///|
/// Shift_JISデコーダーの実装
/// ストリーミングデコードAPIを提供
///|
/// 新しいデコーダーを作成
pub fn Decoder::new() -> Decoder {
{ pending_first_byte: 0, had_replacements: false }
}
///|
/// デコーダーの状態をリセット
pub fn Decoder::reset(self : Decoder) -> Unit {
self.pending_first_byte = 0
self.had_replacements = false
}
///|
/// 置換文字が使用されたかどうかを返す
pub fn Decoder::had_replacements(self : Decoder) -> Bool {
self.had_replacements
}
///|
/// Shift_JISバイト列をUTF-8文字列にデコード(ストリーミング対応)
///
/// 引数:
/// - src: 入力バイト列
/// - last: 最後のチャンクかどうか(falseの場合、不完全なシーケンスを次回に持ち越し)
///
/// 戻り値: デコードされた文字列
pub fn Decoder::decode_to_string(self : Decoder, src~ : Bytes, last : Bool) -> String {
let mut result = ""
let mut i = 0
let len = src.length()
// 前回のペンディングバイトがあれば処理
if self.pending_first_byte != 0 {
if len == 0 {
if last {
// 不完全なシーケンスの終了
result = result + '\uFFFD'.to_string()
self.had_replacements = true
self.pending_first_byte = 0
}
} else {
let b1 = self.pending_first_byte
let b2 = src[0].to_int()
let valid_second = (b2 >= 0x40 && b2 <= 0xFC) && (b2 != 0x7F)
if valid_second {
let code = (b1 << 8) | b2
match decode_jis_x_0208(code=code) {
Some(ch) => result = result + ch.to_string()
None => {
result = result + '\uFFFD'.to_string()
self.had_replacements = true
}
}
i = 1
} else {
// 無効な2バイト目
result = result + '\uFFFD'.to_string()
self.had_replacements = true
// b2を再度処理(ASCII等の可能性があるため、iは進めない)
i = 0
}
self.pending_first_byte = 0
}
}
// メインのデコードループ
while i < len {
let b1 = src[i].to_int()
if b1 < 0x80 {
// ASCII (0x00-0x7F)
result = result + Int::unsafe_to_char(b1).to_string()
i += 1
} else if b1 >= 0xA1 && b1 <= 0xDF {
// 半角カタカナ (0xA1-0xDF) → U+FF61-U+FF9F
let ch = decode_half_width_katakana(byte=b1)
result = result + ch.to_string()
i += 1
} else if (b1 >= 0x81 && b1 <= 0x9F) || (b1 >= 0xE0 && b1 <= 0xEF) {
// 2バイト文字の1バイト目
if i + 1 < len {
// 同じチャンク内に2バイト目がある
let b2 = src[i + 1].to_int()
let valid_second = (b2 >= 0x40 && b2 <= 0xFC) && (b2 != 0x7F)
if valid_second {
let code = (b1 << 8) | b2
match decode_jis_x_0208(code=code) {
Some(ch) => result = result + ch.to_string()
None => {
result = result + '\uFFFD'.to_string()
self.had_replacements = true
}
}
i += 2
} else {
result = result + '\uFFFD'.to_string()
self.had_replacements = true
i += 1
}
} else if last {
// チャンクの末尾で、かつ最後のチャンク
result = result + '\uFFFD'.to_string()
self.had_replacements = true
i += 1
} else {
// ペンディング:次のチャンクを待つ
self.pending_first_byte = b1
i += 1
}
} else {
// 不明なバイト値 (0x80, 0xF0-0xFF)
result = result + '\uFFFD'.to_string()
self.had_replacements = true
i += 1
}
}
result
}