format_parser 2.3.0 → 2.4.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +13 -6
- data/format_parser.gemspec +1 -0
- data/lib/format_parser/version.rb +1 -1
- data/lib/io_utils.rb +18 -33
- data/lib/parsers/cr3_parser/decoder.rb +2 -2
- data/lib/parsers/cr3_parser.rb +13 -11
- data/lib/parsers/heif_parser.rb +46 -46
- data/lib/parsers/iso_base_media_file_format/box.rb +80 -0
- data/lib/parsers/iso_base_media_file_format/decoder.rb +342 -376
- data/lib/parsers/iso_base_media_file_format/utils.rb +89 -0
- data/lib/parsers/mov_parser/decoder.rb +53 -0
- data/lib/parsers/mov_parser.rb +48 -0
- data/lib/parsers/mp4_parser.rb +80 -0
- data/lib/parsers/pdf_parser.rb +5 -2
- data/lib/parsers/webp_parser.rb +2 -2
- data/spec/format_parser_spec.rb +1 -1
- data/spec/parsers/cr3_parser_spec.rb +3 -3
- data/spec/parsers/iso_base_media_file_format/box_spec.rb +399 -0
- data/spec/parsers/iso_base_media_file_format/decoder_spec.rb +53 -178
- data/spec/parsers/iso_base_media_file_format/utils_spec.rb +632 -0
- data/spec/parsers/mov_parser_spec.rb +90 -0
- data/spec/parsers/mp4_parser_spec.rb +114 -0
- data/spec/parsers/pdf_parser_spec.rb +37 -23
- metadata +25 -5
- data/lib/parsers/moov_parser/decoder.rb +0 -353
- data/lib/parsers/moov_parser.rb +0 -165
- data/spec/parsers/moov_parser_spec.rb +0 -144
@@ -0,0 +1,399 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FormatParser::ISOBaseMediaFileFormat::Box do
|
4
|
+
describe '.new' do
|
5
|
+
context 'when no fields/children' do
|
6
|
+
subject { described_class.new('foo', 0, 0) }
|
7
|
+
|
8
|
+
it 'sets them as empty hash/array' do
|
9
|
+
expect(subject.fields).to eq({})
|
10
|
+
expect(subject.children).to eq([])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when fields/children' do
|
15
|
+
let(:fields) { { foo: 1, bar: 'bar' } }
|
16
|
+
let(:children) { [described_class.new('bar', 0, 0)] }
|
17
|
+
|
18
|
+
subject { described_class.new('foo', 0, 0, fields, children) }
|
19
|
+
|
20
|
+
it 'sets them correctly' do
|
21
|
+
expect(subject.fields).to eq(fields)
|
22
|
+
expect(subject.children).to eq(children)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#all_children' do
|
28
|
+
context 'when no types given' do
|
29
|
+
subject do
|
30
|
+
described_class.new('root', 0, 0, nil, [
|
31
|
+
described_class.new('foo', 0, 0),
|
32
|
+
described_class.new('bar', 0, 0)
|
33
|
+
])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns empty array' do
|
37
|
+
expect(subject.all_children).to eq([])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when no children' do
|
42
|
+
subject { described_class.new('root', 0, 0) }
|
43
|
+
|
44
|
+
it 'returns empty array' do
|
45
|
+
expect(subject.all_children('foo')).to eq([])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when no children of given type(s)' do
|
50
|
+
subject do
|
51
|
+
described_class.new('root', 0, 0, nil, [
|
52
|
+
described_class.new('foo', 0, 0),
|
53
|
+
described_class.new('bar', 0, 0, nil, [
|
54
|
+
described_class.new('baz', 0, 0)
|
55
|
+
])
|
56
|
+
])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns empty array' do
|
60
|
+
expect(subject.all_children('baz')).to eq([])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when multiple children of given type(s)' do
|
65
|
+
let(:child_1) { described_class.new('foo', 0, 0) }
|
66
|
+
let(:child_2) do
|
67
|
+
described_class.new('foo', 0, 0, nil, [
|
68
|
+
described_class.new('qux', 0, 0)
|
69
|
+
])
|
70
|
+
end
|
71
|
+
let(:child_3) { described_class.new('bar', 0, 0) }
|
72
|
+
|
73
|
+
subject do
|
74
|
+
described_class.new('root', 0, 0, nil, [
|
75
|
+
child_1,
|
76
|
+
child_2,
|
77
|
+
child_3,
|
78
|
+
described_class.new('baz', 0, 0)
|
79
|
+
])
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns all matching direct children' do
|
83
|
+
expect(subject.all_children('foo', 'bar', 'qux')).to match_array([child_1, child_2, child_3])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#child?' do
|
89
|
+
context 'when no children' do
|
90
|
+
subject { described_class.new('root', 0, 0) }
|
91
|
+
|
92
|
+
it 'returns false' do
|
93
|
+
expect(subject.child?('foo')).to eq(false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when no children of given type' do
|
98
|
+
subject do
|
99
|
+
described_class.new('root', 0, 0, nil, [
|
100
|
+
described_class.new('foo', 0, 0),
|
101
|
+
described_class.new('bar', 0, 0, nil, [
|
102
|
+
described_class.new('baz', 0, 0)
|
103
|
+
])
|
104
|
+
])
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns false' do
|
108
|
+
expect(subject.child?('baz')).to eq(false)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when child of given type' do
|
113
|
+
subject do
|
114
|
+
described_class.new('root', 0, 0, nil, [
|
115
|
+
described_class.new('foo', 0, 0),
|
116
|
+
described_class.new('bar', 0, 0),
|
117
|
+
])
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns true' do
|
121
|
+
expect(subject.child?('foo')).to eq(true)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#first_child' do
|
127
|
+
context 'when no types given' do
|
128
|
+
subject do
|
129
|
+
described_class.new('root', 0, 0, nil, [
|
130
|
+
described_class.new('foo', 0, 0),
|
131
|
+
described_class.new('bar', 0, 0)
|
132
|
+
])
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'returns nil' do
|
136
|
+
expect(subject.first_child).to eq(nil)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when no children' do
|
141
|
+
subject { described_class.new('root', 0, 0) }
|
142
|
+
|
143
|
+
it 'returns nil' do
|
144
|
+
expect(subject.first_child('foo')).to eq(nil)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'when no children of given type(s)' do
|
149
|
+
subject do
|
150
|
+
described_class.new('root', 0, 0, nil, [
|
151
|
+
described_class.new('foo', 0, 0),
|
152
|
+
described_class.new('bar', 0, 0, nil, [
|
153
|
+
described_class.new('baz', 0, 0)
|
154
|
+
])
|
155
|
+
])
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'returns nil' do
|
159
|
+
expect(subject.first_child('baz')).to eq(nil)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when multiple children of given type(s)' do
|
164
|
+
let(:child) { described_class.new('bar', 0, 0) }
|
165
|
+
|
166
|
+
subject do
|
167
|
+
described_class.new('root', 0, 0, nil, [
|
168
|
+
described_class.new('foo', 0, 0, nil, [
|
169
|
+
described_class.new('qux', 0, 0)
|
170
|
+
]),
|
171
|
+
child,
|
172
|
+
described_class.new('bar', 0, 0),
|
173
|
+
described_class.new('baz', 0, 0)
|
174
|
+
])
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns first matching direct child' do
|
178
|
+
expect(subject.first_child('qux', 'baz', 'bar')).to eq(child)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '#all_descendents' do
|
184
|
+
context 'when no types given' do
|
185
|
+
subject do
|
186
|
+
described_class.new('root', 0, 0, nil, [
|
187
|
+
described_class.new('foo', 0, 0),
|
188
|
+
described_class.new('bar', 0, 0)
|
189
|
+
])
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'returns empty array' do
|
193
|
+
expect(subject.all_descendents).to eq([])
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'when no children' do
|
198
|
+
subject { described_class.new('root', 0, 0) }
|
199
|
+
|
200
|
+
it 'returns empty array' do
|
201
|
+
expect(subject.all_descendents('root', 'foo')).to eq([])
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'when no descendents of given type(s)' do
|
206
|
+
subject do
|
207
|
+
described_class.new('root', 0, 0, nil, [
|
208
|
+
described_class.new('foo', 0, 0),
|
209
|
+
described_class.new('bar', 0, 0, nil, [
|
210
|
+
described_class.new('baz', 0, 0)
|
211
|
+
])
|
212
|
+
])
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns empty array' do
|
216
|
+
expect(subject.all_descendents('root', 'qux')).to eq([])
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'when multiple descendents of given type(s)' do
|
221
|
+
let(:descendent_1) { described_class.new('bar', 0, 0) }
|
222
|
+
let(:descendent_2) { described_class.new('baz', 10, 10, nil, [descendent_3]) }
|
223
|
+
let(:descendent_3) { described_class.new('bar', 20, 20) }
|
224
|
+
|
225
|
+
subject do
|
226
|
+
described_class.new('root', 0, 0, nil, [
|
227
|
+
described_class.new('foo', 0, 0, nil, [
|
228
|
+
descendent_1
|
229
|
+
]),
|
230
|
+
descendent_2,
|
231
|
+
described_class.new('qux', 40, 40)
|
232
|
+
])
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'returns all matching descendents' do
|
236
|
+
expect(subject.all_descendents('bar', 'baz')).to match_array([descendent_1, descendent_2, descendent_3])
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '#all_descendents_by_path' do
|
242
|
+
context 'when no children' do
|
243
|
+
subject { described_class.new('root', 0, 0) }
|
244
|
+
|
245
|
+
it 'returns empty array' do
|
246
|
+
expect(subject.all_descendents_by_path(['foo'])).to eq([])
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'when no path' do
|
251
|
+
subject do
|
252
|
+
described_class.new('root', 0, 0, nil, [
|
253
|
+
described_class.new('foo', 0, 0, nil, [
|
254
|
+
described_class.new('bar', 0, 0)
|
255
|
+
])
|
256
|
+
])
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'returns empty array' do
|
260
|
+
expect(subject.all_descendents_by_path([])).to eq([])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when no descendents at given path' do
|
265
|
+
subject do
|
266
|
+
described_class.new('root', 0, 0, nil, [
|
267
|
+
described_class.new('foo', 0, 0, nil, [
|
268
|
+
described_class.new('bar', 0, 0)
|
269
|
+
])
|
270
|
+
])
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'returns empty array' do
|
274
|
+
expect(subject.all_descendents_by_path(%w[foo baz])).to eq([])
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'when multiple descendents at given path' do
|
279
|
+
let(:descendent_1) { described_class.new('bar', 0, 0) }
|
280
|
+
let(:descendent_2) { described_class.new('bar', 0, 0) }
|
281
|
+
|
282
|
+
subject do
|
283
|
+
described_class.new('root', 0, 0, nil, [
|
284
|
+
described_class.new('foo', 0, 0, nil, [
|
285
|
+
descendent_1,
|
286
|
+
described_class.new('baz', 0, 0, nil, [
|
287
|
+
described_class.new('bar', 0, 0)
|
288
|
+
]),
|
289
|
+
descendent_2,
|
290
|
+
])
|
291
|
+
])
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'returns all matching descendents' do
|
295
|
+
expect(subject.all_descendents_by_path(%w[foo bar])).to match_array([descendent_1, descendent_2])
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#first_descendent' do
|
301
|
+
context 'when no children' do
|
302
|
+
subject { described_class.new('root', 0, 0) }
|
303
|
+
|
304
|
+
it 'returns nil' do
|
305
|
+
expect(subject.first_descendent('root', 'foo')).to eq(nil)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'when no descendents of given type(s)' do
|
310
|
+
subject do
|
311
|
+
described_class.new('root', 0, 0, nil, [
|
312
|
+
described_class.new('foo', 0, 0),
|
313
|
+
described_class.new('bar', 0, 0, nil, [
|
314
|
+
described_class.new('baz', 0, 0)
|
315
|
+
])
|
316
|
+
])
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'returns nil' do
|
320
|
+
expect(subject.first_descendent('root', 'qux')).to eq(nil)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context 'when multiple descendents of given type(s)' do
|
325
|
+
let(:descendent) { described_class.new('bar', 0, 0) }
|
326
|
+
|
327
|
+
subject do
|
328
|
+
described_class.new('root', 0, 0, nil, [
|
329
|
+
described_class.new('foo', 0, 0, nil, [
|
330
|
+
descendent
|
331
|
+
]),
|
332
|
+
described_class.new('bar', 0, 0),
|
333
|
+
])
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'returns first matching descendent' do
|
337
|
+
expect(subject.first_descendent('bar')).to be(descendent)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
describe '#first_descendent_by_path' do
|
343
|
+
context 'when no children' do
|
344
|
+
subject { described_class.new('root', 0, 0) }
|
345
|
+
|
346
|
+
it 'returns nil' do
|
347
|
+
expect(subject.first_descendent_by_path(['foo'])).to eq(nil)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context 'when no path' do
|
352
|
+
subject do
|
353
|
+
described_class.new('root', 0, 0, nil, [
|
354
|
+
described_class.new('foo', 0, 0, nil, [
|
355
|
+
described_class.new('bar', 0, 0)
|
356
|
+
])
|
357
|
+
])
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'returns nil' do
|
361
|
+
expect(subject.first_descendent_by_path([])).to eq(nil)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
context 'when no descendents at given path' do
|
366
|
+
subject do
|
367
|
+
described_class.new('root', 0, 0, nil, [
|
368
|
+
described_class.new('foo', 0, 0, nil, [
|
369
|
+
described_class.new('bar', 0, 0)
|
370
|
+
])
|
371
|
+
])
|
372
|
+
end
|
373
|
+
|
374
|
+
it 'returns nil' do
|
375
|
+
expect(subject.first_descendent_by_path(%w[foo baz])).to eq(nil)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
context 'when multiple descendents at given path' do
|
380
|
+
let(:descendent) { described_class.new('bar', 0, 0) }
|
381
|
+
|
382
|
+
subject do
|
383
|
+
described_class.new('root', 0, 0, nil, [
|
384
|
+
described_class.new('foo', 0, 0, nil, [
|
385
|
+
described_class.new('baz', 0, 0, nil, [
|
386
|
+
described_class.new('bar', 0, 0)
|
387
|
+
]),
|
388
|
+
descendent,
|
389
|
+
described_class.new('bar', 0, 0),
|
390
|
+
])
|
391
|
+
])
|
392
|
+
end
|
393
|
+
|
394
|
+
it 'returns first matching descendent' do
|
395
|
+
expect(subject.first_descendent_by_path(%w[foo bar])).to eq(descendent)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
@@ -1,14 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe FormatParser::ISOBaseMediaFileFormat::Decoder do
|
4
|
-
|
5
|
-
context '
|
6
|
-
|
7
|
-
|
4
|
+
describe '#build_box_tree' do
|
5
|
+
context 'when IO not provided' do
|
6
|
+
context 'when IO not previously provided' do
|
7
|
+
it 'raises an error' do
|
8
|
+
expect { subject.build_box_tree(0x0) }.to raise_error(/IO missing - supply a valid IO object/)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when IO previously provided' do
|
13
|
+
let(:io) { StringIO.new('') }
|
14
|
+
it 'does not raise an error' do
|
15
|
+
expect(subject.build_box_tree(0x0, io)).to eq([])
|
16
|
+
expect(subject.build_box_tree(0x0)).to eq([])
|
17
|
+
end
|
8
18
|
end
|
9
19
|
end
|
10
20
|
|
11
|
-
context
|
21
|
+
context 'when max_read smaller than IO length' do
|
12
22
|
let(:io) do
|
13
23
|
# moov
|
14
24
|
# moov
|
@@ -17,41 +27,36 @@ describe FormatParser::ISOBaseMediaFileFormat::Decoder do
|
|
17
27
|
end
|
18
28
|
|
19
29
|
it 'stops building the tree' do
|
20
|
-
expect(subject.
|
30
|
+
expect(subject.build_box_tree(0x0, io).length).to eq(0)
|
21
31
|
expect(io.pos).to eq(0)
|
22
32
|
|
23
|
-
expect(subject.
|
33
|
+
expect(subject.build_box_tree(0x8, io).length).to eq(1)
|
24
34
|
expect(io.pos).to eq(0x8)
|
25
35
|
io.seek(0)
|
26
36
|
|
27
|
-
expect(subject.
|
37
|
+
expect(subject.build_box_tree(0x10, io).length).to eq(2)
|
28
38
|
expect(io.pos).to eq(0x10)
|
29
39
|
end
|
30
40
|
end
|
31
41
|
|
32
|
-
context 'when parsing
|
42
|
+
context 'when parsing unknown box' do
|
33
43
|
let(:io) do
|
34
44
|
# foo
|
35
45
|
# |-> moov
|
36
46
|
input = [0x14].pack('N') + 'foo ' + [0x1].pack('N') + [0x8].pack('N') + 'moov'
|
37
47
|
StringIO.new(input)
|
38
48
|
end
|
49
|
+
let(:result) { subject.build_box_tree(0xFF, io) }
|
39
50
|
|
40
|
-
it
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
expect(foo_atom.type).to eq('foo ')
|
47
|
-
expect(foo_atom.position).to eq(0)
|
48
|
-
expect(foo_atom.size).to eq(0x14)
|
49
|
-
expect(foo_atom.fields).to eq({})
|
50
|
-
expect(foo_atom.children).to eq([])
|
51
|
-
end
|
51
|
+
it('parses successfully') { expect(result.length).to eq(1) }
|
52
|
+
it('parses the correct type') { expect(result[0].type).to eq('foo ') }
|
53
|
+
it('parses the correct position') { expect(result[0].position).to eq(0) }
|
54
|
+
it('parses the correct size') { expect(result[0].size).to eq(0x14) }
|
55
|
+
it('skips additional fields') { expect(result[0].fields).to eq({}) }
|
56
|
+
it('skips children') { expect(result[0].children).to eq([]) }
|
52
57
|
end
|
53
58
|
|
54
|
-
context 'when parsing a container
|
59
|
+
context 'when parsing a container box' do
|
55
60
|
let(:io) do
|
56
61
|
# moov
|
57
62
|
# |-> foo
|
@@ -59,184 +64,54 @@ describe FormatParser::ISOBaseMediaFileFormat::Decoder do
|
|
59
64
|
input = [0x18].pack('N') + 'moov' + [0x8].pack('N') + 'foo ' + [0x8].pack('N') + 'bar '
|
60
65
|
StringIO.new(input)
|
61
66
|
end
|
67
|
+
let(:result) { subject.build_box_tree(0xFF, io) }
|
62
68
|
|
63
|
-
it
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
expect(moov_atom.type).to eq('moov')
|
70
|
-
expect(moov_atom.position).to eq(0)
|
71
|
-
expect(moov_atom.size).to eq(0x18)
|
72
|
-
expect(moov_atom.fields).to eq({})
|
73
|
-
expect(moov_atom.children.length).to eq(2)
|
74
|
-
end
|
69
|
+
it('parses successfully') { expect(result.length).to eq(1) }
|
70
|
+
it('parses the correct type') { expect(result[0].type).to eq('moov') }
|
71
|
+
it('parses the correct position') { expect(result[0].position).to eq(0) }
|
72
|
+
it('parses the correct size') { expect(result[0].size).to eq(0x18) }
|
73
|
+
it('skips additional fields') { expect(result[0].fields).to eq({}) }
|
74
|
+
it('parses children') { expect(result[0].children.length).to eq(2) }
|
75
75
|
end
|
76
76
|
|
77
|
-
context 'when parsing an empty
|
77
|
+
context 'when parsing an empty box' do
|
78
78
|
let(:io) do
|
79
79
|
# nmhd
|
80
80
|
# |-> foo
|
81
81
|
input = [0x18].pack('N') + 'nmhd' + [0x1].pack('c') + 'fla' + [0x2].pack('N') + [0x8].pack('N') + 'foo '
|
82
82
|
StringIO.new(input)
|
83
83
|
end
|
84
|
+
let(:result) { subject.build_box_tree(0xFF, io) }
|
84
85
|
|
85
|
-
it
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
expect(nmhd_atom.type).to eq('nmhd')
|
92
|
-
expect(nmhd_atom.position).to eq(0)
|
93
|
-
expect(nmhd_atom.size).to eq(0x18)
|
94
|
-
expect(nmhd_atom.fields).to include({
|
86
|
+
it('parses successfully') { expect(result.length).to eq(1) }
|
87
|
+
it('parses the correct type') { expect(result[0].type).to eq('nmhd') }
|
88
|
+
it('parses the correct position') { expect(result[0].position).to eq(0) }
|
89
|
+
it('parses the correct size') { expect(result[0].size).to eq(0x18) }
|
90
|
+
it('parses version and flags') do
|
91
|
+
expect(result[0].fields).to include({
|
95
92
|
version: 1,
|
96
93
|
flags: 'fla'
|
97
94
|
})
|
98
|
-
expect(nmhd_atom.children).to eq([])
|
99
95
|
end
|
96
|
+
it('skips children') { expect(result[0].children).to eq([]) }
|
100
97
|
end
|
101
98
|
|
102
|
-
context 'when parsing a uuid
|
99
|
+
context 'when parsing a uuid box' do
|
103
100
|
let(:usertype) { '90f7c66ec2db476b977461e796f0dd4b' }
|
104
101
|
let(:io) do
|
105
|
-
input = [0x20].pack('N') + 'uuid' + [usertype].pack('H*') + [0x8].pack('N') + 'foo '
|
106
|
-
StringIO.new(input)
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'parses type, position, size and usertype, and skips any other fields or children' do
|
110
102
|
# uuid
|
111
103
|
# |-> foo
|
112
|
-
|
113
|
-
|
114
|
-
expect(io.pos).to eq(0x20)
|
115
|
-
|
116
|
-
nmhd_atom = result[0]
|
117
|
-
expect(nmhd_atom.type).to eq('uuid')
|
118
|
-
expect(nmhd_atom.position).to eq(0)
|
119
|
-
expect(nmhd_atom.size).to eq(0x20)
|
120
|
-
expect(nmhd_atom.fields).to include({
|
121
|
-
usertype: usertype,
|
122
|
-
})
|
123
|
-
expect(nmhd_atom.children).to eq([])
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe FormatParser::ISOBaseMediaFileFormat::Decoder::Atom do
|
130
|
-
context 'when initialized' do
|
131
|
-
context 'without fields and/or children' do
|
132
|
-
subject { described_class.new('foo', 0, 0) }
|
133
|
-
|
134
|
-
it 'sets them as an empty array/hash' do
|
135
|
-
expect(subject.type).to eq('foo')
|
136
|
-
expect(subject.position).to eq(0)
|
137
|
-
expect(subject.size).to eq(0)
|
138
|
-
expect(subject.fields).to eq({})
|
139
|
-
expect(subject.children).to eq([])
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
context 'with fields and/or children' do
|
144
|
-
let(:fields) { { foo: 1, bar: 'bar' } }
|
145
|
-
let(:children) { [described_class.new('bar', 0, 0)] }
|
146
|
-
|
147
|
-
subject { described_class.new('foo', 0, 0, fields, children) }
|
148
|
-
|
149
|
-
it 'sets them correctly' do
|
150
|
-
expect(subject.type).to eq('foo')
|
151
|
-
expect(subject.position).to eq(0)
|
152
|
-
expect(subject.size).to eq(0)
|
153
|
-
expect(subject.fields).to eq(fields)
|
154
|
-
expect(subject.children).to eq(children)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
context 'when find_first_descendent is called' do
|
160
|
-
context 'with no children' do
|
161
|
-
subject { described_class.new('root', 0, 0) }
|
162
|
-
it 'returns nil' do
|
163
|
-
expect(subject.find_first_descendent(%w[root foo])).to be_nil
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
context 'with no descendents of the given type(s)' do
|
168
|
-
subject do
|
169
|
-
described_class.new('root', 0, 0, nil, [
|
170
|
-
described_class.new('foo', 0, 0),
|
171
|
-
described_class.new('bar', 0, 0, nil, [
|
172
|
-
described_class.new('baz', 0, 0)
|
173
|
-
])
|
174
|
-
])
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'returns nil' do
|
178
|
-
expect(subject.find_first_descendent(%w[root qux])).to be_nil
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
context 'with multiple descendents of the given type(s)' do
|
183
|
-
let(:descendent) { described_class.new('bar', 0, 0) }
|
184
|
-
|
185
|
-
subject do
|
186
|
-
described_class.new('root', 0, 0, nil, [
|
187
|
-
described_class.new('foo', 0, 0, nil, [
|
188
|
-
descendent
|
189
|
-
]),
|
190
|
-
described_class.new('bar', 0, 0),
|
191
|
-
])
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'returns the first relevant descendent in order of appearance' do
|
195
|
-
expect(subject.find_first_descendent(%w[bar])).to be(descendent)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
context 'when select_descendents is called' do
|
201
|
-
context 'with no children' do
|
202
|
-
subject { described_class.new('root', 0, 0) }
|
203
|
-
it 'returns an empty array' do
|
204
|
-
expect(subject.select_descendents(%w[root foo])).to eq([])
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
context 'with no descendents of the given type(s)' do
|
209
|
-
subject do
|
210
|
-
described_class.new('root', 0, 0, nil, [
|
211
|
-
described_class.new('foo', 0, 0),
|
212
|
-
described_class.new('bar', 0, 0, nil, [
|
213
|
-
described_class.new('baz', 0, 0)
|
214
|
-
])
|
215
|
-
])
|
216
|
-
end
|
217
|
-
|
218
|
-
it 'returns an empty array' do
|
219
|
-
expect(subject.select_descendents(%w[root qux])).to eq([])
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
context 'with multiple descendents of the given type(s)' do
|
224
|
-
let(:descendent_1) { described_class.new('bar', 0, 0) }
|
225
|
-
let(:descendent_3) { described_class.new('bar', 20, 20) }
|
226
|
-
let(:descendent_2) { described_class.new('baz', 10, 10, nil, [descendent_3]) }
|
227
|
-
|
228
|
-
subject do
|
229
|
-
described_class.new('root', 0, 0, nil, [
|
230
|
-
described_class.new('foo', 0, 0, nil, [
|
231
|
-
descendent_1
|
232
|
-
]),
|
233
|
-
descendent_2,
|
234
|
-
])
|
104
|
+
input = [0x20].pack('N') + 'uuid' + [usertype].pack('H*') + [0x8].pack('N') + 'foo '
|
105
|
+
StringIO.new(input)
|
235
106
|
end
|
107
|
+
let(:result) { subject.build_box_tree(0xFF, io) }
|
236
108
|
|
237
|
-
it '
|
238
|
-
|
239
|
-
|
109
|
+
it('parses successfully') { expect(result.length).to eq(1) }
|
110
|
+
it('parses the correct type') { expect(result[0].type).to eq('uuid') }
|
111
|
+
it('parses the correct position') { expect(result[0].position).to eq(0) }
|
112
|
+
it('parses the correct size') { expect(result[0].size).to eq(0x20) }
|
113
|
+
it('parses usertype') { expect(result[0].fields).to include({ usertype: usertype }) }
|
114
|
+
it('skips children') { expect(result[0].children).to eq([]) }
|
240
115
|
end
|
241
116
|
end
|
242
117
|
end
|