#!/usr/bin/env ruby
# (emonti at matasano) Matasano Security LLC 2008

require 'rbkb'
require 'rbkb/command_line'
require 'stringio'

include RBkB::CommandLine

first = 0
last = nil
verbose=true

#------------------------------------------------------------------------------
# Init options and arg parsing
OPTS = {:len => 16}
arg = bkb_stdargs(nil, OPTS)

arg.banner += " <input-file | blank for stdin>"

arg.on("-q", "--[no-]quiet", "Stifle extra data info") {|q| verbose=(!q)}
arg.on("-s", "--start=OFF", Numeric, "Start at offset") {|s| first=s}
arg.on("-e", "--end=OFF", Numeric, "End at offset") {|e| last=e}

begin
  #----------------------------------------------------------------------------
  # Parse arguments

  arg.parse!(ARGV)

  inp = nil

  if inpname=ARGV.shift
    inp=File.open(inpname, "rb") rescue "Error: Can't open file '#{a}'"
  else
    inp = StringIO.new(STDIN.read())
    inpname="stdin"
  end

  # catchall
  if ARGV.length != 0 
      raise "bad arguments - #{ARGV.join(' ')}"
  end

  #----------------------------------------------------------------------------
  # Do stuff

  # Right now this only handles gzip files... no deflate, no stream, no raw LZ
  gzc = "\x1f\x8b"

  off = inp.pos = first
  until inp.eof? or (last and inp.pos >= last)
    # grab 2 byte signature
    sig = inp.read(2)

    break if inp.eof?

    # compare with gzip signature
    if sig == gzc
      # return to start position
      off = (inp.pos -= 2)

      begin
        gz = Zlib::GzipReader.new(inp)
        dat = gz.read
        gz_size = inp.pos

        STDERR.puts "** %d bytes of gzip @ %0.8x" %[gz_size, off]
        if verbose
          STDERR.puts "  Extra info:"
          STDERR.puts "    inflated size = #{ dat.size}"
          gz.get_xtra_info.sort {|a,b| a.to_s <=> b.to_s }.each do |k,v|
            STDERR.puts "#{k.to_s.rjust(18)} = #{v.inspect}"
          end
        end

        # XXX assuming no better than 15% compression rate?
        inp.pos = inp.pos / 4
        next
      rescue
      end
    end

    # start again from next byte
    off = (inp.pos -= 1)
  end
rescue
  bail $!
end


