bytemapper 1.0.13
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.
- checksums.yaml +7 -0
- data/lib/bytemapper.rb +69 -0
- data/lib/bytemapper/chunk.rb +54 -0
- data/lib/bytemapper/flattenable.rb +35 -0
- data/lib/bytemapper/nameable.rb +21 -0
- data/lib/bytemapper/registry.rb +177 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b7915e2b8be3bcd3f677ed08c5a82e8fd135ab941ff9ab8b04c2148cfc7b8441
|
4
|
+
data.tar.gz: c44bf0499a0d15dc77728770edf55a995a12b00987e76ea651eb249c09f0d2e7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea2aa731fde9ad3ef8f22a08d1b0abfa4de8803e7d7849af1ad1c0aebc9c865640e9e62f1ebc91293025c1b76b21cb5bd1b469d510005dead3a6723a6b4ef314
|
7
|
+
data.tar.gz: 9cbb50a69eea518d210ac6fb7bcaeeb9a74ff8b0e6ad3a9ade5f68988d6839c7d2464e9c276781d45fac856704de011352463c60a3b03d563ff90fec16ccf488
|
data/lib/bytemapper.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Bytemapper - Model arbitrary bytestrings as Ruby objects.
|
2
|
+
# Copyright (C) 2020 Jefferson Hudson
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
6
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
7
|
+
# later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module Bytemapper
|
18
|
+
require 'bytemapper/registry'
|
19
|
+
require 'bytemapper/nameable'
|
20
|
+
require 'bytemapper/flattenable'
|
21
|
+
require 'bytemapper/chunk'
|
22
|
+
|
23
|
+
@@registry = Registry.new
|
24
|
+
|
25
|
+
def self.wrap(obj, name = nil, wrapper = {})
|
26
|
+
if (obj.is_a?(Array) || obj.is_a?(String) || obj.is_a?(Symbol))
|
27
|
+
obj = registry.get(obj, name)
|
28
|
+
raise ArgumentError.new "Failed to resolve symbol #{name}" if obj.nil?
|
29
|
+
elsif obj.is_a?(Hash)
|
30
|
+
obj.each do |k, v|
|
31
|
+
wrapper[k] = wrap(v, k)
|
32
|
+
wrapper.define_singleton_method(k) { self.send(:fetch, k) }
|
33
|
+
end
|
34
|
+
wrapper.extend(Flattenable)
|
35
|
+
obj = registry.put(wrapper, name)
|
36
|
+
else
|
37
|
+
raise ArgumentError.new "Invalid object"
|
38
|
+
end
|
39
|
+
obj
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.map(bytes, shape, name = nil)
|
43
|
+
bytes.force_encoding(Encoding::ASCII_8BIT)
|
44
|
+
bytes = StringIO.new(bytes)
|
45
|
+
wrapper = self.wrap(shape, name)
|
46
|
+
Chunk.new(bytes, wrapper, name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.registry
|
50
|
+
@@registry
|
51
|
+
end
|
52
|
+
|
53
|
+
def reset(with_basic_types = true)
|
54
|
+
[
|
55
|
+
[:uint8_t, [8,'C']],
|
56
|
+
[:bool, [8,'C']],
|
57
|
+
[:uint16_t, [16,'S']],
|
58
|
+
[:uint32_t, [32,'L']],
|
59
|
+
[:uint64_t, [64,'Q']],
|
60
|
+
[:int8_t, [8,'c']],
|
61
|
+
[:int16_t, [16,'s']],
|
62
|
+
[:int32_t, [32,'l']],
|
63
|
+
[:int64_t, [64,'q']]
|
64
|
+
].each do |name, type|
|
65
|
+
@@registry.put(type, name)
|
66
|
+
end
|
67
|
+
@@registry
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Bytemapper - Model arbitrary bytestrings as Ruby objects.
|
2
|
+
# Copyright (C) 2020 Jefferson Hudson
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
6
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
7
|
+
# later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module Bytemapper
|
18
|
+
class Chunk
|
19
|
+
attr_reader :bytes, :shape, :name
|
20
|
+
|
21
|
+
def initialize(bytes, shape, name)
|
22
|
+
@bytes = bytes
|
23
|
+
@shape = shape
|
24
|
+
@name = name
|
25
|
+
|
26
|
+
shape.flatten.each do |k,v|
|
27
|
+
singleton_class.instance_eval { attr_reader k }
|
28
|
+
instance_variable_set("@#{k.to_s}", unpack(v))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def string
|
33
|
+
bytes.string
|
34
|
+
end
|
35
|
+
|
36
|
+
def ord
|
37
|
+
bytes.string.split(//).map(&:ord)
|
38
|
+
end
|
39
|
+
|
40
|
+
def chr
|
41
|
+
bytes.string.split(//).map(&:chr)
|
42
|
+
end
|
43
|
+
|
44
|
+
def size
|
45
|
+
@bytes.size
|
46
|
+
end
|
47
|
+
|
48
|
+
def unpack(value, endian = nil)
|
49
|
+
num_bytes, flag = value
|
50
|
+
_bytes = bytes.read(num_bytes >> 3)
|
51
|
+
_bytes.unpack("#{flag}#{endian}")[0] unless _bytes.nil?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Bytemapper - Model arbitrary bytestrings as Ruby objects.
|
2
|
+
# Copyright (C) 2020 Jefferson Hudson
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
6
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
7
|
+
# later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module Bytemapper
|
18
|
+
module Flattenable
|
19
|
+
def flatten(flattened = {}, prefix = nil)
|
20
|
+
each do |k,v|
|
21
|
+
k = prefix.nil? ? k : "#{prefix}_#{k}".to_sym
|
22
|
+
if v.is_a?(Hash)
|
23
|
+
v.flatten(flattened, k)
|
24
|
+
else
|
25
|
+
flattened[k] = v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
flattened
|
29
|
+
end
|
30
|
+
|
31
|
+
def size
|
32
|
+
flatten.values.map(&:first).reduce(:+) >> 3
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Bytemapper - Model arbitrary bytestrings as Ruby objects.
|
2
|
+
# Copyright (C) 2020 Jefferson Hudson
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
6
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
7
|
+
# later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
module Bytemapper
|
17
|
+
module Nameable
|
18
|
+
attr_accessor :names
|
19
|
+
alias :name :names
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# Bytemapper - Model arbitrary bytestrings as Ruby objects.
|
2
|
+
# Copyright (C) 2020 Jefferson Hudson
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU Affero General Public License as published by the Free
|
6
|
+
# Software Foundation, either version 3 of the License, or (at your option) any
|
7
|
+
# later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
12
|
+
# details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
module Bytemapper
|
17
|
+
class Registry
|
18
|
+
require 'bytemapper/nameable'
|
19
|
+
|
20
|
+
attr_reader :names
|
21
|
+
attr_reader :objects
|
22
|
+
|
23
|
+
def initialize(with_basic_types = true)
|
24
|
+
@objects = {}
|
25
|
+
@names = {}
|
26
|
+
register_basic_types unless with_basic_types == false
|
27
|
+
end
|
28
|
+
|
29
|
+
def empty?
|
30
|
+
@objects.size.zero? && @names.size.zero?
|
31
|
+
end
|
32
|
+
|
33
|
+
def flush
|
34
|
+
@objects = {}
|
35
|
+
@names = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def registered?(obj)
|
39
|
+
names.key?(obj) || objects.key?(obj.hash)
|
40
|
+
end
|
41
|
+
|
42
|
+
def get(obj, name = nil)
|
43
|
+
if (obj.is_a?(String) || obj.is_a?(Symbol))
|
44
|
+
name = obj
|
45
|
+
key = @names[obj]
|
46
|
+
elsif (obj.is_a?(Array) || obj.is_a?(Hash))
|
47
|
+
put(obj, name)
|
48
|
+
key = obj.hash
|
49
|
+
else
|
50
|
+
raise ArgumentError "Invalid obj"
|
51
|
+
end
|
52
|
+
@objects[key]
|
53
|
+
end
|
54
|
+
|
55
|
+
def put(obj, name = nil)
|
56
|
+
obj = register_obj(obj)
|
57
|
+
register_name(obj, name)
|
58
|
+
obj
|
59
|
+
end
|
60
|
+
|
61
|
+
def registered_name?(name)
|
62
|
+
@names.key?(name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def registered_obj?(obj)
|
66
|
+
@objects.key?(obj.hash)
|
67
|
+
end
|
68
|
+
|
69
|
+
def register_obj(obj)
|
70
|
+
unless registered_obj?(obj)
|
71
|
+
obj.extend(Nameable)
|
72
|
+
obj.names = Set.new
|
73
|
+
end
|
74
|
+
@objects[obj.hash] ||= obj
|
75
|
+
end
|
76
|
+
|
77
|
+
def register_name(obj, name)
|
78
|
+
unless name.nil?
|
79
|
+
if registered_name?(name) && get(name) != obj
|
80
|
+
raise ArgumentError.new 'Name is already registered'
|
81
|
+
else
|
82
|
+
name = name.to_sym
|
83
|
+
@names[name] ||= obj.hash
|
84
|
+
obj.names << name
|
85
|
+
end
|
86
|
+
end
|
87
|
+
obj
|
88
|
+
end
|
89
|
+
|
90
|
+
def print
|
91
|
+
puts to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_s
|
95
|
+
return "" if @objects.empty?
|
96
|
+
|
97
|
+
# Buffer to build up output.
|
98
|
+
buf = StringIO.new
|
99
|
+
|
100
|
+
# Calculate the width of each column.
|
101
|
+
widths = [
|
102
|
+
@names.keys.size.zero? ? 0 : @names.keys.map(&:size).max + 1, # add space for the `:`
|
103
|
+
7, # length of ID to print
|
104
|
+
@objects.values.map { |o| o.class.to_s.size }.max,
|
105
|
+
@objects.values.map { |v| v.to_s.size }.max
|
106
|
+
]
|
107
|
+
|
108
|
+
# Add an extra space at the beginning and end of each column.
|
109
|
+
widths = widths.map { |p| p += 2 }
|
110
|
+
|
111
|
+
buf << "+"
|
112
|
+
# Build the header line.
|
113
|
+
widths.each do |w|
|
114
|
+
buf << "#{'-' * w}+"
|
115
|
+
end
|
116
|
+
buf << "\n"
|
117
|
+
|
118
|
+
# Build the rows of the table.
|
119
|
+
@objects.each do |id, obj|
|
120
|
+
names = @names.filter { |k,v| v == id }.keys
|
121
|
+
names << '' if names.empty?
|
122
|
+
# Create an entry for each object alias.
|
123
|
+
names.each do |name|
|
124
|
+
buf << "|"
|
125
|
+
|
126
|
+
# Fixup the id string so it pads nicely
|
127
|
+
idstr = id.positive? ? id.to_s[..5] : id.to_s[..6]
|
128
|
+
idstr = id.positive? ? " #{idstr}" : " #{idstr}"
|
129
|
+
|
130
|
+
# Wrap each column value with whitespace.
|
131
|
+
values = [
|
132
|
+
name.empty? ? name : " :#{name} ",
|
133
|
+
idstr,
|
134
|
+
" #{obj.class.to_s} ",
|
135
|
+
" #{obj.to_s} "
|
136
|
+
]
|
137
|
+
|
138
|
+
# Calculate padding for each column.
|
139
|
+
pads = widths.zip(values).map { |a,b| a - b.size }
|
140
|
+
|
141
|
+
values.size.times do |i|
|
142
|
+
buf << "#{values[i]}#{' '*pads[i]}|"
|
143
|
+
end
|
144
|
+
buf << "\n"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Build the trailing line.
|
149
|
+
buf << "+"
|
150
|
+
widths.each do |w|
|
151
|
+
buf << "#{'-' * w}+"
|
152
|
+
end
|
153
|
+
buf << "\n"
|
154
|
+
buf.string
|
155
|
+
end
|
156
|
+
|
157
|
+
def reset(with_basic_types = true)
|
158
|
+
flush
|
159
|
+
register_basic_types unless with_basic_types == false
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
def register_basic_types
|
164
|
+
[
|
165
|
+
[:uint8_t, [8,'C']],
|
166
|
+
[:bool, [8,'C']],
|
167
|
+
[:uint16_t, [16,'S']],
|
168
|
+
[:uint32_t, [32,'L']],
|
169
|
+
[:uint64_t, [64,'Q']],
|
170
|
+
[:int8_t, [8,'c']],
|
171
|
+
[:int16_t, [16,'s']],
|
172
|
+
[:int32_t, [32,'l']],
|
173
|
+
[:int64_t, [64,'q']]
|
174
|
+
].each { |name, type| put(type, name) }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bytemapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.13
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jefferson Hudson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-26 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Model and interact with bytestrings using Ruby objects.
|
14
|
+
email: jefferson.hudson@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/bytemapper.rb
|
20
|
+
- lib/bytemapper/chunk.rb
|
21
|
+
- lib/bytemapper/flattenable.rb
|
22
|
+
- lib/bytemapper/nameable.rb
|
23
|
+
- lib/bytemapper/registry.rb
|
24
|
+
homepage: https://github.com/l4cr0ss/bytemapper
|
25
|
+
licenses:
|
26
|
+
- AGPL-3.0-or-later
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubygems_version: 3.1.3
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: Map byte strings to Ruby objects
|
47
|
+
test_files: []
|