tlv 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGELOG +10 -0
- data/COPYING +728 -0
- data/LICENSE +58 -0
- data/README +38 -0
- data/Rakefile +163 -0
- data/THANKS +0 -0
- data/TODO +2 -0
- data/bin/parse_dgi +50 -0
- data/bin/parse_tlv +51 -0
- data/lib/tlv.rb +11 -0
- data/lib/tlv/b.rb +32 -0
- data/lib/tlv/constructed.rb +116 -0
- data/lib/tlv/dgi.rb +40 -0
- data/lib/tlv/field.rb +24 -0
- data/lib/tlv/parse.rb +87 -0
- data/lib/tlv/parser/dictionaries/asn.rb +63 -0
- data/lib/tlv/parser/dictionaries/dictionaries.rb +2 -0
- data/lib/tlv/parser/dictionaries/emv_tags.rb +130 -0
- data/lib/tlv/parser/parser.rb +167 -0
- data/lib/tlv/raw.rb +31 -0
- data/lib/tlv/tag.rb +51 -0
- data/lib/tlv/tlv.rb +144 -0
- data/lib/tlv/to_bytes.rb +76 -0
- data/test/constructed_test.rb +106 -0
- data/test/dgi_test.rb +122 -0
- data/test/tlv_tag_test.rb +89 -0
- data/test/tlv_test.rb +217 -0
- metadata +108 -0
data/LICENSE
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
This package is copyrighted free software by Tim Becker <tim@kuriositaet.de>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the GPL
|
3
|
+
(see COPYING.txt file), or the conditions below:
|
4
|
+
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
6
|
+
software without restriction, provided that you duplicate all of the
|
7
|
+
original copyright notices and associated disclaimers.
|
8
|
+
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
10
|
+
you do at least ONE of the following:
|
11
|
+
|
12
|
+
a) place your modifications in the Public Domain or otherwise
|
13
|
+
make them Freely Available, such as by posting said
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
15
|
+
the author to include your modifications in the software.
|
16
|
+
|
17
|
+
b) use the modified software only within your corporation or
|
18
|
+
organization.
|
19
|
+
|
20
|
+
c) rename any non-standard executables so the names do not conflict
|
21
|
+
with standard executables, which must also be provided.
|
22
|
+
|
23
|
+
d) make other distribution arrangements with the author.
|
24
|
+
|
25
|
+
3. You may distribute the software in object code or executable
|
26
|
+
form, provided that you do at least ONE of the following:
|
27
|
+
|
28
|
+
a) distribute the executables and library files of the software,
|
29
|
+
together with instructions (in the manual page or equivalent)
|
30
|
+
on where to get the original distribution.
|
31
|
+
|
32
|
+
b) accompany the distribution with the machine-readable source of
|
33
|
+
the software.
|
34
|
+
|
35
|
+
c) give non-standard executables non-standard names, with
|
36
|
+
instructions on where to get the original software distribution.
|
37
|
+
|
38
|
+
d) make other distribution arrangements with the author.
|
39
|
+
|
40
|
+
4. You may modify and include the part of the software into any other
|
41
|
+
software (possibly commercial). But some files in the distribution
|
42
|
+
are not written by the author, so that they are not under this terms.
|
43
|
+
|
44
|
+
They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
|
45
|
+
files under the ./missing directory. See each file for the copying
|
46
|
+
condition.
|
47
|
+
|
48
|
+
5. The scripts and library files supplied as input to or produced as
|
49
|
+
output from the software do not automatically fall under the
|
50
|
+
copyright of the software, but belong to whomever generated them,
|
51
|
+
and may be sold commercially, and may be aggregated with this
|
52
|
+
software.
|
53
|
+
|
54
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
55
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
56
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
57
|
+
PURPOSE.
|
58
|
+
|
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= tlv -- lib to facilitate working with tlv data
|
2
|
+
|
3
|
+
|
4
|
+
== Installing
|
5
|
+
|
6
|
+
Having a "Installing" section is a bit of a chicken or egg question.
|
7
|
+
Someone reading this README has, in all likelyhood already installed the
|
8
|
+
package.
|
9
|
+
|
10
|
+
You can install the +tlv+ package by executing:
|
11
|
+
|
12
|
+
gem install tlv -r
|
13
|
+
|
14
|
+
alternatively, you can download +.tar.gz+ or +.zip+ archives from
|
15
|
+
Rubyforge[http://rubyforge.org/frs/?group_id=2203].
|
16
|
+
|
17
|
+
|
18
|
+
== Mail
|
19
|
+
|
20
|
+
In case you discover bugs, spelling errors, offer suggestions for
|
21
|
+
improvements or would like to help out with the project, you can contact
|
22
|
+
me directly (tim@kuriositaet.de).
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
=
|
data/Rakefile
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require "rdoc/task"
|
2
|
+
require "rubygems/package_task"
|
3
|
+
require "rake/testtask"
|
4
|
+
require "rake/clean"
|
5
|
+
require "rubygems"
|
6
|
+
|
7
|
+
# Some definitions that you'll need to edit in case you reuse this
|
8
|
+
# Rakefile for your own project.
|
9
|
+
|
10
|
+
SHORTNAME ='tlv' # this should be the rubyforge project name
|
11
|
+
DESC ='lib for handling tlv data'
|
12
|
+
PKG_VERSION ='0.0.3'
|
13
|
+
LONG_DESC = <<END_DESC
|
14
|
+
lib for handling tlv (der) and dgi encoded data
|
15
|
+
END_DESC
|
16
|
+
RUBYFORGE_USER ='a2800276'
|
17
|
+
AUTHOR = "Tim Becker"
|
18
|
+
EMAIL = "tim@kuriositaet.de"
|
19
|
+
HOMEPAGE = "http://github.com/a2800276/tlv"
|
20
|
+
|
21
|
+
|
22
|
+
# Specifies the default task to execute. This is often the "test" task
|
23
|
+
# and we'll change things around as soon as we have some tests.
|
24
|
+
|
25
|
+
task :default => [:test]
|
26
|
+
|
27
|
+
# The directory to generate +rdoc+ in.
|
28
|
+
RDOC_DIR="doc/html"
|
29
|
+
|
30
|
+
# This global variable contains files that will be erased by the `clean` task.
|
31
|
+
# The `clean` task itself is automatically generated by requiring `rake/clean`.
|
32
|
+
|
33
|
+
CLEAN << RDOC_DIR << "pkg"
|
34
|
+
|
35
|
+
|
36
|
+
# This is the task that generates the +rdoc+ documentation from the
|
37
|
+
# source files. Instantiating Rake::RDocTask automatically generates a
|
38
|
+
# task called `rdoc`.
|
39
|
+
|
40
|
+
Rake::RDocTask.new do |rd|
|
41
|
+
# Options for documenation generation are specified inside of
|
42
|
+
# this block. For example the following line specifies that the
|
43
|
+
# content of the README file should be the main page of the
|
44
|
+
# documenation.
|
45
|
+
rd.main = "README"
|
46
|
+
|
47
|
+
# The following line specifies all the files to extract
|
48
|
+
# documenation from.
|
49
|
+
rd.rdoc_files.include( "README", "AUTHORS", "LICENSE", "TODO",
|
50
|
+
"CHANGELOG", "bin/**/*", "lib/**/*.rb",
|
51
|
+
"examples/**/*rb", "doc/*.rdoc")
|
52
|
+
# This one specifies the output directory ...
|
53
|
+
rd.rdoc_dir = "doc/html"
|
54
|
+
|
55
|
+
# Or the HTML title of the generated documentation set.
|
56
|
+
rd.title = "#{SHORTNAME}: #{DESC}"
|
57
|
+
|
58
|
+
# These are options specifiying how source code inlined in the
|
59
|
+
# documentation should be formatted.
|
60
|
+
|
61
|
+
rd.options = ["--line-numbers", "--inline-source"]
|
62
|
+
|
63
|
+
# Check:
|
64
|
+
# `rdoc --help` for more rdoc options
|
65
|
+
# the {rdoc documenation home}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html]
|
66
|
+
# or the documentation for the +Rake::RDocTask+ task[http://rake.rubyforge.org/classes/Rake/RDocTask.html]
|
67
|
+
end
|
68
|
+
Rake::RDocTask.new(:rdoc_dev) do |rd|
|
69
|
+
# Options for documenation generation are specified inside of
|
70
|
+
# this block. For example the following line specifies that the
|
71
|
+
# content of the README file should be the main page of the
|
72
|
+
# documenation.
|
73
|
+
rd.main = "README"
|
74
|
+
|
75
|
+
# The following line specifies all the files to extract
|
76
|
+
# documenation from.
|
77
|
+
rd.rdoc_files.include( "README", "AUTHORS", "LICENSE", "TODO",
|
78
|
+
"CHANGELOG", "bin/**/*", "lib/**/*.rb",
|
79
|
+
"examples/**/*rb","test/**/*.rb", "doc/*.rdoc")
|
80
|
+
# This one specifies the output directory ...
|
81
|
+
rd.rdoc_dir = "doc/dev_html"
|
82
|
+
|
83
|
+
# Or the HTML title of the generated documentation set.
|
84
|
+
rd.title = "#{SHORTNAME}: #{DESC}"
|
85
|
+
|
86
|
+
# These are options specifiying how source code inlined in the
|
87
|
+
# documentation should be formatted.
|
88
|
+
|
89
|
+
rd.options = ["--line-numbers", "--inline-source"]
|
90
|
+
|
91
|
+
# Check:
|
92
|
+
# `rdoc --help` for more rdoc options
|
93
|
+
# the {rdoc documenation home}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html]
|
94
|
+
# or the documentation for the +Rake::RDocTask+ task[http://rake.rubyforge.org/classes/Rake/RDocTask.html]
|
95
|
+
end
|
96
|
+
|
97
|
+
# The GemPackageTask facilitates getting all your files collected
|
98
|
+
# together into gem archives. You can also use it to generate tarball
|
99
|
+
# and zip archives.
|
100
|
+
|
101
|
+
# First you'll need to assemble a gemspec
|
102
|
+
|
103
|
+
PKG_FILES = FileList['lib/**/*.rb', 'bin/**/*', 'examples/**/*', '[A-Z]*', 'test/**/*'].to_a
|
104
|
+
|
105
|
+
spec = Gem::Specification.new do |s|
|
106
|
+
s.platform = Gem::Platform::RUBY
|
107
|
+
s.summary = "#{SHORTNAME}: #{DESC}"
|
108
|
+
s.add_dependency "hexy"
|
109
|
+
s.name = SHORTNAME
|
110
|
+
s.version = PKG_VERSION
|
111
|
+
s.files = PKG_FILES
|
112
|
+
s.requirements << "none"
|
113
|
+
s.require_path = 'lib'
|
114
|
+
s.description = LONG_DESC
|
115
|
+
s.author = AUTHOR
|
116
|
+
s.email = EMAIL
|
117
|
+
s.homepage = HOMEPAGE
|
118
|
+
s.has_rdoc = true
|
119
|
+
s.executables = ["parse_tlv", "parse_dgi"]
|
120
|
+
end
|
121
|
+
|
122
|
+
# Adding a new GemPackageTask adds a task named `package`, which generates
|
123
|
+
# packages as gems, tarball and zip archives.
|
124
|
+
Gem::PackageTask.new(spec) do |pkg|
|
125
|
+
pkg.need_zip = true
|
126
|
+
pkg.need_tar_gz = true
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# This task is used to demonstrate how to upload files to Rubyforge.
|
131
|
+
# Calling `upload_page` creates a current version of the +rdoc+
|
132
|
+
# documentation and uploads it to the Rubyforge homepage of the project,
|
133
|
+
# assuming it's hosted there and naming conventions haven't changed.
|
134
|
+
#
|
135
|
+
# This task uses `sh` to call the `scp` binary, which is plattform
|
136
|
+
# dependant and may not be installed on your computer if you're using
|
137
|
+
# Windows. I'm currently not aware of any pure ruby way to do scp
|
138
|
+
# transfers.
|
139
|
+
|
140
|
+
RubyForgeProject=SHORTNAME
|
141
|
+
|
142
|
+
desc "Upload the web pages to the web."
|
143
|
+
task :upload_pages => ["rdoc"] do
|
144
|
+
if RubyForgeProject then
|
145
|
+
path = "/var/www/gforge-projects/#{RubyForgeProject}"
|
146
|
+
sh "scp -r doc/html/* #{RUBYFORGE_USER}@rubyforge.org:#{path}"
|
147
|
+
sh "scp doc/images/*.png #{RUBYFORGE_USER}@rubyforge.org:#{path}/images"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# This task will run the unit tests provided in files called
|
152
|
+
# `test/test*.rb`. The task itself can be run with a call to `rake test`
|
153
|
+
|
154
|
+
Rake::TestTask.new do |t|
|
155
|
+
t.libs << "test"
|
156
|
+
t.libs << "lib"
|
157
|
+
t.test_files = FileList['test/*.rb']
|
158
|
+
t.ruby_opts = ["-rubygems"]
|
159
|
+
t.verbose = true
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
|
data/THANKS
ADDED
File without changes
|
data/bin/parse_dgi
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require 'tlv'
|
5
|
+
require 'tlv/parser/dictionaries/dictionaries'
|
6
|
+
|
7
|
+
USAGE =<<END
|
8
|
+
usage: parse_dgi [-hex] [-dictionaries] [-d dictionary] (file_to_parse | < file_to_parse)
|
9
|
+
-hex interpred input data as hex
|
10
|
+
-dictionaries list available dictionaries
|
11
|
+
END
|
12
|
+
|
13
|
+
hex = ARGV.delete "-hex"
|
14
|
+
list_dictionaries = ARGV.delete "-dictionaries"
|
15
|
+
|
16
|
+
if (i = ARGV.index("-d"))
|
17
|
+
dict = TLV::DICTIONARIES[ARGV[i+1]]
|
18
|
+
ARGV.delete_at i
|
19
|
+
ARGV.delete_at i
|
20
|
+
end
|
21
|
+
file = ARGV.last
|
22
|
+
|
23
|
+
if file
|
24
|
+
unless File.exists?(file) && File.readable?(file)
|
25
|
+
STDERR.puts USAGE
|
26
|
+
exit(1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if list_dictionaries
|
31
|
+
TLV::DICTIONARIES.each_key{|key|
|
32
|
+
puts key
|
33
|
+
}
|
34
|
+
exit(0)
|
35
|
+
end
|
36
|
+
|
37
|
+
io = file ? File.open(file) : STDIN
|
38
|
+
|
39
|
+
lines = io.readlines
|
40
|
+
#lines.each {|line|
|
41
|
+
# puts TLV.s2b(line)+"<<<<<"
|
42
|
+
# puts line
|
43
|
+
#}
|
44
|
+
if hex
|
45
|
+
puts TLV.parse_dgi_hex(lines.join, dict || {})
|
46
|
+
else
|
47
|
+
puts TLV.parse_dgi(lines.join, dict || {})
|
48
|
+
end
|
49
|
+
|
50
|
+
io.close
|
data/bin/parse_tlv
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require 'tlv'
|
5
|
+
require 'tlv/parser/dictionaries/dictionaries'
|
6
|
+
|
7
|
+
|
8
|
+
USAGE =<<END
|
9
|
+
usage: parse_tlv [-hex] [-dictionaries] [-d dictionary] (file_to_parse | < file_to_parse)
|
10
|
+
-hex interpred input data as hex
|
11
|
+
-dictionaries list available dictionaries
|
12
|
+
END
|
13
|
+
|
14
|
+
hex = ARGV.delete "-hex"
|
15
|
+
list_dictionaries = ARGV.delete "-dictionaries"
|
16
|
+
|
17
|
+
if (i = ARGV.index("-d"))
|
18
|
+
dict = TLV::DICTIONARIES[ARGV[i+1]]
|
19
|
+
ARGV.delete_at i
|
20
|
+
ARGV.delete_at i
|
21
|
+
end
|
22
|
+
file = ARGV.last
|
23
|
+
|
24
|
+
if file
|
25
|
+
unless File.exists?(file) && File.readable?(file)
|
26
|
+
STDERR.puts USAGE
|
27
|
+
exit(1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if list_dictionaries
|
32
|
+
TLV::DICTIONARIES.each_key{|key|
|
33
|
+
puts key
|
34
|
+
}
|
35
|
+
exit(0)
|
36
|
+
end
|
37
|
+
|
38
|
+
io = file ? File.open(file) : STDIN
|
39
|
+
|
40
|
+
|
41
|
+
lines = io.readlines
|
42
|
+
#lines.each {|line|
|
43
|
+
# puts TLV.s2b(line)
|
44
|
+
#}
|
45
|
+
if hex
|
46
|
+
puts TLV.parse_hex(lines.join, dict)
|
47
|
+
else
|
48
|
+
puts TLV.parse(lines.join,dict)
|
49
|
+
end
|
50
|
+
|
51
|
+
io.close
|
data/lib/tlv.rb
ADDED
data/lib/tlv/b.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module TLV
|
2
|
+
|
3
|
+
class TLV
|
4
|
+
class B < Field
|
5
|
+
def define_accessor clazz
|
6
|
+
super
|
7
|
+
name = @name
|
8
|
+
len = @length
|
9
|
+
clazz.instance_eval{
|
10
|
+
define_method("#{name}="){|val|
|
11
|
+
raise("invalid value nil") unless val
|
12
|
+
raise("must be a String #{val}") unless val.is_a?(String)
|
13
|
+
raise("incorrect length: #{val}") unless (val.length*8) <= len
|
14
|
+
self.instance_variable_set("@#{name}", val)
|
15
|
+
}
|
16
|
+
|
17
|
+
define_method("#{name}") {
|
18
|
+
self.instance_variable_get("@#{name}") || "\x00" * (len/8)
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse tlv, bytes, _len
|
24
|
+
val = bytes[0, length/8]
|
25
|
+
rest = bytes[length/8, bytes.length]
|
26
|
+
# check val...
|
27
|
+
tlv.send("#{name}=", val)
|
28
|
+
rest
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end # module
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module TLV
|
2
|
+
class TLV
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def mand_tags
|
6
|
+
@mand_tags ||= (self == TLV ? [] : superclass.mand_tags.dup)
|
7
|
+
end
|
8
|
+
def opt_tags
|
9
|
+
@opt_tags ||= (self == TLV ? [] : superclass.opt_tags.dup)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Takes either a subclass of TLV or the following options, which are used to
|
13
|
+
# create an subclass.
|
14
|
+
# Options:
|
15
|
+
# :tag
|
16
|
+
# :display_name
|
17
|
+
#
|
18
|
+
# :classname (will be derived from display_name if not given)
|
19
|
+
# :accessor_name (will be derived from display_name if not given)
|
20
|
+
def mandatory tlv, accessor_name=nil
|
21
|
+
handle_subtag mand_tags, tlv, accessor_name
|
22
|
+
end
|
23
|
+
|
24
|
+
# for constructed tlv's, add subtags that may be present
|
25
|
+
def optional tlv, accessor_name=nil
|
26
|
+
handle_subtag opt_tags, tlv, accessor_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def register tlv
|
30
|
+
@tlv_classes ||= {}
|
31
|
+
warn "tag #{TLV.b2s(tlv.tag)} already defined!" if @tlv_classes[tlv.tag]
|
32
|
+
@tlv_classes[tlv.tag] = tlv
|
33
|
+
end
|
34
|
+
|
35
|
+
def lookup tag
|
36
|
+
return self if tag == self.tag
|
37
|
+
@tlv_classes ||= {}
|
38
|
+
tlv = @tlv_classes[tag]
|
39
|
+
if !tlv && ! (self == TLV)
|
40
|
+
warn "looking up tag #{TLV.b2s(tag)} in super!"
|
41
|
+
raise "bla"
|
42
|
+
tlv ||= super
|
43
|
+
end
|
44
|
+
tlv
|
45
|
+
end
|
46
|
+
|
47
|
+
# internal, common functionality for mndatory and optional
|
48
|
+
def handle_subtag arr, tlv, accessor_name
|
49
|
+
tlv = handle_options(tlv) if tlv.is_a? Hash
|
50
|
+
raise "#{tlv} must be a subclass of TLV!" unless tlv.ancestors.include? TLV
|
51
|
+
if accessor_name
|
52
|
+
tlv= tlv.dup
|
53
|
+
tlv.accessor_name= accessor_name
|
54
|
+
end
|
55
|
+
define_accessor(tlv)
|
56
|
+
|
57
|
+
register(tlv)
|
58
|
+
arr << tlv
|
59
|
+
end
|
60
|
+
|
61
|
+
def handle_options options
|
62
|
+
tag = options[:tag]
|
63
|
+
display_name = options[:display_name]
|
64
|
+
classname = options[:classname] || rubify_c(display_name)
|
65
|
+
new_class = self.const_set(classname, Class.new(TLV))
|
66
|
+
new_class.tlv(tag, display_name, options[:accessor_name])
|
67
|
+
new_class.raw
|
68
|
+
new_class
|
69
|
+
end
|
70
|
+
|
71
|
+
def rubify_a display
|
72
|
+
name = display.strip.gsub(/\s+/, "_")
|
73
|
+
name = name.downcase.to_sym
|
74
|
+
end
|
75
|
+
|
76
|
+
def rubify_c display
|
77
|
+
name = display.gsub(/\s+/, "")
|
78
|
+
end
|
79
|
+
|
80
|
+
def define_accessor tlv_class
|
81
|
+
s = tlv_class
|
82
|
+
# check we are actually creating an accessor for an TLV
|
83
|
+
while s = s.superclass
|
84
|
+
break if s == TLV
|
85
|
+
end
|
86
|
+
raise "not a TLV class!" unless s
|
87
|
+
|
88
|
+
# determine the accessor name
|
89
|
+
# currently the call graph of this method ensures the class
|
90
|
+
# will have an accessor name.
|
91
|
+
name = tlv_class.accessor_name
|
92
|
+
|
93
|
+
define_method("#{name}="){ |val|
|
94
|
+
# must either be an instance of tlv_val
|
95
|
+
# or a raw value.
|
96
|
+
if val.is_a? TLV
|
97
|
+
self.instance_variable_set("@#{name}", val)
|
98
|
+
else
|
99
|
+
v = tlv_class.new
|
100
|
+
# _should_ be a String, but we'll bang anything
|
101
|
+
# into value for now...
|
102
|
+
v.value = val.to_s
|
103
|
+
self.instance_variable_set("@#{name}", v)
|
104
|
+
end
|
105
|
+
}
|
106
|
+
|
107
|
+
define_method("#{name}") {
|
108
|
+
self.instance_variable_get("@#{name}")
|
109
|
+
}
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end #module
|