BitStructEx 0.0.54
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +53 -0
- data/Version +1 -0
- data/lib/ruby/rake/version.rb +71 -0
- data/src/ruby/bit_struct/bit_slicer.rb +202 -0
- data/src/ruby/bit_struct/field.rb +18 -0
- data/src/ruby/bit_struct/nested.rb +32 -0
- data/src/ruby/bit_struct/struct_base.rb +124 -0
- data/src/ruby/bit_struct/unsigned.rb +27 -0
- data/test/ruby/bit_struct/test_bit_slicer.rb +299 -0
- data/test/ruby/bit_struct/test_struct_base.rb +125 -0
- data/test/ruby/runner.rb +115 -0
- metadata +55 -0
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/version'
|
5
|
+
|
6
|
+
|
7
|
+
PROJECT_NAME='BitStructEx'
|
8
|
+
PROJECT_FORGE_ID='bit-struct-ex'
|
9
|
+
|
10
|
+
SRC_DIR='src/ruby'
|
11
|
+
TEST_DIR='test/ruby'
|
12
|
+
|
13
|
+
PKG_VERSION = Rake::Version.new
|
14
|
+
PKG_FILES = FileList[
|
15
|
+
'lib/**/*.rb',
|
16
|
+
'src/**/*.rb',
|
17
|
+
'test/**/*.rb',
|
18
|
+
'Rakefile',
|
19
|
+
'Version'
|
20
|
+
]
|
21
|
+
|
22
|
+
CLOBBER.include 'pkg'
|
23
|
+
|
24
|
+
|
25
|
+
desc "Run all tests, update build number and build gem"
|
26
|
+
task :default => [ :run_tests, :increment_build_number, :build_gem ]
|
27
|
+
|
28
|
+
desc "Execute the unit tests using the specialized test runner"
|
29
|
+
task :run_tests do
|
30
|
+
sh "ruby -I#{TEST_DIR} #{TEST_DIR}/runner.rb --verbose=v"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Increment the build number and upate the Version file"
|
34
|
+
task :increment_build_number => [ :run_tests ] do
|
35
|
+
src = Dir.glob "#{SRC_DIR}/**/*"
|
36
|
+
target = 'Version'
|
37
|
+
unless uptodate?( target, src )
|
38
|
+
new_version = PKG_VERSION.increment( :build )
|
39
|
+
puts "Version: #{new_version}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Build the gem package"
|
44
|
+
task :build_gem => [ :run_tests, :define_gem, :gem ]
|
45
|
+
|
46
|
+
desc "Define the Gem specification and associated task(s)"
|
47
|
+
task :define_gem do
|
48
|
+
PKG_SPEC = eval IO.read( 'GemSpec' ), binding
|
49
|
+
Rake::GemPackageTask.new( PKG_SPEC ) do |pkg|
|
50
|
+
pkg.need_zip = true
|
51
|
+
pkg.need_tar = true
|
52
|
+
end
|
53
|
+
end
|
data/Version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.54
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Rake
|
2
|
+
|
3
|
+
#
|
4
|
+
# Simple helper class for maintaining a Version number within a Rakefile.
|
5
|
+
# Provides an easy way increase the version tags. Supports purely numeric
|
6
|
+
# version tags only.
|
7
|
+
#
|
8
|
+
class Version
|
9
|
+
|
10
|
+
def self.increment( symbol )
|
11
|
+
Version.new.increment symbol
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize( config = {} )
|
15
|
+
@config = config
|
16
|
+
@config[ :version_file ] ||= 'Version'
|
17
|
+
@config[ :version_regex ] ||= /\A(\d+)\.(\d+).(\d+)\Z/
|
18
|
+
@config[ :version_tags ] ||= [ :release, :version, :build ]
|
19
|
+
@tag_values = {}
|
20
|
+
read
|
21
|
+
end
|
22
|
+
|
23
|
+
def increment( symbol )
|
24
|
+
raise "Unknown tag: #{symbol}" unless version_tags.include? symbol
|
25
|
+
read
|
26
|
+
@tag_values[ symbol ] += 1
|
27
|
+
write
|
28
|
+
current_version
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_version
|
32
|
+
version_tags.map { |tag| @tag_values[ tag ] }.join( '.' )
|
33
|
+
end
|
34
|
+
|
35
|
+
alias version current_version
|
36
|
+
|
37
|
+
alias to_s version
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def read
|
42
|
+
version = IO.read version_file
|
43
|
+
raise "Error reading #{version_file}" unless version_regex =~ version
|
44
|
+
version_tags.each_index do |idx|
|
45
|
+
@tag_values[ version_tags[ idx ] ] = Regexp.last_match[ 1 + idx ].to_i
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def write
|
51
|
+
File.open( version_file, 'w' ) do |file|
|
52
|
+
file.write current_version
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def version_file
|
58
|
+
@config[ :version_file ]
|
59
|
+
end
|
60
|
+
|
61
|
+
def version_regex
|
62
|
+
@config[ :version_regex ]
|
63
|
+
end
|
64
|
+
|
65
|
+
def version_tags
|
66
|
+
@config[ :version_tags ]
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
|
2
|
+
module BitStruct
|
3
|
+
|
4
|
+
# Implements access to a 'segment' of a byte string, specified by
|
5
|
+
# offset (from bit 0) and length (in bits). Supports little and big
|
6
|
+
# endian data input and output.
|
7
|
+
#
|
8
|
+
# NOTE: This is highly inefficient. If a segment is byte-aligned,
|
9
|
+
# please use the optimized ByteSlicer class.
|
10
|
+
class BitSlicer
|
11
|
+
|
12
|
+
module Endianess
|
13
|
+
LITTLE_ENDIAN = LITTLE = INTEL = 0
|
14
|
+
BIG_ENDIAN = BIG = MOTOROLA = 1
|
15
|
+
NETWORK_BYTE_ORDER = BIG_ENDIAN
|
16
|
+
end
|
17
|
+
|
18
|
+
include Endianess
|
19
|
+
|
20
|
+
def initialize( bit_offset, bit_length, endianess = MOTOROLA )
|
21
|
+
raise ArgumentError if bit_offset < 0 || bit_length < 0
|
22
|
+
|
23
|
+
@bit_offset = bit_offset
|
24
|
+
@bit_length = bit_length
|
25
|
+
@endianess = endianess
|
26
|
+
end
|
27
|
+
|
28
|
+
def data=( new_data )
|
29
|
+
raise ArgumentError if ( @bit_offset + @bit_length ) > new_data.length * 8
|
30
|
+
@data = new_data
|
31
|
+
end
|
32
|
+
|
33
|
+
def data
|
34
|
+
@data
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_bytes
|
38
|
+
align_shift = required_shift
|
39
|
+
bytes = get_raw_bytes
|
40
|
+
|
41
|
+
# Step 1: Shift all bytes to the right to align bit 0
|
42
|
+
# (in case bit_offset is not on byte border).
|
43
|
+
BitSlicer.shift_bytes_right( bytes, align_shift )
|
44
|
+
|
45
|
+
# Step 2: Strip highest (unused/empty) byte if necessary
|
46
|
+
# (in case bit_length is on byte border, but bit_offset not).
|
47
|
+
data_length = length_in_bytes
|
48
|
+
while bytes.length > data_length
|
49
|
+
bytes = bytes[ 1, bytes.length - 1 ]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Step 3: Apply mask to 'highest' byte
|
53
|
+
# (in case bit_length is not on byte border).
|
54
|
+
bytes[ 0 ] &= highest_byte_mask
|
55
|
+
bytes
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_bytes( bytes )
|
59
|
+
align_shift = required_shift
|
60
|
+
|
61
|
+
# Step 1: Insert empty bytes to allow overflow from shifting.
|
62
|
+
data_length = insert_length_in_bytes
|
63
|
+
while bytes.length < data_length
|
64
|
+
bytes.insert 0, 0x00
|
65
|
+
end
|
66
|
+
while bytes.length > data_length
|
67
|
+
bytes = bytes[ 1, bytes.length - 1 ]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Step 2: Shift all bytes to the left to align bit 0 with the 'destination postion'
|
71
|
+
# (in case bit_offset is not on byte border).
|
72
|
+
BitSlicer.shift_bytes_left( bytes, align_shift )
|
73
|
+
|
74
|
+
# Step 3: Mask out unused parts of first and last byte.
|
75
|
+
bytes[ 0 ] &= insert_first_byte_mask
|
76
|
+
bytes[ bytes.length - 1 ] &= insert_last_byte_mask
|
77
|
+
|
78
|
+
# Step 4: Merge existing data into first and last byte.
|
79
|
+
bytes[ 0 ] |= masked_first_byte
|
80
|
+
bytes[ bytes.length - 1 ] |= masked_last_byte
|
81
|
+
|
82
|
+
# Step 5: Write back the byte data.
|
83
|
+
set_raw_bytes bytes
|
84
|
+
|
85
|
+
data
|
86
|
+
end
|
87
|
+
|
88
|
+
#private
|
89
|
+
|
90
|
+
def get_data( idx )
|
91
|
+
return @data[ idx ] if @endianess == MOTOROLA
|
92
|
+
return @data[ -idx ] if @endianess == INTEL
|
93
|
+
end
|
94
|
+
|
95
|
+
def set_data( idx, val )
|
96
|
+
@data[ idx ] = val if @endianess == MOTOROLA
|
97
|
+
@data[ -idx ] = val if @endianess == INTEL
|
98
|
+
end
|
99
|
+
|
100
|
+
def first_byte
|
101
|
+
data.length - ( ( @bit_offset + @bit_length ) / 8.0 ).ceil
|
102
|
+
end
|
103
|
+
|
104
|
+
def last_byte
|
105
|
+
data.length - 1 - @bit_offset / 8
|
106
|
+
end
|
107
|
+
|
108
|
+
def length_in_bytes
|
109
|
+
( @bit_length / 8.0 ).ceil
|
110
|
+
end
|
111
|
+
|
112
|
+
def insert_length_in_bytes
|
113
|
+
( ( ( @bit_offset & 7 ) + @bit_length ) / 8.0 ).ceil
|
114
|
+
end
|
115
|
+
|
116
|
+
def masked_first_byte
|
117
|
+
get_data( first_byte ) & merge_first_byte_mask
|
118
|
+
end
|
119
|
+
|
120
|
+
def masked_last_byte
|
121
|
+
get_data( last_byte ) & merge_last_byte_mask
|
122
|
+
end
|
123
|
+
|
124
|
+
def required_shift
|
125
|
+
@bit_offset & 7
|
126
|
+
end
|
127
|
+
|
128
|
+
def get_raw_bytes
|
129
|
+
raw_bytes = []
|
130
|
+
first_byte.upto( last_byte ) do |idx|
|
131
|
+
raw_bytes << get_data( idx )
|
132
|
+
end
|
133
|
+
raw_bytes
|
134
|
+
end
|
135
|
+
|
136
|
+
def set_raw_bytes( raw_bytes )
|
137
|
+
first_byte.upto( last_byte ) do |idx|
|
138
|
+
set_data idx, raw_bytes[ idx - first_byte ]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def highest_byte_mask
|
143
|
+
mask_bits = ( ( @bit_length ) & 7 )
|
144
|
+
mask_bits = 8 if mask_bits == 0
|
145
|
+
( 2 ** mask_bits ) - 1
|
146
|
+
end
|
147
|
+
|
148
|
+
def insert_first_byte_mask
|
149
|
+
mask_bits = ( ( @bit_offset + @bit_length ) & 7 )
|
150
|
+
mask_bits = 8 if mask_bits == 0
|
151
|
+
( 2 ** mask_bits ) - 1
|
152
|
+
end
|
153
|
+
|
154
|
+
def insert_last_byte_mask
|
155
|
+
mask_bits = 0xFF
|
156
|
+
( mask_bits << ( @bit_offset & 7 ) ) & 0xFF
|
157
|
+
end
|
158
|
+
|
159
|
+
def merge_first_byte_mask
|
160
|
+
255 - insert_first_byte_mask
|
161
|
+
end
|
162
|
+
|
163
|
+
def merge_last_byte_mask
|
164
|
+
255 - insert_last_byte_mask
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.right_shifted( before, subject, bits )
|
168
|
+
( ( before << 8 | subject ) >> bits ) & 0xFF
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.left_shifted( subject, after, bits )
|
172
|
+
( ( ( subject << 8 | after ) << bits ) >> 8 ) & 0xFF
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.shift_bytes_right( bytes, bit_shift_count )
|
176
|
+
return if bit_shift_count == 0
|
177
|
+
raise ArgumentError if bit_shift_count < 0 || bit_shift_count > 8
|
178
|
+
|
179
|
+
from = bytes.length - 1
|
180
|
+
from.downto( 0 ) do |idx|
|
181
|
+
before = idx > 0 ? bytes[ idx - 1 ] : 0
|
182
|
+
bytes[ idx ] = BitSlicer.right_shifted( before, bytes[ idx ], bit_shift_count )
|
183
|
+
end
|
184
|
+
|
185
|
+
bytes
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.shift_bytes_left( bytes, bit_shift_count )
|
189
|
+
return if bit_shift_count == 0
|
190
|
+
raise ArgumentError if bit_shift_count < 0 || bit_shift_count > 8
|
191
|
+
|
192
|
+
0.upto( bytes.length - 1 ) do |idx|
|
193
|
+
after = bytes[ idx + 1 ] || 0
|
194
|
+
bytes[ idx ] = BitSlicer.left_shifted( bytes[ idx ], after, bit_shift_count )
|
195
|
+
end
|
196
|
+
|
197
|
+
bytes
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module BitStruct
|
3
|
+
|
4
|
+
class Field
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :length
|
8
|
+
attr_reader :description
|
9
|
+
|
10
|
+
def initialize( name, length, description )
|
11
|
+
@name = name
|
12
|
+
@length = length
|
13
|
+
@description = description
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
require 'bit_struct/field'
|
3
|
+
|
4
|
+
module BitStruct
|
5
|
+
|
6
|
+
class NestedField < Field
|
7
|
+
|
8
|
+
def initialize( name, nested_class, description = nil )
|
9
|
+
super name, nil, description
|
10
|
+
@nested_class = nested_class
|
11
|
+
end
|
12
|
+
|
13
|
+
def length
|
14
|
+
@nested_class.length
|
15
|
+
end
|
16
|
+
|
17
|
+
def read( slicer )
|
18
|
+
bytes = slicer.get_bytes
|
19
|
+
@nested_class.new bytes
|
20
|
+
end
|
21
|
+
|
22
|
+
def write( slicer, new_value )
|
23
|
+
# TODO: What should be allowed here?
|
24
|
+
# TODO: new_value.is_a? String
|
25
|
+
# TODO: new_value.is_a? Array
|
26
|
+
# TODO: new_value.is_a? StructBase
|
27
|
+
raise "NYI"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
|
2
|
+
require 'bit_struct/bit_slicer'
|
3
|
+
require 'bit_struct/field'
|
4
|
+
|
5
|
+
# The BitStruct module primarily provides the StructBase class, which in turn
|
6
|
+
# allows the definition of bit-based structures that can be used to access
|
7
|
+
# byte data on a bit offset / length manner.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# class Flags < StructBase
|
12
|
+
# unsigned :direction, 4
|
13
|
+
# unsigned :multiplier, 2
|
14
|
+
# unsigned :offset, 2
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class Entry < StructBase
|
18
|
+
# unsigned :offset, 4
|
19
|
+
# nested :flags, Flags
|
20
|
+
# unsigned :address, 24
|
21
|
+
# unsigned :cache_id, 16
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# In contrast to the already available
|
25
|
+
# http://raa.ruby-lang.org/project/bit-struct/ implementation, BitStructEx
|
26
|
+
# allows nested structures which are not aligned on byte boundaries.
|
27
|
+
#
|
28
|
+
# Author:: Daniel Lukic (mailto:bitstructex@berlinfactor.com)
|
29
|
+
# Copyright:: Copyright (c) 2005 The.Berlin.Factor
|
30
|
+
# License:: Distributes under the GPL
|
31
|
+
#
|
32
|
+
module BitStruct
|
33
|
+
|
34
|
+
# Define a subclass of StructBase and use the available field types (at
|
35
|
+
# least "nested" and "unsigned" are available) to define the bit-based
|
36
|
+
# structure like this:
|
37
|
+
#
|
38
|
+
# * unsigned :name_of_field, length_of_field_in_bits
|
39
|
+
# * nested :name_of_nested_field, class_of_nested_field
|
40
|
+
#
|
41
|
+
# Please see the provided examples in the samples folder for.. well..
|
42
|
+
# examples.
|
43
|
+
#
|
44
|
+
class StructBase < String
|
45
|
+
|
46
|
+
def initialize( data = nil )
|
47
|
+
@data = data
|
48
|
+
end
|
49
|
+
|
50
|
+
def data
|
51
|
+
@data
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
|
56
|
+
def fields
|
57
|
+
@fields ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
def length
|
61
|
+
@fields.inject( 0 ) { |l,f| l + f.length }
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def add_field( field )
|
67
|
+
context = self
|
68
|
+
|
69
|
+
define_method "#{field.name}" do
|
70
|
+
slicer = context.send :get_slicer_for, field
|
71
|
+
slicer.data = @data
|
72
|
+
field.send :read, slicer
|
73
|
+
end
|
74
|
+
define_method "#{field.name}=" do |val|
|
75
|
+
slicer = context.send :get_slicer_for, field
|
76
|
+
slicer.data = @data
|
77
|
+
field.send :write, slicer, val
|
78
|
+
end
|
79
|
+
|
80
|
+
fields << field
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_slicer_for( field )
|
84
|
+
unless slicers[ field ]
|
85
|
+
bit_offset, bit_length = get_field_spec field
|
86
|
+
slicers[ field ] = BitSlicer.new bit_offset, bit_length
|
87
|
+
end
|
88
|
+
slicers[ field ]
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_field_spec( field )
|
92
|
+
index = fields.index field
|
93
|
+
offset = 0
|
94
|
+
0.upto( index - 1 ) { |idx| offset += fields[ idx ].length }
|
95
|
+
return offset, field.length
|
96
|
+
end
|
97
|
+
|
98
|
+
def method_missing( symbol, *args )
|
99
|
+
require "bit_struct/#{symbol.id2name}"
|
100
|
+
|
101
|
+
class_name = make_class_name symbol
|
102
|
+
clazz = const_get class_name.to_sym
|
103
|
+
self.class.send :define_method, symbol do |*args|
|
104
|
+
add_field clazz.new( *args )
|
105
|
+
end
|
106
|
+
|
107
|
+
send symbol, *args
|
108
|
+
end
|
109
|
+
|
110
|
+
def make_class_name( symbol )
|
111
|
+
words = symbol.id2name.split '_'
|
112
|
+
words.map! { |w| w.capitalize }
|
113
|
+
words.join + 'Field'
|
114
|
+
end
|
115
|
+
|
116
|
+
def slicers
|
117
|
+
@slicers ||= {}
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
require 'bit_struct/field'
|
3
|
+
|
4
|
+
module BitStruct
|
5
|
+
|
6
|
+
class UnsignedField < Field
|
7
|
+
|
8
|
+
def initialize( name, length, description = nil )
|
9
|
+
super name, length, description
|
10
|
+
end
|
11
|
+
|
12
|
+
def read( slicer )
|
13
|
+
slicer.get_bytes.inject( 0 ) { |r,b| ( r << 8 ) + b }
|
14
|
+
end
|
15
|
+
|
16
|
+
def write( slicer, new_value )
|
17
|
+
bytes = []
|
18
|
+
while new_value > 0
|
19
|
+
bytes.insert 0, ( new_value & 0xFF )
|
20
|
+
new_value >>= 8
|
21
|
+
end
|
22
|
+
slicer.set_bytes bytes
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require 'bit_struct/bit_slicer'
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
class TestBitSlicer < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def test_endianess
|
11
|
+
slicer = BitStruct::BitSlicer.new 0, 16, BitStruct::BitSlicer::MOTOROLA
|
12
|
+
slicer.data = test_data
|
13
|
+
assert_equal '0x01 0x23 0x45 0x67 0x89', slicer.data.hexify
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_right_shifted
|
17
|
+
assert_equal '34', BitStruct::BitSlicer.right_shifted( 0x12, 0x34, 0 ).hexify
|
18
|
+
assert_equal '23', BitStruct::BitSlicer.right_shifted( 0x12, 0x34, 4 ).hexify
|
19
|
+
assert_equal '12', BitStruct::BitSlicer.right_shifted( 0x12, 0x34, 8 ).hexify
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_left_shifted
|
23
|
+
assert_equal '12', BitStruct::BitSlicer.left_shifted( 0x12, 0x34, 0 ).hexify
|
24
|
+
assert_equal '23', BitStruct::BitSlicer.left_shifted( 0x12, 0x34, 4 ).hexify
|
25
|
+
assert_equal '34', BitStruct::BitSlicer.left_shifted( 0x12, 0x34, 8 ).hexify
|
26
|
+
|
27
|
+
assert_equal '11000011', BitStruct::BitSlicer.left_shifted( 0xF0, 0xF0, 2 ).binarize
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_first_byte
|
31
|
+
assert_equal 4, slicer( 0, 1 ).first_byte
|
32
|
+
assert_equal 4, slicer( 0, 7 ).first_byte
|
33
|
+
assert_equal 4, slicer( 0, 8 ).first_byte
|
34
|
+
assert_equal 3, slicer( 0, 12 ).first_byte
|
35
|
+
assert_equal 3, slicer( 0, 16 ).first_byte
|
36
|
+
assert_equal 3, slicer( 2, 8 ).first_byte
|
37
|
+
assert_equal 4, slicer( 2, 2 ).first_byte
|
38
|
+
assert_equal 2, slicer( 2, 16 ).first_byte
|
39
|
+
assert_equal 2, slicer( 4, 16 ).first_byte
|
40
|
+
assert_equal 2, slicer( 6, 16 ).first_byte
|
41
|
+
assert_equal 2, slicer( 7, 16 ).first_byte
|
42
|
+
assert_equal 2, slicer( 8, 16 ).first_byte
|
43
|
+
assert_equal 1, slicer( 9, 16 ).first_byte
|
44
|
+
assert_equal 1, slicer( 15, 16 ).first_byte
|
45
|
+
assert_equal 1, slicer( 16, 16 ).first_byte
|
46
|
+
assert_equal 0, slicer( 17, 16 ).first_byte
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_last_byte
|
50
|
+
assert_equal 4, slicer( 0, 16 ).last_byte
|
51
|
+
assert_equal 4, slicer( 2, 16 ).last_byte
|
52
|
+
assert_equal 4, slicer( 4, 16 ).last_byte
|
53
|
+
assert_equal 4, slicer( 6, 16 ).last_byte
|
54
|
+
assert_equal 4, slicer( 7, 16 ).last_byte
|
55
|
+
assert_equal 3, slicer( 8, 16 ).last_byte
|
56
|
+
assert_equal 3, slicer( 9, 16 ).last_byte
|
57
|
+
assert_equal 3, slicer( 15, 16 ).last_byte
|
58
|
+
assert_equal 2, slicer( 16, 16 ).last_byte
|
59
|
+
assert_equal 2, slicer( 17, 16 ).last_byte
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_length_in_bytes
|
63
|
+
assert_equal 1, slicer( 0, 1 ).length_in_bytes
|
64
|
+
assert_equal 1, slicer( 0, 4 ).length_in_bytes
|
65
|
+
assert_equal 1, slicer( 0, 8 ).length_in_bytes
|
66
|
+
assert_equal 2, slicer( 0, 9 ).length_in_bytes
|
67
|
+
assert_equal 2, slicer( 0, 14 ).length_in_bytes
|
68
|
+
assert_equal 2, slicer( 0, 16 ).length_in_bytes
|
69
|
+
assert_equal 3, slicer( 0, 20 ).length_in_bytes
|
70
|
+
|
71
|
+
assert_equal 1, slicer( 4, 1 ).length_in_bytes
|
72
|
+
assert_equal 1, slicer( 4, 4 ).length_in_bytes
|
73
|
+
assert_equal 1, slicer( 5, 8 ).length_in_bytes
|
74
|
+
assert_equal 2, slicer( 6, 9 ).length_in_bytes
|
75
|
+
assert_equal 2, slicer( 7, 14 ).length_in_bytes
|
76
|
+
assert_equal 2, slicer( 7, 16 ).length_in_bytes
|
77
|
+
assert_equal 3, slicer( 8, 20 ).length_in_bytes
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_insert_length_in_bytes
|
81
|
+
assert_equal 1, slicer( 0, 1 ).insert_length_in_bytes
|
82
|
+
assert_equal 1, slicer( 0, 4 ).insert_length_in_bytes
|
83
|
+
assert_equal 1, slicer( 0, 8 ).insert_length_in_bytes
|
84
|
+
assert_equal 2, slicer( 0, 9 ).insert_length_in_bytes
|
85
|
+
assert_equal 2, slicer( 0, 14 ).insert_length_in_bytes
|
86
|
+
assert_equal 2, slicer( 0, 16 ).insert_length_in_bytes
|
87
|
+
assert_equal 3, slicer( 0, 20 ).insert_length_in_bytes
|
88
|
+
|
89
|
+
assert_equal 1, slicer( 8, 8 ).insert_length_in_bytes
|
90
|
+
|
91
|
+
assert_equal 1, slicer( 4, 1 ).insert_length_in_bytes
|
92
|
+
assert_equal 1, slicer( 4, 4 ).insert_length_in_bytes
|
93
|
+
assert_equal 2, slicer( 5, 8 ).insert_length_in_bytes
|
94
|
+
assert_equal 2, slicer( 6, 9 ).insert_length_in_bytes
|
95
|
+
assert_equal 3, slicer( 7, 14 ).insert_length_in_bytes
|
96
|
+
assert_equal 3, slicer( 7, 16 ).insert_length_in_bytes
|
97
|
+
assert_equal 3, slicer( 8, 20 ).insert_length_in_bytes
|
98
|
+
assert_equal 3, slicer( 8, 24 ).insert_length_in_bytes
|
99
|
+
assert_equal 4, slicer( 8, 25 ).insert_length_in_bytes
|
100
|
+
assert_equal 3, slicer( 9, 16 ).insert_length_in_bytes
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_highest_byte_mask
|
104
|
+
assert_equal '00111111', slicer( 2, 22 ).highest_byte_mask.binarize
|
105
|
+
assert_equal '00111111', slicer( 0, 22 ).highest_byte_mask.binarize
|
106
|
+
assert_equal '11111111', slicer( 0, 16 ).highest_byte_mask.binarize
|
107
|
+
assert_equal '00111111', slicer( 2, 14 ).highest_byte_mask.binarize
|
108
|
+
assert_equal '11111111', slicer( 2, 16 ).highest_byte_mask.binarize
|
109
|
+
assert_equal '11111111', slicer( 4, 16 ).highest_byte_mask.binarize
|
110
|
+
assert_equal '11111111', slicer( 6, 16 ).highest_byte_mask.binarize
|
111
|
+
assert_equal '11111111', slicer( 7, 16 ).highest_byte_mask.binarize
|
112
|
+
assert_equal '11111111', slicer( 8, 16 ).highest_byte_mask.binarize
|
113
|
+
assert_equal '11111111', slicer( 9, 16 ).highest_byte_mask.binarize
|
114
|
+
assert_equal '11111111', slicer( 15, 16 ).highest_byte_mask.binarize
|
115
|
+
assert_equal '11111111', slicer( 16, 16 ).highest_byte_mask.binarize
|
116
|
+
assert_equal '11111111', slicer( 17, 16 ).highest_byte_mask.binarize
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_insert_first_byte_mask
|
120
|
+
assert_equal '11111111', slicer( 0, 8 ).insert_first_byte_mask.binarize
|
121
|
+
assert_equal '00000011', slicer( 2, 8 ).insert_first_byte_mask.binarize
|
122
|
+
assert_equal '00001111', slicer( 4, 8 ).insert_first_byte_mask.binarize
|
123
|
+
assert_equal '00111111', slicer( 6, 8 ).insert_first_byte_mask.binarize
|
124
|
+
assert_equal '11111111', slicer( 8, 8 ).insert_first_byte_mask.binarize
|
125
|
+
assert_equal '00000011', slicer( 10, 8 ).insert_first_byte_mask.binarize
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_insert_last_byte_mask
|
129
|
+
assert_equal '11111111', slicer( 0, 8 ).insert_last_byte_mask.binarize
|
130
|
+
assert_equal '11111100', slicer( 2, 8 ).insert_last_byte_mask.binarize
|
131
|
+
assert_equal '11110000', slicer( 4, 8 ).insert_last_byte_mask.binarize
|
132
|
+
assert_equal '11000000', slicer( 6, 8 ).insert_last_byte_mask.binarize
|
133
|
+
assert_equal '11111111', slicer( 8, 8 ).insert_last_byte_mask.binarize
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_masked_last_byte
|
137
|
+
slicer = slicer( 12, 24 )
|
138
|
+
assert_equal '00000001', slicer.data[ slicer.first_byte ].binarize
|
139
|
+
assert_equal '11110000', slicer.merge_first_byte_mask.binarize
|
140
|
+
assert_equal '00000000', slicer.masked_first_byte.binarize
|
141
|
+
|
142
|
+
assert_equal '01100111', slicer.data[ slicer.last_byte ].binarize
|
143
|
+
assert_equal '00001111', slicer.merge_last_byte_mask.binarize
|
144
|
+
assert_equal '00000111', slicer.masked_last_byte.binarize
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_required_shift
|
148
|
+
assert_equal 0, slicer( 0, 16 ).required_shift
|
149
|
+
assert_equal 2, slicer( 2, 16 ).required_shift
|
150
|
+
assert_equal 4, slicer( 4, 16 ).required_shift
|
151
|
+
assert_equal 6, slicer( 6, 16 ).required_shift
|
152
|
+
assert_equal 0, slicer( 8, 4 ).required_shift
|
153
|
+
assert_equal 0, slicer( 8, 16 ).required_shift
|
154
|
+
assert_equal 2, slicer( 10, 16 ).required_shift
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_get_raw_bytes
|
158
|
+
# test_data = [ 0x01, 0x23, 0x45, 0x67, 0x89 ].pack( 'C*' )
|
159
|
+
|
160
|
+
assert_equal '0x89', slicer( 0, 8 ).get_raw_bytes.hexify
|
161
|
+
assert_equal '0x67 0x89', slicer( 0, 16 ).get_raw_bytes.hexify
|
162
|
+
assert_equal '0x45 0x67 0x89', slicer( 0, 24 ).get_raw_bytes.hexify
|
163
|
+
|
164
|
+
assert_equal '0x45 0x67 0x89', slicer( 4, 16 ).get_raw_bytes.hexify
|
165
|
+
assert_equal '0x45 0x67 0x89', slicer( 4, 20 ).get_raw_bytes.hexify
|
166
|
+
assert_equal '0x23 0x45 0x67 0x89', slicer( 6, 20 ).get_raw_bytes.hexify
|
167
|
+
|
168
|
+
assert_equal '0x45 0x67', slicer( 12, 8 ).get_raw_bytes.hexify
|
169
|
+
|
170
|
+
assert_equal '0x67', slicer( 8, 4 ).get_raw_bytes.hexify
|
171
|
+
|
172
|
+
assert_equal '0x45 0x67', slicer( 8, 16 ).get_raw_bytes.hexify
|
173
|
+
assert_equal '0x23 0x45', slicer( 16, 16 ).get_raw_bytes.hexify
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_shift_bytes_right
|
177
|
+
assert_equal '0x01 0x23 0x45', BitStruct::BitSlicer.shift_bytes_right( [ 0x12, 0x34, 0x56 ], 4 ).hexify
|
178
|
+
assert_equal '0x00 0x12 0x34', BitStruct::BitSlicer.shift_bytes_right( [ 0x12, 0x34, 0x56 ], 8 ).hexify
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_shift_bytes_left
|
182
|
+
assert_equal '0x23 0x45 0x60', BitStruct::BitSlicer.shift_bytes_left( [ 0x12, 0x34, 0x56 ], 4 ).hexify
|
183
|
+
assert_equal '0x34 0x56 0x00', BitStruct::BitSlicer.shift_bytes_left( [ 0x12, 0x34, 0x56 ], 8 ).hexify
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_get_bytes
|
187
|
+
assert_equal '0x89', slicer( 0, 8 ).get_bytes.hexify
|
188
|
+
assert_equal '0x09', slicer( 0, 4 ).get_bytes.hexify
|
189
|
+
assert_equal '0x08', slicer( 4, 4 ).get_bytes.hexify
|
190
|
+
|
191
|
+
assert_equal '0x07', slicer( 8, 4 ).get_bytes.hexify
|
192
|
+
assert_equal '0x06', slicer( 12, 4 ).get_bytes.hexify
|
193
|
+
|
194
|
+
assert_equal '0x67 0x89', slicer( 4, 8 ).get_raw_bytes.hexify
|
195
|
+
assert_equal '0x06 0x78', BitStruct::BitSlicer.shift_bytes_right( [ 0x67, 0x89 ], 4 ).hexify
|
196
|
+
assert_equal '0x78', slicer( 4, 8 ).get_bytes.hexify
|
197
|
+
|
198
|
+
assert_equal '0x45 0x67', slicer( 12, 8 ).get_raw_bytes.hexify
|
199
|
+
assert_equal '0x04 0x56', BitStruct::BitSlicer.shift_bytes_right( [ 0x45, 0x67 ], 4 ).hexify
|
200
|
+
assert_equal '0x56', slicer( 12, 8 ).get_bytes.hexify
|
201
|
+
|
202
|
+
assert_equal '0x67 0x89', slicer( 0, 16 ).get_bytes.hexify
|
203
|
+
assert_equal '0x45 0x67 0x89', slicer( 0, 24 ).get_bytes.hexify
|
204
|
+
assert_equal '0x05 0x67 0x89', slicer( 0, 22 ).get_bytes.hexify
|
205
|
+
|
206
|
+
assert_equal '0x45 0x67', slicer( 8, 16 ).get_bytes.hexify
|
207
|
+
assert_equal '0x23 0x45', slicer( 16, 16 ).get_bytes.hexify
|
208
|
+
|
209
|
+
assert_equal '0x23 0x45 0x67', slicer( 12, 16 ).get_raw_bytes.hexify
|
210
|
+
assert_equal '0x34 0x56', slicer( 12, 16 ).get_bytes.hexify
|
211
|
+
assert_equal '0x04 0x56', slicer( 12, 12 ).get_bytes.hexify
|
212
|
+
assert_equal '0x56', slicer( 12, 8 ).get_bytes.hexify
|
213
|
+
assert_equal '0x16', slicer( 12, 6 ).get_bytes.hexify
|
214
|
+
assert_equal '0x06', slicer( 12, 4 ).get_bytes.hexify
|
215
|
+
assert_equal '0x02', slicer( 12, 2 ).get_bytes.hexify
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_set_bytes
|
219
|
+
slicer = slicer( 0, 8 )
|
220
|
+
assert_equal 4, slicer.first_byte
|
221
|
+
assert_equal 4, slicer.last_byte
|
222
|
+
assert_equal 1, slicer.length_in_bytes
|
223
|
+
assert_equal 1, slicer.insert_length_in_bytes
|
224
|
+
assert_equal 4, slicer.first_byte
|
225
|
+
assert_equal 4, slicer.last_byte
|
226
|
+
# assert_equal '0x01 0x23 0x45 0x67 0xcd', slicer.set_bytes( [ 0xCD ] ).hexify
|
227
|
+
|
228
|
+
slicer = slicer( 8, 8 )
|
229
|
+
assert_equal 3, slicer.first_byte
|
230
|
+
assert_equal 3, slicer.last_byte
|
231
|
+
assert_equal 1, slicer.length_in_bytes
|
232
|
+
assert_equal 1, slicer.insert_length_in_bytes
|
233
|
+
# assert_equal '0x01 0x23 0x45 0xcd 0x89', slicer.set_bytes( [ 0xCD ] ).hexify
|
234
|
+
|
235
|
+
slicer = slicer( 4, 8 )
|
236
|
+
assert_equal 3, slicer.first_byte
|
237
|
+
assert_equal 4, slicer.last_byte
|
238
|
+
assert_equal 1, slicer.length_in_bytes
|
239
|
+
assert_equal 2, slicer.insert_length_in_bytes
|
240
|
+
# assert_equal '0x01 0x23 0x45 0x6c 0xd9', slicer.set_bytes( [ 0xCD ] ).hexify
|
241
|
+
|
242
|
+
slicer = slicer( 4, 2 )
|
243
|
+
assert_equal 4, slicer.first_byte
|
244
|
+
assert_equal 4, slicer.last_byte
|
245
|
+
assert_equal 1, slicer.length_in_bytes
|
246
|
+
assert_equal 1, slicer.insert_length_in_bytes
|
247
|
+
|
248
|
+
assert_equal '00111111', slicer.insert_first_byte_mask.binarize
|
249
|
+
assert_equal '11110000', slicer.insert_last_byte_mask.binarize
|
250
|
+
|
251
|
+
assert_equal '11000000', slicer.merge_first_byte_mask.binarize
|
252
|
+
assert_equal '00001111', slicer.merge_last_byte_mask.binarize
|
253
|
+
|
254
|
+
assert_equal '10000000', slicer.masked_first_byte.binarize
|
255
|
+
assert_equal '00001001', slicer.masked_last_byte.binarize
|
256
|
+
|
257
|
+
assert_equal '0x01 0x23 0x45 0x67 0x89', slicer.data.hexify
|
258
|
+
assert_equal '0x01 0x23 0x45 0x67 0x89', slicer.set_bytes( [ 0x00 ] ).hexify
|
259
|
+
assert_equal '0x01 0x23 0x45 0x67 0xb9', slicer.set_bytes( [ 0xFF ] ).hexify
|
260
|
+
|
261
|
+
slicer = slicer( 12, 24 )
|
262
|
+
assert_equal 0, slicer.first_byte
|
263
|
+
assert_equal 3, slicer.last_byte
|
264
|
+
assert_equal 3, slicer.length_in_bytes
|
265
|
+
assert_equal 4, slicer.insert_length_in_bytes
|
266
|
+
|
267
|
+
assert_equal '00001111', slicer.insert_first_byte_mask.binarize
|
268
|
+
assert_equal '11110000', slicer.insert_last_byte_mask.binarize
|
269
|
+
|
270
|
+
assert_equal '11110000', slicer.merge_first_byte_mask.binarize
|
271
|
+
assert_equal '00001111', slicer.merge_last_byte_mask.binarize
|
272
|
+
|
273
|
+
assert_equal '00000001', slicer.data[ slicer.first_byte ].binarize
|
274
|
+
assert_equal '00000000', slicer.masked_first_byte.binarize
|
275
|
+
|
276
|
+
assert_equal '01100111', slicer.data[ slicer.last_byte ].binarize
|
277
|
+
assert_equal '00000111', slicer.masked_last_byte.binarize
|
278
|
+
|
279
|
+
assert_equal '0x01 0x23 0x45 0x67 0x89', slicer.data.hexify
|
280
|
+
assert_equal '0x12 0x34 0x56', slicer.get_bytes.hexify
|
281
|
+
assert_equal '0x07 0x75 0x53 0x37 0x89', slicer.set_bytes( [ 0x99, 0x77, 0x55, 0x33 ] ).hexify
|
282
|
+
assert_equal '0x07 0x75 0x53 0x37 0x89', slicer.set_bytes( [ 0xAA, 0xFF, 0x99, 0x77, 0x55, 0x33 ] ).hexify
|
283
|
+
end
|
284
|
+
|
285
|
+
def slicer( bit_offset, bit_length )
|
286
|
+
slicer = BitStruct::BitSlicer.new bit_offset, bit_length
|
287
|
+
slicer.data = test_data.dup
|
288
|
+
slicer
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_data
|
292
|
+
[ 0x01, 0x23, 0x45, 0x67, 0x89 ].pack( 'C*' )
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_data_intel
|
296
|
+
[ 0x89, 0x67, 0x45, 0x23, 0x01].pack( 'C*' )
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require 'bit_struct/struct_base'
|
5
|
+
|
6
|
+
include BitStruct
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
class Flags < StructBase
|
11
|
+
unsigned :direction, 4
|
12
|
+
unsigned :multiplier, 2
|
13
|
+
unsigned :offset, 2
|
14
|
+
end
|
15
|
+
|
16
|
+
class Entry < StructBase
|
17
|
+
unsigned :offset, 4
|
18
|
+
nested :flags, Flags
|
19
|
+
unsigned :address, 24
|
20
|
+
unsigned :cache_id, 16
|
21
|
+
end
|
22
|
+
|
23
|
+
class TestBitStruct < Test::Unit::TestCase
|
24
|
+
|
25
|
+
def test_flags_class
|
26
|
+
fields = Flags.fields
|
27
|
+
assert_equal 3, fields.size
|
28
|
+
|
29
|
+
assert_equal :direction, fields[ 0 ].name
|
30
|
+
assert_equal 4, fields[ 0 ].length
|
31
|
+
assert_equal :multiplier, fields[ 1 ].name
|
32
|
+
assert_equal 2, fields[ 1 ].length
|
33
|
+
assert_equal :offset, fields[ 2 ].name
|
34
|
+
assert_equal 2, fields[ 2 ].length
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_attributes_class
|
38
|
+
fields = Entry.fields
|
39
|
+
assert_equal 4, fields.size
|
40
|
+
|
41
|
+
assert_equal :offset, fields[ 0 ].name
|
42
|
+
assert_equal 4, fields[ 0 ].length
|
43
|
+
assert_equal :flags, fields[ 1 ].name
|
44
|
+
assert_equal 8, fields[ 1 ].length
|
45
|
+
assert_equal :address, fields[ 2 ].name
|
46
|
+
assert_equal 24, fields[ 2 ].length
|
47
|
+
assert_equal :cache_id, fields[ 3 ].name
|
48
|
+
assert_equal 16, fields[ 3 ].length
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_flags_read
|
52
|
+
flags = Flags.new [ 0xFF ].pack( 'C*' )
|
53
|
+
assert_equal 0x0F, flags.direction
|
54
|
+
assert_equal 0x03, flags.multiplier
|
55
|
+
assert_equal 0x03, flags.offset
|
56
|
+
|
57
|
+
flags = Flags.new [ 0x0F ].pack( 'C*' )
|
58
|
+
assert_equal 0x0F, flags.direction
|
59
|
+
assert_equal 0x00, flags.multiplier
|
60
|
+
assert_equal 0x00, flags.offset
|
61
|
+
|
62
|
+
flags = Flags.new [ 0x3F ].pack( 'C*' )
|
63
|
+
assert_equal 0x0F, flags.direction
|
64
|
+
assert_equal 0x03, flags.multiplier
|
65
|
+
assert_equal 0x00, flags.offset
|
66
|
+
|
67
|
+
flags = Flags.new [ 0xCF ].pack( 'C*' )
|
68
|
+
assert_equal 0x0F, flags.direction
|
69
|
+
assert_equal 0x00, flags.multiplier
|
70
|
+
assert_equal 0x03, flags.offset
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_flags_write
|
74
|
+
data = [ 0xFF ].pack( 'C*' )
|
75
|
+
|
76
|
+
flags = Flags.new data
|
77
|
+
assert_equal '0xff', flags.data.hexify
|
78
|
+
assert_equal 0x0F, flags.direction
|
79
|
+
assert_equal 0x03, flags.multiplier
|
80
|
+
assert_equal 0x03, flags.offset
|
81
|
+
|
82
|
+
flags.multiplier = 0
|
83
|
+
assert_equal '0xcf', flags.data.hexify
|
84
|
+
assert_equal 0x0F, flags.direction
|
85
|
+
assert_equal 0x00, flags.multiplier
|
86
|
+
assert_equal 0x03, flags.offset
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_entry_read
|
90
|
+
data = [ 0xAA, 0xFF, 0x01, 0x23, 0x45, 0x67, 0x89 ].pack( 'C*' )
|
91
|
+
entry = Entry.new data
|
92
|
+
|
93
|
+
assert_equal 9, entry.offset
|
94
|
+
assert_equal '0x12 0x34 0x56', entry.address.bytes.hexify
|
95
|
+
assert_equal '0xaf 0xf0', entry.cache_id.bytes.hexify
|
96
|
+
|
97
|
+
flags = entry.flags
|
98
|
+
assert_equal 8, flags.direction
|
99
|
+
assert_equal 3, flags.multiplier
|
100
|
+
assert_equal 1, flags.offset
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_attributes_write
|
104
|
+
data = [ 0xAA, 0xFF, 0x01, 0x23, 0x45, 0x67, 0x89 ].pack( 'C*' )
|
105
|
+
entry = Entry.new data
|
106
|
+
|
107
|
+
entry.offset = 15
|
108
|
+
assert_equal '0x0f', entry.offset.bytes.hexify
|
109
|
+
assert_equal '0xaa 0xff 0x01 0x23 0x45 0x67 0x8f', entry.data.hexify
|
110
|
+
|
111
|
+
entry.address = 0x44332211
|
112
|
+
assert_equal '0x33 0x22 0x11', entry.address.bytes.hexify
|
113
|
+
assert_equal '0xaa 0xff 0x03 0x32 0x21 0x17 0x8f', entry.data.hexify
|
114
|
+
|
115
|
+
entry.cache_id = 0xAABBCCDD
|
116
|
+
assert_equal '0xcc 0xdd', entry.cache_id.bytes.hexify
|
117
|
+
assert_equal '0xac 0xcd 0xd3 0x32 0x21 0x17 0x8f', entry.data.hexify
|
118
|
+
|
119
|
+
flags = entry.flags
|
120
|
+
assert_equal 8, flags.direction
|
121
|
+
assert_equal 3, flags.multiplier
|
122
|
+
assert_equal 1, flags.offset
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
data/test/ruby/runner.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
require 'test/unit/autorunner'
|
5
|
+
|
6
|
+
class String
|
7
|
+
|
8
|
+
def hexify
|
9
|
+
result = ''
|
10
|
+
each_byte do |b|
|
11
|
+
result << "0x#{b.hexify} "
|
12
|
+
end
|
13
|
+
result.chop
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class Array
|
19
|
+
|
20
|
+
def hexify
|
21
|
+
map { |b| "0x#{b && b.hexify}" }.join( ' ' )
|
22
|
+
end
|
23
|
+
|
24
|
+
def binarize
|
25
|
+
map { |b| "%#{b && b.binarize}" }.join( ' ' )
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class Fixnum
|
31
|
+
|
32
|
+
def bytes
|
33
|
+
bytes = []
|
34
|
+
val = to_i
|
35
|
+
while val > 0
|
36
|
+
bytes.insert 0, ( val & 0xFF )
|
37
|
+
val >>= 8
|
38
|
+
end
|
39
|
+
bytes
|
40
|
+
end
|
41
|
+
|
42
|
+
def hexify
|
43
|
+
result = ''
|
44
|
+
val = to_i
|
45
|
+
while val > 0
|
46
|
+
b = val & 0xF
|
47
|
+
result = b.to_s( 16 ) + result
|
48
|
+
val >>= 4
|
49
|
+
end
|
50
|
+
padded result, 2
|
51
|
+
end
|
52
|
+
|
53
|
+
def binarize
|
54
|
+
result = ''
|
55
|
+
val = to_i
|
56
|
+
while val > 0
|
57
|
+
b = val & 1
|
58
|
+
result = b.to_s( 2 ) + result
|
59
|
+
val >>= 1
|
60
|
+
end
|
61
|
+
padded result, 8
|
62
|
+
end
|
63
|
+
|
64
|
+
def padded( val, length_multiplier )
|
65
|
+
padded_length = ( val.length / length_multiplier ).ceil * length_multiplier
|
66
|
+
padded_length = length_multiplier if padded_length == 0
|
67
|
+
pad_size = padded_length - val.length
|
68
|
+
'0' * pad_size + val
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def hexify( data )
|
74
|
+
result = ''
|
75
|
+
data.each_byte do |b|
|
76
|
+
nibble = ( b >> 4 ) & 15
|
77
|
+
result << ( 0x30 + nibble ) if nibble < 10
|
78
|
+
result << ( 0x41 + nibble - 10 ) if nibble >= 10
|
79
|
+
nibble = ( b >> 0 ) & 15
|
80
|
+
result << ( 0x30 + nibble ) if nibble < 10
|
81
|
+
result << ( 0x41 + nibble - 10 ) if nibble >= 10
|
82
|
+
end
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_resource( basedir, relative_filename )
|
87
|
+
basedir = File.dirname basedir unless File.directory? basedir
|
88
|
+
filename = File.join( basedir, relative_filename )
|
89
|
+
raise "Resource not found: #{filename}" unless File.exists? filename
|
90
|
+
return filename
|
91
|
+
end
|
92
|
+
|
93
|
+
def open_resource( basedir, relative_filename )
|
94
|
+
File.new get_resource( basedir, relative_filename ), 'rb'
|
95
|
+
end
|
96
|
+
|
97
|
+
def load_resource( basedir, relative_filename )
|
98
|
+
File.open( get_resource( basedir, relative_filename ), 'rb' ) do |file|
|
99
|
+
return file.read
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class NullLogger < Logger
|
104
|
+
def initialize( *args )
|
105
|
+
super STDOUT
|
106
|
+
@level = WARN
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
NULL_LOGGER = NullLogger.new
|
111
|
+
|
112
|
+
args = [ '--runner=console', '--verbose=v' ]
|
113
|
+
args.concat ARGV
|
114
|
+
success = Test::Unit::AutoRunner.run( true, File.dirname( $0 ), args )
|
115
|
+
exit 10 unless success
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: BitStructEx
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.54
|
7
|
+
date: 2006-04-13 00:00:00 +02:00
|
8
|
+
summary: Simple DSL for defining bit-based structures on byte data.
|
9
|
+
require_paths:
|
10
|
+
- src/ruby
|
11
|
+
email: tfdj {AT} berlinfactor {DOT} com
|
12
|
+
homepage: bit-struct-ex.rubyforge.org.
|
13
|
+
rubyforge_project: bit-struct-ex
|
14
|
+
description: "Allows the specification of bit-based structures and provides an intuitive way of access data. Example: class Flags < StructBase unsigned :direction, 4 unsigned :multiplier, 2 unsigned :offset, 2 end class Entry < StructBase unsigned :offset, 4 nested :flags, Flags unsigned :address, 24 unsigned :cache_id, 16 end In contrast to the already available http://raa.ruby-lang.org/project/bit-struct/ implementation, BitStructEx allows nested structures which are not aligned on byte boundaries."
|
15
|
+
autorequire: bit_struct/struct_base
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- The.French.DJ
|
30
|
+
files:
|
31
|
+
- lib/ruby/rake/version.rb
|
32
|
+
- src/ruby/bit_struct/bit_slicer.rb
|
33
|
+
- src/ruby/bit_struct/field.rb
|
34
|
+
- src/ruby/bit_struct/nested.rb
|
35
|
+
- src/ruby/bit_struct/struct_base.rb
|
36
|
+
- src/ruby/bit_struct/unsigned.rb
|
37
|
+
- test/ruby/runner.rb
|
38
|
+
- test/ruby/bit_struct/test_bit_slicer.rb
|
39
|
+
- test/ruby/bit_struct/test_struct_base.rb
|
40
|
+
- Rakefile
|
41
|
+
- Version
|
42
|
+
test_files: []
|
43
|
+
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
extra_rdoc_files: []
|
47
|
+
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
requirements: []
|
53
|
+
|
54
|
+
dependencies: []
|
55
|
+
|