format_parser 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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