bytemapper 1.0.13
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|