Class: MppReader::FieldMap
- Inherits:
-
Object
- Object
- MppReader::FieldMap
- Defined in:
- lib/mpp_reader/field_map.rb
Overview
Maps logical fields (task name, start, …) to where their values live in an entity’s data blocks. The definition is stored in the project Props under entity-specific keys, as 28-byte entries (ported from MPXJ FieldMap.createFieldMap): mask u32@0, fixed-data offset u16@4, field type u32@12, category u16@20.
Locations: :fixed_data (offset into a FixedData record; a second fixed block is signalled by offsets restarting), :var_data (key into Var2Data; for MPP14 the key is the low word of the field type), :meta_data (bit mask over a FixedMeta record).
Defined Under Namespace
Classes: Item
Constant Summary collapse
- FIXED_DATA_SIZES =
Bytes each data type occupies in a fixed-data record (MPXJ FieldMap#getFixedDataFieldSize); used to size-check records.
Hash.new(0).update( date: 4, integer: 4, duration: 4, time_units: 2, constraint: 2, priority: 2, percentage: 2, task_type: 2, accrue: 2, short: 2, boolean: 2, delay: 2, workgroup: 2, rate_units: 2, earned_value_method: 2, resource_request_type: 2, currency: 8, units: 8, rate: 8, work: 8, work_units: 1, guid: 16 ).freeze
- ENTITIES =
{ task: [FieldTables::TASK_FIELD_BASE, FieldTables::TASK_FIELDS, FieldTables::TASK_FIELD_TYPES, [131_092, 50_331_668]], resource: [FieldTables::RESOURCE_FIELD_BASE, FieldTables::RESOURCE_FIELDS, FieldTables::RESOURCE_FIELD_TYPES, [131_093, 50_331_669]], assignment: [FieldTables::ASSIGNMENT_FIELD_BASE, FieldTables::ASSIGNMENT_FIELDS, FieldTables::ASSIGNMENT_FIELD_TYPES, [131_095, 50_331_671]] }.freeze
Class Method Summary collapse
- .for_assignments(props) ⇒ Object
- .for_resources(props) ⇒ Object
- .for_tasks(props) ⇒ Object
- .from_props(props, entity) ⇒ Object
Instance Method Summary collapse
- #[](field) ⇒ Object
-
#initialize(data, entity:) ⇒ FieldMap
constructor
A new instance of FieldMap.
- #max_fixed_data_size(block) ⇒ Object
Constructor Details
#initialize(data, entity:) ⇒ FieldMap
Returns a new instance of FieldMap.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/mpp_reader/field_map.rb', line 52 def initialize(data, entity:) base, fields, types, = ENTITIES.fetch(entity) @map = {} @max_fixed_data_size = Hash.new(0) last_offset = 0 data_block = 0 pos = 0 while pos + 28 <= data.bytesize mask = data.byteslice(pos, 4).unpack1("V") fixed_offset = data.byteslice(pos + 4, 2).unpack1("v") type_value = data.byteslice(pos + 12, 4).unpack1("V") category = data.byteslice(pos + 20, 2).unpack1("v") pos += 28 next unless (type_value & 0xFFFF0000) == base field = fields[type_value & 0xFFFF] next if field.nil? # NOTE: MPXJ substitutes var data keys for some custom fields # (FieldMap14.VAR_DATA_MAP); not implemented yet. var_key = type_value & 0xFFFF item = case category when 0x0B then Item.new(:meta_data, 0, nil, nil, mask, 0) when 0x64 then Item.new(:meta_data, 0, nil, nil, mask, 1) else if fixed_offset != 0xFFFF data_block += 1 if fixed_offset < last_offset last_offset = fixed_offset Item.new(:fixed_data, data_block, fixed_offset, nil, mask, 0) elsif var_key != 0 Item.new(:var_data, 0, nil, var_key, mask, 0) end end next if item.nil? item.data_type, item.units_field = types[field] if item.location == :fixed_data field_end = item.fixed_offset + FIXED_DATA_SIZES[item.data_type] if field_end > @max_fixed_data_size[item.data_block] @max_fixed_data_size[item.data_block] = field_end end end @map[field] = item end end |
Class Method Details
.for_assignments(props) ⇒ Object
40 |
# File 'lib/mpp_reader/field_map.rb', line 40 def self.for_assignments(props) = from_props(props, :assignment) |
.for_resources(props) ⇒ Object
39 |
# File 'lib/mpp_reader/field_map.rb', line 39 def self.for_resources(props) = from_props(props, :resource) |
.for_tasks(props) ⇒ Object
38 |
# File 'lib/mpp_reader/field_map.rb', line 38 def self.for_tasks(props) = from_props(props, :task) |
.from_props(props, entity) ⇒ Object
42 43 44 45 46 47 48 49 50 |
# File 'lib/mpp_reader/field_map.rb', line 42 def self.from_props(props, entity) data = ENTITIES.fetch(entity)[3].filter_map { |key| props[key] }.first if data.nil? raise UnsupportedFormatError, "no #{entity} field map in project Props - default field maps are not implemented" end new(data, entity: entity) end |
Instance Method Details
#[](field) ⇒ Object
102 |
# File 'lib/mpp_reader/field_map.rb', line 102 def [](field) = @map[field] |
#max_fixed_data_size(block) ⇒ Object
104 |
# File 'lib/mpp_reader/field_map.rb', line 104 def max_fixed_data_size(block) = @max_fixed_data_size[block] |