riffola 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/riffola.rb +240 -0
- data/lib/riffola/version.rb +5 -0
- data/spec/riffola_spec.rb +523 -0
- data/spec/spec_helper.rb +100 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2be335b138c805162b56fb07b14d589a1c90f00fa0a6fed6c1cb9dba482151f4
|
4
|
+
data.tar.gz: c393edd260fc4b43a94feb327449e059a25f46a4189c2b42c1516029619703a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc246a663893068f9c96fcdcbe842112a0c160b63f475b98ad357e8c775613f0f279eb413ad7aad135b9644d44570824c9980493390fc4821c8514a5dd9ffb14
|
7
|
+
data.tar.gz: dd1956dc6c17bffcb1e37e24d33abbb3c79553a600f11a6b26267434f7467bfe283034aad8b63c8f9bf55d3de60d3341500e926febaaf26c171a45fc9314ece1
|
data/lib/riffola.rb
ADDED
@@ -0,0 +1,240 @@
|
|
1
|
+
module Riffola
|
2
|
+
|
3
|
+
# Return a list of Riff chunk objects stored in a file, from a given offset.
|
4
|
+
# A chunk is defined as this:
|
5
|
+
# * A name (4 bytes)
|
6
|
+
# * A size (4 bytes by default)
|
7
|
+
# * A header (0 bytes by default)
|
8
|
+
# * Data (Size bytes)
|
9
|
+
#
|
10
|
+
# Parameters::
|
11
|
+
# * *file* (String): The file name
|
12
|
+
# * *offset* (Integer): The offset to read the file from [default: 0]
|
13
|
+
# * *chunks_format* (Hash<String, Hash<Symbol,Object> >): Chunks format. See Chunk#initialize for details. [default = {}]
|
14
|
+
# * *max_size* (Integer): Maximum readable size (starting from the file's offset) to retrieve chunks, or nil to read till the end of the file [default: nil]
|
15
|
+
# * *parent_chunk* (Chunk or nil): Parent chunk, or nil if none [default: nil]
|
16
|
+
# * *warnings* (Boolean): Do we activate warnings? [default: true]
|
17
|
+
# * *debug* (Boolean): Do we activate debugging logs? [default: false]
|
18
|
+
# * Proc: Optional code called for each chunk being decoded
|
19
|
+
# * Parameters::
|
20
|
+
# * *chunk* (Chunk): Chunk being decoded
|
21
|
+
# * Result::
|
22
|
+
# * Boolean: Do we continue decoding chunks?
|
23
|
+
# Result::
|
24
|
+
# * Array<Chunk>: The chunks list
|
25
|
+
def self.read(file, offset: 0, chunks_format: {}, max_size: nil, parent_chunk: nil, warnings: true, debug: false)
|
26
|
+
chunks = []
|
27
|
+
max_size = File.size(file) - offset if max_size.nil?
|
28
|
+
chunk = max_size > 0 ? Chunk.new(file,
|
29
|
+
offset: offset,
|
30
|
+
chunks_format: chunks_format,
|
31
|
+
max_size: max_size,
|
32
|
+
parent_chunk: parent_chunk,
|
33
|
+
warnings: warnings,
|
34
|
+
debug: debug
|
35
|
+
) : nil
|
36
|
+
while !chunk.nil?
|
37
|
+
chunks << chunk
|
38
|
+
break if block_given? && !yield(chunk)
|
39
|
+
chunk = chunk.next
|
40
|
+
end
|
41
|
+
chunks
|
42
|
+
end
|
43
|
+
|
44
|
+
class Chunk
|
45
|
+
|
46
|
+
# Define default chunk format properties
|
47
|
+
DEFAULT_CHUNK_FORMAT = {
|
48
|
+
size_length: 4,
|
49
|
+
header_size: 0,
|
50
|
+
data_size_correction: 0
|
51
|
+
}
|
52
|
+
|
53
|
+
# Constructor
|
54
|
+
#
|
55
|
+
# Parameters::
|
56
|
+
# * *file_name* (String): The file name
|
57
|
+
# * *offset* (Integer): The offset to read the file from [default: 0]
|
58
|
+
# * *chunks_format* (Hash<String, Hash<Symbol,Object> >): Format of a given set of chunk names (use '*' for all chunks). For each chunk name, the following can be specified: [default = {}]
|
59
|
+
# * *size_length* (Integer): Number of bytes encoding the size of the chunk [default: 4]
|
60
|
+
# * *header_size* (Integer): Size of the chunk's header [default: 0]
|
61
|
+
# * *data_size_correction* (Integer): Correction to apply to the data size read [default: 0]
|
62
|
+
# Each property can also be a Proc taking the file handle (positioned at the beginning of the chunk) and returning the real value:
|
63
|
+
# * Parameters::
|
64
|
+
# * *file* (IO): The file IO, positioned at the beginning of the chunk (at the name)
|
65
|
+
# * Result::
|
66
|
+
# * Object: The corresponding property value
|
67
|
+
# * *max_size* (Integer): Maximum readable size (starting from the file's offset) to retrieve chunks, or nil to read till the end of the file [default: nil]
|
68
|
+
# * *parent_chunk* (Chunk or nil): Parent chunk, or nil if none [default: nil]
|
69
|
+
# * *warnings* (Boolean): Do we activate warnings? [default: true]
|
70
|
+
# * *debug* (Boolean): Do we activate debugging logs? [default: false]
|
71
|
+
def initialize(file_name, offset: 0, chunks_format: {}, max_size: nil, parent_chunk: nil, warnings: true, debug: false)
|
72
|
+
@file_name = file_name
|
73
|
+
@offset = offset
|
74
|
+
@chunks_format = chunks_format
|
75
|
+
# Fill the default format if not present
|
76
|
+
@chunks_format['*'] = {} unless @chunks_format.key?('*')
|
77
|
+
DEFAULT_CHUNK_FORMAT.each do |format_property, default_property_value|
|
78
|
+
@chunks_format['*'][format_property] = default_property_value unless @chunks_format['*'].key?(format_property)
|
79
|
+
end
|
80
|
+
@parent_chunk = parent_chunk
|
81
|
+
@max_size = max_size.nil? ? File.size(@file_name) - @offset : max_size
|
82
|
+
@warnings = warnings
|
83
|
+
@debug = debug
|
84
|
+
# Get chunk format in instance variables named after the property
|
85
|
+
chunk_name = self.name
|
86
|
+
DEFAULT_CHUNK_FORMAT.keys.each do |format_property|
|
87
|
+
property_value = @chunks_format.key?(chunk_name) && @chunks_format[chunk_name].key?(format_property) ? @chunks_format[chunk_name][format_property] : @chunks_format['*'][format_property]
|
88
|
+
if property_value.is_a?(Proc)
|
89
|
+
File.open(@file_name) do |file|
|
90
|
+
file.seek(@offset)
|
91
|
+
property_value = property_value.call(file)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
instance_variable_set(:"@#{format_property}", property_value)
|
95
|
+
end
|
96
|
+
puts "[DEBUG] - Read chunk from #{@file_name}@#{@offset}/#{@max_size}: #{chunk_name} (size length: #{@size_length}, header size: #{@header_size}, data size: #{self.size}/#{@max_size})" if @debug
|
97
|
+
# puts "[DEBUG] - Chunks format: #{@chunks_format.inspect}" if @debug
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return the name of this chunk
|
101
|
+
#
|
102
|
+
# Result::
|
103
|
+
# * String: Chunk name
|
104
|
+
def name
|
105
|
+
chunk_name = nil
|
106
|
+
File.open(@file_name) do |file|
|
107
|
+
file.seek(@offset, IO::SEEK_CUR)
|
108
|
+
chunk_name = file.read(4)
|
109
|
+
end
|
110
|
+
puts "[WARNING] - Doesn't look like a valid chunk name: #{chunk_name}" if @warnings && !chunk_name =~ /^[\w ]{4}$/
|
111
|
+
chunk_name
|
112
|
+
end
|
113
|
+
|
114
|
+
# Return the size of this chunk
|
115
|
+
#
|
116
|
+
# Result::
|
117
|
+
# * Integer: Chunk size in bytes
|
118
|
+
def size
|
119
|
+
chunk_size = nil
|
120
|
+
File.open(@file_name) do |file|
|
121
|
+
file.seek(@offset + 4, IO::SEEK_CUR)
|
122
|
+
case @size_length
|
123
|
+
when 4
|
124
|
+
chunk_size = file.read(@size_length).unpack('L').first
|
125
|
+
when 2
|
126
|
+
chunk_size = file.read(@size_length).unpack('S').first
|
127
|
+
else
|
128
|
+
raise "Can't decode size field of length #{@size_length}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
chunk_size + @data_size_correction
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return the header of this chunk
|
135
|
+
#
|
136
|
+
# Result::
|
137
|
+
# * String: Header
|
138
|
+
def header
|
139
|
+
chunk_header = nil
|
140
|
+
File.open(@file_name) do |file|
|
141
|
+
file.seek(@offset + 4 + @size_length, IO::SEEK_CUR)
|
142
|
+
chunk_header = file.read(@header_size)
|
143
|
+
end
|
144
|
+
chunk_header
|
145
|
+
end
|
146
|
+
|
147
|
+
# Return the data of this chunk
|
148
|
+
#
|
149
|
+
# Result::
|
150
|
+
# * String: Data
|
151
|
+
def data
|
152
|
+
chunk_data = nil
|
153
|
+
data_size = self.size
|
154
|
+
complete_header_size = 4 + @size_length + @header_size
|
155
|
+
puts "[WARNING] - Data size is #{data_size} but the maximum readable size is #{@max_size} and the headers have #{complete_header_size}" if @warnings && complete_header_size + data_size > @max_size
|
156
|
+
File.open(@file_name) do |file|
|
157
|
+
file.seek(@offset + complete_header_size, IO::SEEK_CUR)
|
158
|
+
chunk_data = file.read(data_size)
|
159
|
+
end
|
160
|
+
chunk_data
|
161
|
+
end
|
162
|
+
|
163
|
+
# Return the parent chunk, or nil if none
|
164
|
+
#
|
165
|
+
# Result::
|
166
|
+
# * Chunk or nil: The parent chunk, or nil if none
|
167
|
+
def parent_chunk
|
168
|
+
@parent_chunk
|
169
|
+
end
|
170
|
+
|
171
|
+
# Return a string representation of this chunk
|
172
|
+
#
|
173
|
+
# Result::
|
174
|
+
# * String: tring representation of this chunk
|
175
|
+
def to_s
|
176
|
+
"<Riffola-Chunk #{self.name} (#{@file_name}@#{@offset})>"
|
177
|
+
end
|
178
|
+
|
179
|
+
# Return the next chunk
|
180
|
+
#
|
181
|
+
# Result::
|
182
|
+
# * Chunk or nil: The next chunk, or nil if none
|
183
|
+
def next
|
184
|
+
complete_chunk_size = 4 + @size_length + @header_size + self.size
|
185
|
+
remaining_size = @max_size - complete_chunk_size
|
186
|
+
raise "#{self} - Remaining size for next chunk: #{remaining_size}" if remaining_size < 0
|
187
|
+
remaining_size > 0 ? Chunk.new(@file_name,
|
188
|
+
offset: @offset + complete_chunk_size,
|
189
|
+
chunks_format: @chunks_format,
|
190
|
+
max_size: remaining_size,
|
191
|
+
parent_chunk: @parent_chunk,
|
192
|
+
warnings: @warnings,
|
193
|
+
debug: @debug
|
194
|
+
) : nil
|
195
|
+
end
|
196
|
+
|
197
|
+
# Return this chunk's data as a list of sub-chunks
|
198
|
+
#
|
199
|
+
# Parameters::
|
200
|
+
# * *data_offset* (Integer): The offset to read the sub-chunks from this chunk's data [default: 0]
|
201
|
+
# * *sub_chunks_format* (Hash<String, Hash<Symbol,Object> >): Chunks format. See Chunk#initialize for details. [default = @chunks_format]
|
202
|
+
# * *warnings* (Boolean): Do we activate warnings? [default: @warnings]
|
203
|
+
# * *debug* (Boolean): Do we activate debugging logs? [default: @debug]
|
204
|
+
# * Proc: Optional code called for each chunk being decoded
|
205
|
+
# * Parameters::
|
206
|
+
# * *chunk* (Chunk): Chunk being decoded
|
207
|
+
# * Result::
|
208
|
+
# * Boolean: Do we continue decoding chunks?
|
209
|
+
# Result::
|
210
|
+
# * Array<Chunk>: List of sub-chunks
|
211
|
+
def sub_chunks(data_offset: 0, sub_chunk_size_length: @size_length, sub_chunk_header_size: @header_size, sub_chunks_format: @chunks_format, warnings: @warnings, debug: @debug, &callback)
|
212
|
+
data_size = self.size
|
213
|
+
data_size > 0 ? Riffola.read(@file_name,
|
214
|
+
offset: @offset + 4 + @size_length + @header_size + data_offset,
|
215
|
+
chunks_format: sub_chunks_format,
|
216
|
+
max_size: data_size - data_offset,
|
217
|
+
parent_chunk: self,
|
218
|
+
warnings: @warnings,
|
219
|
+
debug: @debug,
|
220
|
+
&callback
|
221
|
+
) : []
|
222
|
+
end
|
223
|
+
|
224
|
+
# Compare Chunks
|
225
|
+
#
|
226
|
+
# Parameters::
|
227
|
+
# * *other* (Object): Other object
|
228
|
+
# Result::
|
229
|
+
# * Boolean: Are objects equal?
|
230
|
+
def ==(other)
|
231
|
+
other.is_a?(Chunk) &&
|
232
|
+
other.name == self.name &&
|
233
|
+
other.size == self.size &&
|
234
|
+
other.header == self.header &&
|
235
|
+
other.data == self.data
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
@@ -0,0 +1,523 @@
|
|
1
|
+
require 'riffola'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'hex_string'
|
4
|
+
|
5
|
+
describe Riffola do
|
6
|
+
|
7
|
+
# Are we in debug mode?
|
8
|
+
#
|
9
|
+
# Result::
|
10
|
+
# * Boolean: Are we in debug mode?
|
11
|
+
def debug?
|
12
|
+
ENV['TEST_DEBUG'] == '1'
|
13
|
+
end
|
14
|
+
|
15
|
+
HEX_DUMP_CHARS_SIZE = 16
|
16
|
+
|
17
|
+
# Convert a given string in a debuggable hexadecimal format
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *str* (String): String to be converted
|
21
|
+
# Result::
|
22
|
+
# * String: The output
|
23
|
+
def hex_dump(str)
|
24
|
+
str.scan(/.{1,#{HEX_DUMP_CHARS_SIZE}}/m).map do |line|
|
25
|
+
"#{"%-#{HEX_DUMP_CHARS_SIZE * 3}s" % line.to_hex_string}| #{line.gsub(/[^[:print:]]/, '.')}"
|
26
|
+
end.join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get a string encoding chunks
|
30
|
+
#
|
31
|
+
# Parameters::
|
32
|
+
# * *chunks* (Array< Hash<Symbol,Object> >): List of chunks data:
|
33
|
+
# * *name* (String): Chunk's name
|
34
|
+
# * *data* (String): Chunk's data
|
35
|
+
# * *data_size* (Integer): Chunk's data size [default = data.size]
|
36
|
+
# * *header* (String): Chunk's header [default = '']
|
37
|
+
# * *size_length* (Integer): Size in bytes for size encoding [default = 4]
|
38
|
+
# Result::
|
39
|
+
# * String: The encoded chunks
|
40
|
+
def chunks_to_str(chunks)
|
41
|
+
chunks.map do |chunk_info|
|
42
|
+
chunk_info[:header] = '' unless chunk_info.key?(:header)
|
43
|
+
chunk_info[:size_length] = 4 unless chunk_info.key?(:size_length)
|
44
|
+
chunk_info[:data_size] = chunk_info[:data].size unless chunk_info.key?(:data_size)
|
45
|
+
size_pack_code =
|
46
|
+
case chunk_info[:size_length]
|
47
|
+
when 2
|
48
|
+
'S'
|
49
|
+
when 4
|
50
|
+
'L'
|
51
|
+
else
|
52
|
+
raise "Unknown size length to encode: #{chunk_info[:size_length]}"
|
53
|
+
end
|
54
|
+
"#{chunk_info[:name]}#{[chunk_info[:data_size]].pack(size_pack_code)}#{chunk_info[:header]}#{chunk_info[:data]}"
|
55
|
+
end.join
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create a file with some chunks content and call code with its file name
|
59
|
+
#
|
60
|
+
# Parameters::
|
61
|
+
# * *chunks* (Array< Hash<Symbol,Object> >): List of chunks data (check chunks for details). [default = []]:
|
62
|
+
# * Proc: Code called once the file has been created. File is deleted after code execution.
|
63
|
+
# * Parameters::
|
64
|
+
# * *file* (String): File name
|
65
|
+
def with_file_content(chunks = [])
|
66
|
+
Tempfile.open do |tmp_file|
|
67
|
+
tmp_file.write(chunks_to_str(chunks))
|
68
|
+
tmp_file.flush
|
69
|
+
puts "[Test Debug] - File #{tmp_file.path} has content:\n#{hex_dump(File.read(tmp_file))}" if debug?
|
70
|
+
yield tmp_file.path
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return the chunks read from a file content
|
75
|
+
#
|
76
|
+
# Parameters::
|
77
|
+
# * *chunks* (Array< Hash<Symbol,Object> >): List of chunks data. See with_file_content to understand the structure. [default = []]
|
78
|
+
# * *chunks_format* (Object): The chunks_format parameter give to Riffola.read [default: {}]
|
79
|
+
# * Proc: Code called with the chunks decoded from the file
|
80
|
+
# * Parameters::
|
81
|
+
# * *chunks* (Array<Riffola::Chunk>): List of chunks read from the file
|
82
|
+
def read_chunks(chunks = [], chunks_format: {})
|
83
|
+
with_file_content(chunks) do |file|
|
84
|
+
yield Riffola.read(file, chunks_format: chunks_format, debug: debug?)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'reads an empty file' do
|
89
|
+
read_chunks do |chunks|
|
90
|
+
expect(chunks).to eq []
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'reads a file containing 1 chunk' do
|
95
|
+
chunk_name = 'ABCD'
|
96
|
+
chunk_data = 'TestData'
|
97
|
+
read_chunks([
|
98
|
+
{
|
99
|
+
name: chunk_name,
|
100
|
+
data: chunk_data
|
101
|
+
}
|
102
|
+
]) do |chunks|
|
103
|
+
expect(chunks.size).to eq 1
|
104
|
+
chunk = chunks.first
|
105
|
+
expect(chunk.name).to eq chunk_name
|
106
|
+
expect(chunk.size).to eq chunk_data.size
|
107
|
+
expect(chunk.data).to eq chunk_data
|
108
|
+
expect(chunk.header).to eq ''
|
109
|
+
expect(chunk.parent_chunk).to eq nil
|
110
|
+
expect(chunk.next).to eq nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'reads a file containing several chunks' do
|
115
|
+
read_chunks([
|
116
|
+
{
|
117
|
+
name: 'CHK1',
|
118
|
+
data: 'ChunkData1'
|
119
|
+
},
|
120
|
+
{
|
121
|
+
name: 'CHK2',
|
122
|
+
data: 'ChunkData2'
|
123
|
+
},
|
124
|
+
{
|
125
|
+
name: 'CHK3',
|
126
|
+
data: 'ChunkData3'
|
127
|
+
}
|
128
|
+
]) do |chunks|
|
129
|
+
expect(chunks.size).to eq 3
|
130
|
+
chunk = chunks.first
|
131
|
+
expect(chunk.name).to eq 'CHK1'
|
132
|
+
expect(chunk.size).to eq 10
|
133
|
+
expect(chunk.data).to eq 'ChunkData1'
|
134
|
+
expect(chunk.header).to eq ''
|
135
|
+
expect(chunk.parent_chunk).to eq nil
|
136
|
+
expect(chunk.next).to eq chunks[1]
|
137
|
+
chunk = chunk.next
|
138
|
+
expect(chunk.name).to eq 'CHK2'
|
139
|
+
expect(chunk.size).to eq 10
|
140
|
+
expect(chunk.data).to eq 'ChunkData2'
|
141
|
+
expect(chunk.header).to eq ''
|
142
|
+
expect(chunk.parent_chunk).to eq nil
|
143
|
+
expect(chunk.next).to eq chunks[2]
|
144
|
+
chunk = chunk.next
|
145
|
+
expect(chunk.name).to eq 'CHK3'
|
146
|
+
expect(chunk.size).to eq 10
|
147
|
+
expect(chunk.data).to eq 'ChunkData3'
|
148
|
+
expect(chunk.header).to eq ''
|
149
|
+
expect(chunk.parent_chunk).to eq nil
|
150
|
+
expect(chunk.next).to eq nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'reads a file containing several chunks with size encoded in 2 bytes' do
|
155
|
+
read_chunks([
|
156
|
+
{
|
157
|
+
name: 'CHK1',
|
158
|
+
data: 'ChunkData1',
|
159
|
+
size_length: 2
|
160
|
+
},
|
161
|
+
{
|
162
|
+
name: 'CHK2',
|
163
|
+
data: 'ChunkData2',
|
164
|
+
size_length: 2
|
165
|
+
},
|
166
|
+
{
|
167
|
+
name: 'CHK3',
|
168
|
+
data: 'ChunkData3',
|
169
|
+
size_length: 2
|
170
|
+
}
|
171
|
+
], chunks_format: { '*' => { size_length: 2 } }) do |chunks|
|
172
|
+
expect(chunks.size).to eq 3
|
173
|
+
chunk = chunks.first
|
174
|
+
expect(chunk.name).to eq 'CHK1'
|
175
|
+
expect(chunk.size).to eq 10
|
176
|
+
expect(chunk.data).to eq 'ChunkData1'
|
177
|
+
expect(chunk.header).to eq ''
|
178
|
+
expect(chunk.parent_chunk).to eq nil
|
179
|
+
expect(chunk.next).to eq chunks[1]
|
180
|
+
chunk = chunk.next
|
181
|
+
expect(chunk.name).to eq 'CHK2'
|
182
|
+
expect(chunk.size).to eq 10
|
183
|
+
expect(chunk.data).to eq 'ChunkData2'
|
184
|
+
expect(chunk.header).to eq ''
|
185
|
+
expect(chunk.parent_chunk).to eq nil
|
186
|
+
expect(chunk.next).to eq chunks[2]
|
187
|
+
chunk = chunk.next
|
188
|
+
expect(chunk.name).to eq 'CHK3'
|
189
|
+
expect(chunk.size).to eq 10
|
190
|
+
expect(chunk.data).to eq 'ChunkData3'
|
191
|
+
expect(chunk.header).to eq ''
|
192
|
+
expect(chunk.parent_chunk).to eq nil
|
193
|
+
expect(chunk.next).to eq nil
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'reads a file containing several chunks with headers' do
|
198
|
+
read_chunks([
|
199
|
+
{
|
200
|
+
name: 'CHK1',
|
201
|
+
data: 'ChunkData1',
|
202
|
+
header: 'ChunkHeader1'
|
203
|
+
},
|
204
|
+
{
|
205
|
+
name: 'CHK2',
|
206
|
+
data: 'ChunkData2',
|
207
|
+
header: 'ChunkHeader2'
|
208
|
+
},
|
209
|
+
{
|
210
|
+
name: 'CHK3',
|
211
|
+
data: 'ChunkData3',
|
212
|
+
header: 'ChunkHeader3'
|
213
|
+
}
|
214
|
+
], chunks_format: { '*' => { header_size: 12 } }) do |chunks|
|
215
|
+
expect(chunks.size).to eq 3
|
216
|
+
chunk = chunks.first
|
217
|
+
expect(chunk.name).to eq 'CHK1'
|
218
|
+
expect(chunk.size).to eq 10
|
219
|
+
expect(chunk.data).to eq 'ChunkData1'
|
220
|
+
expect(chunk.header).to eq 'ChunkHeader1'
|
221
|
+
expect(chunk.parent_chunk).to eq nil
|
222
|
+
expect(chunk.next).to eq chunks[1]
|
223
|
+
chunk = chunk.next
|
224
|
+
expect(chunk.name).to eq 'CHK2'
|
225
|
+
expect(chunk.size).to eq 10
|
226
|
+
expect(chunk.data).to eq 'ChunkData2'
|
227
|
+
expect(chunk.header).to eq 'ChunkHeader2'
|
228
|
+
expect(chunk.parent_chunk).to eq nil
|
229
|
+
expect(chunk.next).to eq chunks[2]
|
230
|
+
chunk = chunk.next
|
231
|
+
expect(chunk.name).to eq 'CHK3'
|
232
|
+
expect(chunk.size).to eq 10
|
233
|
+
expect(chunk.data).to eq 'ChunkData3'
|
234
|
+
expect(chunk.header).to eq 'ChunkHeader3'
|
235
|
+
expect(chunk.parent_chunk).to eq nil
|
236
|
+
expect(chunk.next).to eq nil
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'reads a file containing several chunks with data size correction' do
|
241
|
+
read_chunks([
|
242
|
+
{
|
243
|
+
name: 'CHK1',
|
244
|
+
data: 'ChunkData1',
|
245
|
+
data_size: 4
|
246
|
+
},
|
247
|
+
{
|
248
|
+
name: 'CHK2',
|
249
|
+
data: 'ChunkData2',
|
250
|
+
data_size: 4
|
251
|
+
},
|
252
|
+
{
|
253
|
+
name: 'CHK3',
|
254
|
+
data: 'ChunkData3',
|
255
|
+
data_size: 4
|
256
|
+
}
|
257
|
+
], chunks_format: { '*' => { data_size_correction: 6 } }) do |chunks|
|
258
|
+
expect(chunks.size).to eq 3
|
259
|
+
chunk = chunks.first
|
260
|
+
expect(chunk.name).to eq 'CHK1'
|
261
|
+
expect(chunk.size).to eq 10
|
262
|
+
expect(chunk.data).to eq 'ChunkData1'
|
263
|
+
expect(chunk.header).to eq ''
|
264
|
+
expect(chunk.parent_chunk).to eq nil
|
265
|
+
expect(chunk.next).to eq chunks[1]
|
266
|
+
chunk = chunk.next
|
267
|
+
expect(chunk.name).to eq 'CHK2'
|
268
|
+
expect(chunk.size).to eq 10
|
269
|
+
expect(chunk.data).to eq 'ChunkData2'
|
270
|
+
expect(chunk.header).to eq ''
|
271
|
+
expect(chunk.parent_chunk).to eq nil
|
272
|
+
expect(chunk.next).to eq chunks[2]
|
273
|
+
chunk = chunk.next
|
274
|
+
expect(chunk.name).to eq 'CHK3'
|
275
|
+
expect(chunk.size).to eq 10
|
276
|
+
expect(chunk.data).to eq 'ChunkData3'
|
277
|
+
expect(chunk.header).to eq ''
|
278
|
+
expect(chunk.parent_chunk).to eq nil
|
279
|
+
expect(chunk.next).to eq nil
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'reads a file containing several chunks with data size correction given as a Proc' do
|
284
|
+
read_chunks([
|
285
|
+
{
|
286
|
+
name: 'CHK1',
|
287
|
+
data: 'ChunkData1',
|
288
|
+
data_size: 4
|
289
|
+
},
|
290
|
+
{
|
291
|
+
name: 'CHK2',
|
292
|
+
data: 'ChunkData2',
|
293
|
+
data_size: 4
|
294
|
+
},
|
295
|
+
{
|
296
|
+
name: 'CHK3',
|
297
|
+
data: 'ChunkData3',
|
298
|
+
data_size: 4
|
299
|
+
}
|
300
|
+
], chunks_format: { '*' => { data_size_correction: proc { |_file| 6 } } }) do |chunks|
|
301
|
+
expect(chunks.size).to eq 3
|
302
|
+
chunk = chunks.first
|
303
|
+
expect(chunk.name).to eq 'CHK1'
|
304
|
+
expect(chunk.size).to eq 10
|
305
|
+
expect(chunk.data).to eq 'ChunkData1'
|
306
|
+
expect(chunk.header).to eq ''
|
307
|
+
expect(chunk.parent_chunk).to eq nil
|
308
|
+
expect(chunk.next).to eq chunks[1]
|
309
|
+
chunk = chunk.next
|
310
|
+
expect(chunk.name).to eq 'CHK2'
|
311
|
+
expect(chunk.size).to eq 10
|
312
|
+
expect(chunk.data).to eq 'ChunkData2'
|
313
|
+
expect(chunk.header).to eq ''
|
314
|
+
expect(chunk.parent_chunk).to eq nil
|
315
|
+
expect(chunk.next).to eq chunks[2]
|
316
|
+
chunk = chunk.next
|
317
|
+
expect(chunk.name).to eq 'CHK3'
|
318
|
+
expect(chunk.size).to eq 10
|
319
|
+
expect(chunk.data).to eq 'ChunkData3'
|
320
|
+
expect(chunk.header).to eq ''
|
321
|
+
expect(chunk.parent_chunk).to eq nil
|
322
|
+
expect(chunk.next).to eq nil
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'reads a file containing several chunks with data size correction on some chunks only' do
|
327
|
+
read_chunks([
|
328
|
+
{
|
329
|
+
name: 'CHK1',
|
330
|
+
data: 'ChunkData1'
|
331
|
+
},
|
332
|
+
{
|
333
|
+
name: 'CHK2',
|
334
|
+
data: 'ChunkData2',
|
335
|
+
data_size: 4
|
336
|
+
},
|
337
|
+
{
|
338
|
+
name: 'CHK3',
|
339
|
+
data: 'ChunkData3',
|
340
|
+
data_size: 14
|
341
|
+
}
|
342
|
+
], chunks_format: { 'CHK2' => { data_size_correction: 6 }, 'CHK3' => { data_size_correction: -4 } }) do |chunks|
|
343
|
+
expect(chunks.size).to eq 3
|
344
|
+
chunk = chunks.first
|
345
|
+
expect(chunk.name).to eq 'CHK1'
|
346
|
+
expect(chunk.size).to eq 10
|
347
|
+
expect(chunk.data).to eq 'ChunkData1'
|
348
|
+
expect(chunk.header).to eq ''
|
349
|
+
expect(chunk.parent_chunk).to eq nil
|
350
|
+
expect(chunk.next).to eq chunks[1]
|
351
|
+
chunk = chunk.next
|
352
|
+
expect(chunk.name).to eq 'CHK2'
|
353
|
+
expect(chunk.size).to eq 10
|
354
|
+
expect(chunk.data).to eq 'ChunkData2'
|
355
|
+
expect(chunk.header).to eq ''
|
356
|
+
expect(chunk.parent_chunk).to eq nil
|
357
|
+
expect(chunk.next).to eq chunks[2]
|
358
|
+
chunk = chunk.next
|
359
|
+
expect(chunk.name).to eq 'CHK3'
|
360
|
+
expect(chunk.size).to eq 10
|
361
|
+
expect(chunk.data).to eq 'ChunkData3'
|
362
|
+
expect(chunk.header).to eq ''
|
363
|
+
expect(chunk.parent_chunk).to eq nil
|
364
|
+
expect(chunk.next).to eq nil
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'reads a file containing several chunks with sub-chunks' do
|
369
|
+
chunk2_data = chunks_to_str([
|
370
|
+
{
|
371
|
+
name: 'SCK1',
|
372
|
+
data: 'SubChunkData1'
|
373
|
+
},
|
374
|
+
{
|
375
|
+
name: 'SCK2',
|
376
|
+
data: 'SubChunkData2'
|
377
|
+
},
|
378
|
+
{
|
379
|
+
name: 'SCK3',
|
380
|
+
data: 'SubChunkData3'
|
381
|
+
}
|
382
|
+
])
|
383
|
+
read_chunks([
|
384
|
+
{
|
385
|
+
name: 'CHK1',
|
386
|
+
data: 'ChunkData1'
|
387
|
+
},
|
388
|
+
{
|
389
|
+
name: 'CHK2',
|
390
|
+
data: chunk2_data
|
391
|
+
},
|
392
|
+
{
|
393
|
+
name: 'CHK3',
|
394
|
+
data: 'ChunkData3'
|
395
|
+
}
|
396
|
+
]) do |chunks|
|
397
|
+
expect(chunks.size).to eq 3
|
398
|
+
chunk = chunks.first
|
399
|
+
expect(chunk.name).to eq 'CHK1'
|
400
|
+
expect(chunk.size).to eq 10
|
401
|
+
expect(chunk.data).to eq 'ChunkData1'
|
402
|
+
expect(chunk.header).to eq ''
|
403
|
+
expect(chunk.parent_chunk).to eq nil
|
404
|
+
expect(chunk.next).to eq chunks[1]
|
405
|
+
chunk = chunk.next
|
406
|
+
expect(chunk.name).to eq 'CHK2'
|
407
|
+
expect(chunk.size).to eq chunk2_data.size
|
408
|
+
expect(chunk.data).to eq chunk2_data
|
409
|
+
expect(chunk.header).to eq ''
|
410
|
+
expect(chunk.parent_chunk).to eq nil
|
411
|
+
expect(chunk.next).to eq chunks[2]
|
412
|
+
chunk = chunk.next
|
413
|
+
expect(chunk.name).to eq 'CHK3'
|
414
|
+
expect(chunk.size).to eq 10
|
415
|
+
expect(chunk.data).to eq 'ChunkData3'
|
416
|
+
expect(chunk.header).to eq ''
|
417
|
+
expect(chunk.parent_chunk).to eq nil
|
418
|
+
expect(chunk.next).to eq nil
|
419
|
+
sub_chunks = chunks[1].sub_chunks
|
420
|
+
expect(sub_chunks.size).to eq 3
|
421
|
+
chunk = sub_chunks.first
|
422
|
+
expect(chunk.name).to eq 'SCK1'
|
423
|
+
expect(chunk.size).to eq 13
|
424
|
+
expect(chunk.data).to eq 'SubChunkData1'
|
425
|
+
expect(chunk.header).to eq ''
|
426
|
+
expect(chunk.parent_chunk).to eq chunks[1]
|
427
|
+
expect(chunk.next).to eq sub_chunks[1]
|
428
|
+
chunk = chunk.next
|
429
|
+
expect(chunk.name).to eq 'SCK2'
|
430
|
+
expect(chunk.size).to eq 13
|
431
|
+
expect(chunk.data).to eq 'SubChunkData2'
|
432
|
+
expect(chunk.header).to eq ''
|
433
|
+
expect(chunk.parent_chunk).to eq chunks[1]
|
434
|
+
expect(chunk.next).to eq sub_chunks[2]
|
435
|
+
chunk = chunk.next
|
436
|
+
expect(chunk.name).to eq 'SCK3'
|
437
|
+
expect(chunk.size).to eq 13
|
438
|
+
expect(chunk.data).to eq 'SubChunkData3'
|
439
|
+
expect(chunk.header).to eq ''
|
440
|
+
expect(chunk.parent_chunk).to eq chunks[1]
|
441
|
+
expect(chunk.next).to eq nil
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'reads a file containing several chunks with sub-chunks having specific formats' do
|
446
|
+
chunk2_data = chunks_to_str([
|
447
|
+
{
|
448
|
+
name: 'SCK1',
|
449
|
+
data: 'SubChunkData1'
|
450
|
+
},
|
451
|
+
{
|
452
|
+
name: 'SCK2',
|
453
|
+
data: 'SubChunkData2',
|
454
|
+
data_size: 7
|
455
|
+
},
|
456
|
+
{
|
457
|
+
name: 'SCK3',
|
458
|
+
data: 'SubChunkData3'
|
459
|
+
}
|
460
|
+
])
|
461
|
+
read_chunks([
|
462
|
+
{
|
463
|
+
name: 'CHK1',
|
464
|
+
data: 'ChunkData1'
|
465
|
+
},
|
466
|
+
{
|
467
|
+
name: 'CHK2',
|
468
|
+
data: chunk2_data
|
469
|
+
},
|
470
|
+
{
|
471
|
+
name: 'CHK3',
|
472
|
+
data: 'ChunkData3'
|
473
|
+
}
|
474
|
+
], chunks_format: { 'SCK2' => { data_size_correction: 6 } }) do |chunks|
|
475
|
+
expect(chunks.size).to eq 3
|
476
|
+
chunk = chunks.first
|
477
|
+
expect(chunk.name).to eq 'CHK1'
|
478
|
+
expect(chunk.size).to eq 10
|
479
|
+
expect(chunk.data).to eq 'ChunkData1'
|
480
|
+
expect(chunk.header).to eq ''
|
481
|
+
expect(chunk.parent_chunk).to eq nil
|
482
|
+
expect(chunk.next).to eq chunks[1]
|
483
|
+
chunk = chunk.next
|
484
|
+
expect(chunk.name).to eq 'CHK2'
|
485
|
+
expect(chunk.size).to eq chunk2_data.size
|
486
|
+
expect(chunk.data).to eq chunk2_data
|
487
|
+
expect(chunk.header).to eq ''
|
488
|
+
expect(chunk.parent_chunk).to eq nil
|
489
|
+
expect(chunk.next).to eq chunks[2]
|
490
|
+
chunk = chunk.next
|
491
|
+
expect(chunk.name).to eq 'CHK3'
|
492
|
+
expect(chunk.size).to eq 10
|
493
|
+
expect(chunk.data).to eq 'ChunkData3'
|
494
|
+
expect(chunk.header).to eq ''
|
495
|
+
expect(chunk.parent_chunk).to eq nil
|
496
|
+
expect(chunk.next).to eq nil
|
497
|
+
sub_chunks = chunks[1].sub_chunks
|
498
|
+
expect(sub_chunks.size).to eq 3
|
499
|
+
chunk = sub_chunks.first
|
500
|
+
expect(chunk.name).to eq 'SCK1'
|
501
|
+
expect(chunk.size).to eq 13
|
502
|
+
expect(chunk.data).to eq 'SubChunkData1'
|
503
|
+
expect(chunk.header).to eq ''
|
504
|
+
expect(chunk.parent_chunk).to eq chunks[1]
|
505
|
+
expect(chunk.next).to eq sub_chunks[1]
|
506
|
+
chunk = chunk.next
|
507
|
+
expect(chunk.name).to eq 'SCK2'
|
508
|
+
expect(chunk.size).to eq 13
|
509
|
+
expect(chunk.data).to eq 'SubChunkData2'
|
510
|
+
expect(chunk.header).to eq ''
|
511
|
+
expect(chunk.parent_chunk).to eq chunks[1]
|
512
|
+
expect(chunk.next).to eq sub_chunks[2]
|
513
|
+
chunk = chunk.next
|
514
|
+
expect(chunk.name).to eq 'SCK3'
|
515
|
+
expect(chunk.size).to eq 13
|
516
|
+
expect(chunk.data).to eq 'SubChunkData3'
|
517
|
+
expect(chunk.header).to eq ''
|
518
|
+
expect(chunk.parent_chunk).to eq chunks[1]
|
519
|
+
expect(chunk.next).to eq nil
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
4
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
5
|
+
# files.
|
6
|
+
#
|
7
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
8
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
9
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
10
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
11
|
+
# a separate helper file that requires the additional dependencies and performs
|
12
|
+
# the additional setup, and require it from the spec files that actually need
|
13
|
+
# it.
|
14
|
+
#
|
15
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
+
RSpec.configure do |config|
|
17
|
+
# rspec-expectations config goes here. You can use an alternate
|
18
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
19
|
+
# assertions if you prefer.
|
20
|
+
config.expect_with :rspec do |expectations|
|
21
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
22
|
+
# and `failure_message` of custom matchers include text for helper methods
|
23
|
+
# defined using `chain`, e.g.:
|
24
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
25
|
+
# # => "be bigger than 2 and smaller than 4"
|
26
|
+
# ...rather than:
|
27
|
+
# # => "be bigger than 2"
|
28
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
29
|
+
end
|
30
|
+
|
31
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
32
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
33
|
+
config.mock_with :rspec do |mocks|
|
34
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
35
|
+
# a real object. This is generally recommended, and will default to
|
36
|
+
# `true` in RSpec 4.
|
37
|
+
mocks.verify_partial_doubles = true
|
38
|
+
end
|
39
|
+
|
40
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
41
|
+
# have no way to turn it off -- the option exists only for backwards
|
42
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
43
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
44
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
45
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
46
|
+
|
47
|
+
# The settings below are suggested to provide a good initial experience
|
48
|
+
# with RSpec, but feel free to customize to your heart's content.
|
49
|
+
=begin
|
50
|
+
# This allows you to limit a spec run to individual examples or groups
|
51
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
52
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
53
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
54
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
55
|
+
config.filter_run_when_matching :focus
|
56
|
+
|
57
|
+
# Allows RSpec to persist some state between runs in order to support
|
58
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
59
|
+
# you configure your source control system to ignore this file.
|
60
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
61
|
+
|
62
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
63
|
+
# recommended. For more details, see:
|
64
|
+
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
65
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
66
|
+
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
67
|
+
config.disable_monkey_patching!
|
68
|
+
|
69
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
70
|
+
# be too noisy due to issues in dependencies.
|
71
|
+
config.warnings = true
|
72
|
+
|
73
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
74
|
+
# file, and it's useful to allow more verbose output when running an
|
75
|
+
# individual spec file.
|
76
|
+
if config.files_to_run.one?
|
77
|
+
# Use the documentation formatter for detailed output,
|
78
|
+
# unless a formatter has already been configured
|
79
|
+
# (e.g. via a command-line flag).
|
80
|
+
config.default_formatter = "doc"
|
81
|
+
end
|
82
|
+
|
83
|
+
# Print the 10 slowest examples and example groups at the
|
84
|
+
# end of the spec run, to help surface which specs are running
|
85
|
+
# particularly slow.
|
86
|
+
config.profile_examples = 10
|
87
|
+
|
88
|
+
# Run specs in random order to surface order dependencies. If you find an
|
89
|
+
# order dependency and want to debug it, you can fix the order by providing
|
90
|
+
# the seed, which is printed after each run.
|
91
|
+
# --seed 1234
|
92
|
+
config.order = :random
|
93
|
+
|
94
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
95
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
96
|
+
# test failures related to randomization by passing the same `--seed` value
|
97
|
+
# as the one that triggered the failure.
|
98
|
+
Kernel.srand config.seed
|
99
|
+
=end
|
100
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: riffola
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Muriel Salvan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hex_string
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby-prof
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Library reading an extended RIFF format, supporting huge files. RIFF
|
84
|
+
format is composed of a list of chunks, each chunk being an identifier, an encoded
|
85
|
+
data size, an optional header and chunk data itself. Riffola has ways to deal with
|
86
|
+
RIFF files taking some liberties on the RIFF format (additional headers, wrong chunk
|
87
|
+
size...).
|
88
|
+
email:
|
89
|
+
- muriel@x-aeon.com
|
90
|
+
executables: []
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- lib/riffola.rb
|
95
|
+
- lib/riffola/version.rb
|
96
|
+
- spec/riffola_spec.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
homepage: https://github.com/Muriel-Salvan/riffola
|
99
|
+
licenses:
|
100
|
+
- BSD-4-Clause
|
101
|
+
metadata: {}
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 2.7.3
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Riffola - Reading extended RIFF files
|
122
|
+
test_files: []
|