ここで問題になるのが、pack文字列の中には読んでみないとデータ長が確定しない場合があること。なので、事前にpack文字列をパースして、判るならば読み込み長を事前に計算する実装にしてみた。以下ソース。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class IO | |
def unpack!(ptn) | |
ptn2 = ptn.dup | |
until ptn2.empty? | |
len += case ptn2 | |
when /\*/ | |
len = nil | |
break | |
when /^[aAcCx](\d+)/ | |
$1 ? $1.to_i : 1 | |
when /^[sSnv](\d+)/ | |
($1 ? $1.to_i : 1) * 2 | |
when /^[iIlLNVfegPp](\d+)/ | |
($1 ? $1.to_i : 1) * 4 | |
when /^[qQdEG](\d+)/ | |
($1 ? $1.to_i : 1) * 8 | |
else | |
len = nil | |
break | |
end | |
ptn.gsub(/^#{$&}/,'') | |
end | |
pos = self.tell if len.nil? | |
ret = read(len).unpack(ptn) | |
if len.nil? | |
pos += ret.pack(ptn).size | |
self.pos = pos | |
ret | |
end | |
end | |
end | |
# use like this | |
open(ARGV[0]) do |f| | |
p f.unpack!('csi') | |
p f.tell | |
end |
本来unpackで消費するバイト数が取得できたり、unpack時に1バイト取ってくる動作をカスタマイズできたりすれば、こんなゴマカシは必要ないわけで。この辺はRubyの入出力周り、とくにIOが安易にunixのファイルに準拠した仕様になっている弊害だと思う。
0 件のコメント:
コメントを投稿