jsanders-bitfields 0.2.4
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/README +0 -0
- data/Rakefile +38 -0
- data/demo.rb +46 -0
- data/lib/bitfields.rb +127 -0
- data/lib/bits.rb +60 -0
- metadata +57 -0
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
rescue Exception
|
4
|
+
puts 'RubyGems is not installed. See http://www.rubygems.org/read/chapter/3 for instructions.'
|
5
|
+
end
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
|
10
|
+
Spec::Rake::SpecTask.new do |t|
|
11
|
+
t.spec_opts = ['-c']
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
14
|
+
t.rcov = true
|
15
|
+
end
|
16
|
+
rescue Exception
|
17
|
+
puts 'RSpec not available. Install it with: sudo gem install rspec'
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'jeweler'
|
22
|
+
Jeweler::Tasks.new do |s|
|
23
|
+
s.name = "bitfields"
|
24
|
+
s.summary = "Simple named bit fields"
|
25
|
+
s.description = "A very simple library for building binary data by declaring named bit fields"
|
26
|
+
s.email = 'sanderjd@gmail.com'
|
27
|
+
s.homepage = 'http://github.com/jsanders/bitfields'
|
28
|
+
s.authors = ['James Sanders']
|
29
|
+
s.has_rdoc = true
|
30
|
+
s.files = ["README",
|
31
|
+
"Rakefile",
|
32
|
+
"demo.rb",
|
33
|
+
"lib/bitfields.rb",
|
34
|
+
"lib/bits.rb"]
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
puts 'Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com'
|
38
|
+
end
|
data/demo.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/lib/bitfields'
|
2
|
+
|
3
|
+
# Make a template
|
4
|
+
BitFields.template :demo do |m|
|
5
|
+
m.bits :beginning, :length => 10, :value => 0b1010101010
|
6
|
+
m.bits :middle, :length => 5
|
7
|
+
m.bits :end, :length => 10, :value => 1
|
8
|
+
end
|
9
|
+
|
10
|
+
# Create an object with that template
|
11
|
+
message = BitFields.create(:demo)
|
12
|
+
|
13
|
+
# 1010101010000000000000001
|
14
|
+
puts message.bit_string
|
15
|
+
|
16
|
+
# Create an object with that template and give it parameters
|
17
|
+
message = BitFields.create(:demo, :middle => 0b11111)
|
18
|
+
|
19
|
+
# 1010101010111110000000001
|
20
|
+
puts message.bit_string
|
21
|
+
# 1557c01
|
22
|
+
puts message.hex_string
|
23
|
+
# 125276001
|
24
|
+
puts message.oct_string
|
25
|
+
# 22379521
|
26
|
+
puts message.integer
|
27
|
+
|
28
|
+
# Compose another message using this object as one of its fields
|
29
|
+
new_message = BitFields.compose do |m|
|
30
|
+
m.bits :before, :length => 1, :value => 1
|
31
|
+
m.add :demo__message, message
|
32
|
+
m.bits :after, :length => 1, :value => 0
|
33
|
+
end
|
34
|
+
|
35
|
+
# 110101010101111100000000010
|
36
|
+
puts new_message.bit_string
|
37
|
+
|
38
|
+
# Compose another message without creating the original message
|
39
|
+
newer_message = BitFields.compose do |m|
|
40
|
+
m.bits :before, :length => 1, :value => 1
|
41
|
+
m.bring :demo, :middle => 0
|
42
|
+
m.bits :after, :length => 1, :value => 0
|
43
|
+
end
|
44
|
+
|
45
|
+
# 110101010100000000000000010
|
46
|
+
puts newer_message.bit_string
|
data/lib/bitfields.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/bits'
|
2
|
+
|
3
|
+
class BitFields
|
4
|
+
|
5
|
+
# Class methods
|
6
|
+
|
7
|
+
def self.template(template_name, &block)
|
8
|
+
template_name = symbol_if_string(template_name)
|
9
|
+
templates[template_name] = block
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.create(template_name, params = {})
|
14
|
+
template_name = symbol_if_string(template_name)
|
15
|
+
if templates[template_name]
|
16
|
+
instance = self.new
|
17
|
+
templates[template_name].call(instance)
|
18
|
+
params.each_pair { | field_name, value | instance[field_name] = value }
|
19
|
+
instance
|
20
|
+
else
|
21
|
+
warn "BitFields: No template named #{template_name}"
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.decode(template_name, value)
|
27
|
+
template_name = symbol_if_string(template_name)
|
28
|
+
if templates[template_name]
|
29
|
+
instance = self.new
|
30
|
+
templates[template_name].call(instance)
|
31
|
+
bit_string = Bits.new(value, instance.total_length).bit_string
|
32
|
+
current_index = 0
|
33
|
+
instance.field_names.each_with_index do |field_name, index|
|
34
|
+
length = instance.field_lengths[index]
|
35
|
+
instance[field_name] = bit_string[current_index, length].to_i(2)
|
36
|
+
current_index += length
|
37
|
+
end
|
38
|
+
instance
|
39
|
+
else
|
40
|
+
warn "BitFields: No template named #{template_name}"
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.compose(&block)
|
46
|
+
composition = self.new
|
47
|
+
yield composition
|
48
|
+
composition
|
49
|
+
end
|
50
|
+
|
51
|
+
# Object methods
|
52
|
+
|
53
|
+
def integer; get_bits.integer end
|
54
|
+
def bit_string; get_bits.bit_string end
|
55
|
+
def hex_string; get_bits.hex_string end
|
56
|
+
def oct_string; get_bits.oct_string end
|
57
|
+
|
58
|
+
def total_length
|
59
|
+
field_lengths.inject { |total, length| total + length }
|
60
|
+
end
|
61
|
+
|
62
|
+
def add(field_name, instance)
|
63
|
+
field_name = BitFields.symbol_if_string(field_name)
|
64
|
+
if instance
|
65
|
+
field_names << field_name
|
66
|
+
field_values << instance.get_bits
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def bring(template_name, params = {})
|
71
|
+
template_name = BitFields.symbol_if_string(template_name)
|
72
|
+
instance = BitFields.create(template_name, params)
|
73
|
+
if instance
|
74
|
+
field_names << template_name
|
75
|
+
field_values << instance.get_bits
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def bits(field_name, params = {})
|
80
|
+
field_name = BitFields.symbol_if_string(field_name)
|
81
|
+
value = params.key?(:value) ? params[:value] : 0
|
82
|
+
length = params.key?(:length) ? params[:length] : 0
|
83
|
+
field_names << field_name
|
84
|
+
field_values << Bits.new(value, length)
|
85
|
+
field_lengths << length
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_bits
|
89
|
+
field_values.inject(nil) do |final, value|
|
90
|
+
final ? final + value : value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def [](field_name)
|
95
|
+
field_name = BitFields.symbol_if_string(field_name)
|
96
|
+
field_values[field_names.index(field_name)] if field_names.index(field_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def []=(field_name, value)
|
100
|
+
self[field_name].set(value) if self[field_name]
|
101
|
+
end
|
102
|
+
|
103
|
+
def field_names
|
104
|
+
@field_names ||= Array.new
|
105
|
+
end
|
106
|
+
|
107
|
+
def field_values
|
108
|
+
@field_values ||= Array.new
|
109
|
+
end
|
110
|
+
|
111
|
+
def field_lengths
|
112
|
+
@field_lengths ||= Array.new
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def self.templates
|
118
|
+
@@templates ||= Hash.new
|
119
|
+
end
|
120
|
+
|
121
|
+
# Helpers
|
122
|
+
|
123
|
+
def self.symbol_if_string(name)
|
124
|
+
name.kind_of?(String) ? name.to_sym : name
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
data/lib/bits.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Bits provides an easy way to store and access sequences of bits,
|
2
|
+
# allowing input and output in multiple formats
|
3
|
+
|
4
|
+
class Bits
|
5
|
+
|
6
|
+
# +bits+:: The bit field to store
|
7
|
+
# +length+:: Length of the bit field - default to calculated length, 0-pad on
|
8
|
+
# MSB
|
9
|
+
|
10
|
+
def initialize(bits, length = 0)
|
11
|
+
@length = length
|
12
|
+
@bits = bit_string_from_input(bits, length)
|
13
|
+
end
|
14
|
+
|
15
|
+
def +(bits)
|
16
|
+
Bits.new("0b#{@bits}" + bit_string_from_input(bits))
|
17
|
+
end
|
18
|
+
|
19
|
+
def bit_string
|
20
|
+
@bits
|
21
|
+
end
|
22
|
+
|
23
|
+
def hex_string
|
24
|
+
@bits.to_i(2).to_s(16)
|
25
|
+
end
|
26
|
+
|
27
|
+
def oct_string
|
28
|
+
@bits.to_i(2).to_s(8)
|
29
|
+
end
|
30
|
+
|
31
|
+
def integer
|
32
|
+
@bits.to_i(2)
|
33
|
+
end
|
34
|
+
|
35
|
+
def set(bits)
|
36
|
+
@bits = bit_string_from_input(bits, @length)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
attr_reader :bits
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def bit_string_from_input(bits, length = 0)
|
46
|
+
case bits
|
47
|
+
when Integer, Fixnum, Bignum
|
48
|
+
"%0#{length}b" % bits
|
49
|
+
when String
|
50
|
+
"%0#{length}b" % Integer(bits)
|
51
|
+
when Bits
|
52
|
+
bits.bits
|
53
|
+
when BitFields
|
54
|
+
bits.get_bits.bits
|
55
|
+
else
|
56
|
+
warn "Unsupported data #{bits} (#{bits.class}) - defaulting to #{length} length zero field"
|
57
|
+
"%0#{length}b" % 0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jsanders-bitfields
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Sanders
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-23 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A very simple library for building binary data by declaring named bit fields
|
17
|
+
email: sanderjd@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- Rakefile
|
27
|
+
- demo.rb
|
28
|
+
- lib/bitfields.rb
|
29
|
+
- lib/bits.rb
|
30
|
+
has_rdoc: true
|
31
|
+
homepage: http://github.com/jsanders/bitfields
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.2.0
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: Simple named bit fields
|
56
|
+
test_files: []
|
57
|
+
|