hakeの日記

Windows環境でプログラミングの勉強をしています。

添付ファイルの処理(Base64)

Rubyの勉強

メールにファイルが添付される場合は

Content-Type: application/octet-stream;
	name="zvol_0.0.4b-1_arm.ipk"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
	filename="zvol_0.0.4b-1_arm.ipk"

H4sIAMP4eEQAA+2aVVAczrPvIUCCQ5CgwYOzsPjiBAshwR0CwZ3FJcBuIBAseHBZnADB3RNs
cXdb3CU4LLInt87Drfo/nPP0P6du3d+nqqtrZnp6uqaqn74N4LW0Mrczc+Yxt3M2c/NF+3fA
以下略

といった感じでエンコードされたテキストデータが付加される、これのBase64によるエンコード/デコードを行ってみる。使用しているメールソフトをみるとエンコード方式は他にもあるみたいだけど、実際に使用されてるのでしょうか?この辺はあまり気にしたことが無いのでわかりません。Rubyのマニュアルを見るとBase64というライブラリがありますが既にobsoleteになっているので、解説どおりにpack/unpackを使ってみる。
Base64は8bit3文字を6bit4文字に変換するということなので、元になるバイナリを3バイトずつエンコードして出力。使用メールでは1行が72文字になっていたので、それに合せる。デコードは1行毎に読み込んで行う。

$/について

当初、実際にメールを介したデータだと上手くデコードできるのに、下のスクリプトエンコードしたデータだとデコードできないという問題が発生しました。エンコードデータのサイズは両方とも同じなのに比較してみると一部異なっている場所があり、正しいデータが「=」に置き換えられている場所が多数。元のバイナリの該当箇所をみると3バイトの中に0x0aがあると問題が発生するみたいだったので、改行あたりが怪しいとにらんで$/をいじったらビンゴでした。
これって仕様なんでしょうか、バグなんでしょうか?

追記

String#to_aは$/で分割されるとのことで、こういう使い方はダメだそうです。下のスクリプトも修正。



参考:packテンプレート文字列(http://www.ruby-lang.org/ja/man/?cmd=view;name=pack%A5%C6%A5%F3%A5%D7%A5%EC%A1%BC%A5%C8%CA%B8%BB%FA%CE%F3

BIN_ORG = 'F:/zvol_0.0.4b-1_arm.ipk'
TEXT    = 'F:/encode.txt'
BIN_DEC = 'F:/bin.ipk'

# 以下を行わないと0x0aが含まれるバイナリで
# エンコードが上手くいかない
# バグ?仕様?
# $temp = $/
# $/ = nil       # 区切り文字を一時的にnilにする
#
# => to_aを使用すると$/で分割されてしまうため


# Binary to Text(Base64)
f = File.open(BIN_ORG)
f.binmode      # only Windows
fout = File.open(TEXT, 'a')
i = 0
while bin = f.read(3)
  #str = bin.to_a.pack('m').chomp
  str = [bin].pack('m').chomp       # 修正
  fout.write(str)
  i += 1
  if i == 18 # 18*4=72文字で改行
    fout.puts
    i = 0
  end
end
fout.puts
fout.flush
fout.close
f.close


nil until fout.closed?
# $/ = $temp     # 区切り文字を元に戻す


# Text to Binary
fout = File.open(BIN_DEC, 'a')
fout.binmode   # only Windows
File.foreach(TEXT) do |line|
    fout.write(line.chomp.unpack('m'))
end
fout.close