Cross package maker. DEB/RPM generation or conversion. Derived from jordansissel/fpm.

⌈⌋ ⎇ branch:  cross package maker


Artifact [983a4f514f]

Artifact 983a4f514f6c3ec2860b0ab87a424112c6b9a050:

  • File lib/rpm/header.rb — part of check-in [35f668b84f] at 2011-05-14 07:49:46 on branch trunk — - factor out the rpm bits into separate class files - include all known rpm 'tag' types (user: jls@semicomplete.com size: 2805)

require File.join(File.dirname(__FILE__), "namespace")
require File.join(File.dirname(__FILE__), "tag")

class RPMFile::Header
  attr_reader :tags
  attr_reader :length

  attr_accessor :magic  # 8-byte string magic
  attr_accessor :index_count  # rpmlib calls this field 'il' unhelpfully
  attr_accessor :data_length   # rpmlib calls this field 'dl' unhelpfully

  HEADER_SIGNED_TYPE = 5
  HEADER_MAGIC = "\x8e\xad\xe8\x01\x00\x00\x00\x00"

  def initialize(rpm)
    @rpm = rpm
    @tags = []
  end

  def read
    # TODO(sissel): update the comments here to reflect learnings about rpm
    # internals
    # At this point assume we've read and consumed the lead and signature.
    #len = @rpm.signature.index_length + @rpm.signature
    #
    # header size is 
    #     ( @rpm.signature.index_length * size of a header entry )
    #     + @rpm.signature.data_length
    #
    # header 'entries' are an 
    #   int32 (tag id), int32 (tag type), int32  (offset), uint32 (count)
    #
    # See rpm's header.c, the headerLoad method function for reference.

    # Header always starts with HEADER_MAGIC + index_count(2bytes) +
    # data_length(2bytes)
    data = @rpm.file.read(16).unpack("a8NN")
    # TODO(sissel): @index_count is really a count, rename?
    @magic, @index_count, @data_length = data
    validate

    entry_size = 16 # tag id, type, offset, count == 16 bytes
    @index_size = @index_count * entry_size
    tag_data = @rpm.file.read(@index_size)
    data = @rpm.file.read(@data_length)
    
    #ap :data => data

    (0 ... @index_count).each do |i|
      offset = i * entry_size
      entry_data = tag_data[i * entry_size, entry_size]
      entry = entry_data.unpack("NNNN")
      entry << data
      tag = ::RPMFile::Tag.new(*entry)
      @tags << tag

      #ap tag.tag => {
        #:type => tag.type, 
        #:offset => tag.offset,
        #:count => tag.count,
        #:value => (tag.value rescue "???"),
      #}
    end # each index
    @length = @magic.size + @index_size + @data_length
  end # def read

  def write
    raise "not implemented yet"
    # Sort tags by type (integer value)
    # emit all tags in order
    # then emit all data segments in same order
  end # def write

  def validate
    # TODO(sissel): raise real exceptions
    if @magic != ::RPMFile::Header::HEADER_MAGIC
      raise "Header magic did not match; got #{@magic.inspect}, " \
            "expected #{::RPMFile::Header::HEADER_MAGIC.inspect}"
    end

    #if !(0..32).include?(@index_count)
      #raise "Invalid 'index_count' value #{@index_count}, expected to be in range [0..32]"
    #end

    #if !(0..8192).include?(@data_length)
      #raise "Invalid 'data_length' value #{@data_length}, expected to be in range [0..8192]"
    #end
  end # def validate
end # class RPMFile::Header