Class: MppReader::Blocks::FixedMeta

Inherits:
Object
  • Object
show all
Defined in:
lib/mpp_reader/blocks/fixed_meta.rb

Overview

Index for a FixedData block. Layout (ported from MPXJ FixedMeta): 16-byte header (magic 0xFADFADBA, unknown, item count, unknown), then fixed-size meta items. The item count in the header is unreliable; the real count is derived from the block size. Bytes 4-7 of each meta item hold the corresponding item’s offset within the FixedData block.

Constant Summary collapse

MAGIC =
0xFADFADBA
HEADER_SIZE =
16

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, item_size) ⇒ FixedMeta

Returns a new instance of FixedMeta.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/mpp_reader/blocks/fixed_meta.rb', line 39

def initialize(data, item_size)
  magic = data.byteslice(0, 4).to_s.unpack1("V")
  unless magic == MAGIC
    raise CorruptFileError, format("bad FixedMeta magic 0x%08x", magic.to_i)
  end

  # The header count can be lower than the block-derived count when
  # stale records linger at the end; some readers must honour it.
  @header_item_count = data.byteslice(8, 4).unpack1("V")
  @item_count = (data.bytesize - HEADER_SIZE) / item_size
  @items = Array.new(@item_count) do |i|
    data.byteslice(HEADER_SIZE + i * item_size, item_size)
  end
end

Instance Attribute Details

#header_item_countObject (readonly)

Returns the value of attribute header_item_count.



12
13
14
# File 'lib/mpp_reader/blocks/fixed_meta.rb', line 12

def header_item_count
  @header_item_count
end

#item_countObject (readonly)

Returns the value of attribute item_count.



12
13
14
# File 'lib/mpp_reader/blocks/fixed_meta.rb', line 12

def item_count
  @item_count
end

Class Method Details

.with_derived_item_size(data, candidates, sibling_item_count) ⇒ Object

Some blocks (e.g. Fixed2Meta) have a version-dependent item size. Pick the candidate that divides the block evenly, preferring one whose item count matches a sibling block’s; otherwise the closest fit by MPXJ’s rule of thumb (header count * size vs available).



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/mpp_reader/blocks/fixed_meta.rb', line 18

def self.with_derived_item_size(data, candidates, sibling_item_count)
  available = data.bytesize - HEADER_SIZE
  header_count = data.byteslice(8, 4).to_s.unpack1("V").to_i
  chosen = nil
  best_distance = nil
  candidates.each do |size|
    next unless (available % size).zero?

    if available / size == sibling_item_count
      chosen = size
      break
    end
    distance = header_count * size - available
    if distance <= 0 && (best_distance.nil? || distance > best_distance)
      chosen = size
      best_distance = distance
    end
  end
  new(data, chosen || candidates.first)
end

Instance Method Details

#[](index) ⇒ Object



54
# File 'lib/mpp_reader/blocks/fixed_meta.rb', line 54

def [](index) = @items[index]

#item_offset(index) ⇒ Object



56
57
58
59
# File 'lib/mpp_reader/blocks/fixed_meta.rb', line 56

def item_offset(index)
  item = @items[index]
  item && item.byteslice(4, 4).to_s.unpack1("V")
end