Ruby-Binary-Parser
Ruby-Binary-Parser is Ruby Gem library providing DSL for parsing binary-data, such as Image files, Video files, etc. Without operating bytes and bits complicatedly, you can parse and read binary-data generically and abstractly.
Description
This library can parse all kind of binary-data structures including non-fixed length of structures and nested structures. For generic parsing, loop and condition(if) statement to define structures is provided in this library. Of course, values of neighbor binary-data can be used as the other binary-data's specification of length.
Furthermore, this library handles all binary-data under the lazy evaluation. So you can read required parts of a binary-data very quickly even if whole of the binary-data is too big,
Notice
Currently, this library supports only READ of binary-data. So you cannot WRITE binary-data directly with this library.
Usage
Look at following examples to quickly understand how to use this library.
Install
$ gem install binary_parser
Example 1
Consider the following (temporary) binary structures which describe Image data.
MyImage (non-fixed length) | |||
Data Name | Type | Bit Length | Number Of Replications |
height | UInt | 8 | 1 |
width | UInt | 8 | 1 |
RGB color bit-map | UInt | 8 * 3 | 'height' * 'width' |
has date? | Flag | 1 | 1 |
date | MyDate | 31 | 'has date?' is 1 => 1 else => 0 |
MyDate (31 bit) | |||
Data Name | Type | Bit Length | Number Of Replications |
year | UInt | 13 | 1 |
month | UInt | 9 | 1 |
day | UInt | 9 | 1 |
You can define MyImage structure in ruby program as following code.
require 'binary_parser'
class MyDate < BinaryParser::TemplateBase
require 'date'
Def do
data :year, UInt, 13
data :month, UInt, 9
data :day, UInt, 9
end
def to_date
return Date.new(year.to_i, month.to_i, day.to_i)
end
end
class MyImage < BinaryParser::TemplateBase
Def do
data :height, UInt, 8
data :width, UInt, 8
TIMES var(:height), :i do
TIMES var(:width), :j do
data :R, UInt, 8
data :G, UInt, 8
data :B, UInt, 8
end
end
data :has_date, Flag, 1
IF cond(:has_date){|v| v.flagged?} do
data :date, MyDate, 31
end
end
end
And then you can parse and read binay-data of MyImage as follows.
File.open('my_image.bin', 'rb') do |f|
image = MyImage.new(f.read)
print "Image size: #{image.height.to_i}x#{image.width.to_i}\n"
ul = image.i[0].j[0]
print "RGB color at the first is (#{ul.R.to_i}, #{ul.G.to_i}, #{ul.B.to_i})\n"
print "Image date: #{image.date.to_date}\n"
end
If 'my_image.bin' is binary-data-file of [0x02, 0x02, 0xe7,0x39,0x62, 0x00,0x00,0x00, 0xe7,0x39,0x62, 0x00,0x00,0x00, 0x9f, 0x78, 0x08, 0x03], you can get output as follows.
Image size: 2x2
RGB color at the first is (231, 57, 98)
Image date: 2014-04-03
For your information, you can dump all binary-data's information as follows.
File.open('my_image.bin', 'rb') do |f|
image = MyImage.new(f.read)
image.show(true)
end
Example 2
You can also define other structures as follows.
class DefExample < BinaryParser::TemplateBase
Def do
data :loop_byte_length, UInt, 8
# Loop until 'loop_byte_length' * 8 bits are parsed.
SPEND var(:loop_byte_length) * 8, :list do
data :length, UInt, 8
# Specifying length by neigbor value.
data :data, Binary, var(:length) * 8
end
data :v1, UInt, 8
data :v2, UInt, 8
# Number of Condition variables is arbitary.
IF cond(:v1, :v2){|v1, v2| v1.to_i == v2.to_i} do
# +, -, *, / is available for var. (Order of [Integer op Variable] is NG.)
data :v3, UInt, (var(:v1) + var(:v2)) * 8
end
end
end
Check this definition by giving some binary-data and calling show method as follows.
i = DefExample.new([0x05, 0x01, 0xff, 0x02, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01].pack("C*"))
i.show(true)
Example 3
If you want to operate Stream-data, StreamTemplateBase class is useful. Define stream as follows.
class StreamExample < BinaryParser::StreamTemplateBase
# Stream which consists of every 4 byte binary-data.
Def(4) do
data :data1, UInt, 8
data :data2, Binary, 24
end
end
And then, get structures from the stream as follows.
File.open('my_image.bin', 'rb') do |f|
stream = StreamExample.new(f)
packet = stream.get_next
puts "data1: #{packet.data1.to_i}, data2: #{packet.data2.to_s}"
stream.get_next.show(true)
end
StreamTemplateBase has many useful methods to choose structures from the stream. If you want to know detail of these methods, please read documentation or concerned source-files.
Documentation
I'm sorry, but only RDoc (auto-generated documentation) is now available. For example, you can read RDoc on web browser by following operations.
$ gem install binary_parser
$ gem server
Server started at http://0.0.0.0:8808
Access shown address by web browser.
Versions
1.0.0 April 6, 2014