bit-protocol 1.0.1

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.
Files changed (8) hide show
  1. checksums.yaml +7 -0
  2. data/GEMFILE +2 -0
  3. data/LICENSE +9 -0
  4. data/README.md +112 -0
  5. data/bitop.rb +57 -0
  6. data/bitproto.rb +174 -0
  7. data/bitstream.rb +29 -0
  8. metadata +75 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d3b4bed5a4a0d7557fc41fa9c9a99483284b1d98f4837de98530982fedbbbd71
4
+ data.tar.gz: 9dae1cf57c7cc9cfb90d0d79f80fdbf2196199b8e2087c61295cd1c410132acd
5
+ SHA512:
6
+ metadata.gz: d6c8abc14a7ee4c3f61def944e08dbbf75a3930f41e7d78820a0a086a3504c46040b91079fddc7e9edbae4aafcbeed316fbb68cb968dc96cc9fe0b033e3bc1e6
7
+ data.tar.gz: e4b7f2570af27f2161329bb34b7d708a5c7b2d67e93bfd87112f2f8e0fc40a157ef8982539b20627dbfcdd00f5c400823f2173684729cc820c583295bc75597c
data/GEMFILE ADDED
@@ -0,0 +1,2 @@
1
+
2
+ gem "bitproto", :git=>"https://github.com/ChenMeng1365/bitproto.git"
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ChenMeng1365
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # bitproto
2
+
3
+ 主要用于位操作、位解构和二进制编码。
4
+
5
+ ## BitOp
6
+
7
+ 位操作模块,提供基本二进制比特位的操作。
8
+
9
+ 分组 & 截取:
10
+
11
+ - `stack(num)`将整数按8位分组。
12
+ - `hextack(num)`将整数按4位分组。
13
+ - `seek(bitstream, hidx, tidx, full)`截取比特位串`bitstream`的子串(从`hidx`到`tidx`),`full`设置为字符串省略长度,对超长字符串仅显示部分子串(不影响其值)。
14
+
15
+ 进制转换 & 值面转换:
16
+
17
+ - `hex2bin(num)`对于(十六进制)大整数,按8位二进制分组转换为字符串并连接起来;对于十六进制字符串,按4位二进制分组转换为字符串并连接起来。
18
+ - `bin2hex(num)`对于(二进制)大整数,按1位十六进制分组转换为字符串并连接起来;对于二进制字符串,按1位十六进制分组转换为字符串并连接起来。
19
+ - `bitval(num)`将二进制字符串转换为整数。
20
+ - `hexval(num)`将十六进制字符串转换为整数。
21
+
22
+ ## BitStream
23
+
24
+ 定义了比特位数据流字符串,以整数序列按字节存储。
25
+
26
+ 导入方式 & 值展示方式:
27
+
28
+ - 表值的数字字符串(`:hex`,`:bin`,`:dec`)
29
+ - 原始二进制数据(`:raw`)
30
+ - 整数序列(`:seq`)
31
+
32
+ ## BitMark
33
+
34
+
35
+
36
+ ## BitProtocol
37
+
38
+ 定义了以比特位组织数据的协议,用于对比特位数据流进行解析和编码。
39
+
40
+ ※ 临时实现,建议重写 ※
41
+
42
+ 协议载入方法:
43
+
44
+ - load(path): 读取指定协议(JSON)文件
45
+ - parse(setting,reset_flag): 解析协议(JSON)文档
46
+ - reset(): 重置协议生成树
47
+
48
+ 表达式解析方法:
49
+
50
+ - eval(type, content): 根据类型估值
51
+ - expr(condition): 条件表达式拆分,解析为变量、操作符、值序列
52
+ - var(condition): 条件表达式解析,以`${}`或`$[]`提取变量中的名称
53
+ - words(condition): 条件表达式解析,以`()`提取序列,以`,`分隔子元素
54
+ - oprt(condition): 条件表达式解析,提取`==`、`in`、`exist`等操作符
55
+
56
+ 查询实现方法:
57
+
58
+ - trace(tree,rtree,dom): 字段验证中**查询**的一种实现方法,通过遍历字段值树,构成一组带有实例值的反向查询路径
59
+ - rtrace(tree,key,dom): 字段验证中**查询**的一种实现方法,根据反向查询路径构成一颗反向查询树
60
+
61
+ 估值验证方法:
62
+
63
+ - validate(env): 根据环境变量验证协议生成树,根据验证的当前方式,需要做两次估值检查
64
+ - evaluate(expr): 条件表达式估值,给协议生成树变量赋值
65
+ - verify(verification, should, actual, &process): 根据验证原则和验证方式,判断协议预定值和数据流实际值是否符合
66
+ - finale(criteria, result): 根据验证结果和验证准则设置,判断是否通过验证
67
+ - normal?(report, rule): 输入规则决定协议匹配后是否达成某项协议的正常结果
68
+
69
+ 该模块维持两个存储:`@_bp_`(比特协议数据流)和`@_pt_`(协议生成树)。前者用以将比特位协议文档读取,加载为原生数据;后者负责构建协议树结构,并验证一些检查条件。
70
+
71
+ 比特位协议通过字段定义数据结构和所需维持的规范。
72
+
73
+ 一个转换为JSON格式的原始比特协议数据流字段如下:
74
+
75
+ ```json
76
+ "字段名称": {
77
+ "description": "字段描述",
78
+ "start-bit": 0, // 字段起始位索引
79
+ "finish-bit": 19, // 字段结束位索引
80
+ "type": "HEX", // 字段类型
81
+ "value": { // 字段值
82
+ "字段值": "字段值描述"
83
+ },
84
+ "condition": "字段存在条件", // 字段存在条件
85
+ "verification": "精确匹配", // 字段验证方式
86
+ "criteria": "失败" // 字段验证结果
87
+ },
88
+ ```
89
+
90
+ * 字段名称、字段描述、字段值描述:均为字符串,用以帮助理解该字段含义。
91
+ * 字段起始位索引、字段结束位索引:为非负正整数,指定比特位范围,计数从0开始。
92
+ * 字段类型:字符串,指定字段值的值表示方式。这里的表示方式,是指对数据流解构后,按协议中本处指定的方式进行数据处理,得到的数据值。比如指名为`HEX`,表示获取该字段数据后,以十六进制字符串形式转换数据,再对其进行校验和运算。`HEX`、`BIN`、`DEC`均是字符串,`STR`为无限制字符串,`INT`和`FLT`为整数和浮点数,`PTR`为仅作提取不做展示加工的原始数据,一般用于运算。可以在类型后面标注长度以方便对齐,比如`BIN(4)`、`HEX(2)`等。
93
+ * 字段值:散列对象,键值对表示字段值和其描述。字段值的设定需要和字段类型保持一致,一般一个具体的字段值是枚举值类型的实例,但为了提高匹配效率,也可以通过列表(`Array`)、范围(`Range`)、集合(`Set`)等方式为一类值做归集。还`PTR`类型是个例外,它的值是协议中另外一个字段名称。
94
+ * 字段值验证方式:字符串,指定字段值的验证方式,根据值的指定方式支持逻辑运算、比较运算、集合运算、谓词运算和查询操作,具体谓词见<< Verification >>。其中除了查询是根据值反向查询描述来匹配其含义,其他验证方式均直接对值进行运算并校验。
95
+ * 字段存在条件:字符串,有些场合字段并非必须出现,通过校验该字段是否存在的条件表达式,在估值不成立时不适用该字段。表达式中适用各类运算符甚至函数,使用`$[PTR]`来指向另一个字段并引用其值。
96
+ * 字段值验证结果:字符串,指定字段验证结果的作用,当验证`失败`时,该字段不通过,数据流不匹配协议;当验证`忽略`时,即使字段验证失败,也不影响数据流适用其他的匹配。
97
+
98
+ | Verification | Name | Description |
99
+ | ------------ | ---- | ----------- |
100
+ | AND | 且 | 逻辑 |
101
+ | OR | 或 | 逻辑 |
102
+ | NOT | 非 | 逻辑 |
103
+ | MATCH | 匹配 | 精确 |
104
+ | LESS | 小于 | 精确 |
105
+ | GREATER | 大于 | 精确 |
106
+ | IN | 属于 | 范围 |
107
+ | INCLUDE | 包含 | 范围 |
108
+ | EXIST | 存在 | 限定 |
109
+ | ALL | 全部 | 限定 |
110
+ | QUERY | 查询 | 反向 |
111
+
112
+ << Verification >>
data/bitop.rb ADDED
@@ -0,0 +1,57 @@
1
+
2
+ module BitOp
3
+ module_function
4
+
5
+ def stack num
6
+ sequence, left = [], num
7
+ until left==0
8
+ rest = left & 0b11111111
9
+ left = left >> 8
10
+ sequence.unshift rest
11
+ end
12
+ return sequence
13
+ end
14
+
15
+ def hextack num
16
+ sequence, left = [], num
17
+ until left==0
18
+ rest = left & 0b1111
19
+ left = left >> 4
20
+ sequence.unshift rest
21
+ end
22
+ return sequence
23
+ end
24
+
25
+ def hex2bin num
26
+ return self.stack(num).map{|c|"%08b"%c}.join if num.is_a?(Integer)
27
+ return num.each_char.map{|c|"%04b" % (eval("0x#{c}"))}.join if num.is_a?(String)
28
+ end
29
+
30
+ def bitval num
31
+ eval("0b"+num)
32
+ end
33
+
34
+ def bin2hex num
35
+ return self.hextack(num).map{|c|"%0x"%c}.join if num.is_a?(Integer)
36
+ return num.split('').each_slice(4).map{|c|"%0x"%eval("0b#{c.join}")}.join if num.is_a?(String)
37
+ end
38
+
39
+ def hexval num
40
+ eval("0x"+num)
41
+ end
42
+
43
+ def seek bitstream, head_index=nil, tail_index=nil, full=false
44
+ q = bitstream.val(:seq, full).select{|c|c!='...'}.map{|c|"%08b"%c}.join
45
+ s = 0 if head_index==:first || head_index==nil
46
+ s = q.length + head_index if head_index.is_a?(Integer) && head_index < 0
47
+ s = head_index if head_index.is_a?(Integer) && head_index >= 0
48
+ s = q.length - 1 if head_index.is_a?(Integer) && head_index >= q.length
49
+ e = -1 if tail_index==:last
50
+ e = q.length + tail_index if tail_index.is_a?(Integer) && tail_index < 0
51
+ e = tail_index if tail_index.is_a?(Integer) && tail_index >= 0
52
+ e = q.length - 1 if tail_index.is_a?(Integer) && tail_index >= q.length
53
+ e = s if tail_index==nil || (e.is_a?(Integer) && s.is_a?(Integer) && e < s)
54
+ # p [q, s, e]
55
+ q[s..e]
56
+ end
57
+ end
data/bitproto.rb ADDED
@@ -0,0 +1,174 @@
1
+ require 'bitop'
2
+ require 'bitstream'
3
+
4
+ module BitProtocol
5
+ module_function
6
+
7
+ def load path
8
+ self.reset unless @_pt_
9
+ path = path[-5..-1]=='.json' ? path : path+'.json'
10
+ @_bp_ = JSON.parse File.read(path)
11
+ return @_bp_, @_pt_
12
+ end
13
+
14
+ def parse setting, reset=false
15
+ self.reset if !@_pt_ || reset
16
+ @_bp_ = JSON.parse setting
17
+ return @_bp_, @_pt_
18
+ end
19
+
20
+ def reset
21
+ @_pt_ = {}
22
+ end
23
+
24
+ def validate env={}
25
+ inst, checks,report = env[:instance], [], []
26
+ (puts "Instance of BitProtocol is nil.";return nil) unless inst
27
+ console_log = env[:log]
28
+
29
+ @_bp_.each do|key, set|
30
+ desc = set['description']
31
+ si, ei = set['start-bit'], set['finish-bit']
32
+ type = set['type']
33
+ should = set['value']
34
+
35
+ bits = BitOp.seek(inst, si, ei)
36
+ actual = self.eval(type, bits)
37
+
38
+ cond = set['condition'] ? self.expr(set['condition']) : []
39
+ vrfy = verify(set['verification'], should, actual)
40
+ cert = finale(set['criteria'], vrfy)
41
+
42
+ @_pt_["$[#{key}]"] = actual if self.evaluate(cond) && vrfy
43
+ checks << [key, desc, si, ei, type, should, actual, cond, vrfy, cert]
44
+ end
45
+
46
+ checkz = []
47
+ checks.each do|check|
48
+ key, desc, si, ei, type, should, actual, cond, vrfy, cert = check
49
+ if vrfy && self.evaluate(cond)
50
+ @_pt_["$[#{key}]"] = actual
51
+ end
52
+ checkz << [key, desc, si, ei, type, should, actual, cond, vrfy, cert]
53
+ end
54
+
55
+ checkz.each do|check|
56
+ key, desc, si, ei, type, should, actual, cond, vrfy, cert = check
57
+
58
+ if self.finale(cert, vrfy) && self.evaluate(cond)
59
+ puts "Field #{key} is #{desc}." if console_log
60
+ show = (vrfy && should[actual]) ? should[actual] : (vrfy && vrfy!=true) ? vrfy : ''
61
+ puts "From #{si} to #{ei} is #{actual}, check should be #{!vrfy ? false : true}. >>>> #{show}" if console_log
62
+ unless cond.empty?
63
+ evar = self.evaluate(cond)
64
+ puts "Condition Expression is #{cond}, evaluation is #{evar}." if console_log
65
+ end
66
+ puts Array.new(128){'='}.join if console_log if console_log
67
+
68
+ report << [key.gsub('$[','').gsub(']',''), desc, show, actual, "#{type}[#{si}-#{ei}]"]
69
+ end
70
+ end
71
+
72
+ return report, @_pt_
73
+ end
74
+
75
+ def eval type, content
76
+ return case type
77
+ when 'HEX'; BitOp.bin2hex(content).to_s.upcase
78
+ when 'BIN'; content
79
+ when 'BIN(4)'; Array.new(4-content.length){'0'}.join+content
80
+ # when 'DEC';
81
+ when 'STR'; content
82
+ else; nil
83
+ end
84
+ end
85
+
86
+ def expr condition
87
+ vars = self.var(condition)
88
+ opts = self.oprt(condition)
89
+ words = self.words(condition)
90
+ vars = words.include?(vars) ? vars : vars
91
+ vals = words.include?(opts) ? words[(words.index(opts)+1)..-1] : words
92
+ return [vars, opts, vals]
93
+ end
94
+
95
+ def var condition
96
+ field = condition.to_s.match(/\$(\[|\{){1}(\w[\d|\_|\w]+)+(\]|\}){1}/).to_s
97
+ name = field.empty? ? nil : field.split('{').last.split('}').first
98
+ return name
99
+ end
100
+
101
+ def words condition
102
+ value = condition.to_s.match(/(\(){0,1}.*[\,|.]+.*(\)){0,1}/).to_s
103
+ list = (value.empty? ? condition.split(' ') : value.split('(').last.split(')').first.to_s.split(',')).map{|s|s.strip}
104
+ return list
105
+ end
106
+
107
+ def oprt condition
108
+ return '==' if condition.to_s.include? '=='
109
+ return 'in' if condition.to_s.include? 'in'
110
+ return 'exist' if condition.to_s.include? 'exist'
111
+ return nil
112
+ end
113
+
114
+ def evaluate expr
115
+ vars, opts, vals = expr # vars include $[] here
116
+ # p [vars, @_pt_[vars], opts, vals]
117
+ return case opts
118
+ when '=='; @_pt_[vars] == vals.first
119
+ when 'in'; vals.include?(@_pt_[vars])
120
+ when 'exist'; !!@_pt_[vars]
121
+ else; true
122
+ end
123
+ end
124
+
125
+ def verify verification, should, actual, &process
126
+ return case verification
127
+ when '精确匹配'
128
+ should.keys.include? actual
129
+ when '精确查询'
130
+ locate = self.rtrace(should, actual, '')
131
+ locate ? locate.gsub('/',' ').strip : false
132
+ else
133
+ false
134
+ end
135
+ end
136
+
137
+ def finale criteria, result
138
+ return case criteria
139
+ when '失败'; result
140
+ when '忽略'; !result
141
+ else; result; end
142
+ end
143
+
144
+ def trace tree,rtree,dom=''
145
+ tree.each do|name, node|
146
+ if node.is_a?(Hash)
147
+ rtree = self.trace(node, rtree, "#{dom}/#{name}")
148
+ elsif node.is_a?(Array)
149
+ node.each do|value| # must be an atom
150
+ rtree["#{dom}/#{name}"] = value
151
+ end
152
+ else
153
+ rtree["#{dom}/#{name}"] = node
154
+ end
155
+ end
156
+ return rtree
157
+ end
158
+
159
+ def rtrace tree, key, dom=''
160
+ rsort = self.trace(tree, {}, dom)
161
+ rtree = {}
162
+ rsort.each do|path, val|
163
+ rtree[val]=path
164
+ end
165
+ return rtree[key]
166
+ end
167
+
168
+ def normal? report, rule
169
+ return true if \
170
+ report.map{|r|r[0]}==['PB','AT','PI1','QoS'] && rule=='一般专线地址' ||
171
+ report.map{|r|r[0]}==['PB','AT','PI2','CC'] && rule=='网吧专线地址'
172
+ return false
173
+ end
174
+ end
data/bitstream.rb ADDED
@@ -0,0 +1,29 @@
1
+
2
+ class BitStream
3
+ def initialize option={}
4
+ option.each do|type, value|
5
+ case type.to_s.downcase.to_sym
6
+ when :hex; @stream = BitOp.stack( eval("0x#{value}") )
7
+ when :bin; @stream = BitOp.stack( eval("0b#{value}") )
8
+ when :dec; @stream = BitOp.stack( value.to_i )
9
+ when :raw; @stream = value[0].is_a?(String) ? value.each_byte.map{|c|c.ord} : value
10
+ when :seq; @stream = value[0].is_a?(Integer) ? value : value.each_char.map{|c|c.ord}
11
+ else; @stream = []
12
+ end
13
+ end
14
+ end
15
+
16
+ def val format='hex', full=false # := number of bytes
17
+ return [] if full.is_a?(Integer) && full <= 0
18
+ e = full+1 if full.is_a?(Integer) && full > 0
19
+ e = 1024 if full==false
20
+ t = @stream.length >= e ? '...' : nil
21
+ return case format.to_s.downcase.to_sym
22
+ when :hex; @stream[0..e].map{|c|"%02x"%c} + (t ? [t] : [])
23
+ when :bin; @stream[0..e].map{|c|"%08b"%c} + (t ? [t] : [])
24
+ when :dec; eval("0b"+@stream[0..e].map{|c|"%08b"%c}.join).to_s + (t ? t : '')
25
+ when :raw; @stream[0..e].map{|c|c.chr}.join + (t ? ' '+t : '')
26
+ when :seq; @stream[0..e] + (t ? [t] : [])
27
+ end
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bit-protocol
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: cc
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 1.1.1
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 1.1.1
26
+ - !ruby/object:Gem::Dependency
27
+ name: casetdown
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.9.0
40
+ description: bit operating, destructuring, and encoding
41
+ email:
42
+ - matthrewchains@gmail.com
43
+ - 18995691365@189.cn
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - GEMFILE
49
+ - LICENSE
50
+ - README.md
51
+ - bitop.rb
52
+ - bitproto.rb
53
+ - bitstream.rb
54
+ homepage: https://github.com/ChenMeng1365/network
55
+ licenses:
56
+ - AGPL-3.0
57
+ metadata: {}
58
+ rdoc_options: []
59
+ require_paths:
60
+ - "."
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubygems_version: 3.6.9
73
+ specification_version: 4
74
+ summary: bitproto
75
+ test_files: []