すがブロ

sugamasaoのhatenablogだよ

RFC2231を読む

人生に三度来るという RFC 読みたい期の第一期

何をとち狂ったのか、仕事の息抜きに RFC を読んでいます。これは人生に三度来るという RFC 読みたい期に突入したと言って良いでしょう。
で、何の RFC を読んでいるかというと、メールの添付ファイル名についてのフォーマット

ここら辺を見ているのだけど、もう少し素人にも優しいページ

ココを見て解読中。

余談

Thunderbird 1.5 がでたばかりの頃は、この RFC2231 に準拠したファイル名を解釈できるメーラーは多くなかったそうで、「XXさんのメールについてる添付ファイルが読めません><」みたいな事があったそうな。
で、その時のファイル名ってのが RFC2322 に準拠した変換をしている・・・はずだけど、微妙に間違っていたらしい。
以下を見ると、一目瞭然で、ファイル名を折り返す際の行末はセミコロンで区切るはずが、改行のみで区切られているという件。

ちなみに、現在、自分の使っている Thunderbird 2.0(MacOSX版)では正しくセミコロンで区切られているようです。

閑話休題

で、 RFC を読んでいるわけだけど、非常にわかりにくい。なので、日本語の解説ページを辺り、デコード方法を考える。
例えば、Japanese Filename ここでの例として、以下のような文字列が現されている*1

Content-Disposition: attachment;
filename*=iso-2022-jp'ja'%1B%24B%24%5B%244%24%5B%242%1B%28B.jpeg

これが「ほごほげ.jpeg」となるようだ。
とりあえず、filename* の解釈とか、iso-2022-jp とか書いてある部分は無視して、本文部分(つまり、「ほごほげ.jpeg」の部分)をどう解釈すれば良いのかを考える。

%1B%24B%24%5B%244%24%5B%242%1B%28B.jpeg

これね。

まず最初に、なんとなくイメージとして、文字コードが ISO2022-JP*2であることから、漢字INや漢字OUTと言ったJIS漢字コードが含まれる事が想像できる。
という訳で、どのように解釈していくかと言うと・・・

  • %がある部分は 16 進数の二桁だよ
  • 元々英数字のものはそのままだよ

という風に見る。つまり、16進数の文字か、16進数ではない文字のどちらかを片側に合わせてあげる必要がある(ややこしい・・・)。
例えば、16進数部分(%XX)を文字列*3に戻してあげれば、普通の文字コード(JISコード)の文字列になるはずである。
というわけで、 ruby で書いてみた。・・・というか、書くに至るまでに2時間くらい掛かった\(^o^)/
ロジック的には分かったんだけど、基数変換とかやってるとわけわからなくなるんよ><

irb(main):150:0* str = '%1B%24B%24%5B%244%24%5B%242%1B%28B.jpeg'
=> "%1B%24B%24%5B%244%24%5B%242%1B%28B.jpeg"
irb(main):151:0> str.gsub(/%([\dA-F][\dA-F])/i) { $1.to_i(16).chr }
=> "\e$B$[$4$[$2\e(B.jpeg"

とりあえず、%の次の二文字を取るのはすぐにできるんだけど、それをどうやって文字に戻すのか、もうパニックですよ。。。
ってか、 gsub とか久しぶりにつかった気がする!
で、こんな感じの文字列になったのだけど、これでは常人には読めない。とりあえず、文字コードUTF-8 にしてみる。

irb(main):153:0* res = str.gsub(/%([\dA-F][\dA-F])/i) { $1.to_i(16).chr }
=> "\e$B$[$4$[$2\e(B.jpeg"
irb(main):154:0> $KCODE='u'
=> "u"
irb(main):155:0> NKF.nkf("-w", res)
=> "ほごほげ.jpeg"

おおぉ、読める!

というわけで

うまい事 %の 16進数を抜き出して、その値をアスキーコード表に基づいて変換してあげると、元の文字列にできますね。
ね、簡単でしょう?

*1:例を簡単にするため、1行のものを使用する

*2:いわゆる「JIS」

*3:例えば、%20だったらスペース、のように