bytemapper 1.0.18 → 1.0.25

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ac5e3c1befb8f914bd5a4f84d6ce7cb9a41a3f0b451153bc797ab9e6ed848cd
4
- data.tar.gz: bba2cd9d3cd7b2361ace18ff87c20783e3545ad1bda12338ae3dc757a6f186f8
3
+ metadata.gz: dce11df6e4ad42a1c8a81853d2e9188fd9a3caaa02692ef12a58dedcae33e296
4
+ data.tar.gz: f95e339d989e6346651cc45d07ca0ae1ffd55e2b0a8bd0071b0014b28aa9868c
5
5
  SHA512:
6
- metadata.gz: 4b13d9d92f750f0354ee3c60be0ac549c132ab071cfc9aed010cb42365ec40416056e1ccde03a9cda8b705b798e47d6d24c2bf90e5933ee202a8ba1337037659
7
- data.tar.gz: a6b93b9463f1b0b4335587e3f33566547ec750dfb88906c5054bcb2862a7835f0e62387827ee0a6de76443dd78c28ae9c2dec6875d29bcf559aa1ba15f845ab9
6
+ metadata.gz: 56c5919a1f298fe359eb3931e941965ac43d003ddf2691c2b93394ca8b0dbdba88ef9b64c55cdda5d0902ac148776bfcc6f6aa7c45d43d6320d5a5f028c0cbfd
7
+ data.tar.gz: '0698b1a5cc71653eb4044f920f4e4428244c88a8cc08ec22c72324e9943efdbbf0e1c7ec7da91bd319c61fdd3c4a3f9e9271889098f503fbb4f3ad52f112d03c'
@@ -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,118 @@
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
56
71
 
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)
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)
70
95
  end
71
- @@registry
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
112
+
113
+ def reset(with_basic_types = true)
114
+ @@registry = Registry.new(with_basic_types)
115
+ end
116
+
117
+ def reverse_lookup(prefix, value = nil)
118
+ @@rl_cache ||= {}
119
+ prefix = "#{prefix.to_s}_"
120
+ lookup = @@rl_cache[prefix]
121
+
122
+ if lookup.nil?
123
+ labels = names.filter { |n| n.start_with?(prefix) }
124
+ values = labels.map { |l| get(l) }
125
+ lookup = Hash[values.zip(labels)]
126
+ @@rl_cache[prefix] = lookup
127
+ end
128
+
129
+ value.nil? ? lookup : lookup[value]
130
+ end
131
+
72
132
  end
73
133
  end
@@ -15,20 +15,32 @@
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
17
  module Bytemapper
18
- class Chunk
19
- attr_reader :bytes, :shape, :name
18
+ require 'bytemapper/flattenable'
19
+ class Chunk < Hash
20
+ include Nameable
21
+ include Flattenable
22
+ attr_reader :bytes, :shape
20
23
 
21
24
  def initialize(bytes, shape, name)
22
25
  @name = name
23
26
  @shape = shape
24
- @bytes = bytes
25
- bytes.truncate(shape.size)
26
-
27
- shape.flatten.each do |k,v|
27
+ @bytes = bytes.is_a?(StringIO) ? bytes : StringIO.new(bytes)
28
+ replace(shape)
29
+ each_pair do |k,v|
30
+ self[k] = if v.is_a?(Hash)
31
+ Chunk.new(@bytes.read(v.size), v, k)
32
+ elsif v.is_a?(Bytemapper::Table)
33
+ if v.unbounded?
34
+ v.populate(@bytes.read(@bytes.size-@bytes.pos))
35
+ else
36
+ v.populate(@bytes.read(v.capacity))
37
+ end
38
+ else
39
+ unpack(v)
40
+ end
28
41
  singleton_class.instance_eval { attr_reader k }
29
- instance_variable_set("@#{k.to_s}", unpack(v))
42
+ instance_variable_set("@#{k.to_s}", self[k])
30
43
  end
31
-
32
44
  end
33
45
 
34
46
  def string
@@ -43,10 +55,22 @@ module Bytemapper
43
55
  bytes.string.split(//).map(&:chr)
44
56
  end
45
57
 
58
+ def capacity
59
+ shape.size
60
+ end
61
+
46
62
  def size
47
63
  bytes.size
48
64
  end
49
65
 
66
+ def consumed
67
+ size
68
+ end
69
+
70
+ def remaining
71
+ capacity - consumed
72
+ end
73
+
50
74
  def unpack(value, endian = nil)
51
75
  num_bytes, flag = value
52
76
  _bytes = bytes.read(num_bytes >> 3)
@@ -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.18
4
+ version: 1.0.25
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