bytemapper 1.0.17 → 1.0.24

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e83e24f91a93a229feb0aefbc769f469d3c04639baded6da987c8920388a624
4
- data.tar.gz: dd471d77244ab576b965ece2235671a5ff2c0ea988bc60bc3465738eed8c0aea
3
+ metadata.gz: ea6f9b415c3147f7af5584a41f5f6c49dbe68fd7137771e6930bba37c8164400
4
+ data.tar.gz: c40ea7b989e39da462f13a2a9e43730eb8efdfdf5e5b4053d0c4d9ffd1eecd43
5
5
  SHA512:
6
- metadata.gz: 5679654a7fc750634f1c31fe17b777ea5345ada747ee40999e67da94feef825a63a4c8b54c6399e6425d3f63518be2a1b5e7cc803c2025c77045306147448194
7
- data.tar.gz: bbc2a75a19432d23122a8c1bf8b88759609fc9a0367e4803a71c063260e7262db8067d890086c22dc12a0fe14b2fc6e4fcbc69aa6907a6b641a582d56cd0d3e9
6
+ metadata.gz: dfbbbd391b56398a95d77bb2e0777241684f4621d0d16a782af0dde25c10afa186817839e01ef659c15aa7b1a46ed7aab0c6a5811c08e8cc15b51fef0ec8ff41
7
+ data.tar.gz: 8c6e57cdf80bb6b921444a5b4d48ee56b682644534d411e9079fc7551018ed692415caa72066588d90c7966816bdc3ad7ee89600beca782afcace6656932f14a
@@ -1,4 +1,4 @@
1
- # Bytemapper - Model arbitrary bytestrings as Ruby objects.
1
+ # Bytemapper - Model arbitrary bytestrings as Ruby objects.
2
2
  # Copyright (C) 2020 Jefferson Hudson
3
3
  #
4
4
  # This program is free software: you can redistribute it and/or modify it under
@@ -16,58 +16,102 @@
16
16
 
17
17
  module Bytemapper
18
18
  require 'bytemapper/registry'
19
+ require 'bytemapper/shape'
20
+ require 'bytemapper/type'
19
21
  require 'bytemapper/nameable'
20
- require 'bytemapper/flattenable'
21
22
  require 'bytemapper/chunk'
23
+ require 'bytemapper/table'
22
24
 
23
25
  @@registry = Registry.new
24
26
 
25
- def self.wrap(obj, name = nil, wrapper = {})
26
- _wrap(obj, name, wrapper)
27
- end
27
+ class << self
28
28
 
29
- def self._wrap(obj, name = nil, wrapper = {})
30
- if (obj.is_a?(Array) || obj.is_a?(String) || obj.is_a?(Symbol))
31
- obj = registry.get(obj, name)
32
- raise ArgumentError.new "Object must not be nil" if obj.nil?
33
- elsif obj.is_a?(Hash)
34
- obj.each do |k, v|
35
- wrapper[k] = _wrap(v, k)
36
- wrapper.define_singleton_method(k) { self.send(:fetch, k) }
29
+ def register(obj, name, fqname = [])
30
+ return if obj.nil?
31
+ name = name.downcase.to_sym unless name.nil?
32
+ fqname << name unless name.nil?
33
+ if is_a_type?(obj)
34
+ name = fqname.size > 1 ? fqname.join('.') : fqname.first
35
+ obj = Type.new(obj)
36
+ put(obj, name)
37
+ elsif is_a_name?(obj)
38
+ register(get(obj), nil, fqname)
39
+ elsif is_a_shape?(obj)
40
+ if registered?(obj)
41
+ obj = get(obj)
42
+ put(obj, name)
43
+ else
44
+ shape = Shape.new
45
+ obj.each do |k,v|
46
+ shape[k] = register(v, k, [].concat(fqname))
47
+ end
48
+ put(shape, name)
49
+ end
50
+ else
51
+ put(obj, name)
37
52
  end
38
- wrapper.extend(Flattenable)
39
- obj = registry.put(wrapper, name)
40
- else
41
- raise ArgumentError.new "Invalid object"
42
53
  end
43
- obj
44
- end
54
+ alias :wrap :register
45
55
 
46
- def self.map(bytes, shape, name = nil)
47
- bytes.force_encoding(Encoding::ASCII_8BIT)
48
- bytes = StringIO.new(bytes)
49
- wrapper = self.wrap(shape, name)
50
- Chunk.new(bytes, wrapper, name)
51
- end
56
+ def is_a_type?(obj)
57
+ obj.is_a?(Type) ||
58
+ obj.is_a?(Array) &&
59
+ obj.size == 2 &&
60
+ obj.first.is_a?(Integer) &&
61
+ obj.last.is_a?(String)
62
+ end
52
63
 
53
- def self.registry
54
- @@registry
55
- end
64
+ def is_a_shape?(obj)
65
+ obj.is_a?(Hash)
66
+ end
67
+
68
+ def is_a_name?(obj)
69
+ obj.is_a?(String) || obj.is_a?(Symbol)
70
+ end
71
+
72
+ def map(bytes, shape, name = nil)
73
+ bytes.force_encoding(Encoding::ASCII_8BIT)
74
+ bytes = StringIO.new(bytes)
75
+ if shape.is_a?(Array)
76
+ chunks = []
77
+ shape.each { |s| chunks << Chunk.new(bytes.read(s.size), s, name) }
78
+ chunks
79
+ else
80
+ shape = wrap(shape, name)
81
+ Chunk.new(bytes, shape, name)
82
+ end
83
+ end
84
+
85
+ def repeat(obj, times = nil)
86
+ Table.new(obj, times)
87
+ end
88
+
89
+ def registered?(obj)
90
+ registry.registered?(obj)
91
+ end
92
+
93
+ def get(obj)
94
+ registry.get(obj)
95
+ end
96
+
97
+ def put(obj, name)
98
+ registry.put(obj, name)
99
+ end
100
+
101
+ def names(filter_key = nil)
102
+ registry.names.keys
103
+ end
104
+
105
+ def print
106
+ registry.print
107
+ end
108
+
109
+ def registry
110
+ @@registry
111
+ end
56
112
 
57
- def reset(with_basic_types = true)
58
- [
59
- [:uint8_t, [8,'C']],
60
- [:bool, [8,'C']],
61
- [:uint16_t, [16,'S']],
62
- [:uint32_t, [32,'L']],
63
- [:uint64_t, [64,'Q']],
64
- [:int8_t, [8,'c']],
65
- [:int16_t, [16,'s']],
66
- [:int32_t, [32,'l']],
67
- [:int64_t, [64,'q']]
68
- ].each do |name, type|
69
- @@registry.put(type, name)
113
+ def reset(with_basic_types = true)
114
+ @@registry = Registry.new(with_basic_types)
70
115
  end
71
- @@registry
72
116
  end
73
117
  end
@@ -15,17 +15,30 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  module Bytemapper
18
- class Chunk
18
+ require 'bytemapper/flattenable'
19
+ class Chunk < Hash
20
+ include Flattenable
19
21
  attr_reader :bytes, :shape, :name
20
22
 
21
23
  def initialize(bytes, shape, name)
22
- @bytes = bytes
23
- @shape = shape
24
24
  @name = name
25
-
26
- shape.flatten.each do |k,v|
25
+ @shape = shape
26
+ @bytes = bytes.is_a?(StringIO) ? bytes : StringIO.new(bytes)
27
+ replace(shape)
28
+ each_pair do |k,v|
29
+ self[k] = if v.is_a?(Hash)
30
+ Chunk.new(@bytes.read(v.size), v, k)
31
+ elsif v.is_a?(Bytemapper::Table)
32
+ if v.unbounded?
33
+ v.populate(@bytes.read(@bytes.size-@bytes.pos))
34
+ else
35
+ v.populate(@bytes.read(v.capacity))
36
+ end
37
+ else
38
+ unpack(v)
39
+ end
27
40
  singleton_class.instance_eval { attr_reader k }
28
- instance_variable_set("@#{k.to_s}", unpack(v))
41
+ instance_variable_set("@#{k.to_s}", self[k])
29
42
  end
30
43
  end
31
44
 
@@ -41,8 +54,20 @@ module Bytemapper
41
54
  bytes.string.split(//).map(&:chr)
42
55
  end
43
56
 
57
+ def capacity
58
+ shape.size
59
+ end
60
+
44
61
  def size
45
- @bytes.size
62
+ bytes.size
63
+ end
64
+
65
+ def consumed
66
+ size
67
+ end
68
+
69
+ def remaining
70
+ capacity - consumed
46
71
  end
47
72
 
48
73
  def unpack(value, endian = nil)
@@ -21,6 +21,8 @@ module Bytemapper
21
21
  k = prefix.nil? ? k : "#{prefix}_#{k}".to_sym
22
22
  if v.is_a?(Hash)
23
23
  v.flatten(flattened, k)
24
+ elsif v.is_a?(Bytemapper::Table)
25
+ v.each_with_index { |e,i| e.flatten(flattened, i) }
24
26
  else
25
27
  flattened[k] = v
26
28
  end
@@ -5,17 +5,22 @@
5
5
  # the terms of the GNU Affero General Public License as published by the Free
6
6
  # Software Foundation, either version 3 of the License, or (at your option) any
7
7
  # later version.
8
-
8
+ #
9
9
  # This program is distributed in the hope that it will be useful, but WITHOUT
10
10
  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
11
  # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
12
12
  # details.
13
-
13
+ #
14
14
  # You should have received a copy of the GNU Affero General Public License
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
16
17
  module Bytemapper
17
18
  module Nameable
19
+ attr_reader :name
18
20
  attr_accessor :names
19
- alias :name :names
21
+
22
+ def name=(val)
23
+ @name ||= val.to_sym
24
+ end
20
25
  end
21
26
  end
@@ -1,4 +1,4 @@
1
- # Bytemapper - Model arbitrary bytestrings as Ruby objects.
1
+ # Bytemapper - Model arbitrary bytestrings as Ruby objects.
2
2
  # Copyright (C) 2020 Jefferson Hudson
3
3
  #
4
4
  # This program is free software: you can redistribute it and/or modify it under
@@ -37,53 +37,58 @@ module Bytemapper
37
37
  end
38
38
 
39
39
  def registered?(obj)
40
- names.key?(obj) || objects.key?(obj.hash)
40
+ v = registered_name?(obj) if obj.respond_to?(:to_sym)
41
+ v || registered_obj?(obj)
41
42
  end
42
43
 
43
- def get(obj, name = nil)
44
- if (obj.is_a?(String) || obj.is_a?(Symbol))
45
- # Object assumed to be a registered name
46
- obj = @objects.fetch(@names[obj])
47
- register_alias(obj, name) unless name.nil?
48
- elsif (obj.is_a?(Array) || obj.is_a?(Hash))
49
- obj = put(obj, name)
44
+ def get(obj)
45
+ if registered_name?(obj)
46
+ obj = obj.to_sym.downcase
47
+ @objects.fetch(@names[obj]) unless obj.nil?
48
+ elsif registered_obj?(obj)
49
+ @objects.fetch(obj.hash)
50
50
  else
51
- raise ArgumentError "Invalid obj"
51
+ nil
52
52
  end
53
- obj
54
53
  end
55
54
 
56
55
  def put(obj, name = nil)
57
56
  obj = register_obj(obj)
58
- register_name(obj, name)
57
+ register_name(obj, name) unless name.nil?
59
58
  obj
60
59
  end
61
60
 
62
61
  def registered_name?(name)
63
- @names.key?(name)
62
+ if name.respond_to?(:to_sym)
63
+ name = name.to_sym.downcase
64
+ @names.key?(name)
65
+ else
66
+ false
67
+ end
64
68
  end
65
69
 
66
70
  def registered_obj?(obj)
67
- @objects.key?(obj.hash)
71
+ @objects.key?(obj.hash)
68
72
  end
69
73
 
70
74
  def register_obj(obj)
71
75
  unless registered_obj?(obj)
72
- obj.extend(Nameable)
73
- obj.names = Set.new
76
+ begin
77
+ obj.extend(Nameable)
78
+ obj.names = Set.new
79
+ rescue TypeError
80
+ end
74
81
  end
75
82
  @objects[obj.hash] ||= obj
76
83
  end
77
84
 
78
85
  def register_name(obj, name)
79
- unless name.nil?
80
- if registered_name?(name) && get(name) != obj
81
- raise ArgumentError.new 'Name is already registered'
82
- else
83
- name = name.to_sym
84
- @names[name] ||= obj.hash
85
- obj.names << name
86
- end
86
+ if registered_name?(name) && get(name) != obj
87
+ raise ArgumentError.new 'Name is already registered'
88
+ else
89
+ name = name.to_sym.downcase
90
+ @names[name] ||= obj.hash
91
+ obj.names << name if obj.respond_to?(:names)
87
92
  end
88
93
  obj
89
94
  end
@@ -99,7 +104,7 @@ module Bytemapper
99
104
  # Buffer to build up output.
100
105
  buf = StringIO.new
101
106
 
102
- # Calculate the width of each column.
107
+ # Calculate the true max width of each column.
103
108
  widths = [
104
109
  @names.keys.size.zero? ? 0 : @names.keys.map(&:size).max + 1, # add space for the `:`
105
110
  7, # length of ID to print
@@ -107,6 +112,10 @@ module Bytemapper
107
112
  @objects.values.map { |v| v.to_s.size }.max
108
113
  ]
109
114
 
115
+ # Truncate more than `max_width` num chars
116
+ max_width = 60
117
+ widths = widths.map { |w| w > max_width ? max_width : w }
118
+
110
119
  # Add an extra space at the beginning and end of each column.
111
120
  widths = widths.map { |p| p += 2 }
112
121
 
@@ -127,21 +136,29 @@ module Bytemapper
127
136
 
128
137
  # Fixup the id string so it pads nicely
129
138
  idstr = id.positive? ? id.to_s[..5] : id.to_s[..6]
130
- idstr = id.positive? ? " #{idstr}" : " #{idstr}"
139
+ idstr = id.positive? ? " #{idstr}" : "#{idstr}"
131
140
 
132
- # Wrap each column value with whitespace.
141
+ # Generate the column values
133
142
  values = [
134
- name.empty? ? name : " :#{name} ",
135
- idstr,
136
- " #{obj.class.to_s} ",
137
- " #{obj.to_s} "
143
+ name.empty? ? name : ":#{name}",
144
+ idstr,
145
+ "#{obj.class.to_s}",
146
+ "#{obj.to_s}"
138
147
  ]
139
148
 
140
- # Calculate padding for each column.
141
- pads = widths.zip(values).map { |a,b| a - b.size }
149
+ # Pad the values to fit in their respective columns, truncating as
150
+ # needed to stay within `max_width`
151
+ values = widths.zip(values).map do |w,v|
152
+ q = w - v.size
153
+ if q < 2
154
+ " #{v[..w-7]} ... "
155
+ else
156
+ " #{v}#{" "*(q-1)}"
157
+ end
158
+ end
142
159
 
143
160
  values.size.times do |i|
144
- buf << "#{values[i]}#{' '*pads[i]}|"
161
+ buf << "#{values[i]}|"
145
162
  end
146
163
  buf << "\n"
147
164
  end
@@ -164,18 +181,29 @@ module Bytemapper
164
181
  private
165
182
  def register_basic_types
166
183
  [
167
- [:char, [8,'c']],
168
- [:uchar, [8,'C']],
169
184
  [:uint8_t, [8,'C']],
185
+ [:u8, [8,'C']],
186
+ [:uchar, [8,'C']],
170
187
  [:bool, [8,'C']],
171
188
  [:uint16_t, [16,'S']],
189
+ [:u16, [16,'S']],
172
190
  [:uint32_t, [32,'L']],
191
+ [:u32, [32,'L']],
173
192
  [:uint64_t, [64,'Q']],
193
+ [:u64, [64,'Q']],
174
194
  [:int8_t, [8,'c']],
195
+ [:i8, [8,'c']],
196
+ [:char, [8,'c']],
175
197
  [:int16_t, [16,'s']],
198
+ [:i16, [16,'s']],
176
199
  [:int32_t, [32,'l']],
177
- [:int64_t, [64,'q']]
178
- ].each { |name, type| put(type, name) }
200
+ [:i32, [32,'l']],
201
+ [:int64_t, [64,'q']],
202
+ [:i64, [64,'q']]
203
+ ].each do |name, type|
204
+ type = Type.new(type)
205
+ put(type, name)
206
+ end
179
207
  end
180
208
  end
181
209
  end
@@ -0,0 +1,34 @@
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/flattenable'
19
+ require 'bytemapper/nameable'
20
+ class Shape < Hash
21
+ include Flattenable
22
+ include Nameable
23
+
24
+ def []=(k,v)
25
+ super
26
+ singleton_class.instance_eval { attr_reader k }
27
+ instance_variable_set("@#{k.to_s}", self[k])
28
+ end
29
+
30
+ def size
31
+ flatten.values.map(&:size).reduce(:+)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module Bytemapper
2
+ module NilTimes
3
+ refine NilClass do
4
+ def times
5
+ 0
6
+ end
7
+ end
8
+ end
9
+
10
+ class Table < Array
11
+ include Flattenable
12
+ include Nameable
13
+ attr_reader :shape, :rows, :bytes
14
+ using NilTimes
15
+
16
+ def initialize(shape, rows = nil)
17
+ @shape = Bytemapper.get(shape)
18
+ rows.times { self << @shape }
19
+ end
20
+
21
+ def populate(bytes)
22
+ bytes = bytes.nil? ? '' : bytes
23
+ @bytes = bytes.is_a?(StringIO) ? bytes : StringIO.new(bytes)
24
+ @bytes.string.force_encoding(Encoding::ASCII_8BIT)
25
+ if unbounded?
26
+ (bytes.size / shape.size).times { self << @shape }
27
+ end
28
+
29
+ table = Table.new(shape)
30
+ table.clear
31
+ (bytes.size / shape.size).times { table << Chunk.new(@bytes.read(shape.size), shape, shape.name) }
32
+ table
33
+ end
34
+
35
+ def unbounded?
36
+ empty?
37
+ end
38
+
39
+ def size
40
+ empty? ? 0 : map(&:size).reduce(:+)
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,26 @@
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/nameable'
19
+ class Type < Array
20
+ include Nameable
21
+
22
+ def size
23
+ first / 8
24
+ end
25
+ end
26
+ 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
+
17
+ module Bytemapper
18
+ module Typeable
19
+ attr_accessor :type
20
+ end
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bytemapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.17
4
+ version: 1.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jefferson Hudson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-30 00:00:00.000000000 Z
11
+ date: 2020-08-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Model and interact with bytestrings using Ruby objects.
14
14
  email: jefferson.hudson@gmail.com
@@ -21,6 +21,10 @@ files:
21
21
  - lib/bytemapper/flattenable.rb
22
22
  - lib/bytemapper/nameable.rb
23
23
  - lib/bytemapper/registry.rb
24
+ - lib/bytemapper/shape.rb
25
+ - lib/bytemapper/table.rb
26
+ - lib/bytemapper/type.rb
27
+ - lib/bytemapper/typeable.rb
24
28
  homepage: https://github.com/l4cr0ss/bytemapper
25
29
  licenses:
26
30
  - AGPL-3.0-or-later