paul@137 | 1 | #!/usr/bin/env python |
paul@137 | 2 | |
paul@137 | 3 | """ |
paul@137 | 4 | Java class file decoder. Specification found at the following URL: |
paul@137 | 5 | http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html |
paul@186 | 6 | |
paul@186 | 7 | Copyright (C) 2004, 2005, 2006, 2011 Paul Boddie <paul@boddie.org.uk> |
paul@186 | 8 | Copyright (C) 2010 Braden Thomas <bradenthomas@me.com> |
dmd@188 | 9 | Copyright (C) 2011 David Drysdale <dmd@lurklurk.org> |
paul@186 | 10 | |
paul@186 | 11 | This program is free software; you can redistribute it and/or modify it under |
paul@186 | 12 | the terms of the GNU Lesser General Public License as published by the Free |
paul@186 | 13 | Software Foundation; either version 3 of the License, or (at your option) any |
paul@186 | 14 | later version. |
paul@186 | 15 | |
paul@186 | 16 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@186 | 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@186 | 18 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
paul@186 | 19 | details. |
paul@186 | 20 | |
paul@186 | 21 | You should have received a copy of the GNU Lesser General Public License along |
paul@186 | 22 | with this program. If not, see <http://www.gnu.org/licenses/>. |
paul@137 | 23 | """ |
paul@137 | 24 | |
paul@137 | 25 | import struct # for general decoding of class files |
paul@137 | 26 | |
paul@137 | 27 | # Utility functions. |
paul@137 | 28 | |
paul@137 | 29 | def u1(data): |
paul@137 | 30 | return struct.unpack(">B", data[0:1])[0] |
paul@137 | 31 | |
paul@137 | 32 | def u2(data): |
paul@137 | 33 | return struct.unpack(">H", data[0:2])[0] |
paul@137 | 34 | |
paul@137 | 35 | def s2(data): |
paul@137 | 36 | return struct.unpack(">h", data[0:2])[0] |
paul@137 | 37 | |
paul@137 | 38 | def u4(data): |
paul@137 | 39 | return struct.unpack(">L", data[0:4])[0] |
paul@137 | 40 | |
paul@137 | 41 | def s4(data): |
paul@137 | 42 | return struct.unpack(">l", data[0:4])[0] |
paul@137 | 43 | |
paul@137 | 44 | def s8(data): |
paul@137 | 45 | return struct.unpack(">q", data[0:8])[0] |
paul@137 | 46 | |
paul@137 | 47 | def f4(data): |
paul@137 | 48 | return struct.unpack(">f", data[0:4])[0] |
paul@137 | 49 | |
paul@137 | 50 | def f8(data): |
paul@137 | 51 | return struct.unpack(">d", data[0:8])[0] |
paul@137 | 52 | |
paul@185 | 53 | def su1(value): |
paul@185 | 54 | return struct.pack(">B", value) |
paul@185 | 55 | |
paul@185 | 56 | def su2(value): |
paul@185 | 57 | return struct.pack(">H", value) |
paul@185 | 58 | |
paul@185 | 59 | def ss2(value): |
paul@185 | 60 | return struct.pack(">h", value) |
paul@185 | 61 | |
paul@185 | 62 | def su4(value): |
paul@185 | 63 | return struct.pack(">L", value) |
paul@185 | 64 | |
paul@185 | 65 | def ss4(value): |
paul@185 | 66 | return struct.pack(">l", value) |
paul@185 | 67 | |
paul@185 | 68 | def ss8(value): |
paul@185 | 69 | return struct.pack(">q", value) |
paul@185 | 70 | |
paul@185 | 71 | def sf4(value): |
paul@185 | 72 | return struct.pack(">f", value) |
paul@185 | 73 | |
paul@185 | 74 | def sf8(value): |
paul@185 | 75 | return struct.pack(">d", value) |
paul@185 | 76 | |
paul@137 | 77 | # Useful tables and constants. |
paul@137 | 78 | |
paul@137 | 79 | descriptor_base_type_mapping = { |
paul@137 | 80 | "B" : "int", |
paul@137 | 81 | "C" : "str", |
paul@137 | 82 | "D" : "float", |
paul@137 | 83 | "F" : "float", |
paul@137 | 84 | "I" : "int", |
paul@137 | 85 | "J" : "int", |
paul@137 | 86 | "L" : "object", |
paul@137 | 87 | "S" : "int", |
paul@137 | 88 | "Z" : "bool", |
paul@137 | 89 | "[" : "list" |
paul@137 | 90 | } |
paul@137 | 91 | |
paul@141 | 92 | type_names_to_default_values = { |
paul@141 | 93 | "int" : 0, |
paul@141 | 94 | "str" : u"", |
paul@141 | 95 | "float" : 0.0, |
paul@141 | 96 | "object" : None, |
paul@141 | 97 | "bool" : 0, # NOTE: Should be False. |
paul@141 | 98 | "list" : [] |
paul@141 | 99 | } |
paul@141 | 100 | |
paul@141 | 101 | def get_default_for_type(type_name): |
paul@141 | 102 | global type_names_to_default_values |
paul@141 | 103 | return type_names_to_default_values.get(type_name) |
paul@141 | 104 | |
paul@137 | 105 | PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SUPER, SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE, INTERFACE, ABSTRACT, STRICT = \ |
paul@137 | 106 | 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800 |
paul@137 | 107 | |
paul@137 | 108 | def has_flags(flags, desired): |
paul@137 | 109 | desired_flags = reduce(lambda a, b: a | b, desired, 0) |
paul@137 | 110 | return (flags & desired_flags) == desired_flags |
paul@137 | 111 | |
paul@137 | 112 | # Useful mix-ins. |
paul@137 | 113 | |
paul@137 | 114 | class PythonMethodUtils: |
paul@137 | 115 | symbol_sep = "___" # was "$" |
paul@137 | 116 | type_sep = "__" # replaces "/" |
paul@137 | 117 | array_sep = "_array_" # was "[]" |
paul@137 | 118 | base_seps = ("_", "_") # was "<" and ">" |
paul@137 | 119 | |
paul@137 | 120 | def get_unqualified_python_name(self): |
paul@137 | 121 | name = self.get_name() |
paul@137 | 122 | if str(name) == "<init>": |
paul@137 | 123 | return "__init__" |
paul@137 | 124 | elif str(name) == "<clinit>": |
paul@137 | 125 | return "__clinit__" |
paul@137 | 126 | else: |
paul@137 | 127 | return str(name) |
paul@137 | 128 | |
paul@137 | 129 | def get_python_name(self): |
paul@137 | 130 | name = self.get_unqualified_python_name() |
paul@137 | 131 | if name == "__clinit__": |
paul@137 | 132 | return name |
paul@137 | 133 | return name + self.symbol_sep + self._get_descriptor_as_name() |
paul@137 | 134 | |
paul@137 | 135 | def _get_descriptor_as_name(self): |
paul@137 | 136 | l = [] |
paul@137 | 137 | for descriptor_type in self.get_descriptor()[0]: |
paul@137 | 138 | l.append(self._get_type_as_name(descriptor_type)) |
paul@137 | 139 | return self.symbol_sep.join(l) |
paul@137 | 140 | |
paul@137 | 141 | def _get_type_as_name(self, descriptor_type, s=""): |
paul@137 | 142 | base_type, object_type, array_type = descriptor_type |
paul@137 | 143 | if base_type == "L": |
paul@137 | 144 | return object_type.replace("/", self.type_sep) + s |
paul@137 | 145 | elif base_type == "[": |
paul@137 | 146 | return self._get_type_as_name(array_type, s + self.array_sep) |
paul@137 | 147 | else: |
paul@137 | 148 | return self.base_seps[0] + base_type + self.base_seps[1] + s |
paul@137 | 149 | |
paul@137 | 150 | class PythonNameUtils: |
paul@137 | 151 | def get_python_name(self): |
paul@137 | 152 | # NOTE: This may not be comprehensive. |
paul@137 | 153 | if not str(self.get_name()).startswith("["): |
paul@137 | 154 | return str(self.get_name()).replace("/", ".") |
paul@137 | 155 | else: |
paul@137 | 156 | return self._get_type_name( |
paul@137 | 157 | get_field_descriptor( |
paul@137 | 158 | str(self.get_name()) |
paul@137 | 159 | ) |
paul@137 | 160 | ).replace("/", ".") |
paul@137 | 161 | |
paul@137 | 162 | def _get_type_name(self, descriptor_type): |
paul@137 | 163 | base_type, object_type, array_type = descriptor_type |
paul@137 | 164 | if base_type == "L": |
paul@137 | 165 | return object_type |
paul@137 | 166 | elif base_type == "[": |
paul@137 | 167 | return self._get_type_name(array_type) |
paul@137 | 168 | else: |
paul@137 | 169 | return descriptor_base_type_mapping[base_type] |
paul@137 | 170 | |
paul@137 | 171 | class NameUtils: |
paul@137 | 172 | def get_name(self): |
paul@137 | 173 | if self.name_index != 0: |
paul@137 | 174 | return self.class_file.constants[self.name_index - 1] |
paul@137 | 175 | else: |
paul@137 | 176 | # Some name indexes are zero to indicate special conditions. |
paul@137 | 177 | return None |
paul@137 | 178 | |
paul@137 | 179 | class NameAndTypeUtils: |
paul@137 | 180 | def get_name(self): |
paul@137 | 181 | if self.name_and_type_index != 0: |
paul@137 | 182 | return self.class_file.constants[self.name_and_type_index - 1].get_name() |
paul@137 | 183 | else: |
paul@137 | 184 | # Some name indexes are zero to indicate special conditions. |
paul@137 | 185 | return None |
paul@137 | 186 | |
paul@137 | 187 | def get_field_descriptor(self): |
paul@137 | 188 | if self.name_and_type_index != 0: |
paul@137 | 189 | return self.class_file.constants[self.name_and_type_index - 1].get_field_descriptor() |
paul@137 | 190 | else: |
paul@137 | 191 | # Some name indexes are zero to indicate special conditions. |
paul@137 | 192 | return None |
paul@137 | 193 | |
paul@137 | 194 | def get_method_descriptor(self): |
paul@137 | 195 | if self.name_and_type_index != 0: |
paul@137 | 196 | return self.class_file.constants[self.name_and_type_index - 1].get_method_descriptor() |
paul@137 | 197 | else: |
paul@137 | 198 | # Some name indexes are zero to indicate special conditions. |
paul@137 | 199 | return None |
paul@137 | 200 | |
paul@137 | 201 | def get_class(self): |
paul@137 | 202 | return self.class_file.constants[self.class_index - 1] |
paul@137 | 203 | |
paul@137 | 204 | # Symbol parsing. |
paul@137 | 205 | |
paul@137 | 206 | def get_method_descriptor(s): |
paul@137 | 207 | assert s[0] == "(" |
paul@137 | 208 | params = [] |
paul@137 | 209 | s = s[1:] |
paul@137 | 210 | while s[0] != ")": |
paul@137 | 211 | parameter_descriptor, s = _get_parameter_descriptor(s) |
paul@137 | 212 | params.append(parameter_descriptor) |
paul@137 | 213 | if s[1] != "V": |
paul@137 | 214 | return_type, s = _get_field_type(s[1:]) |
paul@137 | 215 | else: |
paul@137 | 216 | return_type, s = None, s[1:] |
paul@137 | 217 | return params, return_type |
paul@137 | 218 | |
paul@137 | 219 | def get_field_descriptor(s): |
paul@137 | 220 | return _get_field_type(s)[0] |
paul@137 | 221 | |
paul@137 | 222 | def _get_parameter_descriptor(s): |
paul@137 | 223 | return _get_field_type(s) |
paul@137 | 224 | |
paul@137 | 225 | def _get_component_type(s): |
paul@137 | 226 | return _get_field_type(s) |
paul@137 | 227 | |
paul@137 | 228 | def _get_field_type(s): |
paul@137 | 229 | base_type, s = _get_base_type(s) |
paul@137 | 230 | object_type = None |
paul@137 | 231 | array_type = None |
paul@137 | 232 | if base_type == "L": |
paul@137 | 233 | object_type, s = _get_object_type(s) |
paul@137 | 234 | elif base_type == "[": |
paul@137 | 235 | array_type, s = _get_array_type(s) |
paul@137 | 236 | return (base_type, object_type, array_type), s |
paul@137 | 237 | |
paul@137 | 238 | def _get_base_type(s): |
paul@137 | 239 | if len(s) > 0: |
paul@137 | 240 | return s[0], s[1:] |
paul@137 | 241 | else: |
paul@137 | 242 | return None, s |
paul@137 | 243 | |
paul@137 | 244 | def _get_object_type(s): |
paul@137 | 245 | if len(s) > 0: |
paul@137 | 246 | s_end = s.find(";") |
paul@137 | 247 | assert s_end != -1 |
paul@137 | 248 | return s[:s_end], s[s_end+1:] |
paul@137 | 249 | else: |
paul@137 | 250 | return None, s |
paul@137 | 251 | |
paul@137 | 252 | def _get_array_type(s): |
paul@137 | 253 | if len(s) > 0: |
paul@137 | 254 | return _get_component_type(s) |
paul@137 | 255 | else: |
paul@137 | 256 | return None, s |
paul@137 | 257 | |
paul@137 | 258 | # Constant information. |
paul@137 | 259 | |
paul@137 | 260 | class ClassInfo(NameUtils, PythonNameUtils): |
paul@137 | 261 | def init(self, data, class_file): |
paul@137 | 262 | self.class_file = class_file |
paul@137 | 263 | self.name_index = u2(data[0:2]) |
paul@137 | 264 | return data[2:] |
paul@185 | 265 | def serialize(self): |
paul@185 | 266 | return su2(self.name_index) |
paul@137 | 267 | |
paul@137 | 268 | class RefInfo(NameAndTypeUtils): |
paul@137 | 269 | def init(self, data, class_file): |
paul@137 | 270 | self.class_file = class_file |
paul@137 | 271 | self.class_index = u2(data[0:2]) |
paul@137 | 272 | self.name_and_type_index = u2(data[2:4]) |
paul@137 | 273 | return data[4:] |
paul@185 | 274 | def serialize(self): |
paul@185 | 275 | return su2(self.class_index)+su2(self.name_and_type_index) |
paul@137 | 276 | |
paul@137 | 277 | class FieldRefInfo(RefInfo, PythonNameUtils): |
paul@137 | 278 | def get_descriptor(self): |
paul@137 | 279 | return RefInfo.get_field_descriptor(self) |
paul@137 | 280 | |
paul@137 | 281 | class MethodRefInfo(RefInfo, PythonMethodUtils): |
paul@137 | 282 | def get_descriptor(self): |
paul@137 | 283 | return RefInfo.get_method_descriptor(self) |
paul@137 | 284 | |
paul@137 | 285 | class InterfaceMethodRefInfo(MethodRefInfo): |
paul@137 | 286 | pass |
paul@137 | 287 | |
paul@137 | 288 | class NameAndTypeInfo(NameUtils, PythonNameUtils): |
paul@137 | 289 | def init(self, data, class_file): |
paul@137 | 290 | self.class_file = class_file |
paul@137 | 291 | self.name_index = u2(data[0:2]) |
paul@137 | 292 | self.descriptor_index = u2(data[2:4]) |
paul@137 | 293 | return data[4:] |
paul@137 | 294 | |
paul@185 | 295 | def serialize(self): |
paul@185 | 296 | return su2(self.name_index)+su2(self.descriptor_index) |
paul@185 | 297 | |
paul@137 | 298 | def get_field_descriptor(self): |
paul@137 | 299 | return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) |
paul@137 | 300 | |
paul@137 | 301 | def get_method_descriptor(self): |
paul@137 | 302 | return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) |
paul@137 | 303 | |
paul@137 | 304 | class Utf8Info: |
paul@137 | 305 | def init(self, data, class_file): |
paul@137 | 306 | self.class_file = class_file |
paul@137 | 307 | self.length = u2(data[0:2]) |
paul@137 | 308 | self.bytes = data[2:2+self.length] |
paul@137 | 309 | return data[2+self.length:] |
paul@137 | 310 | |
paul@185 | 311 | def serialize(self): |
paul@185 | 312 | return su2(self.length)+self.bytes |
paul@185 | 313 | |
paul@137 | 314 | def __str__(self): |
paul@137 | 315 | return self.bytes |
paul@137 | 316 | |
paul@137 | 317 | def __unicode__(self): |
paul@137 | 318 | return unicode(self.bytes, "utf-8") |
paul@137 | 319 | |
paul@137 | 320 | def get_value(self): |
paul@137 | 321 | return str(self) |
paul@137 | 322 | |
paul@137 | 323 | class StringInfo: |
paul@137 | 324 | def init(self, data, class_file): |
paul@137 | 325 | self.class_file = class_file |
paul@137 | 326 | self.string_index = u2(data[0:2]) |
paul@137 | 327 | return data[2:] |
paul@137 | 328 | |
paul@185 | 329 | def serialize(self): |
paul@185 | 330 | return su2(self.string_index) |
paul@185 | 331 | |
paul@137 | 332 | def __str__(self): |
paul@137 | 333 | return str(self.class_file.constants[self.string_index - 1]) |
paul@137 | 334 | |
paul@137 | 335 | def __unicode__(self): |
paul@137 | 336 | return unicode(self.class_file.constants[self.string_index - 1]) |
paul@137 | 337 | |
paul@137 | 338 | def get_value(self): |
paul@137 | 339 | return str(self) |
paul@137 | 340 | |
paul@137 | 341 | class SmallNumInfo: |
paul@137 | 342 | def init(self, data, class_file): |
paul@137 | 343 | self.class_file = class_file |
paul@137 | 344 | self.bytes = data[0:4] |
paul@137 | 345 | return data[4:] |
paul@185 | 346 | def serialize(self): |
paul@185 | 347 | return self.bytes |
paul@137 | 348 | |
paul@137 | 349 | class IntegerInfo(SmallNumInfo): |
paul@137 | 350 | def get_value(self): |
paul@137 | 351 | return s4(self.bytes) |
paul@137 | 352 | |
paul@137 | 353 | class FloatInfo(SmallNumInfo): |
paul@137 | 354 | def get_value(self): |
paul@137 | 355 | return f4(self.bytes) |
paul@137 | 356 | |
paul@137 | 357 | class LargeNumInfo: |
paul@137 | 358 | def init(self, data, class_file): |
paul@137 | 359 | self.class_file = class_file |
paul@137 | 360 | self.high_bytes = data[0:4] |
paul@137 | 361 | self.low_bytes = data[4:8] |
paul@137 | 362 | return data[8:] |
paul@185 | 363 | def serialize(self): |
paul@185 | 364 | return self.high_bytes+self.low_bytes |
paul@185 | 365 | |
paul@137 | 366 | |
paul@137 | 367 | class LongInfo(LargeNumInfo): |
paul@137 | 368 | def get_value(self): |
paul@137 | 369 | return s8(self.high_bytes + self.low_bytes) |
paul@137 | 370 | |
paul@137 | 371 | class DoubleInfo(LargeNumInfo): |
paul@137 | 372 | def get_value(self): |
paul@137 | 373 | return f8(self.high_bytes + self.low_bytes) |
paul@137 | 374 | |
paul@137 | 375 | # Other information. |
paul@137 | 376 | # Objects of these classes are generally aware of the class they reside in. |
paul@137 | 377 | |
paul@137 | 378 | class ItemInfo(NameUtils): |
paul@137 | 379 | def init(self, data, class_file): |
paul@137 | 380 | self.class_file = class_file |
paul@137 | 381 | self.access_flags = u2(data[0:2]) |
paul@137 | 382 | self.name_index = u2(data[2:4]) |
paul@137 | 383 | self.descriptor_index = u2(data[4:6]) |
paul@137 | 384 | self.attributes, data = self.class_file._get_attributes(data[6:]) |
paul@137 | 385 | return data |
paul@189 | 386 | |
paul@185 | 387 | def serialize(self): |
paul@185 | 388 | od = su2(self.access_flags)+su2(self.name_index)+su2(self.descriptor_index) |
paul@185 | 389 | od += self.class_file._serialize_attributes(self.attributes) |
paul@185 | 390 | return od |
paul@137 | 391 | |
paul@137 | 392 | class FieldInfo(ItemInfo, PythonNameUtils): |
paul@137 | 393 | def get_descriptor(self): |
paul@137 | 394 | return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) |
paul@137 | 395 | |
paul@137 | 396 | class MethodInfo(ItemInfo, PythonMethodUtils): |
paul@137 | 397 | def get_descriptor(self): |
paul@137 | 398 | return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) |
paul@137 | 399 | |
paul@137 | 400 | class AttributeInfo: |
paul@137 | 401 | def init(self, data, class_file): |
paul@137 | 402 | self.attribute_length = u4(data[0:4]) |
paul@137 | 403 | self.info = data[4:4+self.attribute_length] |
paul@137 | 404 | return data[4+self.attribute_length:] |
paul@189 | 405 | |
paul@185 | 406 | def serialize(self): |
paul@185 | 407 | return su4(self.attribute_length)+self.info |
paul@137 | 408 | |
paul@137 | 409 | # NOTE: Decode the different attribute formats. |
paul@137 | 410 | |
paul@137 | 411 | class SourceFileAttributeInfo(AttributeInfo, NameUtils, PythonNameUtils): |
paul@137 | 412 | def init(self, data, class_file): |
paul@137 | 413 | self.class_file = class_file |
paul@137 | 414 | self.attribute_length = u4(data[0:4]) |
paul@137 | 415 | # Permit the NameUtils mix-in. |
paul@137 | 416 | self.name_index = self.sourcefile_index = u2(data[4:6]) |
paul@137 | 417 | return data[6:] |
paul@189 | 418 | |
paul@185 | 419 | def serialize(self): |
paul@185 | 420 | return su4(self.attribute_length)+su2(self.name_index) |
paul@137 | 421 | |
paul@137 | 422 | class ConstantValueAttributeInfo(AttributeInfo): |
paul@137 | 423 | def init(self, data, class_file): |
paul@137 | 424 | self.class_file = class_file |
paul@137 | 425 | self.attribute_length = u4(data[0:4]) |
paul@137 | 426 | self.constant_value_index = u2(data[4:6]) |
paul@137 | 427 | assert 4+self.attribute_length == 6 |
paul@137 | 428 | return data[4+self.attribute_length:] |
paul@137 | 429 | |
paul@137 | 430 | def get_value(self): |
paul@137 | 431 | return self.class_file.constants[self.constant_value_index - 1].get_value() |
paul@137 | 432 | |
paul@185 | 433 | def serialize(self): |
paul@185 | 434 | return su4(self.attribute_length)+su2(self.constant_value_index) |
paul@185 | 435 | |
paul@137 | 436 | class CodeAttributeInfo(AttributeInfo): |
paul@137 | 437 | def init(self, data, class_file): |
paul@137 | 438 | self.class_file = class_file |
paul@137 | 439 | self.attribute_length = u4(data[0:4]) |
paul@137 | 440 | self.max_stack = u2(data[4:6]) |
paul@137 | 441 | self.max_locals = u2(data[6:8]) |
paul@137 | 442 | self.code_length = u4(data[8:12]) |
paul@137 | 443 | end_of_code = 12+self.code_length |
paul@137 | 444 | self.code = data[12:end_of_code] |
paul@137 | 445 | self.exception_table_length = u2(data[end_of_code:end_of_code+2]) |
paul@137 | 446 | self.exception_table = [] |
paul@137 | 447 | data = data[end_of_code + 2:] |
paul@137 | 448 | for i in range(0, self.exception_table_length): |
paul@137 | 449 | exception = ExceptionInfo() |
paul@137 | 450 | data = exception.init(data) |
paul@137 | 451 | self.exception_table.append(exception) |
paul@137 | 452 | self.attributes, data = self.class_file._get_attributes(data) |
paul@137 | 453 | return data |
paul@189 | 454 | |
paul@185 | 455 | def serialize(self): |
paul@185 | 456 | od = su4(self.attribute_length)+su2(self.max_stack)+su2(self.max_locals)+su4(self.code_length)+self.code |
paul@185 | 457 | od += su2(self.exception_table_length) |
paul@185 | 458 | for e in self.exception_table: |
paul@185 | 459 | od += e.serialize() |
paul@185 | 460 | od += self.class_file._serialize_attributes(self.attributes) |
paul@185 | 461 | return od |
paul@137 | 462 | |
paul@137 | 463 | class ExceptionsAttributeInfo(AttributeInfo): |
paul@137 | 464 | def init(self, data, class_file): |
paul@137 | 465 | self.class_file = class_file |
paul@137 | 466 | self.attribute_length = u4(data[0:4]) |
paul@137 | 467 | self.number_of_exceptions = u2(data[4:6]) |
paul@137 | 468 | self.exception_index_table = [] |
paul@137 | 469 | index = 6 |
paul@137 | 470 | for i in range(0, self.number_of_exceptions): |
paul@137 | 471 | self.exception_index_table.append(u2(data[index:index+2])) |
paul@137 | 472 | index += 2 |
paul@137 | 473 | return data[index:] |
paul@137 | 474 | |
paul@137 | 475 | def get_exception(self, i): |
paul@137 | 476 | exception_index = self.exception_index_table[i] |
paul@137 | 477 | return self.class_file.constants[exception_index - 1] |
paul@185 | 478 | |
paul@185 | 479 | def serialize(self): |
paul@185 | 480 | od = su4(self.attribute_length)+su2(self.number_of_exceptions) |
paul@185 | 481 | for ei in self.exception_index_table: |
paul@185 | 482 | od += su2(ei) |
paul@185 | 483 | return od |
paul@137 | 484 | |
paul@137 | 485 | class InnerClassesAttributeInfo(AttributeInfo): |
paul@137 | 486 | def init(self, data, class_file): |
paul@137 | 487 | self.class_file = class_file |
paul@137 | 488 | self.attribute_length = u4(data[0:4]) |
paul@137 | 489 | self.number_of_classes = u2(data[4:6]) |
paul@137 | 490 | self.classes = [] |
paul@137 | 491 | data = data[6:] |
paul@137 | 492 | for i in range(0, self.number_of_classes): |
paul@137 | 493 | inner_class = InnerClassInfo() |
paul@137 | 494 | data = inner_class.init(data, self.class_file) |
paul@137 | 495 | self.classes.append(inner_class) |
paul@137 | 496 | return data |
paul@137 | 497 | |
paul@185 | 498 | def serialize(self): |
paul@185 | 499 | od = su4(self.attribute_length)+su2(self.number_of_classes) |
paul@185 | 500 | for c in self.classes: |
paul@185 | 501 | od += c.serialize() |
paul@185 | 502 | return od |
paul@185 | 503 | |
paul@137 | 504 | class SyntheticAttributeInfo(AttributeInfo): |
paul@137 | 505 | pass |
paul@137 | 506 | |
paul@137 | 507 | class LineNumberAttributeInfo(AttributeInfo): |
paul@137 | 508 | def init(self, data, class_file): |
paul@137 | 509 | self.class_file = class_file |
paul@137 | 510 | self.attribute_length = u4(data[0:4]) |
paul@137 | 511 | self.line_number_table_length = u2(data[4:6]) |
paul@137 | 512 | self.line_number_table = [] |
paul@137 | 513 | data = data[6:] |
paul@137 | 514 | for i in range(0, self.line_number_table_length): |
paul@137 | 515 | line_number = LineNumberInfo() |
paul@137 | 516 | data = line_number.init(data) |
paul@137 | 517 | self.line_number_table.append(line_number) |
paul@137 | 518 | return data |
paul@185 | 519 | |
paul@185 | 520 | def serialize(self): |
paul@185 | 521 | od = su4(self.attribute_length)+su2(self.line_number_table_length) |
paul@185 | 522 | for ln in self.line_number_table: |
paul@185 | 523 | od += ln.serialize() |
paul@185 | 524 | return od |
paul@137 | 525 | |
paul@137 | 526 | class LocalVariableAttributeInfo(AttributeInfo): |
paul@137 | 527 | def init(self, data, class_file): |
paul@137 | 528 | self.class_file = class_file |
paul@137 | 529 | self.attribute_length = u4(data[0:4]) |
paul@137 | 530 | self.local_variable_table_length = u2(data[4:6]) |
paul@137 | 531 | self.local_variable_table = [] |
paul@137 | 532 | data = data[6:] |
paul@137 | 533 | for i in range(0, self.local_variable_table_length): |
paul@137 | 534 | local_variable = LocalVariableInfo() |
paul@137 | 535 | data = local_variable.init(data, self.class_file) |
paul@137 | 536 | self.local_variable_table.append(local_variable) |
paul@137 | 537 | return data |
paul@137 | 538 | |
paul@185 | 539 | def serialize(self): |
paul@185 | 540 | od = su4(self.attribute_length)+su2(self.local_variable_table_length) |
paul@185 | 541 | for lv in self.local_variable_table: |
paul@185 | 542 | od += lv.serialize() |
paul@185 | 543 | return od |
paul@185 | 544 | |
dmd@188 | 545 | class LocalVariableTypeAttributeInfo(AttributeInfo): |
dmd@188 | 546 | def init(self, data, class_file): |
dmd@188 | 547 | self.class_file = class_file |
dmd@188 | 548 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 549 | local_variable_type_table_length = u2(data[4:6]) |
dmd@188 | 550 | data = data[6:] |
dmd@188 | 551 | self.local_variable_type_table = [] |
dmd@188 | 552 | for i in range(0, local_variable_type_table_length): |
dmd@188 | 553 | local_variable = LocalVariableInfo() |
dmd@188 | 554 | data = local_variable.init(data, self.class_file) |
dmd@188 | 555 | self.local_variable_type_table.append(local_variable) |
dmd@188 | 556 | return data |
dmd@188 | 557 | |
dmd@188 | 558 | def serialize(self): |
dmd@188 | 559 | od = su4(self.attribute_length)+su2(len(self.local_variable_type_table)) |
dmd@188 | 560 | od += "".join([lv.serialize() for lv in self.local_variable_type_table]) |
dmd@188 | 561 | return od |
dmd@188 | 562 | |
paul@137 | 563 | class DeprecatedAttributeInfo(AttributeInfo): |
paul@137 | 564 | pass |
paul@137 | 565 | |
dmd@188 | 566 | class VerificationTypeInfo(object): |
dmd@188 | 567 | def __init__(self, tag): |
dmd@188 | 568 | self.tag = tag |
paul@189 | 569 | |
dmd@188 | 570 | def init(self, data, class_file): |
dmd@188 | 571 | self.class_file = class_file |
dmd@188 | 572 | tag = u1(data[0:1]) |
dmd@188 | 573 | assert(tag == self.tag) |
dmd@188 | 574 | return data[1:] |
paul@189 | 575 | |
dmd@188 | 576 | def serialize(self): |
dmd@188 | 577 | return su1(self.tag) |
paul@189 | 578 | |
dmd@188 | 579 | class TopVariableInfo(VerificationTypeInfo): |
dmd@188 | 580 | TAG = 0 |
paul@189 | 581 | |
dmd@188 | 582 | class IntegerVariableInfo(VerificationTypeInfo): |
dmd@188 | 583 | TAG = 1 |
paul@189 | 584 | |
dmd@188 | 585 | class FloatVariableInfo(VerificationTypeInfo): |
dmd@188 | 586 | TAG = 2 |
paul@189 | 587 | |
dmd@188 | 588 | class DoubleVariableInfo(VerificationTypeInfo): |
dmd@188 | 589 | TAG = 3 |
paul@189 | 590 | |
dmd@188 | 591 | class LongVariableInfo(VerificationTypeInfo): |
dmd@188 | 592 | TAG = 4 |
paul@189 | 593 | |
dmd@188 | 594 | class NullVariableInfo(VerificationTypeInfo): |
dmd@188 | 595 | TAG = 5 |
paul@189 | 596 | |
dmd@188 | 597 | class UninitializedThisVariableInfo(VerificationTypeInfo): |
dmd@188 | 598 | TAG = 6 |
paul@189 | 599 | |
dmd@188 | 600 | class ObjectVariableInfo(VerificationTypeInfo): |
dmd@188 | 601 | TAG = 7 |
paul@189 | 602 | |
dmd@188 | 603 | def init(self, data, class_file): |
dmd@188 | 604 | data = super(ObjectVariableInfo, self).init(data, class_file) |
dmd@188 | 605 | self.cpool_index = u2(data) |
dmd@188 | 606 | return data[2:] |
paul@189 | 607 | |
dmd@188 | 608 | def serialize(self): |
dmd@188 | 609 | return super(ObjectVariableInfo, self).serialize() + su2(self.cpool_index) |
paul@189 | 610 | |
dmd@188 | 611 | class UninitializedVariableInfo(VerificationTypeInfo): |
dmd@188 | 612 | TAG = 8 |
paul@189 | 613 | |
dmd@188 | 614 | def init(self, data, class_file): |
dmd@188 | 615 | data = super(UninitializedVariableInfo, self).init(data, class_file) |
dmd@188 | 616 | self.offset = u2(data) |
dmd@188 | 617 | return data[2:] |
paul@189 | 618 | |
dmd@188 | 619 | def serialize(self): |
dmd@188 | 620 | return super(UninitializedVariableInfo, self).serialize() + su2(self.offset) |
dmd@188 | 621 | |
dmd@188 | 622 | VARIABLE_INFO_CLASSES = (TopVariableInfo, IntegerVariableInfo, FloatVariableInfo, DoubleVariableInfo, |
dmd@188 | 623 | LongVariableInfo, NullVariableInfo, UninitializedThisVariableInfo, |
dmd@188 | 624 | ObjectVariableInfo, UninitializedVariableInfo) |
dmd@188 | 625 | VARIABLE_INFO_TAG_MAP = dict([(cls.TAG, cls) for cls in VARIABLE_INFO_CLASSES]) |
dmd@188 | 626 | |
paul@189 | 627 | # Exception. |
paul@189 | 628 | |
dmd@188 | 629 | class UnknownVariableInfo: |
dmd@188 | 630 | def __init__(self, tag): |
dmd@188 | 631 | self.tag = tag |
paul@189 | 632 | |
dmd@188 | 633 | def __str__(self): |
dmd@188 | 634 | return repr(self.tag) |
dmd@188 | 635 | |
dmd@188 | 636 | def create_verification_type_info(data): |
paul@189 | 637 | # Does not consume data, just does lookahead. |
dmd@188 | 638 | tag = u1(data[0:1]) |
dmd@188 | 639 | if tag in VARIABLE_INFO_TAG_MAP: |
dmd@188 | 640 | return VARIABLE_INFO_TAG_MAP[tag](tag) |
dmd@188 | 641 | else: |
dmd@188 | 642 | raise UnknownVariableInfo, tag |
dmd@188 | 643 | |
dmd@188 | 644 | class StackMapFrame(object): |
dmd@188 | 645 | def __init__(self, frame_type): |
dmd@188 | 646 | self.frame_type = frame_type |
paul@189 | 647 | |
dmd@188 | 648 | def init(self, data, class_file): |
dmd@188 | 649 | self.class_file = class_file |
dmd@188 | 650 | frame_type = u1(data[0:1]) |
dmd@188 | 651 | assert(frame_type == self.frame_type) |
dmd@188 | 652 | return data[1:] |
paul@189 | 653 | |
dmd@188 | 654 | def serialize(self): |
dmd@188 | 655 | return su1(self.frame_type) |
paul@189 | 656 | |
dmd@188 | 657 | class SameFrame(StackMapFrame): |
dmd@188 | 658 | TYPE_LOWER = 0 |
dmd@188 | 659 | TYPE_UPPER = 63 |
paul@189 | 660 | |
dmd@188 | 661 | class SameLocals1StackItemFrame(StackMapFrame): |
dmd@188 | 662 | TYPE_LOWER = 64 |
dmd@188 | 663 | TYPE_UPPER = 127 |
paul@189 | 664 | |
dmd@188 | 665 | def init(self, data, class_file): |
dmd@188 | 666 | data = super(SameLocals1StackItemFrame, self).init(data, class_file) |
dmd@188 | 667 | self.offset_delta = self.frame_type - 64 |
dmd@188 | 668 | self.stack = [create_verification_type_info(data)] |
dmd@188 | 669 | return self.stack[0].init(data, class_file) |
paul@189 | 670 | |
dmd@188 | 671 | def serialize(self): |
dmd@188 | 672 | return super(SameLocals1StackItemFrame, self).serialize()+self.stack[0].serialize() |
paul@189 | 673 | |
dmd@188 | 674 | class SameLocals1StackItemFrameExtended(StackMapFrame): |
dmd@188 | 675 | TYPE_LOWER = 247 |
dmd@188 | 676 | TYPE_UPPER = 247 |
paul@189 | 677 | |
dmd@188 | 678 | def init(self, data, class_file): |
dmd@188 | 679 | data = super(SameLocals1StackItemFrameExtended, self).init(data, class_file) |
dmd@188 | 680 | self.offset_delta = u2(data[0:2]) |
dmd@188 | 681 | data = data[2:] |
dmd@188 | 682 | self.stack = [create_verification_type_info(data)] |
dmd@188 | 683 | return self.stack[0].init(data, class_file) |
paul@189 | 684 | |
dmd@188 | 685 | def serialize(self): |
dmd@188 | 686 | return super(SameLocals1StackItemFrameExtended, self).serialize()+su2(self.offset_delta)+self.stack[0].serialize() |
paul@189 | 687 | |
dmd@188 | 688 | class ChopFrame(StackMapFrame): |
dmd@188 | 689 | TYPE_LOWER = 248 |
dmd@188 | 690 | TYPE_UPPER = 250 |
paul@189 | 691 | |
dmd@188 | 692 | def init(self, data, class_file): |
dmd@188 | 693 | data = super(ChopFrame, self).init(data, class_file) |
dmd@188 | 694 | self.offset_delta = u2(data[0:2]) |
dmd@188 | 695 | return data[2:] |
paul@189 | 696 | |
dmd@188 | 697 | def serialize(self): |
dmd@188 | 698 | return super(ChopFrame, self).serialize()+su2(self.offset_delta) |
paul@189 | 699 | |
dmd@188 | 700 | class SameFrameExtended(StackMapFrame): |
dmd@188 | 701 | TYPE_LOWER = 251 |
dmd@188 | 702 | TYPE_UPPER = 251 |
paul@189 | 703 | |
dmd@188 | 704 | def init(self, data, class_file): |
dmd@188 | 705 | data = super(SameFrameExtended, self).init(data, class_file) |
dmd@188 | 706 | self.offset_delta = u2(data[0:2]) |
dmd@188 | 707 | return data[2:] |
paul@189 | 708 | |
dmd@188 | 709 | def serialize(self): |
dmd@188 | 710 | return super(SameFrameExtended, self).serialize()+su2(self.offset_delta) |
paul@189 | 711 | |
dmd@188 | 712 | class AppendFrame(StackMapFrame): |
dmd@188 | 713 | TYPE_LOWER = 252 |
dmd@188 | 714 | TYPE_UPPER = 254 |
paul@189 | 715 | |
dmd@188 | 716 | def init(self, data, class_file): |
dmd@188 | 717 | data = super(AppendFrame, self).init(data, class_file) |
dmd@188 | 718 | self.offset_delta = u2(data[0:2]) |
dmd@188 | 719 | data = data[2:] |
dmd@188 | 720 | num_locals = self.frame_type - 251 |
dmd@188 | 721 | self.locals = [] |
dmd@188 | 722 | for ii in xrange(num_locals): |
dmd@188 | 723 | info = create_verification_type_info(data) |
dmd@188 | 724 | data = info.init(data, class_file) |
dmd@188 | 725 | self.locals.append(info) |
dmd@188 | 726 | return data |
paul@189 | 727 | |
dmd@188 | 728 | def serialize(self): |
dmd@188 | 729 | od = super(AppendFrame, self).serialize()+su2(self.offset_delta) |
dmd@188 | 730 | od += "".join([l.serialize() for l in self.locals]) |
dmd@188 | 731 | return od |
paul@189 | 732 | |
dmd@188 | 733 | class FullFrame(StackMapFrame): |
dmd@188 | 734 | TYPE_LOWER = 255 |
dmd@188 | 735 | TYPE_UPPER = 255 |
paul@189 | 736 | |
dmd@188 | 737 | def init(self, data, class_file): |
dmd@188 | 738 | data = super(FullFrame, self).init(data, class_file) |
dmd@188 | 739 | self.offset_delta = u2(data[0:2]) |
dmd@188 | 740 | num_locals = u2(data[2:4]) |
dmd@188 | 741 | data = data[4:] |
dmd@188 | 742 | self.locals = [] |
dmd@188 | 743 | for ii in xrange(num_locals): |
dmd@188 | 744 | info = create_verification_type_info(data) |
dmd@188 | 745 | data = info.init(data, class_file) |
dmd@188 | 746 | self.locals.append(info) |
dmd@188 | 747 | num_stack_items = u2(data[0:2]) |
dmd@188 | 748 | data = data[2:] |
dmd@188 | 749 | self.stack = [] |
dmd@188 | 750 | for ii in xrange(num_stack_items): |
dmd@188 | 751 | stack_item = create_verification_type_info(data) |
dmd@188 | 752 | data = stack_item.init(data, class_file) |
dmd@188 | 753 | self.stack.append(stack_item) |
dmd@188 | 754 | return data |
paul@189 | 755 | |
dmd@188 | 756 | def serialize(self): |
dmd@188 | 757 | od = super(FullFrame, self).serialize()+su2(self.offset_delta)+su2(len(self.locals)) |
dmd@188 | 758 | od += "".join([l.serialize() for l in self.locals]) |
dmd@188 | 759 | od += su2(len(self.stack)) |
dmd@188 | 760 | od += "".join([s.serialize() for s in self.stack]) |
dmd@188 | 761 | return od |
dmd@188 | 762 | |
dmd@188 | 763 | FRAME_CLASSES = (SameFrame, SameLocals1StackItemFrame, SameLocals1StackItemFrameExtended, |
dmd@188 | 764 | ChopFrame, SameFrameExtended, AppendFrame, FullFrame) |
dmd@188 | 765 | |
paul@189 | 766 | # Exception. |
paul@189 | 767 | |
dmd@188 | 768 | class UnknownStackFrame: |
dmd@188 | 769 | def __init__(self, frame_type): |
dmd@188 | 770 | self.frame_type = frame_type |
dmd@188 | 771 | def __str__(self): |
dmd@188 | 772 | return repr(self.frame_type) |
dmd@188 | 773 | |
dmd@188 | 774 | def create_stack_frame(data): |
paul@189 | 775 | # Does not consume data, just does lookahead. |
dmd@188 | 776 | frame_type = u1(data[0:1]) |
dmd@188 | 777 | for cls in FRAME_CLASSES: |
dmd@188 | 778 | if frame_type >= cls.TYPE_LOWER and frame_type <= cls.TYPE_UPPER: |
dmd@188 | 779 | return cls(frame_type) |
dmd@188 | 780 | raise UnknownStackFrame, frame_type |
dmd@188 | 781 | |
dmd@188 | 782 | class StackMapTableAttributeInfo(AttributeInfo): |
dmd@188 | 783 | def init(self, data, class_file): |
dmd@188 | 784 | self.class_file = class_file |
dmd@188 | 785 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 786 | num_entries = u2(data[4:6]) |
dmd@188 | 787 | self.entries = [] |
dmd@188 | 788 | data = data[6:] |
dmd@188 | 789 | for i in range(0, num_entries): |
dmd@188 | 790 | frame = create_stack_frame(data) |
dmd@188 | 791 | data = frame.init(data, class_file) |
dmd@188 | 792 | self.entries.append(frame) |
dmd@188 | 793 | return data |
paul@189 | 794 | |
dmd@188 | 795 | def serialize(self): |
dmd@188 | 796 | od = su4(self.attribute_length)+su2(len(self.entries)) |
dmd@188 | 797 | od += "".join([e.serialize() for e in self.entries]) |
dmd@188 | 798 | return od |
dmd@188 | 799 | |
dmd@188 | 800 | class EnclosingMethodAttributeInfo(AttributeInfo): |
dmd@188 | 801 | def init(self, data, class_file): |
dmd@188 | 802 | self.class_file = class_file |
dmd@188 | 803 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 804 | self.class_index = u2(data[4:6]) |
dmd@188 | 805 | self.method_index = u2(data[6:8]) |
dmd@188 | 806 | return data[8:] |
paul@189 | 807 | |
dmd@188 | 808 | def serialize(self): |
dmd@188 | 809 | return su4(self.attribute_length)+su2(self.class_index)+su2(self.method_index) |
dmd@188 | 810 | |
dmd@188 | 811 | class SignatureAttributeInfo(AttributeInfo): |
dmd@188 | 812 | def init(self, data, class_file): |
dmd@188 | 813 | self.class_file = class_file |
dmd@188 | 814 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 815 | self.signature_index = u2(data[4:6]) |
dmd@188 | 816 | return data[6:] |
paul@189 | 817 | |
dmd@188 | 818 | def serialize(self): |
dmd@188 | 819 | return su4(self.attribute_length)+su2(self.signature_index) |
dmd@188 | 820 | |
dmd@188 | 821 | class SourceDebugExtensionAttributeInfo(AttributeInfo): |
dmd@188 | 822 | def init(self, data, class_file): |
dmd@188 | 823 | self.class_file = class_file |
dmd@188 | 824 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 825 | self.debug_extension = data[4:(4 + self.attribute_length)] |
dmd@188 | 826 | return data[(4+ self.attribute_length):] |
paul@189 | 827 | |
dmd@188 | 828 | def serialize(self): |
dmd@188 | 829 | return su4(self.attribute_length)+self.debug_extension |
dmd@188 | 830 | |
dmd@188 | 831 | class ElementValue(object): |
dmd@188 | 832 | def __init__(self, tag): |
dmd@188 | 833 | self.tag = tag |
paul@189 | 834 | |
dmd@188 | 835 | def init(self, data, class_file): |
dmd@188 | 836 | self.class_file = class_file |
dmd@188 | 837 | tag = chr(u1(data[0:1])) |
dmd@188 | 838 | assert(tag == self.tag) |
dmd@188 | 839 | return data[1:] |
paul@189 | 840 | |
dmd@188 | 841 | def serialize(self): |
dmd@188 | 842 | return su1(ord(self.tag)) |
paul@189 | 843 | |
dmd@188 | 844 | class ConstValue(ElementValue): |
dmd@188 | 845 | def init(self, data, class_file): |
dmd@188 | 846 | data = super(ConstValue, self).init(data, class_file) |
dmd@188 | 847 | self.const_value_index = u2(data[0:2]) |
dmd@188 | 848 | return data[2:] |
paul@189 | 849 | |
dmd@188 | 850 | def serialize(self): |
dmd@188 | 851 | return super(ConstValue, self).serialize()+su2(self.const_value_index) |
paul@189 | 852 | |
dmd@188 | 853 | class EnumConstValue(ElementValue): |
dmd@188 | 854 | def init(self, data, class_file): |
dmd@188 | 855 | data = super(EnumConstValue, self).init(data, class_file) |
dmd@188 | 856 | self.type_name_index = u2(data[0:2]) |
dmd@188 | 857 | self.const_name_index = u2(data[2:4]) |
dmd@188 | 858 | return data[4:] |
paul@189 | 859 | |
dmd@188 | 860 | def serialize(self): |
dmd@188 | 861 | return super(EnumConstValue, self).serialize()+su2(self.type_name_index)+su2(self.const_name_index) |
paul@189 | 862 | |
dmd@188 | 863 | class ClassInfoValue(ElementValue): |
dmd@188 | 864 | def init(self, data, class_file): |
dmd@188 | 865 | data = super(ClassInfoValue, self).init(data, class_file) |
dmd@188 | 866 | self.class_info_index = u2(data[0:2]) |
dmd@188 | 867 | return data[2:] |
paul@189 | 868 | |
dmd@188 | 869 | def serialize(self): |
dmd@188 | 870 | return super(ClassInfoValue, self).serialize()+su2(self.class_info_index) |
paul@189 | 871 | |
dmd@188 | 872 | class AnnotationValue(ElementValue): |
dmd@188 | 873 | def init(self, data, class_file): |
dmd@188 | 874 | data = super(AnnotationValue, self).init(data, class_file) |
dmd@188 | 875 | self.annotation_value = Annotation() |
dmd@188 | 876 | return self.annotation_value.init(data, class_file) |
paul@189 | 877 | |
dmd@188 | 878 | def serialize(self): |
dmd@188 | 879 | return super(AnnotationValue, self).serialize()+self.annotation_value.serialize() |
paul@189 | 880 | |
dmd@188 | 881 | class ArrayValue(ElementValue): |
dmd@188 | 882 | def init(self, data, class_file): |
dmd@188 | 883 | data = super(ArrayValue, self).init(data, class_file) |
dmd@188 | 884 | num_values = u2(data[0:2]) |
dmd@188 | 885 | data = data[2:] |
dmd@188 | 886 | self.values = [] |
dmd@188 | 887 | for ii in xrange(num_values): |
dmd@188 | 888 | element_value = create_element_value(data) |
dmd@188 | 889 | data = element_value.init(data, class_file) |
dmd@188 | 890 | self.values.append(element_value) |
dmd@188 | 891 | return data |
paul@189 | 892 | |
dmd@188 | 893 | def serialize(self): |
dmd@188 | 894 | od = super(ArrayValue, self).serialize()+su2(len(self.values)) |
dmd@188 | 895 | od += "".join([v.serialize() for v in self.values]) |
dmd@188 | 896 | return od |
paul@189 | 897 | |
paul@189 | 898 | # Exception. |
paul@189 | 899 | |
dmd@188 | 900 | class UnknownElementValue: |
dmd@188 | 901 | def __init__(self, tag): |
dmd@188 | 902 | self.tag = tag |
dmd@188 | 903 | def __str__(self): |
dmd@188 | 904 | return repr(self.tag) |
dmd@188 | 905 | |
dmd@188 | 906 | def create_element_value(data): |
dmd@188 | 907 | tag = chr(u1(data[0:1])) |
dmd@188 | 908 | if tag in ('B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's'): |
dmd@188 | 909 | return ConstValue(tag) |
dmd@188 | 910 | elif tag == 'e': |
dmd@188 | 911 | return EnumConstValue(tag) |
dmd@188 | 912 | elif tag == 'c': |
dmd@188 | 913 | return ClassInfoValue(tag) |
dmd@188 | 914 | elif tag == '@': |
dmd@188 | 915 | return AnnotationValue(tag) |
dmd@188 | 916 | elif tag == '[': |
dmd@188 | 917 | return ArrayValue(tag) |
dmd@188 | 918 | else: |
dmd@188 | 919 | raise UnknownElementValue, tag |
dmd@188 | 920 | |
dmd@188 | 921 | class Annotation(object): |
dmd@188 | 922 | def init(self, data, class_file): |
dmd@188 | 923 | self.class_file = class_file |
dmd@188 | 924 | self.type_index = u2(data[0:2]) |
dmd@188 | 925 | num_element_value_pairs = u2(data[2:4]) |
dmd@188 | 926 | data = data[4:] |
dmd@188 | 927 | self.element_value_pairs = [] |
dmd@188 | 928 | for ii in xrange(num_element_value_pairs): |
dmd@188 | 929 | element_name_index = u2(data[0:2]) |
dmd@188 | 930 | data = data[2:] |
dmd@188 | 931 | element_value = create_element_value(data) |
dmd@188 | 932 | data = element_value.init(data, class_file) |
dmd@188 | 933 | self.element_value_pairs.append((element_name_index, element_value)) |
dmd@188 | 934 | return data |
paul@189 | 935 | |
dmd@188 | 936 | def serialize(self): |
dmd@188 | 937 | od = su2(self.type_index)+su2(len(self.element_value_pairs)) |
dmd@188 | 938 | od += "".join([su2(evp[0])+evp[1].serialize() for evp in self.element_value_pairs]) |
dmd@188 | 939 | return od |
dmd@188 | 940 | |
dmd@188 | 941 | class RuntimeAnnotationsAttributeInfo(AttributeInfo): |
dmd@188 | 942 | def init(self, data, class_file): |
dmd@188 | 943 | self.class_file = class_file |
dmd@188 | 944 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 945 | num_annotations = u2(data[4:6]) |
dmd@188 | 946 | data = data[6:] |
dmd@188 | 947 | self.annotations = [] |
dmd@188 | 948 | for ii in xrange(num_annotations): |
dmd@188 | 949 | annotation = Annotation() |
dmd@188 | 950 | data = annotation.init(data, class_file) |
dmd@188 | 951 | self.annotations.append(annotation) |
dmd@188 | 952 | return data |
paul@189 | 953 | |
dmd@188 | 954 | def serialize(self): |
dmd@188 | 955 | od = su4(self.attribute_length)+su2(len(self.annotations)) |
dmd@188 | 956 | od += "".join([a.serialize() for a in self.annotations]) |
dmd@188 | 957 | return od |
dmd@188 | 958 | |
dmd@188 | 959 | class RuntimeVisibleAnnotationsAttributeInfo(RuntimeAnnotationsAttributeInfo): |
dmd@188 | 960 | pass |
dmd@188 | 961 | |
dmd@188 | 962 | class RuntimeInvisibleAnnotationsAttributeInfo(RuntimeAnnotationsAttributeInfo): |
dmd@188 | 963 | pass |
dmd@188 | 964 | |
dmd@188 | 965 | class RuntimeParameterAnnotationsAttributeInfo(AttributeInfo): |
dmd@188 | 966 | def init(self, data, class_file): |
dmd@188 | 967 | self.class_file = class_file |
dmd@188 | 968 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 969 | num_parameters = u1(data[4:5]) |
dmd@188 | 970 | data = data[5:] |
dmd@188 | 971 | self.parameter_annotations = [] |
dmd@188 | 972 | for ii in xrange(num_parameters): |
dmd@188 | 973 | num_annotations = u2(data[0:2]) |
dmd@188 | 974 | data = data[2:] |
dmd@188 | 975 | annotations = [] |
dmd@188 | 976 | for jj in xrange(num_annotations): |
dmd@188 | 977 | annotation = Annotation() |
dmd@188 | 978 | data = annotation.init(data, class_file) |
dmd@188 | 979 | annotations.append(annotation) |
dmd@188 | 980 | self.parameter_annotations.append(annotations) |
dmd@188 | 981 | return data |
paul@189 | 982 | |
dmd@188 | 983 | def serialize(self): |
dmd@188 | 984 | od = su4(self.attribute_length)+su1(len(self.parameter_annotations)) |
dmd@188 | 985 | for pa in self.parameter_annotations: |
dmd@188 | 986 | od += su2(len(pa)) |
dmd@188 | 987 | od += "".join([a.serialize() for a in pa]) |
dmd@188 | 988 | return od |
dmd@188 | 989 | |
dmd@188 | 990 | class RuntimeVisibleParameterAnnotationsAttributeInfo(RuntimeParameterAnnotationsAttributeInfo): |
dmd@188 | 991 | pass |
dmd@188 | 992 | |
dmd@188 | 993 | class RuntimeInvisibleParameterAnnotationsAttributeInfo(RuntimeParameterAnnotationsAttributeInfo): |
dmd@188 | 994 | pass |
dmd@188 | 995 | |
dmd@188 | 996 | class AnnotationDefaultAttributeInfo(AttributeInfo): |
dmd@188 | 997 | def init(self, data, class_file): |
dmd@188 | 998 | self.class_file = class_file |
dmd@188 | 999 | self.attribute_length = u4(data[0:4]) |
dmd@188 | 1000 | data = data[4:] |
dmd@188 | 1001 | self.default_value = create_element_value(data) |
dmd@188 | 1002 | return self.default_value.init(data, class_file) |
paul@189 | 1003 | |
dmd@188 | 1004 | def serialize(self): |
dmd@188 | 1005 | return su4(self.attribute_length)+self.default_value.serialize() |
dmd@188 | 1006 | |
paul@137 | 1007 | # Child classes of the attribute information classes. |
paul@137 | 1008 | |
paul@137 | 1009 | class ExceptionInfo: |
paul@137 | 1010 | def init(self, data): |
paul@137 | 1011 | self.start_pc = u2(data[0:2]) |
paul@137 | 1012 | self.end_pc = u2(data[2:4]) |
paul@137 | 1013 | self.handler_pc = u2(data[4:6]) |
paul@137 | 1014 | self.catch_type = u2(data[6:8]) |
paul@137 | 1015 | return data[8:] |
paul@189 | 1016 | |
paul@185 | 1017 | def serialize(self): |
paul@185 | 1018 | return su2(self.start_pc)+su2(self.end_pc)+su2(self.handler_pc)+su2(self.catch_type) |
paul@137 | 1019 | |
paul@137 | 1020 | class InnerClassInfo(NameUtils): |
paul@137 | 1021 | def init(self, data, class_file): |
paul@137 | 1022 | self.class_file = class_file |
paul@137 | 1023 | self.inner_class_info_index = u2(data[0:2]) |
paul@137 | 1024 | self.outer_class_info_index = u2(data[2:4]) |
paul@137 | 1025 | # Permit the NameUtils mix-in. |
paul@137 | 1026 | self.name_index = self.inner_name_index = u2(data[4:6]) |
paul@137 | 1027 | self.inner_class_access_flags = u2(data[6:8]) |
paul@137 | 1028 | return data[8:] |
paul@189 | 1029 | |
paul@185 | 1030 | def serialize(self): |
paul@185 | 1031 | return su2(self.inner_class_info_index)+su2(self.outer_class_info_index)+su2(self.name_index)+su2(self.inner_class_access_flags) |
paul@137 | 1032 | |
paul@137 | 1033 | class LineNumberInfo: |
paul@137 | 1034 | def init(self, data): |
paul@137 | 1035 | self.start_pc = u2(data[0:2]) |
paul@137 | 1036 | self.line_number = u2(data[2:4]) |
paul@137 | 1037 | return data[4:] |
paul@185 | 1038 | |
paul@185 | 1039 | def serialize(self): |
paul@185 | 1040 | return su2(self.start_pc)+su2(self.line_number) |
paul@137 | 1041 | |
paul@137 | 1042 | class LocalVariableInfo(NameUtils, PythonNameUtils): |
paul@137 | 1043 | def init(self, data, class_file): |
paul@137 | 1044 | self.class_file = class_file |
paul@137 | 1045 | self.start_pc = u2(data[0:2]) |
paul@137 | 1046 | self.length = u2(data[2:4]) |
paul@137 | 1047 | self.name_index = u2(data[4:6]) |
paul@137 | 1048 | self.descriptor_index = u2(data[6:8]) |
paul@137 | 1049 | self.index = u2(data[8:10]) |
paul@137 | 1050 | return data[10:] |
paul@137 | 1051 | |
paul@137 | 1052 | def get_descriptor(self): |
paul@137 | 1053 | return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) |
paul@185 | 1054 | |
paul@185 | 1055 | def serialize(self): |
paul@185 | 1056 | return su2(self.start_pc)+su2(self.length)+su2(self.name_index)+su2(self.descriptor_index)+su2(self.index) |
paul@137 | 1057 | |
paul@137 | 1058 | # Exceptions. |
paul@137 | 1059 | |
paul@137 | 1060 | class UnknownTag(Exception): |
dmd@188 | 1061 | def __init__(self, tag): |
dmd@188 | 1062 | self.tag = tag |
dmd@188 | 1063 | def __str__(self): |
dmd@188 | 1064 | return repr(self.tag) |
paul@137 | 1065 | |
paul@137 | 1066 | class UnknownAttribute(Exception): |
dmd@188 | 1067 | def __init__(self, name): |
dmd@188 | 1068 | self.name = name |
paul@137 | 1069 | |
dmd@188 | 1070 | ATTR_NAMES_TO_CLASS = {"SourceFile": SourceFileAttributeInfo, |
dmd@188 | 1071 | "ConstantValue": ConstantValueAttributeInfo, |
dmd@188 | 1072 | "Code": CodeAttributeInfo, |
dmd@188 | 1073 | "Exceptions": ExceptionsAttributeInfo, |
dmd@188 | 1074 | "InnerClasses": InnerClassesAttributeInfo, |
dmd@188 | 1075 | "Synthetic": SyntheticAttributeInfo, |
dmd@188 | 1076 | "LineNumberTable": LineNumberAttributeInfo, |
dmd@188 | 1077 | "LocalVariableTable": LocalVariableAttributeInfo, |
dmd@188 | 1078 | "Deprecated": DeprecatedAttributeInfo, |
dmd@188 | 1079 | # Java SE 1.6, class file >= 50.0, VMSpec v3 s4.7.4 |
dmd@188 | 1080 | "StackMapTable": StackMapTableAttributeInfo, |
dmd@188 | 1081 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.7 |
dmd@188 | 1082 | "EnclosingMethod": EnclosingMethodAttributeInfo, |
dmd@188 | 1083 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.9 |
dmd@188 | 1084 | "Signature": SignatureAttributeInfo, |
dmd@188 | 1085 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.11 |
dmd@188 | 1086 | "SourceDebugExtension": SourceDebugExtensionAttributeInfo, |
dmd@188 | 1087 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.14 |
dmd@188 | 1088 | "LocalVariableTypeTable": LocalVariableTypeAttributeInfo, |
dmd@188 | 1089 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.16 |
dmd@188 | 1090 | "RuntimeVisibleAnnotations": RuntimeVisibleAnnotationsAttributeInfo, |
dmd@188 | 1091 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.17 |
dmd@188 | 1092 | "RuntimeInvisibleAnnotations": RuntimeInvisibleAnnotationsAttributeInfo, |
dmd@188 | 1093 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.18 |
dmd@188 | 1094 | "RuntimeVisibleParameterAnnotations": RuntimeVisibleParameterAnnotationsAttributeInfo, |
dmd@188 | 1095 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.19 |
dmd@188 | 1096 | "RuntimeInvisibleParameterAnnotations": RuntimeInvisibleParameterAnnotationsAttributeInfo, |
dmd@188 | 1097 | # Java SE 1.5, class file >= 49.0, VMSpec v3 s4.7.20 |
dmd@188 | 1098 | "AnnotationDefault": AnnotationDefaultAttributeInfo,} |
dmd@188 | 1099 | |
paul@137 | 1100 | # Abstractions for the main structures. |
paul@137 | 1101 | |
paul@137 | 1102 | class ClassFile: |
paul@137 | 1103 | |
paul@137 | 1104 | "A class representing a Java class file." |
paul@137 | 1105 | |
paul@137 | 1106 | def __init__(self, s): |
paul@137 | 1107 | |
paul@137 | 1108 | """ |
paul@137 | 1109 | Process the given string 's', populating the object with the class |
paul@137 | 1110 | file's details. |
paul@137 | 1111 | """ |
paul@137 | 1112 | |
paul@185 | 1113 | self.attribute_class_to_index = None |
dmd@188 | 1114 | magic = u4(s[0:]) |
dmd@188 | 1115 | if magic != 0xCAFEBABE: |
dmd@188 | 1116 | raise UnknownAttribute, magic |
paul@185 | 1117 | self.minorv,self.majorv = u2(s[4:]),u2(s[6:]) |
paul@137 | 1118 | self.constants, s = self._get_constants(s[8:]) |
paul@137 | 1119 | self.access_flags, s = self._get_access_flags(s) |
paul@137 | 1120 | self.this_class, s = self._get_this_class(s) |
paul@137 | 1121 | self.super_class, s = self._get_super_class(s) |
paul@137 | 1122 | self.interfaces, s = self._get_interfaces(s) |
paul@137 | 1123 | self.fields, s = self._get_fields(s) |
paul@137 | 1124 | self.methods, s = self._get_methods(s) |
paul@137 | 1125 | self.attributes, s = self._get_attributes(s) |
paul@137 | 1126 | |
paul@185 | 1127 | def serialize(self): |
paul@185 | 1128 | od = su4(0xCAFEBABE)+su2(self.minorv)+su2(self.majorv) |
paul@185 | 1129 | od += self._serialize_constants() |
paul@185 | 1130 | od += self._serialize_access_flags() |
paul@185 | 1131 | od += self._serialize_this_class() |
paul@185 | 1132 | od += self._serialize_super_class() |
paul@185 | 1133 | od += self._serialize_interfaces() |
paul@185 | 1134 | od += self._serialize_fields() |
paul@185 | 1135 | od += self._serialize_methods() |
paul@185 | 1136 | od += self._serialize_attributes(self.attributes) |
paul@185 | 1137 | return od |
paul@185 | 1138 | |
paul@185 | 1139 | def _encode_const(self, c): |
paul@185 | 1140 | od = '' |
paul@185 | 1141 | if isinstance(c, Utf8Info): |
paul@185 | 1142 | od += su1(1) |
paul@185 | 1143 | elif isinstance(c, IntegerInfo): |
paul@185 | 1144 | od += su1(3) |
paul@185 | 1145 | elif isinstance(c, FloatInfo): |
paul@185 | 1146 | od += su1(4) |
paul@185 | 1147 | elif isinstance(c, LongInfo): |
paul@185 | 1148 | od += su1(5) |
paul@185 | 1149 | elif isinstance(c, DoubleInfo): |
paul@185 | 1150 | od += su1(6) |
paul@185 | 1151 | elif isinstance(c, ClassInfo): |
paul@185 | 1152 | od += su1(7) |
paul@185 | 1153 | elif isinstance(c, StringInfo): |
paul@185 | 1154 | od += su1(8) |
paul@185 | 1155 | elif isinstance(c, FieldRefInfo): |
paul@185 | 1156 | od += su1(9) |
dmd@188 | 1157 | elif isinstance(c, InterfaceMethodRefInfo): # check subclass first |
dmd@188 | 1158 | od += su1(11) |
paul@185 | 1159 | elif isinstance(c, MethodRefInfo): |
paul@185 | 1160 | od += su1(10) |
paul@185 | 1161 | elif isinstance(c, NameAndTypeInfo): |
paul@185 | 1162 | od += su1(12) |
paul@185 | 1163 | else: |
paul@185 | 1164 | return od |
paul@185 | 1165 | od += c.serialize() |
paul@185 | 1166 | return od |
paul@185 | 1167 | |
paul@137 | 1168 | def _decode_const(self, s): |
paul@137 | 1169 | tag = u1(s[0:1]) |
paul@137 | 1170 | if tag == 1: |
paul@137 | 1171 | const = Utf8Info() |
paul@137 | 1172 | elif tag == 3: |
paul@137 | 1173 | const = IntegerInfo() |
paul@137 | 1174 | elif tag == 4: |
paul@137 | 1175 | const = FloatInfo() |
paul@137 | 1176 | elif tag == 5: |
paul@137 | 1177 | const = LongInfo() |
paul@137 | 1178 | elif tag == 6: |
paul@137 | 1179 | const = DoubleInfo() |
paul@137 | 1180 | elif tag == 7: |
paul@137 | 1181 | const = ClassInfo() |
paul@137 | 1182 | elif tag == 8: |
paul@137 | 1183 | const = StringInfo() |
paul@137 | 1184 | elif tag == 9: |
paul@137 | 1185 | const = FieldRefInfo() |
paul@137 | 1186 | elif tag == 10: |
paul@137 | 1187 | const = MethodRefInfo() |
paul@137 | 1188 | elif tag == 11: |
paul@137 | 1189 | const = InterfaceMethodRefInfo() |
paul@137 | 1190 | elif tag == 12: |
paul@137 | 1191 | const = NameAndTypeInfo() |
paul@137 | 1192 | else: |
paul@137 | 1193 | raise UnknownTag, tag |
paul@137 | 1194 | |
paul@137 | 1195 | # Initialise the constant object. |
paul@137 | 1196 | |
paul@137 | 1197 | s = const.init(s[1:], self) |
paul@137 | 1198 | return const, s |
paul@137 | 1199 | |
paul@137 | 1200 | def _get_constants_from_table(self, count, s): |
paul@137 | 1201 | l = [] |
paul@137 | 1202 | # Have to skip certain entries specially. |
paul@137 | 1203 | i = 1 |
paul@137 | 1204 | while i < count: |
paul@137 | 1205 | c, s = self._decode_const(s) |
paul@137 | 1206 | l.append(c) |
paul@137 | 1207 | # Add a blank entry after "large" entries. |
paul@137 | 1208 | if isinstance(c, LargeNumInfo): |
paul@137 | 1209 | l.append(None) |
paul@137 | 1210 | i += 1 |
paul@137 | 1211 | i += 1 |
paul@137 | 1212 | return l, s |
paul@137 | 1213 | |
paul@137 | 1214 | def _get_items_from_table(self, cls, number, s): |
paul@137 | 1215 | l = [] |
paul@137 | 1216 | for i in range(0, number): |
paul@137 | 1217 | f = cls() |
paul@137 | 1218 | s = f.init(s, self) |
paul@137 | 1219 | l.append(f) |
paul@137 | 1220 | return l, s |
paul@137 | 1221 | |
paul@137 | 1222 | def _get_methods_from_table(self, number, s): |
paul@137 | 1223 | return self._get_items_from_table(MethodInfo, number, s) |
paul@137 | 1224 | |
paul@137 | 1225 | def _get_fields_from_table(self, number, s): |
paul@137 | 1226 | return self._get_items_from_table(FieldInfo, number, s) |
paul@137 | 1227 | |
paul@137 | 1228 | def _get_attribute_from_table(self, s): |
paul@137 | 1229 | attribute_name_index = u2(s[0:2]) |
paul@137 | 1230 | constant_name = self.constants[attribute_name_index - 1].bytes |
dmd@188 | 1231 | if constant_name in ATTR_NAMES_TO_CLASS: |
dmd@188 | 1232 | attribute = ATTR_NAMES_TO_CLASS[constant_name]() |
paul@137 | 1233 | else: |
paul@137 | 1234 | raise UnknownAttribute, constant_name |
paul@137 | 1235 | s = attribute.init(s[2:], self) |
paul@137 | 1236 | return attribute, s |
paul@137 | 1237 | |
paul@137 | 1238 | def _get_attributes_from_table(self, number, s): |
paul@137 | 1239 | attributes = [] |
paul@137 | 1240 | for i in range(0, number): |
paul@137 | 1241 | attribute, s = self._get_attribute_from_table(s) |
paul@137 | 1242 | attributes.append(attribute) |
paul@137 | 1243 | return attributes, s |
paul@137 | 1244 | |
paul@137 | 1245 | def _get_constants(self, s): |
paul@137 | 1246 | count = u2(s[0:2]) |
paul@137 | 1247 | return self._get_constants_from_table(count, s[2:]) |
paul@137 | 1248 | |
paul@185 | 1249 | def _serialize_constants(self): |
paul@185 | 1250 | return su2(len(self.constants)+1)+"".join([self._encode_const(c) for c in self.constants]) |
paul@185 | 1251 | |
paul@137 | 1252 | def _get_access_flags(self, s): |
paul@137 | 1253 | return u2(s[0:2]), s[2:] |
paul@185 | 1254 | |
paul@185 | 1255 | def _serialize_access_flags(self): |
paul@185 | 1256 | return su2(self.access_flags) |
paul@137 | 1257 | |
paul@137 | 1258 | def _get_this_class(self, s): |
paul@137 | 1259 | index = u2(s[0:2]) |
paul@137 | 1260 | return self.constants[index - 1], s[2:] |
paul@137 | 1261 | |
paul@185 | 1262 | def _serialize_this_class(self): |
paul@185 | 1263 | return su2(self.constants.index(self.this_class)+1) |
paul@185 | 1264 | |
paul@185 | 1265 | def _serialize_super_class(self): |
paul@185 | 1266 | return su2(self.constants.index(self.super_class)+1) |
paul@185 | 1267 | |
paul@165 | 1268 | def _get_super_class(self, s): |
paul@165 | 1269 | index = u2(s[0:2]) |
paul@165 | 1270 | if index != 0: |
paul@165 | 1271 | return self.constants[index - 1], s[2:] |
paul@165 | 1272 | else: |
paul@165 | 1273 | return None, s[2:] |
paul@137 | 1274 | |
paul@137 | 1275 | def _get_interfaces(self, s): |
paul@137 | 1276 | interfaces = [] |
paul@137 | 1277 | number = u2(s[0:2]) |
paul@137 | 1278 | s = s[2:] |
paul@137 | 1279 | for i in range(0, number): |
paul@137 | 1280 | index = u2(s[0:2]) |
paul@137 | 1281 | interfaces.append(self.constants[index - 1]) |
paul@137 | 1282 | s = s[2:] |
paul@137 | 1283 | return interfaces, s |
paul@137 | 1284 | |
paul@185 | 1285 | def _serialize_interfaces(self): |
dmd@188 | 1286 | return su2(len(self.interfaces))+"".join([su2(self.constants.index(interf)+1) for interf in self.interfaces]) |
paul@185 | 1287 | |
paul@137 | 1288 | def _get_fields(self, s): |
paul@137 | 1289 | number = u2(s[0:2]) |
paul@137 | 1290 | return self._get_fields_from_table(number, s[2:]) |
paul@137 | 1291 | |
paul@185 | 1292 | def _serialize_fields(self): |
paul@185 | 1293 | od = su2(len(self.fields)) |
paul@185 | 1294 | od += "".join([f.serialize() for f in self.fields]) |
paul@185 | 1295 | return od |
paul@185 | 1296 | |
paul@137 | 1297 | def _get_attributes(self, s): |
paul@137 | 1298 | number = u2(s[0:2]) |
paul@137 | 1299 | return self._get_attributes_from_table(number, s[2:]) |
paul@137 | 1300 | |
paul@185 | 1301 | def _serialize_attributes(self, attrs): |
paul@185 | 1302 | od = su2(len(attrs)) |
paul@185 | 1303 | if len(attrs) == 0: return od |
paul@185 | 1304 | if self.attribute_class_to_index == None: |
paul@185 | 1305 | self.attribute_class_to_index = {} |
paul@185 | 1306 | index = 0 |
paul@185 | 1307 | for c in self.constants: |
paul@185 | 1308 | index += 1 |
dmd@188 | 1309 | if isinstance(c, Utf8Info) and str(c) in ATTR_NAMES_TO_CLASS.keys(): |
dmd@188 | 1310 | self.attribute_class_to_index[ATTR_NAMES_TO_CLASS[str(c)]]=index |
paul@185 | 1311 | for attribute in attrs: |
paul@185 | 1312 | for (classtype,name_index) in self.attribute_class_to_index.iteritems(): |
paul@185 | 1313 | if isinstance(attribute, classtype): |
paul@185 | 1314 | od += su2(name_index) |
paul@185 | 1315 | break |
paul@185 | 1316 | od += attribute.serialize() |
paul@185 | 1317 | return od |
paul@185 | 1318 | |
paul@137 | 1319 | def _get_methods(self, s): |
paul@137 | 1320 | number = u2(s[0:2]) |
paul@137 | 1321 | return self._get_methods_from_table(number, s[2:]) |
paul@137 | 1322 | |
paul@185 | 1323 | def _serialize_methods(self): |
paul@185 | 1324 | od = su2(len(self.methods)) |
paul@185 | 1325 | od += "".join([m.serialize() for m in self.methods]) |
paul@185 | 1326 | return od |
paul@185 | 1327 | |
paul@185 | 1328 | |
paul@137 | 1329 | if __name__ == "__main__": |
paul@137 | 1330 | import sys |
paul@137 | 1331 | f = open(sys.argv[1], "rb") |
dmd@188 | 1332 | in_data = f.read() |
dmd@188 | 1333 | c = ClassFile(in_data) |
paul@137 | 1334 | f.close() |
dmd@188 | 1335 | out_data = c.serialize() |
dmd@188 | 1336 | assert(in_data == out_data) |
paul@137 | 1337 | |
paul@137 | 1338 | # vim: tabstop=4 expandtab shiftwidth=4 |