無難なBMSの指針

ファイル名に非ASCII文字を使わないでください

ギリシャ語Windows環境で、メモ帳で書かれエクスプローラーの圧縮フォルダーに送られた、ごく普通のBMSのZIP書庫。ギリシャ語環境ではBMS関連ソフトウェアによって正常に再生されます。

非ギリシャ語環境では文字化けし、ファイル名に不可視の制御文字が混入したり、エクスプローラーの圧縮フォルダーからファイルが見えず展開できなくなる場合があります。なぜ文字化けするのかというと、非ASCII文字を符号化・復号化する仕組みが言語環境ごとに異なるからです。

メモ帳による符号化
バイト列CFC4D6C1
米国英語ÏÄÖÁ
タイ語ฤึ
日本語
簡体字
韓国語
繁体字
圧縮フォルダー
バイト列8E839480
米国英語ÄâöÇ
タイ語
日本語
簡体字
韓国語
繁体字

気が利いた外部アーカイバーソフトウェアは使用者に文字化けを気づかせない場合があり、便利な一方で困った事態を引き起こしもします。展開時にフォルダー名の先頭部分が「ルモ・」に化けて、そのままRAR書庫としてTorrentパッケージに収録されてしまった例などが知られています。

OEM符号化ZIP
バイト列D9D3FCB3
米国英語
タイ語
日本語
簡体字
韓国語
繁体字
RAR内CP932バイト列
バイト列D9D38145
米国英語
タイ語
日本語
簡体字
韓国語
繁体字

ASCIIだけが文字化けしません。ファイル名の非ASCII文字を目視で見つけるのは難しい場合があるので、BMSテキスト内を[^\t-~]などの条件で正規表現検索して確認しましょう。

ASCIIは文字化けしませんが、非ASCII文字の誤った復号化に巻き込まれる場合はあります。

バイト列B6F32E776176
韓国語.wav
日本語wav

これは日本語Windows環境では、拡張子なしのファイルカ・wav」になります。

言語環境を問わずにBMSを正しく再生させる方法は、いまのところ二つしかありません。

BMSテキストをUnicodeで保存する

Windows 2000以降のメモ帳はUnicodeをサポートしています。メモ帳でBMSファイルを開き、「名前を付けて保存」ダイアログの「文字コード」欄から「UTF-8」を選択して、保存してください。(Windows NT 4.0のメモ帳はUTF-8を知りません。UCS-2の読み書きは可能です。UCS-2とは基本多言語面限定のUTF-16 (LE-BOM)であり、サロゲートペアは使えません。)

iBMSCはUnicodeをサポートしています。ただしBOMなしのUTF-8を自動認識しません。また音声プレビュー機能はANSIで書き表わせるファイル名しか再生しません。保存は正しく行われます。

HDX/IIDXvはUnicodeをサポートしています。ただしv1.13/v3.04時点では、冗長なバイト列を受け入れてしまいます。また基本多言語面にない文字を扱うBMSファイルは、HDX/IIDXvではCESU-8で符号化される必要があります。これは他の正しいUTF-8実装とは互換性がありません。

LR2やBMSEやuBMplayはUnicodeをサポートしていません。UTF-8のバイト列はANSIコードページで復号され、文字化けします。その結果、非ASCII名のファイルは参照に失敗します。#TITLEなどの文字列値が非ANSI文字を含む場合、LR2のデータベースに良くない影響があるかもしれません。

BMSフォルダーに、ANSI版(古い文字符号化方式)とUnicode版を同梱する例を紹介します。

このCP932符号化テキストは、韓国語環境では#TITLE _(갌3 걐곙 )_”や is …”に文字化けします(CP932とCP949を自動判別してくれるruv-itなどは除く)。しかしUnicode版は文字化けしないので、元の文字を判断するための根拠になります。

余談:複数の符号化形式が混在する例

KBP2012「結界」から引用
BMS韓国語日本語
#TITLE됌뙅둉火結界
#WAV010.wav0オオ.wav

感想欄でion_tracker氏が指摘しておられますが、ファイル名をASCIIのみで構成すれば、圧縮形式や符号化形式が何であれ、著者の意図通りにBMSが鳴ります。そうしないならBMSテキストの符号化形式は統一するべきだし、ファイル名やフォルダー名もUnicodeで圧縮しなければなりません。

Unicode差分つき無断再配布: https://hitkey.nekokan.dyndns.info/Genkai-UTF8.zip

ファイル名やフォルダー名もUnicodeで圧縮する

圧縮形式はRARが無難です(2002年5月版WinRAR v3.00以降がサポートするRAR2.91以上)。非ASCIIのファイル名を確実に格納できます。ファイル名の符号化形式は変則的ですが、基本的なバイト列はUTF-16LEの変形です。WinRAR v3.80まではWindows 95にも導入できます。Windows OSが(3.xや95/98/MeやNT 4.0ではなく)2000以降であれば、展開も確実に行えます。

7z形式も、非ASCIIファイル名をUTF-16LEで格納します。ただし7-Zip 15.14以降で作成された7z書庫をWinRAR 5.31以降で展開する場合は、7zxa.dllの最新版(7-Zip Extraに同梱)をWinRARインストールフォルダーに上書きしておく必要があります。

じつのところZIP形式もUnicodeに対応していますが(7-Zipならcu=onパラメータで作成)、Vista以前のエクスプローラーでそれを展開すると文字化けします(格納されたファイル名のUTF-8バイト列を、OEMコードページで復号するため)。またWindows 7ではKB2704299が必要です。Windows XPおよびそれ以前のエクスプローラー圧縮フォルダーは、deflate方式のZIP書庫にのみ対応しています。Windows Vista以降はdeflate64方式もサポートしています。

ギガバイト単位の巨大なBMSパッケージはRAR5で圧縮するのが良さそうです。分割圧縮可能、展開が高速、リカバリレコード付加可能、ファイル名をUTF-8バイト列で格納(バイナリを直接検索できます)。ただしWindows 95/98/Meは切り捨てることになります。Windows 2000上にはWinRAR 5.xを導入できませんが、7-Zipを用いれば、RAR5書庫の展開は可能です。2017年4月版WinRAR v5.50 beta1以降、WinRARにおけるRAR圧縮の既定形式はRAR4からRAR5に変更されました。

Windows Vistaまでを切り捨ててよいなら、UTF-8符号化ZIP書庫が最良です。OSを問わず標準の機能で展開できるからです。LZMA方式で圧縮すれば、Windows 10のエクスプローラーでさえ展開できないので、誤ったファイル名が展開される心配はありません(ZIPを選ぶ意味もないけど)。

Unicodeの諸問題

Mac OS Xは内部ではファイル名を分解して扱います。」は「ミ + リ + ハ + ゙ + ー + ル」になります。これはUnicode NFD仕様の実装のひとつですが、実際にテストしないと結果を推測しがたい部分があります。#WAV01 안녕.wav」(<U+C548> <U+B155>)は「안녕.wav」(<U+110B U+1161 U+11AB> <U+1102 U+1167 U+11BC>)を参照できるのでしょうか?

もし参照できるとすれば、システムは等価性を考慮することになりますが、では次の例のようなファイル参照は最終的にどのように処理されるのでしょうか? 等価性を考慮しないWindows上では、三つの音声は当然ながら別個のファイルとして区別され、別々に鳴らされるわけですが……

#TITLE Han God
#BPM 140
#WAV01 .wav // U+795E
#WAV02 .wav // U+FA19
#WAV03 神󠄀.wav // U+795E U+E0100
#00111:010203

検証用書庫は、Explzh v7.54で開くとファイルが一個見えなかったり、7-Zip 17.00 betaのcu=onでZIP圧縮するとWinRAR v5.50 beta 1で正しく展開できなかったり、Windows環境に限定してさえデータ交換がうまくいきません。この書庫がMac OS X上で正しく展開されるのか、私にはわかりません。

ファイルシステムの差異も無視できません。以下はWindowsとLinuxでの最長の名前の例です。

[Windows] D:\𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙.txt

[Linux] 𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙𛀀󠄀゙.txt

𛀀󠄀゙」の詳細
コードポイントU+1B000U+E0100U+3099
UTF-8バイト列F0 9B 80 80F3 A0 84 80E3 82 99
UTF-16代用対表現U+D82CU+DC00U+DB40U+DD00U+3099
UTF-16LEバイト列2C D800 DC40 DB00 DD99 30
CESU-8バイト列ED A0 ACED B0 80ED AD 80ED B4 80E3 82 99

Windowsのパス最大長はUTF-16LE換算で260文字Linuxのファイル名最大長は255バイトです。𛀀󠄀゙」はWindows NTFSにとって五文字分、UTF-8のファイルシステムにとって11バイト分です。長めの非ASCIIファイル名をWindows上で書庫に圧縮すると、別のOS上で書庫から展開できなくなったり、ファイルにアクセスできなくなったりする可能性があります。

Unicodeは言語環境の差異による文字化けを根絶しますが、かわりに実装水準の違いによるトラブルをもたらします。ターゲットをUnicode対応機種に限る場合でも、ファイル名に非ASCII文字を使うのは避けたほうが無難です。

たとえばファイル名に混入するゼロ幅スペースは極端に発見しづらい参照ミスの原因になりうるし、古いOSでは基本多言語面の範囲外文字は「豆腐tofu」として表示されるので見分けがつきません。不可視の空白類や制御文字は予想外に多く、それを用いた悪戯も知られています(たとえば書字方向変更)。「見えない文字」は潜在的に危険なので、ASCII空白文字の使用も推奨できません。

すべてのASCII印字可能文字が安全であるわけではありません

結論からいえば、かろうじて安全といえるのは英数字とアンダースコア(_)くらいです。ファイル名の先頭や末尾以外なら、ハイフンマイナス(-)も許容範囲でしょうか。

ファイル名 - 脚注2」の通り、Windowsにおいてファイル名末尾の空白は安全ではありません。たとえば外部アーカイバーの場合、展開できなかったり(これvsこれ)、コマンドプロンプト以外では削除できないフォルダーが作られたりします(旧版WinRARでサブフォルダーに展開時)。

Webからの参照が面倒な名前の例: <a href="%23WAV06%20&amp;copy%3B.%20%20%20.rar">

これらは問題になりうる名前の一例です。もしもすべてのWeb管理者が、HTMLをUTF-8で符号化し、属性値を必ず引用符で括り、危険な記号をすべてエスケープし、アップロードされるファイルの名前を無害化する処置を怠らず、名前に関する既知のテストケースをすべてクリアしているなら、「文字以外の機能を持ちうる記号」の使用をためらう理由はありません。

じつのところ、OSには予約名というものがあるし、Webの属性値には異なるいくつかの表現がありえますから(たとえばBase64)、英数字のみを使う場合でさえ、リスクを完全に回避できるわけではありません。しかしBMSにとって本質的でないこのような問題に、趣味の開発者の貴重な労力を割いてもらうというのは、あまり賢明な選択ではありません。

Windows上で「#WAV01 abc.wav」は実際の「ABC.WAV」を参照できてしまいますが、Linuxでは大文字小文字が区別されますAngolmoisはWindowsとの互換性を考慮し、明示的に大文字小文字を同一視します。しかし、BMS著者はそれを当てにするべきではありません。BMSテキスト上で参照されるファイル名と、実際のファイル名は、大文字小文字まで一致させてください。

打ち切り