#!/usr/bin/ruby
#
# Classe per la manipolazione di header nel formato Ogg
#
# By F. Piantini, 09/07/2006
#

require 'binaryfile'

class OggHeader

  # - - - - - - - - - - - - - - - - - - - -
  attr_reader :tot_page_size, :num_segs, :segs_len
  
  # - - - - - - - - - - - - - - - - - - - -
  CAPTURE_PATTERN_LEN = 4
  ABS_GP_BYTES = 8
  STREAM_SN_BYTES = 4
  PAGE_SEQNUM_BYTES = 4
  CKSUM_BYTES = 4
  
  HTF_PACKET_TYPE_MASK = 0x01
  HTF_FIRST_PAGE_FLAG = 0x02
  HTF_LAST_PAGE_FLAG = 0x04
  
  # Private methods - - - - - - - - - - - -
  private

  # Read from files method
  def rff_segment_table
    @tot_page_size = 0;
    @num_segs.times do |cont| 
      @segs_len[cont] = @in_file.getc
      @tot_page_size += @segs_len[cont]
    end
    @header_size += @num_segs
  end

  # print methods
  def print_header_type_flag
      printf("Header type flag          = 0x%02X - ", @header_type_flag)
    if ((@header_type_flag & HTF_PACKET_TYPE_MASK) != 0)
      printf "Continued packet, "
    else
      printf "Fresh packet, "
    end
    if ((@header_type_flag & HTF_FIRST_PAGE_FLAG) != 0)
      printf "First page (bos), "
    else
      printf "Not First page, "
    end
    if ((@header_type_flag & HTF_LAST_PAGE_FLAG) != 0)
      printf "Last page (eos)"
    else
      printf "Not Last page"
    end
    printf "\n"
  end

  def print_segment_table
    printf("Segments table            =");
    @num_segs.times { |cont| printf(" %d", @segs_len[cont]) }
    printf "\n"
    printf("Total header + page size  = %d + %d (total %d)\n", @header_size, 
           @tot_page_size, @header_size + @tot_page_size)
  end

  # Protected methods - - - - - - - - - - -
  protected
  
  # Public methods  - - - - - - - - - - - -
  public

  def initialize    # called by "new" method
    @segs_len = Array.new
  end
  
  def link_to_file(file)
    @in_file = file
  end
  
  def read_from_file

    @capture_pattern = @in_file.read(CAPTURE_PATTERN_LEN)
    @stream_structure_ver = @in_file.getc
    @header_type_flag = @in_file.getc
    @abs_granule_pos = @in_file.getint(ABS_GP_BYTES)
    @stream_sn = @in_file.getint(STREAM_SN_BYTES)
    @page_seqnum = @in_file.getint(PAGE_SEQNUM_BYTES)
    @page_cksum = @in_file.getint(CKSUM_BYTES)
    @num_segs = @in_file.getc

    @header_size = CAPTURE_PATTERN_LEN + 1 + 1 + ABS_GP_BYTES + 
      STREAM_SN_BYTES + PAGE_SEQNUM_BYTES + CKSUM_BYTES + 1
    
    rff_segment_table
  end
  
  def print
    printf("Capture pattern           = %s\n", @capture_pattern)
    printf("Stream structure version  = %s\n", @stream_structure_ver)

    print_header_type_flag

    printf("Absolute granule position = 0x%016X\n", @abs_granule_pos)
    printf("Stream serial number      = 0x%08X\n", @stream_sn)
    printf("Page sequence number      = 0x%08X\n", @page_seqnum)
    printf("Page checksum             = 0x%08X\n", @page_cksum)
    printf("Number of segments        = %d\n", @num_segs);
    
    print_segment_table

  end

end
