class GitObjectBrowser::Models::PackedObject

Constants

TYPES

Attributes

header[R]
object[R]
raw_data[R]

Public Class Methods

new(index, input) click to toggle source
Calls superclass method GitObjectBrowser::Models::Bindata::new
# File lib/git-object-browser/models/packed_object.rb, line 26
def initialize(index, input)
  super(input)
  @index = index
end
path?(relpath) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 88
def self.path?(relpath)
  return relpath =~ %r{\Aobjects/pack/pack-[0-9a-f]{40}\.pack\z}
end

Public Instance Methods

parse(offset) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 31
def parse(offset)
  parse_raw(offset)
  input = "#{ @object_type } #{ @object_size }\0" + @raw_data
  @object = GitObject.new(nil).parse_inflated(input)
  self
end
parse_header(offset) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 55
def parse_header(offset)
  seek(offset)
  (type, size, header_size) = parse_type_and_size
  type = TYPES[type]
  { :type => type, :size => size, :header_size => header_size }
end
parse_ofs_delta_header(offset, header) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 62
def parse_ofs_delta_header(offset, header)
  (delta_offset, delta_header_size) = parse_delta_offset
  header[:base_offset] = offset - delta_offset
  header[:header_size] += delta_header_size
  header
end
parse_raw(offset) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 38
def parse_raw(offset)
  @offset = offset
  @header = parse_header(offset)

  if @header[:type] == 'ofs_delta'
    obj_ofs_delta
  elsif @header[:type] == 'ref_delta'
    obj_ref_delta
  else
    @object_type = @header[:type]
    @object_size = @header[:size]
    @raw_data = zlib_inflate
  end

  [@object_type, @object_size]
end
parse_ref_delta_header(header) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 69
def parse_ref_delta_header(header)
  header[:base_sha1]   = hex(20)
  header[:header_size] += 20
  header
end
to_hash() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 75
def to_hash
  return {
    :offset => @offset,
    :type => @header[:type], # commit, tree, blob, tag, ofs_delta, ref_delta
    :size => @header[:size],
    :header_size => @header[:header_size],
    :base_offset => @header[:base_offset],
    :delta_commands => @delta_commands,
    :base_size => @base_size,
    :object => @object.to_hash,
  }
end

Private Instance Methods

delta_command() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 135
def delta_command
  cmd = byte
  data = nil
  if cmd & 0b10000000 != 0
    (offset, size) = parse_base_offset_and_size(cmd)
    data = @base[offset, size]
    @raw_data << data
    @delta_commands << { :source => :base, :offset => offset, :size => size }
  elsif cmd != 0
    size = cmd
    data = raw(size)
    @raw_data << data
    @delta_commands << { :source => :delta, :size => size }
  else
    raise 'delta command is 0'
  end
  @delta_commands.last[:data] = shorten_utf8(data, 2000)
end
load_base_and_patch_delta() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 106
def load_base_and_patch_delta
  begin
    pack = PackedObject.new(@index, @in)
    (@object_type, _) = pack.parse_raw(@header[:base_offset])
    @base = pack.raw_data
  ensure
    seek(@offset + @header[:header_size])
  end

  switch_source(StringIO.new(zlib_inflate)) { patch_delta }
end
obj_ofs_delta() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 94
def obj_ofs_delta
  parse_ofs_delta_header(@offset, @header)
  load_base_and_patch_delta
end
obj_ref_delta() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 99
def obj_ref_delta
  parse_ref_delta_header(@header)
  index_entry = @index.find(@header[:base_sha1])
  @header[:base_offset] = index_entry[:offset]
  load_base_and_patch_delta
end
parse_base_offset_and_size(cmd) click to toggle source

patch-delta.c

# File lib/git-object-browser/models/packed_object.rb, line 225
def parse_base_offset_and_size(cmd)
  offset = size = 0
  offset  = byte       if cmd & 0b00000001 != 0
  offset |= byte << 8  if cmd & 0b00000010 != 0
  offset |= byte << 16 if cmd & 0b00000100 != 0
  offset |= byte << 24 if cmd & 0b00001000 != 0
  size    = byte       if cmd & 0b00010000 != 0
  size   |= byte << 8  if cmd & 0b00100000 != 0
  size   |= byte << 16 if cmd & 0b01000000 != 0
  size = 0x10000 if size == 0
  return [offset, size]
end
parse_delta_offset() click to toggle source

sha1_file.c get_delta_base

https://github.com/git/git/blob/master/sha1_file.c

unpack-objects.c unpack_delta_entry

https://github.com/git/git/blob/master/builtin/unpack-objects.c
# File lib/git-object-browser/models/packed_object.rb, line 211
def parse_delta_offset
  offset   = -1
  hdr_size = 0
  begin
    hdr        = byte
    hdr_size  += 1
    continue   = hdr & 0b10000000
    low_offset = hdr & 0b01111111
    offset     = ((offset + 1) << 7) | low_offset
  end while continue != 0
  return [offset, hdr_size]
end
parse_size() click to toggle source

delta.h get_delta_hdr_size

# File lib/git-object-browser/models/packed_object.rb, line 195
def parse_size
  size     = 0
  size_len = 0
  begin
    hdr       = byte
    continue  = (hdr & 0b10000000)
    size     += (hdr & 0b01111111) << size_len
    size_len += 7
  end while continue != 0
  return size
end
parse_type_and_size() click to toggle source

sha1_file.c unpack_object_header_buffer unpack-objects.c unpack_one

# File lib/git-object-browser/models/packed_object.rb, line 177
def parse_type_and_size
  hdr      = byte
  hdr_size = 1
  continue = (hdr & 0b10000000)
  type     = (hdr & 0b01110000) >> 4
  size     = (hdr & 0b00001111)
  size_len = 4
  while continue != 0
    hdr        = byte
    hdr_size  += 1
    continue   = (hdr & 0b10000000)
    size      += (hdr & 0b01111111) << size_len
    size_len  += 7
  end
  return [type, size, hdr_size]
end
patch_delta() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 118
def patch_delta
  @base_size  = parse_size
  if @base.size != @base_size
    raise 'incollect base size'
  end

  @object_size = parse_size
  @delta_commands = []
  @raw_data = ''
  while ! @in.eof?
    delta_command
  end
  if @object_size != @raw_data.size
    raise 'incollect delta size'
  end
end
shorten_utf8(bin, length) click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 154
def shorten_utf8(bin, length)
  str = bin.force_encoding('UTF-8')
  str = '(not UTF-8)' unless str.valid_encoding?
  str = str[0, length] + '...' if str.length > length
  str
end
zlib_inflate() click to toggle source
# File lib/git-object-browser/models/packed_object.rb, line 161
def zlib_inflate
  store = Zlib::Inflate.new
  buffer = ''
  while buffer.size < @header[:size]
    rawdata = raw(4096)
    if rawdata.size == 0
      raise 'inflate error'
    end
    buffer << store.inflate(rawdata)
  end
  store.close
  buffer
end