unageanu-javaclass 0.2.1 → 0.4.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.
Files changed (48) hide show
  1. data/ChangeLog +5 -0
  2. data/javaclass.gemspec +18 -0
  3. data/lib/javaclass.rb +1 -0
  4. data/lib/javaclass/accessflag.rb +1 -1
  5. data/lib/javaclass/attribute.rb +293 -2
  6. data/lib/javaclass/base.rb +33 -4
  7. data/lib/javaclass/code.rb +78 -0
  8. data/lib/javaclass/constant.rb +2 -2
  9. data/lib/javaclass/member.rb +18 -18
  10. data/lib/javaclass/reader.rb +460 -6
  11. data/sample/caller.rb +95 -0
  12. data/sample/java_class/com/example/Constants.class +0 -0
  13. data/sample/java_class/com/example/Deprecated.class +0 -0
  14. data/sample/java_class/com/example/InnerClass.class +0 -0
  15. data/sample/java_class/com/example/InnerClassImpl.class +0 -0
  16. data/sample/java_class/com/example/Kitten.class +0 -0
  17. data/sample/java_class/com/example/ThrowsException.class +0 -0
  18. data/sample/java_class/com/example/annotation/Annotated.class +0 -0
  19. data/sample/java_class/com/example/annotation/AnnotatedMethod.class +0 -0
  20. data/sample/java_class/com/example/annotation/ClassAnnotationA.class +0 -0
  21. data/sample/java_class/com/example/annotation/HasDefaultValue.class +0 -0
  22. data/sample/java_class/com/example/annotation/RuntimeAnnotationA.class +0 -0
  23. data/sample/java_class/com/example/annotation/RuntimeAnnotationB.class +0 -0
  24. data/sample/java_class/com/example/annotation/RuntimeAnnotationC.class +0 -0
  25. data/sample/java_class/com/example/annotation/SourceAnnotationA.class +0 -0
  26. data/sample/java_class/com/example/caller/A.class +0 -0
  27. data/sample/java_class/com/example/caller/B.class +0 -0
  28. data/sample/java_class/com/example/caller/C.class +0 -0
  29. data/sample/java_class/com/example/caller/CallSample$A.class +0 -0
  30. data/sample/java_class/com/example/caller/CallSample$B.class +0 -0
  31. data/sample/java_class/com/example/caller/CallSample$C.class +0 -0
  32. data/sample/java_class/com/example/caller/CallSample.class +0 -0
  33. data/sample/java_class/com/example/caller/D.class +0 -0
  34. data/sample/java_class/com/example/code/Statement.class +0 -0
  35. data/sample/java_class/com/example/types/TypeVariables.class +0 -0
  36. data/sample/java_src/com/example/caller/A.java +19 -0
  37. data/sample/java_src/com/example/caller/B.java +7 -0
  38. data/sample/java_src/com/example/caller/C.java +7 -0
  39. data/sample/java_src/com/example/caller/CallSample.java +23 -0
  40. data/sample/java_src/com/example/caller/D.java +5 -0
  41. data/sample/java_src/com/example/code/Statement.java +41 -0
  42. data/sample/sample.rb +3 -3
  43. data/test/all_tests.rb +9 -0
  44. data/test/java_src/com/example/TestClass1.java +35 -0
  45. data/test/test_attribute.rb +150 -2
  46. data/test/test_class.rb +0 -1
  47. data/test/test_member.rb +4 -1
  48. metadata +44 -46
data/ChangeLog CHANGED
@@ -0,0 +1,5 @@
1
+ 2010-01-17 0.4.0
2
+ * add sample/caller.rb.
3
+
4
+ 2009-12-23 0.3.0
5
+ * support the analysis of stack map table attributes and code attribute.
data/javaclass.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "unageanu-javaclass"
3
+ spec.version = "0.4.0"
4
+ spec.summary = "javaclass is a java class file parser for ruby."
5
+ spec.author = "Masaya Yamauchi"
6
+ spec.email = "y-masaya@red.hot.co.jp"
7
+ spec.homepage = "http://github.com/unageanu/javaclass/tree/master"
8
+ spec.test_files = Dir.glob( "test/**/*" )
9
+ spec.files = [
10
+ "README",
11
+ "javaclass.gemspec",
12
+ "ChangeLog"
13
+ ]+Dir.glob( "lib/**/*" )+Dir.glob( "sample/**/*" )+spec.test_files
14
+ spec.has_rdoc = true
15
+ spec.rdoc_options << "--main" << "README"
16
+ spec.extra_rdoc_files = ["README"]
17
+ spec.add_dependency('rubyzip', '>= 0.9.1')
18
+ end
data/lib/javaclass.rb CHANGED
@@ -10,5 +10,6 @@ require "javaclass/attribute"
10
10
  require "javaclass/class"
11
11
  require "javaclass/constant"
12
12
  require "javaclass/member"
13
+ require "javaclass/code"
13
14
  require "javaclass/reader"
14
15
  require "javaclass/ziputils"
@@ -3,7 +3,7 @@ require "javaclass/base"
3
3
  module JavaClass
4
4
 
5
5
  #
6
- #===クラスのアクセスフラグの基底クラス。
6
+ #===アクセスフラグの基底クラス。
7
7
  #
8
8
  class AccessFlag
9
9
  include JavaClass::Base
@@ -803,10 +803,14 @@ module JavaClass
803
803
 
804
804
  body = to_byte( @max_stack, 2)
805
805
  body += to_byte( @max_locals, 2)
806
- body += to_byte( @codes.length, 4)
806
+
807
+ tmp = []
807
808
  @codes.each {|c|
808
- body += to_byte( c, 1 )
809
+ tmp += c.to_bytes
809
810
  }
811
+ body += to_byte( tmp.length, 4)
812
+ body += tmp
813
+
810
814
  body += to_byte( @exception_table.length, 2)
811
815
  @exception_table.each {|ex|
812
816
  body += ex.to_bytes()
@@ -1058,4 +1062,291 @@ module JavaClass
1058
1062
  attr :signature_index, true
1059
1063
  attr :index, true
1060
1064
  end
1065
+
1066
+ #
1067
+ #=== スタックマップテーブル属性
1068
+ #
1069
+ class StackMapTableAttribute < Attribute
1070
+ #
1071
+ #===コンストラクタ
1072
+ #
1073
+ #*java_class::属性の所有者であるJavaクラス
1074
+ #*name_index::名前を示すconstant_poolのインデックス
1075
+ #*stack_map_frame_entries::スタックマップフレームエントリ
1076
+ #
1077
+ def initialize( java_class, name_index, stack_map_frame_entries=[] )
1078
+ super( java_class, name_index)
1079
+ @stack_map_frame_entries = stack_map_frame_entries
1080
+ end
1081
+ def to_bytes
1082
+ bytes = super
1083
+ body = to_byte( @stack_map_frame_entries.length, 2 )
1084
+ @stack_map_frame_entries.each {|e|
1085
+ body += e.to_bytes()
1086
+ }
1087
+ bytes += to_byte( body.length, 4 )
1088
+ bytes += body
1089
+ end
1090
+ attr :stack_map_frame_entries, true
1091
+ end
1092
+
1093
+ #
1094
+ #=== スタックマップフレーム
1095
+ #
1096
+ class StackMapFrame
1097
+ include JavaClass::Base
1098
+ #
1099
+ #===コンストラクタ
1100
+ #
1101
+ #*frame_type::種別
1102
+ #
1103
+ def initialize(frame_type)
1104
+ @frame_type = frame_type
1105
+ end
1106
+ def to_bytes
1107
+ to_byte( frame_type, 1 )
1108
+ end
1109
+ #種別
1110
+ attr :frame_type, true
1111
+ end
1112
+
1113
+ #
1114
+ #=== same_frame
1115
+ #
1116
+ class SameFrame < StackMapFrame
1117
+ end
1118
+
1119
+ #
1120
+ #=== same_locals_1_stack_item_frame
1121
+ #
1122
+ class SameLocals1StackItemFrame < StackMapFrame
1123
+ #
1124
+ #===コンストラクタ
1125
+ #
1126
+ #*frame_type::種別
1127
+ #*verification_type_info:: 型情報
1128
+ #
1129
+ def initialize(frame_type, verification_type_info=[])
1130
+ super(frame_type)
1131
+ @verification_type_info = verification_type_info
1132
+ end
1133
+ def to_bytes
1134
+ bytes = super
1135
+ verification_type_info.each {|v|
1136
+ bytes += v.to_bytes
1137
+ }
1138
+ bytes
1139
+ end
1140
+ #型情報
1141
+ attr :verification_type_info, true
1142
+ end
1143
+
1144
+ #
1145
+ #=== same_locals_1_stack_item_frame_extended
1146
+ #
1147
+ class SameLocals1StackItemFrameExtended < StackMapFrame
1148
+ #
1149
+ #===コンストラクタ
1150
+ #
1151
+ #*frame_type::種別
1152
+ #*offset_delta:: オフセットデルタ
1153
+ #*verification_type_info:: 型情報
1154
+ #
1155
+ def initialize(frame_type, offset_delta, verification_type_info=[])
1156
+ super(frame_type)
1157
+ @offset_delta = offset_delta
1158
+ @verification_type_info = verification_type_info
1159
+ end
1160
+ def to_bytes
1161
+ bytes = super
1162
+ bytes += to_byte( offset_delta, 2 )
1163
+ verification_type_info.each {|v|
1164
+ bytes += v.to_bytes
1165
+ }
1166
+ bytes
1167
+ end
1168
+ #オフセットデルタ
1169
+ attr :offset_delta, true
1170
+ #型情報
1171
+ attr :verification_type_info, true
1172
+ end
1173
+
1174
+ #
1175
+ #=== chop_frame
1176
+ #
1177
+ class ChopFrame < StackMapFrame
1178
+ #
1179
+ #===コンストラクタ
1180
+ #
1181
+ #*frame_type::種別
1182
+ #*offset_delta:: オフセットデルタ
1183
+ #
1184
+ def initialize(frame_type, offset_delta)
1185
+ super(frame_type)
1186
+ @offset_delta = offset_delta
1187
+ end
1188
+ def to_bytes
1189
+ bytes = super
1190
+ bytes += to_byte( offset_delta, 2 )
1191
+ bytes
1192
+ end
1193
+ #オフセットデルタ
1194
+ attr :offset_delta, true
1195
+ end
1196
+
1197
+ #
1198
+ #=== same_frame_extended
1199
+ #
1200
+ class SameFrameExtended < StackMapFrame
1201
+
1202
+ #
1203
+ #===コンストラクタ
1204
+ #
1205
+ #*frame_type::種別
1206
+ #*offset_delta:: オフセットデルタ
1207
+ #
1208
+ def initialize(frame_type, offset_delta)
1209
+ super(frame_type)
1210
+ @offset_delta = offset_delta
1211
+ end
1212
+ def to_bytes
1213
+ bytes = super
1214
+ bytes += to_byte( offset_delta, 2 )
1215
+ bytes
1216
+ end
1217
+ #オフセットデルタ
1218
+ attr :offset_delta, true
1219
+ end
1220
+
1221
+ #
1222
+ #=== append_frame
1223
+ #
1224
+ class AppendFrame < StackMapFrame
1225
+ #
1226
+ #===コンストラクタ
1227
+ #
1228
+ #*frame_type::種別
1229
+ #*offset_delta:: オフセットデルタ
1230
+ #*verification_type_info:: 型情報
1231
+ #
1232
+ def initialize(frame_type, offset_delta, verification_type_info=[])
1233
+ super(frame_type)
1234
+ @offset_delta = offset_delta
1235
+ @verification_type_info = verification_type_info
1236
+ end
1237
+ def to_bytes
1238
+ bytes = super
1239
+ bytes += to_byte( offset_delta, 2 )
1240
+ verification_type_info.each {|v|
1241
+ bytes += v.to_bytes
1242
+ }
1243
+ bytes
1244
+ end
1245
+ #オフセットデルタ
1246
+ attr :offset_delta, true
1247
+ #型情報
1248
+ attr :verification_type_info, true
1249
+ end
1250
+
1251
+ #
1252
+ #=== full_frame
1253
+ #
1254
+ class FullFrame < StackMapFrame
1255
+ #
1256
+ #===コンストラクタ
1257
+ #
1258
+ #*frame_type::種別
1259
+ #*offset_delta:: オフセットデルタ
1260
+ #*verification_type_info:: 型情報
1261
+ #
1262
+ def initialize(frame_type, offset_delta,
1263
+ verification_type_info_local=[], verification_type_info_stack=[])
1264
+ super(frame_type)
1265
+ @offset_delta = offset_delta
1266
+ @verification_type_info_local = verification_type_info_local
1267
+ @verification_type_info_stack = verification_type_info_stack
1268
+ end
1269
+ def to_bytes
1270
+ bytes = super
1271
+ bytes += to_byte( offset_delta, 2 )
1272
+ [verification_type_info_local, verification_type_info_stack].each {|vi|
1273
+ bytes += to_byte( vi.length, 2 )
1274
+ vi.each {|v|
1275
+ bytes += v.to_bytes
1276
+ }
1277
+ }
1278
+ bytes
1279
+ end
1280
+ #オフセットデルタ
1281
+ attr :offset_delta, true
1282
+ #ローカルの型情報
1283
+ attr :verification_type_info_local, true
1284
+ #スタックの型情報
1285
+ attr :verification_type_info_stack, true
1286
+ end
1287
+
1288
+ #
1289
+ #=== 変数情報(Object_variable_info,Uninitialized_variable_info以外)
1290
+ #
1291
+ class VariableInfo
1292
+ include JavaClass::Base
1293
+ #
1294
+ #===コンストラクタ
1295
+ #
1296
+ #*tag::タグ
1297
+ #
1298
+ def initialize(tag)
1299
+ @tag = tag
1300
+ end
1301
+ def to_bytes
1302
+ to_byte( tag, 1 )
1303
+ end
1304
+ #タグ
1305
+ attr :tag, true
1306
+ end
1307
+
1308
+ #
1309
+ #=== 変数情報(Object_variable_info)
1310
+ #
1311
+ class ObjectVariableInfo < VariableInfo
1312
+ include JavaClass::Base
1313
+ #
1314
+ #===コンストラクタ
1315
+ #
1316
+ #*tag::タグ
1317
+ #*cpool_index:: cpool_index
1318
+ #
1319
+ def initialize(tag,cpool_index)
1320
+ super(tag)
1321
+ @cpool_index = cpool_index
1322
+ end
1323
+ def to_bytes
1324
+ super + to_byte( cpool_index, 2 )
1325
+ end
1326
+ #cpool_index
1327
+ attr :cpool_index, true
1328
+ end
1329
+
1330
+ #
1331
+ #=== 変数情報(Uninitialized_variable_info)
1332
+ #
1333
+ class UninitializedVariableInfo < VariableInfo
1334
+ include JavaClass::Base
1335
+ #
1336
+ #===コンストラクタ
1337
+ #
1338
+ #*tag::タグ
1339
+ #*offset:: オフセット
1340
+ #
1341
+ def initialize(tag,offset)
1342
+ super(tag)
1343
+ @offset = offset
1344
+ end
1345
+ def to_bytes
1346
+ super + to_byte( offset, 2 )
1347
+ end
1348
+ #オフセット
1349
+ attr :offset, true
1350
+ end
1351
+
1061
1352
  end
@@ -1,11 +1,40 @@
1
1
 
2
2
  module JavaClass
3
-
3
+
4
+ #ユーティリティ
5
+ module Utils
6
+
7
+ #配列で指定されたパスをすべて探索して配下のjar,classを解析し通知する
8
+ #*paths:: 探索するパスの配列。ファイルの場合、jarまたはclassであれば解析。
9
+ # ディレクトリであれば再帰的に探索。
10
+ def self.each_class( *paths, &block )
11
+ paths.each {|path|
12
+ if File.directory?( path )
13
+ JavaClass::Utils.each_class( *Dir.glob("#{path}/*"), &block )
14
+ elsif File.file?( path )
15
+ if path =~ /\.class$/
16
+ open( path, "r" ) {|f|
17
+ block.call(JavaClass.from( f ))
18
+ }
19
+ elsif path =~ /\.jar$/
20
+ JavaClass::ZipUtils.each_class( path, &block )
21
+ end
22
+ end
23
+ }
24
+ end
25
+ end
26
+
4
27
  module Base
5
28
 
6
29
  # 0..255の数字の配列に変換する
7
- def to_byte( value, length )
30
+ def to_byte( value, length, signed=false )
8
31
  return [0x00]*length if value == nil
32
+
33
+ if signed && value < 0
34
+ border = 0x80 << (8 * (length-1))
35
+ value = (value + border) | border
36
+ end
37
+
9
38
  tmp = []
10
39
  length.times {|i|
11
40
  tmp.unshift( value & 0xFF )
@@ -359,9 +388,9 @@ module JavaClass
359
388
  when 0xfe; str = "impdep1"
360
389
  when 0xff; str = "impdep2"
361
390
  else
362
- aise "unknown code. code=" << code.to_s
391
+ raise "unknown code. code=" << code.to_s
363
392
  end
364
- return str;
393
+ return str
365
394
  end
366
395
 
367
396
  end
@@ -0,0 +1,78 @@
1
+
2
+
3
+ module JavaClass
4
+
5
+ # コード
6
+ class Code
7
+ include JavaClass::Base
8
+ def initialize( java_class, index, opcode, operands=[], wide=false )
9
+ @java_class = java_class
10
+ @index = index
11
+ @opcode = opcode
12
+ @operands = operands
13
+ @wide = wide
14
+ end
15
+ def to_s
16
+ # opts = values = operands.inject(""){|str,i|
17
+ # if i.name == "index"
18
+ # c = @java_class.get_constant(i.value)
19
+ # str += c.kind_of?(MemberRefConstant) ? c.name_and_type.name : c.to_s
20
+ # end
21
+ # str
22
+ # }
23
+ values = operands.map{|i|i.to_s}
24
+ values.unshift( Converters.convert_code(opcode) )
25
+ values.unshift( "#{@index} :" )
26
+ # values.push( "#" + opts ) if !opts.empty?
27
+ return values.join(" ")
28
+ end
29
+ def to_bytes
30
+ bytes = []
31
+ bytes += to_byte( 0xC4, 1 ) if wide
32
+ bytes += to_byte( opcode, 1 )
33
+ operands.each {|o|
34
+ bytes += o.to_bytes
35
+ }
36
+ return bytes
37
+ end
38
+ # JavaClass
39
+ attr :java_class, true
40
+ # インデックス
41
+ attr :index, true
42
+ # opcode
43
+ attr :opcode, true
44
+ # operands
45
+ attr :operands, true
46
+ # wideかどうか
47
+ attr :wide, true
48
+ end
49
+
50
+ # オペランド
51
+ class Operand
52
+ include JavaClass::Base
53
+ def initialize( size, value, name="" )
54
+ @size = size
55
+ @value = value
56
+ @name=name
57
+ end
58
+ def to_s
59
+ value.to_s
60
+ end
61
+ def to_bytes
62
+ bytes = []
63
+ if size =~ /(u|s)(\d)/
64
+ bytes += to_byte( value, $2.to_i, $1=="s" )
65
+ else
66
+ raise "unknown size. size=#{size}"
67
+ end
68
+ return bytes
69
+ end
70
+ # データサイズ( s1, u1 ..etc.. )
71
+ attr :size, true
72
+ # 値
73
+ attr :value, true
74
+ # 表示名
75
+ attr :name, true
76
+ end
77
+
78
+ end