文字コード変換DLLのtconvlib.dllを直しました。実に8年越しの対処となります。
修正内容 §
ISO-2022-JPへ変換を行ったとき、終了時に2バイト文字モードだった場合、US-ASCIIモードに戻すエスケープシーケンスが入っていなかったので挿入するようにした。
最後にモードを戻す義務がどこまであるかは、RFC等を見た範囲では必ずしも明確ではなかったと記憶しますが、もはやかなり忘却の彼方です。
この問題はたいていの場合顕在化しません。なぜかといえば、改行コードが1バイト文字なので、行末で必ず1バイトモードに戻るからです。
この問題が顕在化するのは、メールのSubjectのエンコードが主です。SubjectをMIMEエンコードした時に、実装がまずいと文字化けの原因になります。たとえば、"あA"というSubjectがあり、"あ"だけをMIMEエンコードしたとします。このとき、MIMEエンコードしていない"A"はあくまで"A"であって他の文字ではありません。しかし、単純にMIMEエンコードをデコードして置換するだけ、という良くない実装が行われるケースがあります。このとき、従来のtconvlib.dllを使って文字コード変換を行うと、"あ"の後で戻るエスケープシーケンスが無いので、"A"は2バイト文字の1バイト目として認識され、文字化けします。
この問題は本質的にMIMEエンコードを扱うプログラム側で解決されるべきものだと思いますが、それはさておき、最後にUS-ASCIIに戻さないのも不自然な実装だし、tconvlib.dll側を直すだけで改善されるケースも多いと思うので、tconvlib.dllも直しました。
なぜ8年も放置されたのか §
仕様の不自然な点を解消する等の目的で、大々的なコードの改変に取り組んだものの、途中で力尽きていたからです。途中まで組んだコードを放棄して元のバージョンに戻って修正するか、それとも、そのままの方針で大工事を行うか、決断しきれず放置されていました。
更に時間が経過すると、ソースの詳細も忘れてしまいました。作業の手順、状況も忘れて、うかつにソースに触れなくなってしまいました。
今回は、「完全にUnicode時代に入った結果として、もうtconvを改善する必要はない」と割り切って、tconv 0.8のソースに戻ってそこから修正を入れました。
技術的な問題 §
しかし、一瞬で終わると思った修正は難工事になりました。
Visual SourceSafeが勝手にテキストファイル扱いして改行シーケンスを壊してしまったEUC-JPのテストファイルのおかげでテストがこけたり。ソースを読んだり。久々にVisual C++ 6.0を起動したり。
ソースの修正も簡単には行きませんでした。APIを変えずに動作を変えるためには、IsEOFでEOFになったときにバッファにエスケープシーケンスを足して「まだEOFではない」と嘘のリターンを行うというトリッキーな方法で解決しました。