javaclass 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Rakefile +51 -0
  2. data/Readme.txt +47 -0
  3. data/history.txt +29 -0
  4. data/lib/javaclass/access_flags.rb +44 -0
  5. data/lib/javaclass/class_magic.rb +27 -0
  6. data/lib/javaclass/class_version.rb +65 -0
  7. data/lib/javaclass/constant_pool.rb +85 -0
  8. data/lib/javaclass/constants/base.rb +31 -0
  9. data/lib/javaclass/constants/double_reference.rb +81 -0
  10. data/lib/javaclass/constants/single_reference.rb +58 -0
  11. data/lib/javaclass/constants/value.rb +114 -0
  12. data/lib/javaclass/java_class_header.rb +88 -0
  13. data/lib/javaclass/references.rb +31 -0
  14. data/lib/javaclass/string_ux.rb +39 -0
  15. data/lib/javaclass.rb +14 -0
  16. data/test/data/AccessFlagsTestAbstract.class +0 -0
  17. data/test/data/AccessFlagsTestAbstract.java +3 -0
  18. data/test/data/AccessFlagsTestFinal.class +0 -0
  19. data/test/data/AccessFlagsTestFinal.java +3 -0
  20. data/test/data/AccessFlagsTestInterface.class +0 -0
  21. data/test/data/AccessFlagsTestInterface.java +3 -0
  22. data/test/data/AccessFlagsTestPackage.class +0 -0
  23. data/test/data/AccessFlagsTestPackage.java +3 -0
  24. data/test/data/AccessFlagsTestPublic$InnerClass.class +0 -0
  25. data/test/data/AccessFlagsTestPublic.class +0 -0
  26. data/test/data/AccessFlagsTestPublic.java +7 -0
  27. data/test/data/ClassVersionTest.java +1 -0
  28. data/test/data/ClassVersionTest10.class +0 -0
  29. data/test/data/ClassVersionTest11.class +0 -0
  30. data/test/data/ClassVersionTest12.class +0 -0
  31. data/test/data/ClassVersionTest13.class +0 -0
  32. data/test/data/ClassVersionTest14.class +0 -0
  33. data/test/data/ClassVersionTest15.class +0 -0
  34. data/test/data/ClassVersionTest16.class +0 -0
  35. data/test/data/ConstantPoolTest.class +0 -0
  36. data/test/data/ConstantPoolTest.java +20 -0
  37. data/test/data/makeAccessFlagsTest.bat +9 -0
  38. data/test/data/makeClassVersionTest.bat +35 -0
  39. data/test/data/makeConstantPoolTest.bat +6 -0
  40. data/test/setup.rb +14 -0
  41. data/test/test_access_flags.rb +53 -0
  42. data/test/test_base.rb +22 -0
  43. data/test/test_class_version.rb +59 -0
  44. data/test/test_constant_pool.rb +90 -0
  45. data/test/test_java_class_header.rb +30 -0
  46. data/test/test_references.rb +29 -0
  47. data/test/test_string_ux.rb +30 -0
  48. data/test/ts_all_tests.rb +36 -0
  49. metadata +106 -0
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+
9
+ jcversion = '0.0.2'
10
+
11
+ gemspec = Gem::Specification.new do |s|
12
+ s.name = 'javaclass'
13
+ s.version = jcversion
14
+ s.summary ='A parser and disassembler for Java class files'
15
+ s.files = FileList['Readme.txt', '{lib,test}/**/*.*', 'history.txt', 'Rakefile']
16
+ s.test_files = FileList["{test}/**/test_*.rb"]
17
+ s.require_path = 'lib'
18
+ s.has_rdoc = true
19
+ s.rubyforge_project = 'javaclass'
20
+ s.homepage = 'http://javaclass.rubyforge.org/'
21
+ s.author = 'Peter Kofler'
22
+ s.email = 'bruno41 at rubyforge dot org'
23
+ # TODO use new cc email
24
+ s.platform = Gem::Platform::RUBY
25
+ end
26
+
27
+ Rake::GemPackageTask.new(gemspec) do |pkg|
28
+ pkg.need_zip = true
29
+ end
30
+
31
+ Rake::PackageTask.new(gemspec.name, gemspec.version) do |pkg|
32
+ #pkg.need_tar = true - no compress in tar on unxutils in Windows
33
+ #pkg.need_tar_gz = true - no compress in tar on unxutils in Windows
34
+ pkg.need_zip = true
35
+ pkg.package_files.include gemspec.files
36
+ end
37
+
38
+ Rake::TestTask.new do |t|
39
+ t.pattern = 'test/**/test_*.rb'
40
+ t.warning = true
41
+ t.verbose = false
42
+ end
43
+
44
+ Rake::RDocTask.new do |rdoc|
45
+ # rdoc.rdoc_dir = 'html'
46
+ rdoc.title = "JavaClass javaclass-#{jcversion} Documentation"
47
+ rdoc.main = 'Readme.txt'
48
+ rdoc.rdoc_files.include 'Readme.txt', 'lib/**/*.rb', 'history.txt'
49
+ end
50
+
51
+ task :default => :test
data/Readme.txt ADDED
@@ -0,0 +1,47 @@
1
+ JavaClass
2
+ by {Peter Kofler}[http://kofler.dot.at/work/]
3
+
4
+ * {Homepage}[http://javaclass.rubyforge.org/]
5
+ * {Rubyforge Project}[http://rubyforge.org/projects/javaclass]
6
+ * email bruno41 at rubyforge dot org
7
+
8
+ == Description
9
+
10
+ JavaClass (Java Class File Parser) is a
11
+ parser and disassembler for Java class files, similar to the javap command.
12
+ It provides access to the package, protected, and public fields and methods
13
+ of the classes passed to it together with a list of all outgoing references.
14
+
15
+ == Motivation
16
+
17
+ I am still doing Java most of the time. I used to be quite enthusiatic about
18
+ it, but after 9 years I can see the advantages of being a polyglot. So I use
19
+ Ruby for all kind of stuff, just for fun. Recently I needed some Java class
20
+ analysis and happened to write it with Ruby. As I am a puritan, I did not
21
+ want to call javap from my script, so I started disassembling the class files,
22
+ which might be the the base for some serious static code analysis tools. (I
23
+ started adding methods to that end...)
24
+
25
+ == Install
26
+
27
+ sudo gem install javaclass
28
+
29
+ == Usage
30
+
31
+ require 'javaclass'
32
+
33
+ clazz = JavaClass.parse('packagename/Public.class')
34
+ clazz.version # => 50.0
35
+ clazz.constant_pool.items[1] # => packagename/Public
36
+ clazz.access_flags.public? # => true
37
+ clazz.this_class # => packagename/Public
38
+ clazz.super_class # => java/lang/Object
39
+ clazz.references.referenced_methods[0] # => java/lang/Object.<init>:()V
40
+
41
+ == Requirements
42
+
43
+ JavaClass does not depend on any other installed libraries or gems.
44
+
45
+ == License
46
+
47
+ Same as Ruby.
data/history.txt ADDED
@@ -0,0 +1,29 @@
1
+ === 0.0.2 08/04/2009
2
+
3
+ * refactored code to smaller objects for version and constant pool
4
+ * fixed float and double constant pool items
5
+ * added tests
6
+ * continued implementation with class names and references
7
+
8
+ === 0.0.1 01/03/2009
9
+
10
+ * initial version extracted from ClassList project
11
+ * reads the class version and package/public flag of a class
12
+ * understands the constant pool but does not use it
13
+
14
+ === Planned
15
+
16
+ * continue function for fields and methods
17
+ * implement
18
+ * dump to return the class same as javap
19
+ * isAnnotation (checks version>=5 & superclass)
20
+ * are Annotation extendable, if so how do they look? (javap)
21
+ * isEnum (checks version>=5 & superclass)
22
+ * are Enums extendable (yes), if so how do they look? (javap)
23
+ * test
24
+ * test with all classes of all JDKs against javap from this version
25
+ * Java 1.0 - private protected fields.
26
+ * Java 1.0 - http://www.javaworld.com/javaworld/javaqa/1999-06/03-synchronized.html
27
+ * think about
28
+ * "metric" if all referencing classes of a class is another package, propose moving it there.
29
+ * add zip gem to load classes directly from the classpath (i.e. the jars), add gem dependency
@@ -0,0 +1,44 @@
1
+ require 'javaclass/string_ux'
2
+
3
+ module JavaClass
4
+
5
+ # The access flags of a class or interface.
6
+ # Author:: Peter Kofler
7
+ class AccessFlags
8
+
9
+ # Access flags as defined by JVM spec.
10
+ ACC_PUBLIC = 0x0001
11
+ ACC_FINAL = 0x0010
12
+ ACC_SUPER = 0x0020 # old invokespecial instruction semantics
13
+ ACC_INTERFACE = 0x0200
14
+ ACC_ABSTRACT = 0x0400
15
+ ACC_OTHER = 0xffff ^ ACC_PUBLIC ^ ACC_FINAL ^ ACC_SUPER ^ ACC_INTERFACE ^ ACC_ABSTRACT
16
+
17
+ def initialize(data, pos)
18
+ @flags = data.u2(pos)
19
+ raise "inconsistent flags #{flags}" if abstract? && final?
20
+ raise "inconsistent flags #{flags}" if interface? && (!abstract? || final?)
21
+ raise "inconsistent flags #{flags}" if (@flags & ACC_OTHER) != 0
22
+ end
23
+
24
+ # Return +true+ if the class is public.
25
+ def public?
26
+ (@flags & ACC_PUBLIC) != 0
27
+ end
28
+ alias accessible? public?
29
+
30
+ def final?
31
+ (@flags & ACC_FINAL) != 0
32
+ end
33
+
34
+ def abstract?
35
+ (@flags & ACC_ABSTRACT) != 0
36
+ end
37
+
38
+ def interface?
39
+ (@flags & ACC_INTERFACE) != 0
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,27 @@
1
+ module JavaClass
2
+
3
+ # The +CAFEBABE+ magic of a class file.
4
+ # Author:: Peter Kofler
5
+ class ClassMagic
6
+
7
+ CAFE_BABE = "\xCA\xFE\xBA\xBE"
8
+
9
+ # Check the class magic in the _data_ beginning at position _start_ (which is usually 0).
10
+ def initialize(data, start=0)
11
+ # "parsing"
12
+ @bytes = data[start..start+3]
13
+ end
14
+
15
+ # Return +true+ if the data was valid, i.e. if the class started with +CAFEBABE+.
16
+ def valid?
17
+ @bytes == CAFE_BABE
18
+ end
19
+
20
+ # Return the value of the magic in this class.
21
+ def bytes
22
+ @bytes.dup
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,65 @@
1
+ require 'javaclass/string_ux'
2
+
3
+ module JavaClass
4
+
5
+ # Version of a class file.
6
+ # Author:: Peter Kofler
7
+ # See:: http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#75883
8
+ class ClassVersion
9
+
10
+ attr_reader :minor
11
+ attr_reader :major
12
+
13
+ # Extract the class version from the bytes _data_ starting at position _start_ (which is usually 4).
14
+ def initialize(data, start=4)
15
+ # parsing
16
+ @minor = data.u2(start)
17
+ @major = data.u2(start+2)
18
+ end
19
+
20
+ # Return the class file version as +major+.+minor+ string like 48.0 (Java 1.4) or 50.0 (Java 6).
21
+ def to_s
22
+ "#{@major}.#{@minor}"
23
+ end
24
+
25
+ # Return the version as +major+.+minor+ float.
26
+ def to_f
27
+ if @minor <= 0
28
+ denom = 1.0
29
+ else
30
+ denom = 1.0 * 10**(Math.log10(@minor).floor + 1)
31
+ end
32
+
33
+ @major + @minor/denom
34
+ end
35
+
36
+ # Return a debug output of this version.
37
+ def dump
38
+ [" minor version: #{@minor}", " major version: #{@major}"]
39
+ end
40
+
41
+ # Return the JDK version corresponding to this version like "1.6" or "unknown" if none matched.
42
+ def jdk_version
43
+ v = to_f
44
+ if v >= 45.0 && v <= 45.3 # 1.0.2 supports class file format versions 45.0 through 45.3 inclusive.
45
+ '1.0'
46
+ elsif v > 45.3 && v <= 45.65535 # 1.1.X can support class file formats of versions in the range 45.0 through 45.65535 inclusive
47
+ '1.1'
48
+ elsif v == 46.0 # JDK 1.2=46
49
+ '1.2'
50
+ elsif v == 47.0 # JDK 1.3=47
51
+ '1.3'
52
+ elsif v == 48.0 # JDK 1.4=48
53
+ '1.4'
54
+ elsif v == 49.0 # J2SE 5.0=49
55
+ '1.5'
56
+ elsif v == 50.0 # J2SE 6.0=50
57
+ '1.6'
58
+ else
59
+ 'unknown'
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,85 @@
1
+ require 'javaclass/string_ux'
2
+ require 'javaclass/constants/value'
3
+ require 'javaclass/constants/single_reference'
4
+ require 'javaclass/constants/double_reference'
5
+
6
+ module JavaClass
7
+
8
+ # Container of the constant pool's constants.
9
+ # Author:: Peter Kofler
10
+ class ConstantPool
11
+
12
+ # Types of constants by their +tag+.
13
+ CONSTANT_TYPE_TAGS = {
14
+ CLASS_TAG = 7 => Constants::ConstantClass,
15
+ FIELD_TAG = 9 => Constants::ConstantField,
16
+ METHOD_TAG = 10 => Constants::ConstantMethod,
17
+ INTERFACE_METHOD_TAG = 11 => Constants::ConstantInterfaceMethod,
18
+ STRING_TAG = 8 => Constants::ConstantString,
19
+ INT_TAG = 3 => Constants::ConstantInt,
20
+ FLOAT_TAG = 4 => Constants::ConstantFloat,
21
+ LONG_TAG = 5 => Constants::ConstantLong,
22
+ DOUBLE_TAG = 6 => Constants::ConstantDouble,
23
+ NAME_AND_TYPE_TAG = 12 => Constants::ConstantNameAndType,
24
+ ASCIZ_TAG = 1 => Constants::ConstantAsciz,
25
+ }
26
+
27
+ # Size of the whole constant pool in bytes.
28
+ attr_reader :size
29
+
30
+ # Parse the constant pool from the bytes _data_ beginning at position _start_ (which is usually 8).
31
+ def initialize(data, start=8)
32
+ @pool = {} # cnt (fixnum) => constant
33
+
34
+ # parsing
35
+ @item_count = data.u2(start)
36
+ pos = start + 2
37
+ cnt = 1
38
+ while cnt <= @item_count-1
39
+
40
+ type = CONSTANT_TYPE_TAGS[data.u1(pos)]
41
+ unless type
42
+ #puts dump.join("\n")
43
+ raise "const ##{cnt} = unknown constant pool tag #{data[pos]} at pos #{pos} in class"
44
+ end
45
+
46
+ constant = type.new(@pool, data, pos)
47
+ @pool[cnt] = constant
48
+ pos += constant.size
49
+ cnt += constant.slots
50
+
51
+ end
52
+
53
+ @size = pos - start
54
+ end
55
+
56
+ # Return the number of pool items. This number might be larger than +items+ available,
57
+ # because +long+ and +double+ constants take two slots.
58
+ def item_count
59
+ @item_count-1
60
+ end
61
+
62
+ # Return the _index_'th pool item. _index_ is the real index in the pool which may skip numbers.
63
+ def[](index)
64
+ @pool[index]
65
+ end
66
+
67
+ # Return an array of the ordered list of constants.
68
+ def items
69
+ @pool.keys.sort.collect { |k| self[k] }
70
+ end
71
+
72
+ # Return an array of all constants of the given _tags_ types.
73
+ def find(*tags)
74
+ items.find_all { |item| tags.include? item.tag }
75
+ end
76
+
77
+ # Return a debug output of the whole pool.
78
+ def dump
79
+ [" Constant pool:"] + @pool.keys.sort.collect { |k| "const ##{k} = #{self[k].dump}"}
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
@@ -0,0 +1,31 @@
1
+ require 'javaclass/string_ux'
2
+
3
+ module JavaClass
4
+ module Constants # :nodoc:
5
+
6
+ # Superclass of constant values in the constant pool. Every constant has a +name+, a +tag+ and a +size+ in bytes.
7
+ # Author:: Peter Kofler
8
+ class Base
9
+
10
+ attr_reader :name
11
+ attr_reader :tag
12
+ attr_reader :size
13
+ attr_reader :slots
14
+
15
+ # Set default constants.
16
+ def initialize(name=nil)
17
+ @name = self.class.to_s[/::[^:]+$/][10..-1] # skip modules (::) and "Constant"
18
+ @name = name if name
19
+ @size = 3
20
+ @slots = 1
21
+ end
22
+
23
+ # Return part of debug output.
24
+ def dump
25
+ "#{@name}\t" # #{@tag}
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,81 @@
1
+ require 'javaclass/constants/single_reference'
2
+
3
+ module JavaClass
4
+ module Constants # :nodoc:
5
+
6
+ # Superclass of double reference constants like +ConstantField+ (+FieldRef+) in the constant pool.
7
+ # Author:: Peter Kofler
8
+ class DoubleReference < SingleReference
9
+
10
+ attr_reader :second_index
11
+
12
+ # Define a double reference into _pool_ from _data_ beginning at _start_
13
+ def initialize(pool, data, start, name=nil)
14
+ super(pool, data, start, name)
15
+ @size = 5
16
+
17
+ @second_index = data.u2(start+3)
18
+ end
19
+
20
+ # Return the second value, which is the referenced value from the pool.
21
+ def second_value
22
+ get(@second_index)
23
+ end
24
+
25
+ # Return the value, which are both referenced values from the pool.
26
+ def to_s
27
+ "#{super}.#{second_value}"
28
+ end
29
+
30
+ # Return part of debug output.
31
+ def dump
32
+ "#{@name}\t##{@first_index}.##{@second_index};\t// #{to_s}"
33
+ end
34
+
35
+ end
36
+
37
+ class ConstantField < DoubleReference
38
+ alias class_index first_index
39
+ alias name_and_type_index second_index
40
+ def initialize(pool, data, start)
41
+ super(pool, data, start)
42
+ end
43
+ alias class_name first_value
44
+ end
45
+
46
+ class ConstantMethod < DoubleReference
47
+ alias class_index first_index
48
+ alias name_and_type_index second_index
49
+ def initialize(pool, data, start)
50
+ super(pool, data, start)
51
+ end
52
+ alias class_name first_value
53
+ end
54
+
55
+ class ConstantInterfaceMethod < DoubleReference
56
+ alias class_index first_index
57
+ alias name_and_type_index second_index
58
+ def initialize(pool, data, start)
59
+ super(pool, data, start)
60
+ end
61
+ alias class_name first_value
62
+ end
63
+
64
+ class ConstantNameAndType < DoubleReference
65
+ alias name_index first_index
66
+ alias descriptor_index second_index
67
+ def initialize(pool, data, start)
68
+ super(pool, data, start)
69
+ end
70
+
71
+ def to_s
72
+ "#{get(name_index)}:#{get(descriptor_index)}"
73
+ end
74
+
75
+ def dump
76
+ "#{@name}\t##{name_index}:##{descriptor_index};// #{to_s}"
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,58 @@
1
+ require 'javaclass/constants/base'
2
+
3
+ module JavaClass
4
+ module Constants # :nodoc:
5
+
6
+ # Superclass of single reference constants like +ConstantClass+ (+Class+) in the constant pool.
7
+ # Author:: Peter Kofler
8
+ class SingleReference < Base
9
+
10
+ attr_reader :first_index
11
+
12
+ # Define a single reference into _pool_ from _data_ beginning at _start_
13
+ def initialize(pool, data, start, name=nil)
14
+ super(name)
15
+ @tag = data.u1(start)
16
+
17
+ @enclosing_pool = pool
18
+ @first_index = data.u2(start+1)
19
+ end
20
+
21
+ # Return the value, which is the referenced value from the pool.
22
+ def first_value
23
+ get(@first_index)
24
+ end
25
+ alias to_s first_value
26
+
27
+ # Return part of debug output.
28
+ def dump
29
+ super + "##{@first_index};\t// #{to_s}"
30
+ end
31
+
32
+ protected
33
+
34
+ # Get a reference _ref_ from the +enclosing_pool+
35
+ def get(ref)
36
+ @enclosing_pool[ref].to_s
37
+ end
38
+
39
+ end
40
+
41
+ class ConstantClass < SingleReference
42
+ alias name_index first_index
43
+ def initialize(pool, data, start)
44
+ super(pool, data, start, "class")
45
+ end
46
+ alias class_name first_value
47
+ end
48
+
49
+ class ConstantString < SingleReference
50
+ alias string_index first_index
51
+ def initialize(pool, data, start)
52
+ super(pool, data, start)
53
+ end
54
+ alias string_value first_value
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,114 @@
1
+ require 'javaclass/constants/base'
2
+
3
+ module JavaClass
4
+ module Constants # :nodoc:
5
+
6
+ # Superclass of value constants like +ConstantInt+ (+Integer+) in the constant pool.
7
+ # Author:: Peter Kofler
8
+ class Value < Base
9
+
10
+ attr_reader :value
11
+
12
+ # Create a constant value with an optional downcase _name_
13
+ def initialize(name=self.class.to_s[/::[^:]+$/][10..-1].downcase)
14
+ super(name)
15
+ end
16
+
17
+ # Return the value as string.
18
+ def to_s
19
+ @value.to_s
20
+ end
21
+
22
+ # Return part of debug output.
23
+ def dump
24
+ super + "#{@value}"
25
+ end
26
+
27
+ protected
28
+
29
+ # Define a +value+ from _data_ beginning at position _start_ with the _size_ in bytes and _slots_ (1 or 2).
30
+ def get_value(data, start, size, slots=1)
31
+ @tag = data.u1(start)
32
+ @size = size
33
+ @slots = slots
34
+
35
+ data[start+1..start+size-1]
36
+ end
37
+
38
+ # Dummy method to "fix" unused warning of param _pool_ in Eclipse.
39
+ def silence_unused_warning(pool)
40
+ raise "pool is nil" unless pool
41
+ end
42
+
43
+ end
44
+
45
+ class ConstantInt < Value
46
+ def initialize(pool, data, start)
47
+ super()
48
+ silence_unused_warning(pool)
49
+ @value = get_value(data, start, 5).u4
50
+ end
51
+
52
+ def dump
53
+ super + ';'
54
+ end
55
+ end
56
+
57
+ class ConstantFloat < Value
58
+ def initialize(pool, data, start)
59
+ super()
60
+ silence_unused_warning(pool)
61
+ @value = get_value(data, start, 5).single
62
+ end
63
+ def to_s
64
+ super.upcase # sprintf('%E',@value)
65
+ end
66
+ def dump
67
+ super + 'f;'
68
+ end
69
+ end
70
+
71
+ class ConstantLong < Value
72
+ def initialize(pool, data, start)
73
+ super()
74
+ silence_unused_warning(pool)
75
+ @value = get_value(data, start, 9, 2).u8
76
+ end
77
+ def dump
78
+ super + 'l;'
79
+ end
80
+ end
81
+
82
+ class ConstantDouble < Value
83
+ def initialize(pool, data, start)
84
+ super()
85
+ silence_unused_warning(pool)
86
+ @value = get_value(data, start, 9, 2).double
87
+ end
88
+ def to_s
89
+ @value.to_s.upcase # sprintf('%E',@value)
90
+ end
91
+ def dump
92
+ super + 'd;'
93
+ end
94
+ end
95
+
96
+ class ConstantAsciz < Value
97
+ alias string value
98
+ def initialize(pool, data, start)
99
+ super('Asciz')
100
+ silence_unused_warning(pool)
101
+ @tag = data.u1(start)
102
+
103
+ @length = data.u2(start+1)
104
+ @size = 3 + @length
105
+ @value = data[start+3..start+3+@length-1]
106
+ end
107
+
108
+ def dump
109
+ super + ';'
110
+ end
111
+ end
112
+
113
+ end
114
+ end