rasn1 0.16.2 → 0.17.0

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: da1e2001517b21898280f0c865be1f0ca74c350d536d2cf80253291819e4536b
4
- data.tar.gz: 2becfcf1810e777d9a4dc2f497f1a6fdd67e2dae319f3d15100d66a4566ce410
3
+ metadata.gz: 67e24db40c3ec0a8e7d7ad23211549c1aadda9511ea73f632034a4cdefa97ae0
4
+ data.tar.gz: d8847b0b52cce0014f02772077da519df146c14a1f65ffebc72cc206e888b0cd
5
5
  SHA512:
6
- metadata.gz: 2671492ba54d676699a6238ecfd95703b8f2ebbe5cf40adea249f3ef394b1476d4a03bb6da419349753b5ffe05d25c93bdc25aa6614ec5676f2de9b8147dea78
7
- data.tar.gz: 3524a58800943b251980b78e5935f1af88a3e5d84ee209bfd910447c00142661f07d4067ffd48892dd767409a92b0dcaca5598e0078520e6b8996d7ab466e909
6
+ metadata.gz: 12da7b29112a40073dd64e3eb949412cd941932d63fb87e2cf36cf020c1df784cdd85e6e2cd04113f8bf74e7b16c630fad2346b885933874f86dcd329f42511b
7
+ data.tar.gz: a5294cfc1a3ebc0430c1be31558ed1e33ac97e5d87ad8ff3c14d6c8633b251d53b33e7818762f46bb6272c4f71da439a42aa86f79413c3af405b5b3d076777a3
data/README.md CHANGED
@@ -52,7 +52,9 @@ ComplexRecord ::= SEQUENCE {
52
52
  }
53
53
  ```
54
54
 
55
- ### Create a ASN.1 model
55
+ ### Create an ASN.1 model
56
+
57
+ A model is created this way:
56
58
 
57
59
  ```ruby
58
60
  class Record < RASN1::Model
@@ -63,14 +65,31 @@ class Record < RASN1::Model
63
65
  end
64
66
  ```
65
67
 
68
+ or, this ways in a more rubyish style:
69
+
70
+ ```ruby
71
+ # This Record class is defined as a sequence conaining:
72
+ # * an ID (integer)
73
+ # * a room number (integer, with explicit tag, optional)
74
+ # * a house if (integer, with explicit tag and a default value)
75
+ class Record < RASN1::Model
76
+ sequence :record do
77
+ integer(:id)
78
+ integer(:room, implicit: 0, optional: true)
79
+ integer(:house, implicit: 1, default: 0)
80
+ end
81
+ end
82
+ ```
83
+
66
84
  More comple classes may be designed by nesting simple classes. For example:
67
85
 
68
86
  ```ruby
69
87
  class ComplexRecord < RASN1::Model
70
- sequence :cplx_record,
71
- content: [boolean(:bool),
72
- octet_string(:data, explicit: 0),
73
- model(:a_record, Record)]
88
+ sequence :cplx_record do
89
+ boolean(:bool)
90
+ octet_string(:data, explicit: 0)
91
+ model(:a_record, Record) # Use another model in model
92
+ end
74
93
  end
75
94
  ```
76
95
 
@@ -115,10 +134,6 @@ record.set id: 124, house: 155
115
134
  record.to_der # => String
116
135
  ```
117
136
 
118
- ### More information
119
-
120
- see <https://github.com/sdaubert/rasn1/wiki>
121
-
122
137
  ## Contributing
123
138
 
124
- Bug reports and pull requests are welcome on GitHub at <https://github.com/sdaubert/rasn1>.
139
+ Bug reports and pull requests are welcome on GitHub at <https://codeberg.org/lemontree55/rasn1>.
data/lib/rasn1/errors.rb CHANGED
@@ -26,7 +26,7 @@ module RASN1
26
26
 
27
27
  # CHOICE error: {Types::Choice#chosen} not set
28
28
  class ChoiceError < RASN1::Error
29
- # @param [Types::Base] object
29
+ # @param object [Types::Base]
30
30
  def initialize(object)
31
31
  @object = object
32
32
  super()
@@ -42,7 +42,7 @@ module RASN1
42
42
  # @version 0.11.0
43
43
  # @author Sylvain Daubert
44
44
  class ConstraintError < Error
45
- # @param [Types::Base] object
45
+ # @param object [Types::Base]
46
46
  def initialize(object)
47
47
  @object = object
48
48
  super()
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of RASN1
4
+ # See https://codeberg.org/lemontree55/rasn1 for more informations
5
+ # Copyright (C) 2016-2024 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
7
+ # This program is published under MIT license.
8
+
9
+ module RASN1
10
+ class Model
11
+ # Define helper methods to define models
12
+ # @author Sylvain Daubert
13
+ module Accel
14
+ # @return [Hash]
15
+ attr_reader :options
16
+
17
+ # On inheritance, create +@elements+ class variable
18
+ # @param klass [Class]
19
+ # @return [void]
20
+ def inherited(klass)
21
+ super
22
+ current_elements = @elements
23
+ klass.class_eval { @elements = current_elements.dup }
24
+ end
25
+
26
+ # @since 0.17.0
27
+ def elements
28
+ return @elements unless @elements.nil?
29
+
30
+ @elements = []
31
+ end
32
+
33
+ # Use another model in this model
34
+ # @param name [String,Symbol]
35
+ # @param model_klass [Class]
36
+ # @return [Elem]
37
+ def model(name, model_klass)
38
+ push_element(ModelElem.new(name, model_klass))
39
+ end
40
+
41
+ # @since 0.17.0
42
+ # @param [BaseElem, WrapElem, ModelElem] elem
43
+ # @return [BaseElem, WrapElem, ModelElem] elem
44
+ def push_element(elem)
45
+ elements << elem
46
+ elem
47
+ end
48
+
49
+ # @since 0.17.0
50
+ def root
51
+ elements.last
52
+ end
53
+
54
+ # @since 0.17.0
55
+ def root=(elem)
56
+ if elements.empty?
57
+ elements << elem
58
+ else
59
+ elements[-1] = elem
60
+ end
61
+ end
62
+
63
+ # @overload wrapper(element, options={})
64
+ # Use a {Wrapper} around a {Types::Base} or a {Model} object
65
+ # @param element [Types::Base,Model]
66
+ # @param options [Hash]
67
+ # @return [WrapElem]
68
+ # @since 0.12
69
+ # @overload(options={})
70
+ # @param options [Hash]
71
+ # @return [WrapElem]
72
+ # @yieldreturn [BaseElem, ModelElem] element to wrapp
73
+ # @since 0.17.0
74
+ def wrapper(element_or_options={}, options={}, &)
75
+ case element_or_options
76
+ when Hash
77
+ element = generate_content(&).last
78
+ options = element_or_options
79
+ else
80
+ element = element_or_options
81
+ end
82
+ push_element(WrapElem.new(element, options))
83
+ end
84
+
85
+ # Update options of root element.
86
+ # May be used when subclassing.
87
+ # class Model1 < RASN1::Model
88
+ # sequence :seq, implicit: 0,
89
+ # content: [bool(:bool), integer(:int)]
90
+ # end
91
+ #
92
+ # # same as Model1 but with implicit tag set to 1
93
+ # class Model2 < Model1
94
+ # root_options implicit: 1
95
+ # end
96
+ # @param options [Hash]
97
+ # @return [void]
98
+ # @since 0.12.0 may change name through +:name+
99
+ def root_options(options)
100
+ @options = options
101
+ return unless options.key?(:name)
102
+
103
+ self.root = root.dup
104
+ root.name = options[:name]
105
+ end
106
+
107
+ # @private
108
+ # @param accel_name [String,Symbol]
109
+ # @param klass [Class]
110
+ # @since 0.11.0
111
+ # @since 0.12.0 track source location on error (adfoster-r7)
112
+ def define_type_accel_base(accel_name, klass)
113
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
114
+ def #{accel_name}(name, options={}) # def sequence(name, type, options)
115
+ options[:name] = name
116
+ proc = proc do |opts|
117
+ #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
118
+ end
119
+ push_element(BaseElem.new(name, proc, nil))
120
+ end
121
+ EVAL
122
+ end
123
+
124
+ # @private
125
+ # @param accel_name [String,Symbol]
126
+ # @param klass [Class]
127
+ # @since 0.17.0
128
+ def define_type_accel_container(accel_name, klass)
129
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
130
+ def #{accel_name}(name, options={}, &block) # def sequence(name, type, options, &block)
131
+ options[:name] = name
132
+ proc = proc do |opts|
133
+ #{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
134
+ end
135
+ options[:content] ||= []
136
+ options[:content] += generate_content(&block)
137
+ push_element(BaseElem.new(name, proc, options[:content]))
138
+ end
139
+ EVAL
140
+ end
141
+
142
+ # @private
143
+ # @since 0.17.0
144
+ def generate_content
145
+ return [] unless block_given?
146
+
147
+ previous_elements = @elements
148
+ @elements = []
149
+ yield
150
+ content = @elements
151
+ @elements = previous_elements
152
+ content
153
+ end
154
+
155
+ # @private
156
+ # @param accel_name [String,Symbol]
157
+ # @param klass [Class]
158
+ # @since 0.11.0
159
+ # @since 0.12.0 track source location on error (adfoster-r7)
160
+ def define_type_accel_of(accel_name, klass)
161
+ singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
162
+ def #{accel_name}_of(name, type, options={}) # def sequence_of(name, type, options)
163
+ options[:name] = name
164
+ proc = proc do |opts|
165
+ #{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
166
+ end
167
+ push_element(BaseElem.new(name, proc, nil))
168
+ end
169
+ EVAL
170
+ end
171
+
172
+ # Define an accelarator to access a type in a model definition
173
+ # @param accel_name [String]
174
+ # @param klass [Class] class to instanciate
175
+ # @since 0.11.0
176
+ # @since 0.12.0 track source location on error (adfoster-r7)
177
+ def define_type_accel(accel_name, klass)
178
+ if klass <= Types::SequenceOf
179
+ define_type_accel_of(accel_name, klass)
180
+ elsif (klass <= Types::Sequence) || (klass <= Types::Choice)
181
+ define_type_accel_container(accel_name, klass)
182
+ else
183
+ define_type_accel_base(accel_name, klass)
184
+ end
185
+ end
186
+
187
+ # @param name [Symbol,String] name of object in model
188
+ # @param options [Hash]
189
+ # @return [Elem]
190
+ # @note This method is named +objectid+ and not +object_id+ to not override
191
+ # +Object#object_id+.
192
+ # @see Types::ObjectId#initialize
193
+ def objectid(name, options={})
194
+ options[:name] = name
195
+ proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
196
+ push_element(BaseElem.new(name, proc, nil))
197
+ end
198
+
199
+ # @param name [Symbol,String] name of object in model
200
+ # @param options [Hash]
201
+ # @return [Elem]
202
+ # @see Types::Any#initialize
203
+ def any(name, options={})
204
+ options[:name] = name
205
+ proc = proc { |opts| Types::Any.new(options.merge(opts)) }
206
+ push_element(BaseElem.new(name, proc, nil))
207
+ end
208
+
209
+ # Give type name (aka class name)
210
+ # @return [String]
211
+ def type
212
+ return @type if defined? @type
213
+
214
+ @type = self.to_s.gsub(/.*::/, '')
215
+ end
216
+
217
+ # Parse a DER/BER encoded string
218
+ # @param str [String]
219
+ # @param ber [Boolean] accept BER encoding or not
220
+ # @return [Model]
221
+ # @raise [ASN1Error] error on parsing
222
+ def parse(str, ber: false)
223
+ model = new
224
+ model.parse!(str, ber: ber)
225
+ model
226
+ end
227
+ end
228
+ end
229
+ end