format_parser 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.travis.yml +1 -0
  4. data/README.md +14 -11
  5. data/format_parser.gemspec +11 -10
  6. data/lib/care.rb +9 -17
  7. data/lib/format_parser.rb +11 -13
  8. data/lib/format_parser/version.rb +1 -1
  9. data/lib/io_constraint.rb +3 -3
  10. data/lib/io_utils.rb +4 -10
  11. data/lib/parsers/aiff_parser.rb +9 -10
  12. data/lib/parsers/dpx_parser.rb +42 -42
  13. data/lib/parsers/dsl.rb +2 -2
  14. data/lib/parsers/exif_parser.rb +3 -8
  15. data/lib/parsers/fdx_parser.rb +3 -3
  16. data/lib/parsers/gif_parser.rb +3 -5
  17. data/lib/parsers/jpeg_parser.rb +4 -8
  18. data/lib/parsers/moov_parser.rb +8 -6
  19. data/lib/parsers/moov_parser/decoder.rb +105 -122
  20. data/lib/parsers/mp3_parser.rb +36 -46
  21. data/lib/parsers/mp3_parser/id3_v1.rb +7 -13
  22. data/lib/parsers/mp3_parser/id3_v2.rb +6 -6
  23. data/lib/parsers/png_parser.rb +5 -12
  24. data/lib/parsers/psd_parser.rb +2 -2
  25. data/lib/parsers/tiff_parser.rb +10 -12
  26. data/lib/parsers/wav_parser.rb +3 -3
  27. data/lib/read_limiter.rb +3 -7
  28. data/lib/remote_io.rb +3 -6
  29. data/spec/care_spec.rb +10 -10
  30. data/spec/file_information_spec.rb +1 -3
  31. data/spec/format_parser_spec.rb +6 -6
  32. data/spec/io_utils_spec.rb +7 -7
  33. data/spec/parsers/exif_parser_spec.rb +2 -3
  34. data/spec/parsers/gif_parser_spec.rb +1 -1
  35. data/spec/parsers/jpeg_parser_spec.rb +0 -1
  36. data/spec/parsers/moov_parser_spec.rb +2 -3
  37. data/spec/parsers/png_parser_spec.rb +1 -1
  38. data/spec/parsers/tiff_parser_spec.rb +0 -1
  39. data/spec/parsers/wav_parser_spec.rb +3 -3
  40. data/spec/read_limiter_spec.rb +0 -1
  41. data/spec/remote_fetching_spec.rb +34 -20
  42. data/spec/remote_io_spec.rb +20 -21
  43. data/spec/spec_helper.rb +2 -2
  44. metadata +19 -4
@@ -18,8 +18,8 @@ module FormatParser
18
18
  private
19
19
 
20
20
  def __define(name, value)
21
- throw ArgumentError("empty array") if value.empty?
22
- throw ArgumentError("requires array of symbols") if value.any? { |s| !s.is_a?(Symbol) }
21
+ throw ArgumentError('empty array') if value.empty?
22
+ throw ArgumentError('requires array of symbols') if value.any? { |s| !s.is_a?(Symbol) }
23
23
  define_method(name) do
24
24
  value
25
25
  end
@@ -11,8 +11,6 @@ class FormatParser::EXIFParser
11
11
  def readbyte
12
12
  if byte = read(1)
13
13
  byte.unpack('C').first
14
- else
15
- nil
16
14
  end
17
15
  end
18
16
 
@@ -62,19 +60,16 @@ class FormatParser::EXIFParser
62
60
 
63
61
  def orientation_parser(raw_exif_data)
64
62
  value = raw_exif_data.orientation.to_i
65
- if valid_orientation?(value)
66
- @orientation = ORIENTATIONS[value - 1]
67
- end
63
+ @orientation = ORIENTATIONS[value - 1] if valid_orientation?(value)
68
64
  end
69
65
 
70
66
  def valid_orientation?(value)
71
67
  (1..ORIENTATIONS.length).include?(value)
72
68
  end
73
69
 
74
- def cr2_check(file_io)
70
+ def cr2_check(_file_io)
75
71
  @file_io.seek(8)
76
72
  cr2_check_bytes = @file_io.read(2)
77
- cr2_check_bytes == "CR" ? true : false
73
+ cr2_check_bytes == 'CR'
78
74
  end
79
-
80
75
  end
@@ -6,7 +6,7 @@ class FormatParser::FDXParser
6
6
  natures :document
7
7
 
8
8
  def call(io)
9
- return if !xml_check(io)
9
+ return unless xml_check(io)
10
10
  file_and_document_type = safe_read(io, 100)
11
11
  file_type, document_type = check_for_document_type(file_and_document_type)
12
12
  return if file_type != :fdx
@@ -18,12 +18,12 @@ class FormatParser::FDXParser
18
18
 
19
19
  def xml_check(io)
20
20
  xml_check = safe_read(io, 5)
21
- xml_check == "<?xml"
21
+ xml_check == '<?xml'
22
22
  end
23
23
 
24
24
  def check_for_document_type(file_and_document_type)
25
25
  sanitized_data = file_and_document_type.downcase
26
- if sanitized_data.include?("finaldraft") && sanitized_data.include?("script")
26
+ if sanitized_data.include?('finaldraft') && sanitized_data.include?('script')
27
27
  return :fdx, :script
28
28
  else
29
29
  return
@@ -14,7 +14,7 @@ class FormatParser::GIFParser
14
14
  return unless HEADERS.include?(header)
15
15
 
16
16
  w, h = safe_read(io, 4).unpack('vv')
17
- gct_byte, bgcolor_index, pixel_aspect_ratio = safe_read(io, 5).unpack('Cvv')
17
+ gct_byte, _bgcolor_index, _pixel_aspect_ratio = safe_read(io, 5).unpack('Cvv')
18
18
 
19
19
  # and actually onwards for this:
20
20
  # http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
@@ -24,12 +24,10 @@ class FormatParser::GIFParser
24
24
  bytes_per_color = gct_byte >> 6
25
25
  unpacked_radix = gct_byte & 0b00000111
26
26
  num_colors = 2**(unpacked_radix + 1)
27
- gct_table_size = num_colors*bytes_per_color
27
+ gct_table_size = num_colors * bytes_per_color
28
28
 
29
29
  # If we have the global color table - skip over it
30
- if has_gct
31
- safe_read(io, gct_table_size)
32
- end
30
+ safe_read(io, gct_table_size) if has_gct
33
31
 
34
32
  # Now it gets interesting - we are at the place where an
35
33
  # application extension for the NETSCAPE2.0 block will occur.
@@ -24,10 +24,6 @@ class FormatParser::JPEGParser
24
24
 
25
25
  private
26
26
 
27
- def advance(n)
28
- safe_read(@buf, n); nil
29
- end
30
-
31
27
  def read_char
32
28
  safe_read(@buf, 1).unpack('C').first
33
29
  end
@@ -68,7 +64,6 @@ class FormatParser::JPEGParser
68
64
  nil # Due to the way JPEG is structured it is possible that some invalid inputs will get caught
69
65
  end
70
66
 
71
-
72
67
  # Read a byte, if it is 0xFF then skip bytes as long as they are also 0xFF (byte stuffing)
73
68
  # and return the first byte scanned that is not 0xFF
74
69
  def read_next_marker
@@ -85,7 +80,8 @@ class FormatParser::JPEGParser
85
80
  size = read_char
86
81
 
87
82
  if length == (size * 3) + 8
88
- @width, @height = width, height
83
+ @width = width
84
+ @height = height
89
85
  else
90
86
  raise InvalidStructure
91
87
  end
@@ -93,7 +89,7 @@ class FormatParser::JPEGParser
93
89
 
94
90
  def scan_app1_frame
95
91
  frame = @buf.read(8)
96
- if frame.include?("Exif")
92
+ if frame.include?('Exif')
97
93
  scanner = FormatParser::EXIFParser.new(:jpeg, @buf)
98
94
  if scanner.scan_image_exif
99
95
  @exif_output = scanner.exif_data
@@ -111,7 +107,7 @@ class FormatParser::JPEGParser
111
107
 
112
108
  def skip_frame
113
109
  length = read_short - 2
114
- advance(length)
110
+ safe_skip(@buf, length)
115
111
  end
116
112
 
117
113
  FormatParser.register_parser_constructor self
@@ -7,9 +7,9 @@ class FormatParser::MOOVParser
7
7
  # we can reasonably call "file type" (something
8
8
  # usable as a filename extension)
9
9
  FTYP_MAP = {
10
- "qt " => :mov,
11
- "mp4 " => :mp4,
12
- "m4a " => :m4a,
10
+ 'qt ' => :mov,
11
+ 'mp4 ' => :mp4,
12
+ 'm4a ' => :m4a,
13
13
  }
14
14
 
15
15
  natures :video
@@ -20,7 +20,7 @@ class FormatParser::MOOVParser
20
20
  private_constant :Decoder
21
21
 
22
22
  def call(io)
23
- return nil unless matches_moov_definition?(io)
23
+ return unless matches_moov_definition?(io)
24
24
 
25
25
  # Now we know we are in a MOOV, so go back and parse out the atom structure.
26
26
  # Parsing out the atoms does not read their contents - at least it doesn't
@@ -40,7 +40,8 @@ class FormatParser::MOOVParser
40
40
  ftyp_atom = decoder.find_first_atom_by_path(atom_tree, 'ftyp')
41
41
  file_type = ftyp_atom.field_value(:major_brand)
42
42
 
43
- width, height = nil, nil
43
+ width = nil
44
+ height = nil
44
45
 
45
46
  # Try to find the width and height in the tkhd
46
47
  if tkhd = decoder.find_first_atom_by_path(atom_tree, 'moov', 'trak', 'tkhd')
@@ -50,7 +51,8 @@ class FormatParser::MOOVParser
50
51
 
51
52
  # Try to find the "topmost" duration (respecting edits)
52
53
  if mdhd = decoder.find_first_atom_by_path(atom_tree, 'moov', 'mvhd')
53
- timescale, duration = mdhd.field_value(:tscale), mdhd.field_value(:duration)
54
+ timescale = mdhd.field_value(:tscale)
55
+ duration = mdhd.field_value(:duration)
54
56
  media_duration_s = duration / timescale.to_f
55
57
  end
56
58
 
@@ -2,10 +2,9 @@
2
2
  # read atoms and parse their data fields if applicable. Also contains
3
3
  # a few utility functions for finding atoms in a list etc.
4
4
  class FormatParser::MOOVParser::Decoder
5
-
6
5
  class Atom < Struct.new(:at, :atom_size, :atom_type, :path, :children, :atom_fields)
7
6
  def to_s
8
- "%s (%s): %d bytes at offset %d" % [atom_type, path.join('.'), atom_size, at]
7
+ '%s (%s): %d bytes at offset %d' % [atom_type, path.join('.'), atom_size, at]
9
8
  end
10
9
 
11
10
  def field_value(data_field)
@@ -20,10 +19,10 @@ class FormatParser::MOOVParser::Decoder
20
19
  end
21
20
 
22
21
  # Atoms (boxes) that are known to only contain children, no data fields
23
- KNOWN_BRANCH_ATOM_TYPES = %w( moov mdia trak clip edts minf dinf stbl udta meta)
22
+ KNOWN_BRANCH_ATOM_TYPES = %w(moov mdia trak clip edts minf dinf stbl udta meta)
24
23
 
25
24
  # Atoms (boxes) that are known to contain both leaves and data fields
26
- KNOWN_BRANCH_AND_LEAF_ATOM_TYPES = %w( meta ) # the udta.meta thing used by iTunes
25
+ KNOWN_BRANCH_AND_LEAF_ATOM_TYPES = %w(meta) # the udta.meta thing used by iTunes
27
26
 
28
27
  # Limit how many atoms we scan in sequence, to prevent derailments
29
28
  MAX_ATOMS_AT_LEVEL = 128
@@ -32,13 +31,13 @@ class FormatParser::MOOVParser::Decoder
32
31
  # matches the type, drilling down if a list of atom names is given
33
32
  def find_first_atom_by_path(atoms, *atom_types)
34
33
  type_to_find = atom_types.shift
35
- requisite = atoms.find {|e| e.atom_type == type_to_find }
34
+ requisite = atoms.find { |e| e.atom_type == type_to_find }
36
35
 
37
36
  # Return if we found our match
38
37
  return requisite if atom_types.empty?
39
38
 
40
39
  # Return nil if we didn't find the match at this nesting level
41
- return nil unless requisite
40
+ return unless requisite
42
41
 
43
42
  # ...otherwise drill further down
44
43
  find_first_atom_by_path(requisite.children || [], *atom_types)
@@ -50,7 +49,7 @@ class FormatParser::MOOVParser::Decoder
50
49
  # numbr of bytes is reserved for the compatible brands, 4 bytes per
51
50
  # brand.
52
51
  num_brands = (atom_size - 8 - 8) / 4
53
- ret = {
52
+ {
54
53
  major_brand: read_bytes(io, 4),
55
54
  minor_version: read_binary_coded_decimal(io),
56
55
  compatible_brands: (1..num_brands).map { read_bytes(io, 4) },
@@ -60,94 +59,88 @@ class FormatParser::MOOVParser::Decoder
60
59
  def parse_tkhd_atom(io, _)
61
60
  version = read_byte_value(io)
62
61
  is_v1 = version == 1
63
- tkhd_info_bites = [
64
- :version, version,
65
- :flags, read_chars(io, 3),
66
- :ctime, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
67
- :mtime, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
68
- :trak_id, read_32bit_uint(io),
69
- :reserved_1, read_chars(io, 4),
70
- :duration, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
71
- :reserved_2, read_chars(io, 8),
72
- :layer, read_16bit_uint(io),
73
- :alternate_group, read_16bit_uint(io),
74
- :volume, read_16bit_uint(io),
75
- :reserved_3, read_chars(io, 2),
76
- :matrix_structure, (1..9).map { read_32bit_fixed_point(io) },
77
- :track_width, read_32bit_fixed_point(io),
78
- :track_height, read_32bit_fixed_point(io),
79
- ]
80
- repack(tkhd_info_bites)
62
+ {
63
+ version: version,
64
+ flags: read_chars(io, 3),
65
+ ctime: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
66
+ mtime: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
67
+ trak_id: read_32bit_uint(io),
68
+ reserved_1: read_chars(io, 4),
69
+ duration: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
70
+ reserved_2: read_chars(io, 8),
71
+ layer: read_16bit_uint(io),
72
+ alternate_group: read_16bit_uint(io),
73
+ volume: read_16bit_uint(io),
74
+ reserved_3: read_chars(io, 2),
75
+ matrix_structure: (1..9).map { read_32bit_fixed_point(io) },
76
+ track_width: read_32bit_fixed_point(io),
77
+ track_height: read_32bit_fixed_point(io),
78
+ }
81
79
  end
82
80
 
83
81
  def parse_mdhd_atom(io, _)
84
82
  version = read_byte_value(io)
85
83
  is_v1 = version == 1
86
- mdhd_info_bites = [
87
- :version, version,
88
- :flags, read_bytes(io, 3),
89
- :ctime, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
90
- :mtime, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
91
- :tscale, read_32bit_uint(io),
92
- :duration, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
93
- :language, read_32bit_uint(io),
94
- :quality, read_32bit_uint(io),
95
- ]
96
- repack(mdhd_info_bites)
84
+ {
85
+ version: version,
86
+ flags: read_bytes(io, 3),
87
+ ctime: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
88
+ mtime: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
89
+ tscale: read_32bit_uint(io),
90
+ duration: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
91
+ language: read_32bit_uint(io),
92
+ quality: read_32bit_uint(io),
93
+ }
97
94
  end
98
95
 
99
96
  def parse_vmhd_atom(io, _)
100
- vmhd_info_bites = [
101
- :version, read_byte_value(io),
102
- :flags, read_bytes(io, 3),
103
- :graphics_mode, read_bytes(io, 2),
104
- :opcolor_r, read_32bit_uint(io),
105
- :opcolor_g, read_32bit_uint(io),
106
- :opcolor_b, read_32bit_uint(io),
107
- ]
108
- repack(vmhd_info_bites)
97
+ {
98
+ version: read_byte_value(io),
99
+ flags: read_bytes(io, 3),
100
+ graphics_mode: read_bytes(io, 2),
101
+ opcolor_r: read_32bit_uint(io),
102
+ opcolor_g: read_32bit_uint(io),
103
+ opcolor_b: read_32bit_uint(io),
104
+ }
109
105
  end
110
106
 
111
107
  def parse_mvhd_atom(io, _)
112
108
  version = read_byte_value(io)
113
109
  is_v1 = version == 1
114
- mvhd_info_bites = [
115
- :version, version,
116
- :flags, read_bytes(io, 3),
117
- :ctime, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
118
- :mtime, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
119
- :tscale, read_32bit_uint(io),
120
- :duration, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
121
- :preferred_rate, read_32bit_uint(io),
122
- :reserved, read_bytes(io, 10),
123
- :matrix_structure, (1..9).map { read_32bit_fixed_point(io) },
124
- :preview_time, read_32bit_uint(io),
125
- :preview_duration, read_32bit_uint(io),
126
- :poster_time, read_32bit_uint(io),
127
- :selection_time, read_32bit_uint(io),
128
- :selection_duration, read_32bit_uint(io),
129
- :current_time, read_32bit_uint(io),
130
- :next_trak_id, read_32bit_uint(io),
131
- ]
132
- repack(mvhd_info_bites)
110
+ {
111
+ version: version,
112
+ flags: read_bytes(io, 3),
113
+ ctime: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
114
+ mtime: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
115
+ tscale: read_32bit_uint(io),
116
+ duration: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
117
+ preferred_rate: read_32bit_uint(io),
118
+ reserved: read_bytes(io, 10),
119
+ matrix_structure: (1..9).map { read_32bit_fixed_point(io) },
120
+ preview_time: read_32bit_uint(io),
121
+ preview_duration: read_32bit_uint(io),
122
+ poster_time: read_32bit_uint(io),
123
+ selection_time: read_32bit_uint(io),
124
+ selection_duration: read_32bit_uint(io),
125
+ current_time: read_32bit_uint(io),
126
+ next_trak_id: read_32bit_uint(io),
127
+ }
133
128
  end
134
129
 
135
130
  def parse_dref_atom(io, _)
136
- dref_info_bites = [
137
- :version, read_byte_value(io),
138
- :flags, read_bytes(io, 3),
139
- :num_entries, read_32bit_uint(io),
140
- ]
141
- dict = repack(dref_info_bites)
131
+ dict = {
132
+ version: read_byte_value(io),
133
+ flags: read_bytes(io, 3),
134
+ num_entries: read_32bit_uint(io),
135
+ }
142
136
  num_entries = dict[:num_entries]
143
137
  entries = (1..num_entries).map do
144
- dref_entry_bites = [
145
- :size, read_32bit_uint(io),
146
- :type, read_bytes(io, 4),
147
- :version, read_bytes(io, 1),
148
- :flags, read_bytes(io, 3),
149
- ]
150
- entry = repack(dref_entry_bites)
138
+ entry = {
139
+ size: read_32bit_uint(io),
140
+ type: read_bytes(io, 4),
141
+ version: read_bytes(io, 1),
142
+ flags: read_bytes(io, 3),
143
+ }
151
144
  entry[:data] = read_bytes(io, entry[:size] - 12)
152
145
  entry
153
146
  end
@@ -156,21 +149,19 @@ class FormatParser::MOOVParser::Decoder
156
149
  end
157
150
 
158
151
  def parse_elst_atom(io, _)
159
- elst_info_bites = [
160
- :version, read_byte_value(io),
161
- :flags, read_bytes(io, 3),
162
- :num_entries, read_32bit_uint(io),
163
- ]
164
- dict = repack(elst_info_bites)
152
+ dict = {
153
+ version: read_byte_value(io),
154
+ flags: read_bytes(io, 3),
155
+ num_entries: read_32bit_uint(io),
156
+ }
165
157
  is_v1 = dict[:version] == 1 # Usual is 0, version 1 has 64bit durations
166
158
  num_entries = dict[:num_entries]
167
159
  entries = (1..num_entries).map do
168
- entry_bites = [
169
- :track_duration, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
170
- :media_time, is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
171
- :media_rate, read_32bit_uint(io),
172
- ]
173
- repack(entry_bites)
160
+ {
161
+ track_duration: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
162
+ media_time: is_v1 ? read_64bit_uint(io) : read_32bit_uint(io),
163
+ media_rate: read_32bit_uint(io),
164
+ }
174
165
  end
175
166
  dict[:entries] = entries
176
167
  dict
@@ -178,21 +169,20 @@ class FormatParser::MOOVParser::Decoder
178
169
 
179
170
  def parse_hdlr_atom(io, atom_size)
180
171
  sub_io = StringIO.new(io.read(atom_size - 8))
181
- hdlr_info_bites = [
182
- :version, read_byte_value(sub_io),
183
- :flags, read_bytes(sub_io, 3),
184
- :component_type, read_bytes(sub_io, 4),
185
- :component_subtype, read_bytes(sub_io, 4),
186
- :component_manufacturer, read_bytes(sub_io, 4),
187
- :component_flags, read_bytes(sub_io, 4),
188
- :component_flags_mask, read_bytes(sub_io, 4),
189
- :component_name, sub_io.read,
190
- ]
191
- repack(hdlr_info_bites)
172
+ {
173
+ version: read_byte_value(sub_io),
174
+ flags: read_bytes(sub_io, 3),
175
+ component_type: read_bytes(sub_io, 4),
176
+ component_subtype: read_bytes(sub_io, 4),
177
+ component_manufacturer: read_bytes(sub_io, 4),
178
+ component_flags: read_bytes(sub_io, 4),
179
+ component_flags_mask: read_bytes(sub_io, 4),
180
+ component_name: sub_io.read,
181
+ }
192
182
  end
193
183
 
194
184
  def parse_atom_fields_per_type(io, atom_size, atom_type)
195
- if respond_to?("parse_#{atom_type}_atom", including_privates = true)
185
+ if respond_to?("parse_#{atom_type}_atom", true)
196
186
  send("parse_#{atom_type}_atom", io, atom_size)
197
187
  else
198
188
  nil # We can't look inside this leaf atom
@@ -208,29 +198,28 @@ class FormatParser::MOOVParser::Decoder
208
198
  MAX_ATOMS_AT_LEVEL.times do
209
199
  atom_pos = io.pos
210
200
 
211
- if atom_pos - initial_pos >= max_read
212
- break
213
- end
201
+ break if atom_pos - initial_pos >= max_read
214
202
 
215
- size_and_type = io.read(4+4)
216
- if size_and_type.to_s.bytesize < 8
217
- break
218
- end
203
+ size_and_type = io.read(4 + 4)
204
+ break if size_and_type.to_s.bytesize < 8
219
205
 
220
206
  atom_size, atom_type = size_and_type.unpack('Na4')
221
207
 
222
208
  # If atom_size is specified to be 1, it is larger than what fits into the
223
209
  # 4 bytes and we need to read it right after the atom type
224
- if atom_size == 1
225
- atom_size = read_64bit_uint(io)
226
- end
210
+ atom_size = read_64bit_uint(io) if atom_size == 1
211
+
212
+ # We are allowed to read what comes after
213
+ # the atom size and atom type, but not any more than that
214
+ size_of_atom_type_and_size = io.pos - atom_pos
215
+ atom_size_sans_header = atom_size - size_of_atom_type_and_size
227
216
 
228
217
  children, fields = if KNOWN_BRANCH_AND_LEAF_ATOM_TYPES.include?(atom_type)
229
- parse_atom_children_and_data_fields(io, atom_size, atom_type)
218
+ parse_atom_children_and_data_fields(io, atom_size_sans_header, atom_type)
230
219
  elsif KNOWN_BRANCH_ATOM_TYPES.include?(atom_type)
231
- [extract_atom_stream(io, atom_size - 8, current_branch + [atom_type]), nil]
220
+ [extract_atom_stream(io, atom_size_sans_header, current_branch + [atom_type]), nil]
232
221
  else # Assume leaf atom
233
- [nil, parse_atom_fields_per_type(io, atom_size, atom_type)]
222
+ [nil, parse_atom_fields_per_type(io, atom_size_sans_header, atom_type)]
234
223
  end
235
224
 
236
225
  atoms << Atom.new(atom_pos, atom_size, atom_type, current_branch + [atom_type], children, fields)
@@ -241,11 +230,11 @@ class FormatParser::MOOVParser::Decoder
241
230
  end
242
231
 
243
232
  def read_16bit_fixed_point(io)
244
- whole, fraction = io.read(2).unpack('CC')
233
+ _whole, _fraction = io.read(2).unpack('CC')
245
234
  end
246
235
 
247
236
  def read_32bit_fixed_point(io)
248
- whole, fraction = io.read(4).unpack('nn')
237
+ _whole, _fraction = io.read(4).unpack('nn')
249
238
  end
250
239
 
251
240
  def read_chars(io, n)
@@ -274,12 +263,6 @@ class FormatParser::MOOVParser::Decoder
274
263
 
275
264
  def read_binary_coded_decimal(io)
276
265
  bcd_string = io.read(4)
277
- bcd_string.insert(0, '0') if bcd_string.length.odd?
278
266
  [bcd_string].pack('H*').unpack('C*')
279
267
  end
280
-
281
- def repack(properties_to_packspecs)
282
- keys, bytes = properties_to_packspecs.partition.with_index { |_, i| i.even? }
283
- Hash[keys.zip(bytes)]
284
- end
285
268
  end