Simple zcat(1) in Perl with Compress::Raw::Zlib

Perlのzlibインターフェイスは沢山あってよく分からないが、単純に圧縮/解凍をするだけならCompress::Raw::Zlibがシンプルで良さそうだ。
これでzcat(1)を実装すると以下のようになる。

#!perl -w
use strict;
use Compress::Raw::Zlib;
my $z = Compress::Raw::Zlib::Inflate->new(
    -WindowBits => WANT_GZIP,
);
foreach my $file(@ARGV) {
    open my $fh, '<', $file or die "Cannot open $file: $!";

    while(read $fh, my $buf, 1024) {
        my $d;
        my $status = $z->inflate($buf, \$d, 1);
        ($status == Z_OK or $status == Z_STREAM_END)
            or die "Inflation error: $status";
        print $d;
    }
}

その他のハイレベルなライブラリ、たとえばIO::ZlibやIO::Compress::Gzip/IO::Uncompres::Gunzipなどは、圧縮アルゴリズムに関わらない統一したインターフェイスを提供するなどの利点があるが、対象がgzip固定ならC::Raw::Zlibで何の問題もなく、むしろ軽くて使いやすい。
また、上記のハイレベルなライブラリはコンストラクタでgzip headerの妥当性をチェックする等ある意味エラーに強いのだが、ソケットのように一度のreadで完全なgzip headerを読み込めない可能性があるファイルハンドルを渡すとデータが不整合とみなされる事があり、HTTP clientには適さない。この点、C::Raw::Zlibのinflate()は1 byteずつ渡しても正しく処理してくれるため、HTTP clientでは積極的に採用する理由がある。