binary_struct 1.0.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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +82 -0
- data/Rakefile +5 -0
- data/binary_struct.gemspec +29 -0
- data/lib/binary_struct.rb +189 -0
- data/lib/binary_struct/version.rb +3 -0
- data/spec/binary_struct_spec.rb +110 -0
- data/spec/data/test.gif +0 -0
- data/spec/gif_spec.rb +47 -0
- data/spec/spec_helper.rb +16 -0
- metadata +129 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Red Hat, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# BinaryStruct
|
2
|
+
|
3
|
+
BinaryStruct is a class for dealing with binary structured data. It simplifies
|
4
|
+
expressing what the binary structure looks like, with the ability to name the
|
5
|
+
parts. Given this definition, it is easy to encode/decode the binary structure
|
6
|
+
from/to a Hash.
|
7
|
+
|
8
|
+
## Example Usage
|
9
|
+
|
10
|
+
As an example, we will show reading and writing a .gif header. This example is
|
11
|
+
also in spec/gif_spec.rb.
|
12
|
+
|
13
|
+
### Create the structure definition
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gif_header = BinaryStruct.new([
|
17
|
+
"a3", :magic,
|
18
|
+
"a3", :version,
|
19
|
+
"S", :width,
|
20
|
+
"S", :height,
|
21
|
+
"a", :flags,
|
22
|
+
"C", :bg_color_index,
|
23
|
+
"C", :pixel_aspect_ratio
|
24
|
+
])
|
25
|
+
```
|
26
|
+
|
27
|
+
### Read the header
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
header_size = gif_header.size
|
31
|
+
header = File.open("test.gif", "rb") { |f| f.read(header_size) }
|
32
|
+
gif_header.decode(header)
|
33
|
+
|
34
|
+
=> {
|
35
|
+
:magic => "GIF",
|
36
|
+
:version => "89a",
|
37
|
+
:width => 16,
|
38
|
+
:height => 16,
|
39
|
+
:flags => "\x80",
|
40
|
+
:bg_color_index => 0,
|
41
|
+
:pixel_aspect_ratio => 0
|
42
|
+
}
|
43
|
+
```
|
44
|
+
|
45
|
+
### Write the header
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
header = gif_header.encode({
|
49
|
+
:magic => "GIF",
|
50
|
+
:version => "89a",
|
51
|
+
:width => 16,
|
52
|
+
:height => 16,
|
53
|
+
:flags => "\x80",
|
54
|
+
:bg_color_index => 0,
|
55
|
+
:pixel_aspect_ratio => 0
|
56
|
+
})
|
57
|
+
File.open("test.gif", "wb") { |f| f.write(header) }
|
58
|
+
|
59
|
+
=> "GIF89a\x10\x00\x10\x00\x80\x00\x00"
|
60
|
+
```
|
61
|
+
|
62
|
+
## Installation
|
63
|
+
|
64
|
+
Add this line to your application's Gemfile:
|
65
|
+
|
66
|
+
gem 'binary_struct'
|
67
|
+
|
68
|
+
And then execute:
|
69
|
+
|
70
|
+
$ bundle
|
71
|
+
|
72
|
+
Or install it yourself as:
|
73
|
+
|
74
|
+
$ gem install binary_struct
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
1. Fork it
|
79
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
80
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
81
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
82
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'binary_struct/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "binary_struct"
|
8
|
+
spec.version = BinaryStruct::VERSION
|
9
|
+
spec.authors = ["Oleg Barenboim", "Jason Frey"]
|
10
|
+
spec.email = ["chessbyte@gmail.com", "fryguy9@gmail.com"]
|
11
|
+
spec.description = %q{
|
12
|
+
BinaryStruct is a class for dealing with binary structured data. It simplifies
|
13
|
+
expressing what the binary structure looks like, with the ability to name the
|
14
|
+
parts. Given this definition, it is easy to encode/decode the binary structure
|
15
|
+
from/to a Hash.
|
16
|
+
}
|
17
|
+
spec.summary = %q{BinaryStruct is a class for dealing with binary structured data.}
|
18
|
+
spec.homepage = "http://github.com/ManageIQ/binary_struct"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files`.split($/)
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require "binary_struct/version"
|
2
|
+
require "enumerator"
|
3
|
+
|
4
|
+
class BinaryStruct
|
5
|
+
SIZES = {
|
6
|
+
'A' => 1, # String with trailing NULs and spaces removed
|
7
|
+
'a' => 1, # String
|
8
|
+
'B' => nil, # Extract bits from each character (MSB first)
|
9
|
+
'b' => nil, # Extract bits from each character (LSB first)
|
10
|
+
'C' => 1, # Extract a character as an unsigned integer
|
11
|
+
'c' => 1, # Extract a character as a signed integer
|
12
|
+
'E' => nil, # Treat sizeof(double) characters as a double in little-endian byte order
|
13
|
+
'e' => nil, # Treat sizeof(float) characters as a float in little-endian byte order
|
14
|
+
'G' => nil, # Treat sizeof(double) characters as a double in network byte order
|
15
|
+
'g' => nil, # Treat sizeof(float) characters as a float in network byte order
|
16
|
+
'H' => nil, # Extract hex nibbles from each character (most significant first)
|
17
|
+
'h' => nil, # Extract hex nibbles from each character (least significant first)
|
18
|
+
'I' => 4, # Treat sizeof(int) successive characters as an unsigned native integer
|
19
|
+
'i' => 4, # Treat sizeof(int) successive characters as a signed native integer
|
20
|
+
'L' => 4, # Treat 4 successive characters as an unsigned native long integer
|
21
|
+
'l' => 4, # Treat 4 successive characters as a signed native long integer
|
22
|
+
'M' => 1, # Extract a quoted printable string
|
23
|
+
'm' => 1, # Extract a Base64 encoded string
|
24
|
+
'N' => 4, # Treat 4 characters as an unsigned long in network byte order
|
25
|
+
'n' => 2, # Treat 2 characters as an unsigned short in network byte order
|
26
|
+
'P' => nil, # Treat sizeof(char *) characters as a pointer, and return len characters from the referenced location
|
27
|
+
'p' => nil, # Treat sizeof(char *) characters as a pointer to a null-terminated string
|
28
|
+
'Q' => 8, # Treat 8 characters as an unsigned quad word (64 bits)
|
29
|
+
'q' => 8, # Treat 8 characters as a signed quad word (64 bits)
|
30
|
+
'S' => 2, # Treat 2 successive characters as an unsigned short in native byte order
|
31
|
+
's' => 2, # Treat 2 successive characters as a signed short in native byte order
|
32
|
+
'U' => nil, # Extract UTF-8 characters as unsigned integers
|
33
|
+
'u' => nil, # Extract a UU-encoded string
|
34
|
+
'V' => 4, # Treat 4 characters as an unsigned long in little-endian byte order
|
35
|
+
'v' => 2, # Treat 2 characters as an unsigned short in little-endian byte order
|
36
|
+
'w' => nil, # BER-compressed integer
|
37
|
+
'X' => -1, # Skip backward one character
|
38
|
+
'x' => 1, # Skip forward one character
|
39
|
+
'Z' => 1, # String with trailing NULs removed
|
40
|
+
}
|
41
|
+
|
42
|
+
STRING_FORMATS = %w{A a M m u}
|
43
|
+
|
44
|
+
def initialize(definition = nil)
|
45
|
+
self.definition = definition unless definition.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
def definition
|
49
|
+
@definition
|
50
|
+
end
|
51
|
+
|
52
|
+
def definition=(value)
|
53
|
+
if value.kind_of?(self.class)
|
54
|
+
@definition = value.definition.dup
|
55
|
+
else
|
56
|
+
value = Array(value)
|
57
|
+
self.class.validate_definition(value)
|
58
|
+
@definition = value
|
59
|
+
end
|
60
|
+
@size = @decode_format = @decode_name = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def size
|
64
|
+
@size ||= self.class.get_size(@definition)
|
65
|
+
end
|
66
|
+
|
67
|
+
def decode(data, num = 1)
|
68
|
+
values = self.decode_to_array(data, num)
|
69
|
+
return self.decoded_array_to_hash!(values) if num == 1
|
70
|
+
|
71
|
+
result = []
|
72
|
+
num.times { result << self.decoded_array_to_hash!(values) }
|
73
|
+
return result
|
74
|
+
end
|
75
|
+
|
76
|
+
def decode_to_array(data, num = 1)
|
77
|
+
raise ArgumentError, "data cannot be nil" if data.nil?
|
78
|
+
@decode_format, @decode_names = self.class.prep_decode(@definition) if @decode_format.nil?
|
79
|
+
format = (num == 1) ? @decode_format : @decode_format * num
|
80
|
+
return data.unpack(format)
|
81
|
+
end
|
82
|
+
|
83
|
+
def decoded_array_to_hash!(array)
|
84
|
+
hash = {}
|
85
|
+
@decode_names.each do |k|
|
86
|
+
v = array.shift
|
87
|
+
next if k.nil?
|
88
|
+
hash[k] = v
|
89
|
+
end
|
90
|
+
return hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def encode(hash)
|
94
|
+
return encode_hash(hash) unless hash.kind_of?(Array)
|
95
|
+
|
96
|
+
data = ""
|
97
|
+
hash.each { |h| data << self.encode_hash(h) }
|
98
|
+
return data
|
99
|
+
end
|
100
|
+
|
101
|
+
def encode_hash(hash)
|
102
|
+
data = ""
|
103
|
+
@definition.each_slice(2) do |format, name|
|
104
|
+
raise "member not found: #{name}" unless name.nil? || hash.has_key?(name)
|
105
|
+
value = unless name.nil?
|
106
|
+
hash[name]
|
107
|
+
else
|
108
|
+
STRING_FORMATS.include?(format[0, 1]) ? '0' : 0
|
109
|
+
end
|
110
|
+
data << [value].pack(format)
|
111
|
+
end
|
112
|
+
return data
|
113
|
+
end
|
114
|
+
|
115
|
+
def ==(other)
|
116
|
+
self.definition == other.definition
|
117
|
+
end
|
118
|
+
|
119
|
+
def each(&block)
|
120
|
+
self.definition.each_slice(2, &block)
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Methods to handle the old style of calling
|
125
|
+
#
|
126
|
+
|
127
|
+
@@structs_by_definition = {}
|
128
|
+
|
129
|
+
def self.clear_structs_by_definition_cache
|
130
|
+
@@structs_by_definition.clear
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.sizeof(definition)
|
134
|
+
d = @@structs_by_definition[definition]
|
135
|
+
d = @@structs_by_definition[definition] = definition.kind_of?(self) ? definition : self.new(definition) if d.nil?
|
136
|
+
d.size
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.decode(data, definition)
|
140
|
+
d = @@structs_by_definition[definition]
|
141
|
+
d = @@structs_by_definition[definition] = definition.kind_of?(self) ? definition : self.new(definition) if d.nil?
|
142
|
+
d.decode(data)
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.encode(hash, definition)
|
146
|
+
d = @@structs_by_definition[definition]
|
147
|
+
d = @@structs_by_definition[definition] = definition.kind_of?(self) ? definition : self.new(definition) if d.nil?
|
148
|
+
d.encode(hash)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def self.validate_definition(definition)
|
154
|
+
raise "definition must be an array of format/name pairs" if definition.empty? || definition.length % 2 != 0
|
155
|
+
definition.each_slice(2) do |format, name|
|
156
|
+
type, count = format[0, 1], format[1..-1]
|
157
|
+
raise "unrecognized format: #{type}" unless SIZES.has_key?(type)
|
158
|
+
raise "unsupported format: #{type}" if SIZES[type].nil?
|
159
|
+
unless count.empty? || count == '*'
|
160
|
+
begin
|
161
|
+
count = Integer(count)
|
162
|
+
rescue
|
163
|
+
raise "unsupported count: #{count}"
|
164
|
+
end
|
165
|
+
raise "unsupported count: #{count}" if count < 0
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.get_size(definition)
|
171
|
+
size = 0
|
172
|
+
definition.each_slice(2) do |format, name|
|
173
|
+
type, count = format[0, 1], format[1..-1]
|
174
|
+
count = count.empty? ? 1 : count.to_i
|
175
|
+
size += (count * SIZES[type])
|
176
|
+
end
|
177
|
+
return size
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.prep_decode(definition)
|
181
|
+
formats = ""
|
182
|
+
names = []
|
183
|
+
definition.each_slice(2) do |format, name|
|
184
|
+
formats << format
|
185
|
+
names << name
|
186
|
+
end
|
187
|
+
return formats, names
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
|
2
|
+
|
3
|
+
require 'binary_struct'
|
4
|
+
|
5
|
+
describe BinaryStruct do
|
6
|
+
STRUCT_DEF = [
|
7
|
+
'Q', :quad,
|
8
|
+
'L', 'long',
|
9
|
+
'S', :short,
|
10
|
+
'C', nil,
|
11
|
+
'a0', 'none',
|
12
|
+
'a', nil,
|
13
|
+
'a2', 'bc',
|
14
|
+
]
|
15
|
+
STRUCT_DEF_SIZE = 18
|
16
|
+
|
17
|
+
STRUCT_DEF_ASTERISK = ['a*', :word]
|
18
|
+
STRUCT_DEF_ASTERISK_SIZE = 0 # '*' is ignored
|
19
|
+
|
20
|
+
STRUCT_DEF_UNRECOGNIZED_FORMAT = ['D', nil]
|
21
|
+
STRUCT_DEF_UNSUPPORTED_FORMAT = ['B', nil]
|
22
|
+
STRUCT_DEF_UNSUPPORTED_COUNT_NEG = ['a-1', nil]
|
23
|
+
STRUCT_DEF_UNSUPPORTED_COUNT_INV = ['aX', nil]
|
24
|
+
|
25
|
+
STRUCT_ENCODED_STR = "\000\111\222\333\444\555\666\777\000\111\222\333\000\111\0000BC"
|
26
|
+
STRUCT_DECODED_HASH = {:quad=>18426034930503010560, "long"=>3683797248, :short=>18688, "bc"=>"BC", "none"=>""}
|
27
|
+
|
28
|
+
it('.new') { lambda { BinaryStruct.new }.should_not raise_error }
|
29
|
+
it('.new with definition') { lambda { BinaryStruct.new(STRUCT_DEF) }.should_not raise_error }
|
30
|
+
it('.new with definition with *') { lambda { BinaryStruct.new(STRUCT_DEF_ASTERISK) }.should_not raise_error }
|
31
|
+
it '.new with another BinaryStruct' do
|
32
|
+
s = BinaryStruct.new(STRUCT_DEF)
|
33
|
+
s2 = BinaryStruct.new(s)
|
34
|
+
s2.should == s
|
35
|
+
s2.should_not equal(s)
|
36
|
+
end
|
37
|
+
|
38
|
+
it('.new with unrecognized format') { lambda { BinaryStruct.new(STRUCT_DEF_UNRECOGNIZED_FORMAT) }.should raise_error(RuntimeError) }
|
39
|
+
it('.new with unsupported format') { lambda { BinaryStruct.new(STRUCT_DEF_UNSUPPORTED_FORMAT) }.should raise_error(RuntimeError) }
|
40
|
+
it('.new with unsupported negative count') { lambda { BinaryStruct.new(STRUCT_DEF_UNSUPPORTED_COUNT_NEG) }.should raise_error(RuntimeError) }
|
41
|
+
it('.new with unsupported invalid count') { lambda { BinaryStruct.new(STRUCT_DEF_UNSUPPORTED_COUNT_INV) }.should raise_error(RuntimeError) }
|
42
|
+
|
43
|
+
it('#definition=') { lambda { BinaryStruct.new.definition = STRUCT_DEF }.should_not raise_error }
|
44
|
+
it('#definition= with definition with *') { lambda { BinaryStruct.new.definition = STRUCT_DEF_ASTERISK }.should_not raise_error }
|
45
|
+
|
46
|
+
it('#definition= with unrecognized format') { lambda { BinaryStruct.new.definition = STRUCT_DEF_UNRECOGNIZED_FORMAT }.should raise_error(RuntimeError) }
|
47
|
+
it('#definition= with unsupported format') { lambda { BinaryStruct.new.definition = STRUCT_DEF_UNSUPPORTED_FORMAT }.should raise_error(RuntimeError) }
|
48
|
+
it('#definition= with unsupported negative count') { lambda { BinaryStruct.new.definition = STRUCT_DEF_UNSUPPORTED_COUNT_NEG }.should raise_error(RuntimeError) }
|
49
|
+
it('#definition= with unsupported invalid count') { lambda { BinaryStruct.new.definition = STRUCT_DEF_UNSUPPORTED_COUNT_INV }.should raise_error(RuntimeError) }
|
50
|
+
|
51
|
+
it('#size') { BinaryStruct.new(STRUCT_DEF).size.should == STRUCT_DEF_SIZE }
|
52
|
+
it('#size with definition with *') { BinaryStruct.new(STRUCT_DEF_ASTERISK).size.should == STRUCT_DEF_ASTERISK_SIZE }
|
53
|
+
|
54
|
+
it '#decode' do
|
55
|
+
BinaryStruct.new(STRUCT_DEF).decode(STRUCT_ENCODED_STR).should == STRUCT_DECODED_HASH
|
56
|
+
end
|
57
|
+
|
58
|
+
it '#decode with definition with *' do
|
59
|
+
BinaryStruct.new(STRUCT_DEF_ASTERISK).decode("Testing").should == {:word => "Testing"}
|
60
|
+
end
|
61
|
+
|
62
|
+
it '#decode against multiple records' do
|
63
|
+
BinaryStruct.new(STRUCT_DEF).decode(STRUCT_ENCODED_STR * 10, 10).should == [STRUCT_DECODED_HASH] * 10
|
64
|
+
end
|
65
|
+
|
66
|
+
it '#encode' do
|
67
|
+
BinaryStruct.new(STRUCT_DEF).encode(STRUCT_DECODED_HASH).should == STRUCT_ENCODED_STR
|
68
|
+
end
|
69
|
+
|
70
|
+
it '#encode with definition with *' do
|
71
|
+
BinaryStruct.new(STRUCT_DEF_ASTERISK).encode({:word => "Testing"}).should == "Testing"
|
72
|
+
end
|
73
|
+
|
74
|
+
it '#encode against multiple records' do
|
75
|
+
BinaryStruct.new(STRUCT_DEF).encode([STRUCT_DECODED_HASH] * 10).should == (STRUCT_ENCODED_STR * 10)
|
76
|
+
end
|
77
|
+
|
78
|
+
it '#== against another BinaryStruct' do
|
79
|
+
BinaryStruct.new(STRUCT_DEF).should == BinaryStruct.new(STRUCT_DEF)
|
80
|
+
BinaryStruct.new(STRUCT_DEF).should_not == BinaryStruct.new(STRUCT_DEF_ASTERISK)
|
81
|
+
end
|
82
|
+
|
83
|
+
it '#each will iterate over definition' do
|
84
|
+
dup_def = []
|
85
|
+
BinaryStruct.new(STRUCT_DEF).each { |field, name| dup_def << field << name }
|
86
|
+
dup_def.should == STRUCT_DEF
|
87
|
+
end
|
88
|
+
|
89
|
+
context "old style methods" do
|
90
|
+
after(:each) { BinaryStruct.clear_structs_by_definition_cache }
|
91
|
+
|
92
|
+
it '#sizeof' do
|
93
|
+
BinaryStruct.sizeof(STRUCT_DEF).should == STRUCT_DEF_SIZE
|
94
|
+
# Do it twice for consistency reasons
|
95
|
+
BinaryStruct.sizeof(STRUCT_DEF).should == STRUCT_DEF_SIZE
|
96
|
+
end
|
97
|
+
|
98
|
+
it '#decode' do
|
99
|
+
BinaryStruct.decode(STRUCT_ENCODED_STR, STRUCT_DEF).should == STRUCT_DECODED_HASH
|
100
|
+
# Do it twice for consistency reasons
|
101
|
+
BinaryStruct.decode(STRUCT_ENCODED_STR, STRUCT_DEF).should == STRUCT_DECODED_HASH
|
102
|
+
end
|
103
|
+
|
104
|
+
it '#encode' do
|
105
|
+
BinaryStruct.encode(STRUCT_DECODED_HASH, STRUCT_DEF).should == STRUCT_ENCODED_STR
|
106
|
+
# Do it twice for consistency reasons
|
107
|
+
BinaryStruct.encode(STRUCT_DECODED_HASH, STRUCT_DEF).should == STRUCT_ENCODED_STR
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/spec/data/test.gif
ADDED
Binary file
|
data/spec/gif_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
|
2
|
+
|
3
|
+
require 'binary_struct'
|
4
|
+
|
5
|
+
describe BinaryStruct do
|
6
|
+
let(:gif_header) do
|
7
|
+
BinaryStruct.new([
|
8
|
+
"a3", :magic,
|
9
|
+
"a3", :version,
|
10
|
+
"S", :width,
|
11
|
+
"S", :height,
|
12
|
+
"a", :flags,
|
13
|
+
"C", :bg_color_index,
|
14
|
+
"C", :pixel_aspect_ratio
|
15
|
+
])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "read a gif header" do
|
19
|
+
filename = File.join(File.dirname(__FILE__), %w{data test.gif})
|
20
|
+
|
21
|
+
header_size = gif_header.size
|
22
|
+
header = File.open(filename, "rb") { |f| f.read(header_size) }
|
23
|
+
gif_header.decode(header).should == {
|
24
|
+
:magic => "GIF",
|
25
|
+
:version => "89a",
|
26
|
+
:width => 16,
|
27
|
+
:height => 16,
|
28
|
+
:flags => "\x80",
|
29
|
+
:bg_color_index => 0,
|
30
|
+
:pixel_aspect_ratio => 0
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "write a gif header" do
|
35
|
+
header = gif_header.encode({
|
36
|
+
:magic => "GIF",
|
37
|
+
:version => "89a",
|
38
|
+
:width => 16,
|
39
|
+
:height => 16,
|
40
|
+
:flags => "\x80",
|
41
|
+
:bg_color_index => 0,
|
42
|
+
:pixel_aspect_ratio => 0
|
43
|
+
})
|
44
|
+
|
45
|
+
header.should == "GIF89a\x10\x00\x10\x00\x80\x00\x00"
|
46
|
+
end
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
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
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
|
11
|
+
# Run specs in random order to surface order dependencies. If you find an
|
12
|
+
# order dependency and want to debug it, you can fix the order by providing
|
13
|
+
# the seed, which is printed after each run.
|
14
|
+
# --seed 1234
|
15
|
+
config.order = 'random'
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: binary_struct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Oleg Barenboim
|
9
|
+
- Jason Frey
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-04-16 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bundler
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.3'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.3'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rake
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
description: ! '
|
64
|
+
|
65
|
+
BinaryStruct is a class for dealing with binary structured data. It simplifies
|
66
|
+
|
67
|
+
expressing what the binary structure looks like, with the ability to name the
|
68
|
+
|
69
|
+
parts. Given this definition, it is easy to encode/decode the binary structure
|
70
|
+
|
71
|
+
from/to a Hash.
|
72
|
+
|
73
|
+
'
|
74
|
+
email:
|
75
|
+
- chessbyte@gmail.com
|
76
|
+
- fryguy9@gmail.com
|
77
|
+
executables: []
|
78
|
+
extensions: []
|
79
|
+
extra_rdoc_files: []
|
80
|
+
files:
|
81
|
+
- .gitignore
|
82
|
+
- .rspec
|
83
|
+
- Gemfile
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- binary_struct.gemspec
|
88
|
+
- lib/binary_struct.rb
|
89
|
+
- lib/binary_struct/version.rb
|
90
|
+
- spec/binary_struct_spec.rb
|
91
|
+
- spec/data/test.gif
|
92
|
+
- spec/gif_spec.rb
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
homepage: http://github.com/ManageIQ/binary_struct
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
hash: 1202061900940413800
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
hash: 1202061900940413800
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 1.8.24
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: BinaryStruct is a class for dealing with binary structured data.
|
125
|
+
test_files:
|
126
|
+
- spec/binary_struct_spec.rb
|
127
|
+
- spec/data/test.gif
|
128
|
+
- spec/gif_spec.rb
|
129
|
+
- spec/spec_helper.rb
|