無難なBMSの指針

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

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

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

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

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

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

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

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

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

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

言語環境を問わずにBMSを正しく再生させる方法は、いまのところ二つしかありません。(BMS形式にこだわる必要がない場合は、第三の方法も選択できます。)

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

Windows NT系のメモ帳(notepad.exe)は、NT 4.0以降はUnicodeをサポートしています。

Windows 2000からWindows 10 October 2018 Update 1809までのメモ帳:

メモ帳でBMSファイルを開き、「名前を付けて保存」ダイアログの「文字コード」欄から「UTF-8」を選択して、保存してください。

Windows 10 May 2019 Update 1903以降のメモ帳:

メモ帳でBMSファイルを開き、「名前を付けて保存」ダイアログの「文字コード」欄から「UTF-8 (BOM 付き)」を選択して、保存してください。

Windows NT 4.0のメモ帳:

Windows NT 4.0のメモ帳はUTF-8を知りません。BOMつきUTF-16(Little Endian)の読み書きは可能です。メモ帳でBMSファイルを開き、「名前を付けて保存」ダイアログで「Unicode で保存する」をチェックして保存すると、BMSテキストはUTF-16LE (BOMつき)で符号化されます。

正確にいえば、Windows NT 4.0のファイルシステムはUCS-2を採用しているそうです。UCS-2は「基本多言語面限定のUTF-16」と考えることができます。UCS-2ではサロゲートペアは扱えないため、追加面に収録された絵文字などの類は一切扱えません。

……ということになっているはずなのですが、実際はファイルシステムから見えるバイトシーケンスがWindows 2000以降のそれと同一であれば特に問題は発生しないようです。

iBMSC

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

μBMSC

iBMSCの音声プレビュー機能に関する不具合はμBMSCで解消されました。またμBMSCでは既定のencodingが変更されたため、BOMなしのUTF-8を問題なく認識してくれるようになりました。そのかわり日本語や韓国語のBMSを開くと文字化けするようになりました。Encodingを指定して開き直すことで解決可能です。

HDX/IIDXv

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

LR2, BMSE/uBMplay, その他

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

Windows 10 April 2018 Update 1803以降(正しくはWindows 10 Redstone 4のInsider Preview以降)、システムロケールにUTF-8を選択できるようになりました。このオプションを有効化した環境では、LR2やBMSEやuBMplayがUTF-8符号化BMSを正しく再生できるようになり、そのかわり従来のANSIコードページで書かれた「非ASCIIファイル名を参照するBMS」が正しく再生されなくなります(期待通りには音が鳴らなくなったり文字化けしたりするようになります)。

以下の方法はもはや現代的ではありません。

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

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

前述の方法はもはや現代的ではありません。Unicode版BMSのかわりに、BMSON形式のファイルを同梱することを推奨します。「システムロケールがUTF-8でない従来環境のための、およびUTF-8を知らない旧型機種のための、ANSI版BMS」と、「新しいBMSON対応機種のためのBMSON」を同梱できれば、互換性が問題になる状況はほぼ避けられるでしょう。

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

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.9以上)。非ASCIIのファイル名を確実に格納できます。ファイル名の符号化形式は変則的ですが、基本的なバイト列はUTF-16LEの変形です。WinRAR v3.80まではWindows 95にも導入できます。Windows NT 4.0以降のNT系OSであれば、展開も確実に行えます。

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

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

ギガバイト単位の巨大なBMSパッケージはRAR5で圧縮するのが良さそうです。分割圧縮可能、クイックオープンインフォメーションにより高速に展開可能、リカバリレコード付加可能、ファイル名をUTF-8バイト列で格納(バイナリを直接検索できます)。ただしWindows 95/98/Meは切り捨てることになります。WinRAR 5.x以降を導入できないWindows 2000上でも、7-Zipを用いればRAR5書庫を展開できます。2017年4月版WinRAR v5.50 beta 1以降、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>)は「&#x110B;&#x1161;&#x11AB;&#x1102;&#x1167;&#x11BC;.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

(U+FA19はHTML仕様範囲外なので、例示では他の文字の組み合わせで代用しています)

検証用書庫は、Explzh v7.58で開くとファイルが一個見えなかったり(v7.99で確認したところ、いつのまにかどこかの版で修正されたようでした)7-Zip 24.01 betaでZIP圧縮するとWinRARで正しく展開できなかったり、Windows環境に限定してさえデータ交換がうまくいきません。この書庫がMac OS X上で正しく展開されるのか、私にはわかりません。

なおUbuntu 19.10上のUNRAR 5.61 beta 1で、前述の検証用RAR4書庫は正しく展開されません。7z形式、RAR5形式、ファイル名がUTF-8で符号化されたZIP形式などの書庫であれば、Ubuntu上でもWindows上と同等のファイル名で展開されます。また前述のBMSを変換したBMSON(この段落の書庫に同梱)は、Ubuntu上でもWindows上でもbeatorajaによって同等に再生されます。

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

[Windows] D:\𛀀󠄀゙(50回繰り返し).txt

[Linux] 𛀀󠄀゙(22回繰り返し).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テキスト上で参照されるファイル名と、実際のファイル名は、大文字小文字まで一致させてください。

打ち切り