1 #!/usr/bin/env python 2 3 """ 4 Java class file decoder. Specification found at the following URL: 5 http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html 6 7 Copyright (C) 2004, 2005, 2006, 2011 Paul Boddie <paul@boddie.org.uk> 8 Copyright (C) 2010 Braden Thomas <bradenthomas@me.com> 9 10 This program is free software; you can redistribute it and/or modify it under 11 the terms of the GNU Lesser General Public License as published by the Free 12 Software Foundation; either version 3 of the License, or (at your option) any 13 later version. 14 15 This program is distributed in the hope that it will be useful, but WITHOUT 16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 18 details. 19 20 You should have received a copy of the GNU Lesser General Public License along 21 with this program. If not, see <http://www.gnu.org/licenses/>. 22 """ 23 24 import struct # for general decoding of class files 25 26 # Utility functions. 27 28 def u1(data): 29 return struct.unpack(">B", data[0:1])[0] 30 31 def u2(data): 32 return struct.unpack(">H", data[0:2])[0] 33 34 def s2(data): 35 return struct.unpack(">h", data[0:2])[0] 36 37 def u4(data): 38 return struct.unpack(">L", data[0:4])[0] 39 40 def s4(data): 41 return struct.unpack(">l", data[0:4])[0] 42 43 def s8(data): 44 return struct.unpack(">q", data[0:8])[0] 45 46 def f4(data): 47 return struct.unpack(">f", data[0:4])[0] 48 49 def f8(data): 50 return struct.unpack(">d", data[0:8])[0] 51 52 def su1(value): 53 return struct.pack(">B", value) 54 55 def su2(value): 56 return struct.pack(">H", value) 57 58 def ss2(value): 59 return struct.pack(">h", value) 60 61 def su4(value): 62 return struct.pack(">L", value) 63 64 def ss4(value): 65 return struct.pack(">l", value) 66 67 def ss8(value): 68 return struct.pack(">q", value) 69 70 def sf4(value): 71 return struct.pack(">f", value) 72 73 def sf8(value): 74 return struct.pack(">d", value) 75 76 # Useful tables and constants. 77 78 descriptor_base_type_mapping = { 79 "B" : "int", 80 "C" : "str", 81 "D" : "float", 82 "F" : "float", 83 "I" : "int", 84 "J" : "int", 85 "L" : "object", 86 "S" : "int", 87 "Z" : "bool", 88 "[" : "list" 89 } 90 91 type_names_to_default_values = { 92 "int" : 0, 93 "str" : u"", 94 "float" : 0.0, 95 "object" : None, 96 "bool" : 0, # NOTE: Should be False. 97 "list" : [] 98 } 99 100 def get_default_for_type(type_name): 101 global type_names_to_default_values 102 return type_names_to_default_values.get(type_name) 103 104 PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SUPER, SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE, INTERFACE, ABSTRACT, STRICT = \ 105 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800 106 107 def has_flags(flags, desired): 108 desired_flags = reduce(lambda a, b: a | b, desired, 0) 109 return (flags & desired_flags) == desired_flags 110 111 # Useful mix-ins. 112 113 class PythonMethodUtils: 114 symbol_sep = "___" # was "$" 115 type_sep = "__" # replaces "/" 116 array_sep = "_array_" # was "[]" 117 base_seps = ("_", "_") # was "<" and ">" 118 119 def get_unqualified_python_name(self): 120 name = self.get_name() 121 if str(name) == "<init>": 122 return "__init__" 123 elif str(name) == "<clinit>": 124 return "__clinit__" 125 else: 126 return str(name) 127 128 def get_python_name(self): 129 name = self.get_unqualified_python_name() 130 if name == "__clinit__": 131 return name 132 return name + self.symbol_sep + self._get_descriptor_as_name() 133 134 def _get_descriptor_as_name(self): 135 l = [] 136 for descriptor_type in self.get_descriptor()[0]: 137 l.append(self._get_type_as_name(descriptor_type)) 138 return self.symbol_sep.join(l) 139 140 def _get_type_as_name(self, descriptor_type, s=""): 141 base_type, object_type, array_type = descriptor_type 142 if base_type == "L": 143 return object_type.replace("/", self.type_sep) + s 144 elif base_type == "[": 145 return self._get_type_as_name(array_type, s + self.array_sep) 146 else: 147 return self.base_seps[0] + base_type + self.base_seps[1] + s 148 149 class PythonNameUtils: 150 def get_python_name(self): 151 # NOTE: This may not be comprehensive. 152 if not str(self.get_name()).startswith("["): 153 return str(self.get_name()).replace("/", ".") 154 else: 155 return self._get_type_name( 156 get_field_descriptor( 157 str(self.get_name()) 158 ) 159 ).replace("/", ".") 160 161 def _get_type_name(self, descriptor_type): 162 base_type, object_type, array_type = descriptor_type 163 if base_type == "L": 164 return object_type 165 elif base_type == "[": 166 return self._get_type_name(array_type) 167 else: 168 return descriptor_base_type_mapping[base_type] 169 170 class NameUtils: 171 def get_name(self): 172 if self.name_index != 0: 173 return self.class_file.constants[self.name_index - 1] 174 else: 175 # Some name indexes are zero to indicate special conditions. 176 return None 177 178 class NameAndTypeUtils: 179 def get_name(self): 180 if self.name_and_type_index != 0: 181 return self.class_file.constants[self.name_and_type_index - 1].get_name() 182 else: 183 # Some name indexes are zero to indicate special conditions. 184 return None 185 186 def get_field_descriptor(self): 187 if self.name_and_type_index != 0: 188 return self.class_file.constants[self.name_and_type_index - 1].get_field_descriptor() 189 else: 190 # Some name indexes are zero to indicate special conditions. 191 return None 192 193 def get_method_descriptor(self): 194 if self.name_and_type_index != 0: 195 return self.class_file.constants[self.name_and_type_index - 1].get_method_descriptor() 196 else: 197 # Some name indexes are zero to indicate special conditions. 198 return None 199 200 def get_class(self): 201 return self.class_file.constants[self.class_index - 1] 202 203 # Symbol parsing. 204 205 def get_method_descriptor(s): 206 assert s[0] == "(" 207 params = [] 208 s = s[1:] 209 while s[0] != ")": 210 parameter_descriptor, s = _get_parameter_descriptor(s) 211 params.append(parameter_descriptor) 212 if s[1] != "V": 213 return_type, s = _get_field_type(s[1:]) 214 else: 215 return_type, s = None, s[1:] 216 return params, return_type 217 218 def get_field_descriptor(s): 219 return _get_field_type(s)[0] 220 221 def _get_parameter_descriptor(s): 222 return _get_field_type(s) 223 224 def _get_component_type(s): 225 return _get_field_type(s) 226 227 def _get_field_type(s): 228 base_type, s = _get_base_type(s) 229 object_type = None 230 array_type = None 231 if base_type == "L": 232 object_type, s = _get_object_type(s) 233 elif base_type == "[": 234 array_type, s = _get_array_type(s) 235 return (base_type, object_type, array_type), s 236 237 def _get_base_type(s): 238 if len(s) > 0: 239 return s[0], s[1:] 240 else: 241 return None, s 242 243 def _get_object_type(s): 244 if len(s) > 0: 245 s_end = s.find(";") 246 assert s_end != -1 247 return s[:s_end], s[s_end+1:] 248 else: 249 return None, s 250 251 def _get_array_type(s): 252 if len(s) > 0: 253 return _get_component_type(s) 254 else: 255 return None, s 256 257 # Constant information. 258 259 class ClassInfo(NameUtils, PythonNameUtils): 260 def init(self, data, class_file): 261 self.class_file = class_file 262 self.name_index = u2(data[0:2]) 263 return data[2:] 264 def serialize(self): 265 return su2(self.name_index) 266 267 class RefInfo(NameAndTypeUtils): 268 def init(self, data, class_file): 269 self.class_file = class_file 270 self.class_index = u2(data[0:2]) 271 self.name_and_type_index = u2(data[2:4]) 272 return data[4:] 273 def serialize(self): 274 return su2(self.class_index)+su2(self.name_and_type_index) 275 276 class FieldRefInfo(RefInfo, PythonNameUtils): 277 def get_descriptor(self): 278 return RefInfo.get_field_descriptor(self) 279 280 class MethodRefInfo(RefInfo, PythonMethodUtils): 281 def get_descriptor(self): 282 return RefInfo.get_method_descriptor(self) 283 284 class InterfaceMethodRefInfo(MethodRefInfo): 285 pass 286 287 class NameAndTypeInfo(NameUtils, PythonNameUtils): 288 def init(self, data, class_file): 289 self.class_file = class_file 290 self.name_index = u2(data[0:2]) 291 self.descriptor_index = u2(data[2:4]) 292 return data[4:] 293 294 def serialize(self): 295 return su2(self.name_index)+su2(self.descriptor_index) 296 297 def get_field_descriptor(self): 298 return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) 299 300 def get_method_descriptor(self): 301 return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) 302 303 class Utf8Info: 304 def init(self, data, class_file): 305 self.class_file = class_file 306 self.length = u2(data[0:2]) 307 self.bytes = data[2:2+self.length] 308 return data[2+self.length:] 309 310 def serialize(self): 311 return su2(self.length)+self.bytes 312 313 def __str__(self): 314 return self.bytes 315 316 def __unicode__(self): 317 return unicode(self.bytes, "utf-8") 318 319 def get_value(self): 320 return str(self) 321 322 class StringInfo: 323 def init(self, data, class_file): 324 self.class_file = class_file 325 self.string_index = u2(data[0:2]) 326 return data[2:] 327 328 def serialize(self): 329 return su2(self.string_index) 330 331 def __str__(self): 332 return str(self.class_file.constants[self.string_index - 1]) 333 334 def __unicode__(self): 335 return unicode(self.class_file.constants[self.string_index - 1]) 336 337 def get_value(self): 338 return str(self) 339 340 class SmallNumInfo: 341 def init(self, data, class_file): 342 self.class_file = class_file 343 self.bytes = data[0:4] 344 return data[4:] 345 def serialize(self): 346 return self.bytes 347 348 class IntegerInfo(SmallNumInfo): 349 def get_value(self): 350 return s4(self.bytes) 351 352 class FloatInfo(SmallNumInfo): 353 def get_value(self): 354 return f4(self.bytes) 355 356 class LargeNumInfo: 357 def init(self, data, class_file): 358 self.class_file = class_file 359 self.high_bytes = data[0:4] 360 self.low_bytes = data[4:8] 361 return data[8:] 362 def serialize(self): 363 return self.high_bytes+self.low_bytes 364 365 366 class LongInfo(LargeNumInfo): 367 def get_value(self): 368 return s8(self.high_bytes + self.low_bytes) 369 370 class DoubleInfo(LargeNumInfo): 371 def get_value(self): 372 return f8(self.high_bytes + self.low_bytes) 373 374 # Other information. 375 # Objects of these classes are generally aware of the class they reside in. 376 377 class ItemInfo(NameUtils): 378 def init(self, data, class_file): 379 self.class_file = class_file 380 self.access_flags = u2(data[0:2]) 381 self.name_index = u2(data[2:4]) 382 self.descriptor_index = u2(data[4:6]) 383 self.attributes, data = self.class_file._get_attributes(data[6:]) 384 return data 385 def serialize(self): 386 od = su2(self.access_flags)+su2(self.name_index)+su2(self.descriptor_index) 387 od += self.class_file._serialize_attributes(self.attributes) 388 return od 389 390 class FieldInfo(ItemInfo, PythonNameUtils): 391 def get_descriptor(self): 392 return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) 393 394 class MethodInfo(ItemInfo, PythonMethodUtils): 395 def get_descriptor(self): 396 return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) 397 398 class AttributeInfo: 399 def init(self, data, class_file): 400 self.attribute_length = u4(data[0:4]) 401 self.info = data[4:4+self.attribute_length] 402 return data[4+self.attribute_length:] 403 def serialize(self): 404 return su4(self.attribute_length)+self.info 405 406 # NOTE: Decode the different attribute formats. 407 408 class SourceFileAttributeInfo(AttributeInfo, NameUtils, PythonNameUtils): 409 def init(self, data, class_file): 410 self.class_file = class_file 411 self.attribute_length = u4(data[0:4]) 412 # Permit the NameUtils mix-in. 413 self.name_index = self.sourcefile_index = u2(data[4:6]) 414 return data[6:] 415 def serialize(self): 416 return su4(self.attribute_length)+su2(self.name_index) 417 418 class ConstantValueAttributeInfo(AttributeInfo): 419 def init(self, data, class_file): 420 self.class_file = class_file 421 self.attribute_length = u4(data[0:4]) 422 self.constant_value_index = u2(data[4:6]) 423 assert 4+self.attribute_length == 6 424 return data[4+self.attribute_length:] 425 426 def get_value(self): 427 return self.class_file.constants[self.constant_value_index - 1].get_value() 428 429 def serialize(self): 430 return su4(self.attribute_length)+su2(self.constant_value_index) 431 432 class CodeAttributeInfo(AttributeInfo): 433 def init(self, data, class_file): 434 self.class_file = class_file 435 self.attribute_length = u4(data[0:4]) 436 self.max_stack = u2(data[4:6]) 437 self.max_locals = u2(data[6:8]) 438 self.code_length = u4(data[8:12]) 439 end_of_code = 12+self.code_length 440 self.code = data[12:end_of_code] 441 self.exception_table_length = u2(data[end_of_code:end_of_code+2]) 442 self.exception_table = [] 443 data = data[end_of_code + 2:] 444 for i in range(0, self.exception_table_length): 445 exception = ExceptionInfo() 446 data = exception.init(data) 447 self.exception_table.append(exception) 448 self.attributes, data = self.class_file._get_attributes(data) 449 return data 450 def serialize(self): 451 od = su4(self.attribute_length)+su2(self.max_stack)+su2(self.max_locals)+su4(self.code_length)+self.code 452 od += su2(self.exception_table_length) 453 for e in self.exception_table: 454 od += e.serialize() 455 od += self.class_file._serialize_attributes(self.attributes) 456 return od 457 458 class ExceptionsAttributeInfo(AttributeInfo): 459 def init(self, data, class_file): 460 self.class_file = class_file 461 self.attribute_length = u4(data[0:4]) 462 self.number_of_exceptions = u2(data[4:6]) 463 self.exception_index_table = [] 464 index = 6 465 for i in range(0, self.number_of_exceptions): 466 self.exception_index_table.append(u2(data[index:index+2])) 467 index += 2 468 return data[index:] 469 470 def get_exception(self, i): 471 exception_index = self.exception_index_table[i] 472 return self.class_file.constants[exception_index - 1] 473 474 def serialize(self): 475 od = su4(self.attribute_length)+su2(self.number_of_exceptions) 476 for ei in self.exception_index_table: 477 od += su2(ei) 478 return od 479 480 class InnerClassesAttributeInfo(AttributeInfo): 481 def init(self, data, class_file): 482 self.class_file = class_file 483 self.attribute_length = u4(data[0:4]) 484 self.number_of_classes = u2(data[4:6]) 485 self.classes = [] 486 data = data[6:] 487 for i in range(0, self.number_of_classes): 488 inner_class = InnerClassInfo() 489 data = inner_class.init(data, self.class_file) 490 self.classes.append(inner_class) 491 return data 492 493 def serialize(self): 494 od = su4(self.attribute_length)+su2(self.number_of_classes) 495 for c in self.classes: 496 od += c.serialize() 497 return od 498 499 class SyntheticAttributeInfo(AttributeInfo): 500 pass 501 502 class LineNumberAttributeInfo(AttributeInfo): 503 def init(self, data, class_file): 504 self.class_file = class_file 505 self.attribute_length = u4(data[0:4]) 506 self.line_number_table_length = u2(data[4:6]) 507 self.line_number_table = [] 508 data = data[6:] 509 for i in range(0, self.line_number_table_length): 510 line_number = LineNumberInfo() 511 data = line_number.init(data) 512 self.line_number_table.append(line_number) 513 return data 514 515 def serialize(self): 516 od = su4(self.attribute_length)+su2(self.line_number_table_length) 517 for ln in self.line_number_table: 518 od += ln.serialize() 519 return od 520 521 class LocalVariableAttributeInfo(AttributeInfo): 522 def init(self, data, class_file): 523 self.class_file = class_file 524 self.attribute_length = u4(data[0:4]) 525 self.local_variable_table_length = u2(data[4:6]) 526 self.local_variable_table = [] 527 data = data[6:] 528 for i in range(0, self.local_variable_table_length): 529 local_variable = LocalVariableInfo() 530 data = local_variable.init(data, self.class_file) 531 self.local_variable_table.append(local_variable) 532 return data 533 534 def serialize(self): 535 od = su4(self.attribute_length)+su2(self.local_variable_table_length) 536 for lv in self.local_variable_table: 537 od += lv.serialize() 538 return od 539 540 class DeprecatedAttributeInfo(AttributeInfo): 541 pass 542 543 # Child classes of the attribute information classes. 544 545 class ExceptionInfo: 546 def init(self, data): 547 self.start_pc = u2(data[0:2]) 548 self.end_pc = u2(data[2:4]) 549 self.handler_pc = u2(data[4:6]) 550 self.catch_type = u2(data[6:8]) 551 return data[8:] 552 def serialize(self): 553 return su2(self.start_pc)+su2(self.end_pc)+su2(self.handler_pc)+su2(self.catch_type) 554 555 class InnerClassInfo(NameUtils): 556 def init(self, data, class_file): 557 self.class_file = class_file 558 self.inner_class_info_index = u2(data[0:2]) 559 self.outer_class_info_index = u2(data[2:4]) 560 # Permit the NameUtils mix-in. 561 self.name_index = self.inner_name_index = u2(data[4:6]) 562 self.inner_class_access_flags = u2(data[6:8]) 563 return data[8:] 564 def serialize(self): 565 return su2(self.inner_class_info_index)+su2(self.outer_class_info_index)+su2(self.name_index)+su2(self.inner_class_access_flags) 566 567 class LineNumberInfo: 568 def init(self, data): 569 self.start_pc = u2(data[0:2]) 570 self.line_number = u2(data[2:4]) 571 return data[4:] 572 573 def serialize(self): 574 return su2(self.start_pc)+su2(self.line_number) 575 576 class LocalVariableInfo(NameUtils, PythonNameUtils): 577 def init(self, data, class_file): 578 self.class_file = class_file 579 self.start_pc = u2(data[0:2]) 580 self.length = u2(data[2:4]) 581 self.name_index = u2(data[4:6]) 582 self.descriptor_index = u2(data[6:8]) 583 self.index = u2(data[8:10]) 584 return data[10:] 585 586 def get_descriptor(self): 587 return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1])) 588 589 def serialize(self): 590 return su2(self.start_pc)+su2(self.length)+su2(self.name_index)+su2(self.descriptor_index)+su2(self.index) 591 592 # Exceptions. 593 594 class UnknownTag(Exception): 595 pass 596 597 class UnknownAttribute(Exception): 598 pass 599 600 # Abstractions for the main structures. 601 602 class ClassFile: 603 604 "A class representing a Java class file." 605 606 def __init__(self, s): 607 608 """ 609 Process the given string 's', populating the object with the class 610 file's details. 611 """ 612 613 self.attribute_class_to_index = None 614 self.minorv,self.majorv = u2(s[4:]),u2(s[6:]) 615 self.constants, s = self._get_constants(s[8:]) 616 self.access_flags, s = self._get_access_flags(s) 617 self.this_class, s = self._get_this_class(s) 618 self.super_class, s = self._get_super_class(s) 619 self.interfaces, s = self._get_interfaces(s) 620 self.fields, s = self._get_fields(s) 621 self.methods, s = self._get_methods(s) 622 self.attributes, s = self._get_attributes(s) 623 624 def serialize(self): 625 od = su4(0xCAFEBABE)+su2(self.minorv)+su2(self.majorv) 626 od += self._serialize_constants() 627 od += self._serialize_access_flags() 628 od += self._serialize_this_class() 629 od += self._serialize_super_class() 630 od += self._serialize_interfaces() 631 od += self._serialize_fields() 632 od += self._serialize_methods() 633 od += self._serialize_attributes(self.attributes) 634 return od 635 636 def _encode_const(self, c): 637 od = '' 638 if isinstance(c, Utf8Info): 639 od += su1(1) 640 elif isinstance(c, IntegerInfo): 641 od += su1(3) 642 elif isinstance(c, FloatInfo): 643 od += su1(4) 644 elif isinstance(c, LongInfo): 645 od += su1(5) 646 elif isinstance(c, DoubleInfo): 647 od += su1(6) 648 elif isinstance(c, ClassInfo): 649 od += su1(7) 650 elif isinstance(c, StringInfo): 651 od += su1(8) 652 elif isinstance(c, FieldRefInfo): 653 od += su1(9) 654 elif isinstance(c, MethodRefInfo): 655 od += su1(10) 656 elif isinstance(c, InterfaceMethodRefInfo): 657 od += su1(11) 658 elif isinstance(c, NameAndTypeInfo): 659 od += su1(12) 660 else: 661 return od 662 od += c.serialize() 663 return od 664 665 def _decode_const(self, s): 666 tag = u1(s[0:1]) 667 if tag == 1: 668 const = Utf8Info() 669 elif tag == 3: 670 const = IntegerInfo() 671 elif tag == 4: 672 const = FloatInfo() 673 elif tag == 5: 674 const = LongInfo() 675 elif tag == 6: 676 const = DoubleInfo() 677 elif tag == 7: 678 const = ClassInfo() 679 elif tag == 8: 680 const = StringInfo() 681 elif tag == 9: 682 const = FieldRefInfo() 683 elif tag == 10: 684 const = MethodRefInfo() 685 elif tag == 11: 686 const = InterfaceMethodRefInfo() 687 elif tag == 12: 688 const = NameAndTypeInfo() 689 else: 690 raise UnknownTag, tag 691 692 # Initialise the constant object. 693 694 s = const.init(s[1:], self) 695 return const, s 696 697 def _get_constants_from_table(self, count, s): 698 l = [] 699 # Have to skip certain entries specially. 700 i = 1 701 while i < count: 702 c, s = self._decode_const(s) 703 l.append(c) 704 # Add a blank entry after "large" entries. 705 if isinstance(c, LargeNumInfo): 706 l.append(None) 707 i += 1 708 i += 1 709 return l, s 710 711 def _get_items_from_table(self, cls, number, s): 712 l = [] 713 for i in range(0, number): 714 f = cls() 715 s = f.init(s, self) 716 l.append(f) 717 return l, s 718 719 def _get_methods_from_table(self, number, s): 720 return self._get_items_from_table(MethodInfo, number, s) 721 722 def _get_fields_from_table(self, number, s): 723 return self._get_items_from_table(FieldInfo, number, s) 724 725 def _get_attribute_from_table(self, s): 726 attribute_name_index = u2(s[0:2]) 727 constant_name = self.constants[attribute_name_index - 1].bytes 728 if constant_name == "SourceFile": 729 attribute = SourceFileAttributeInfo() 730 elif constant_name == "ConstantValue": 731 attribute = ConstantValueAttributeInfo() 732 elif constant_name == "Code": 733 attribute = CodeAttributeInfo() 734 elif constant_name == "Exceptions": 735 attribute = ExceptionsAttributeInfo() 736 elif constant_name == "InnerClasses": 737 attribute = InnerClassesAttributeInfo() 738 elif constant_name == "Synthetic": 739 attribute = SyntheticAttributeInfo() 740 elif constant_name == "LineNumberTable": 741 attribute = LineNumberAttributeInfo() 742 elif constant_name == "LocalVariableTable": 743 attribute = LocalVariableAttributeInfo() 744 elif constant_name == "Deprecated": 745 attribute = DeprecatedAttributeInfo() 746 else: 747 raise UnknownAttribute, constant_name 748 s = attribute.init(s[2:], self) 749 return attribute, s 750 751 def _get_attributes_from_table(self, number, s): 752 attributes = [] 753 for i in range(0, number): 754 attribute, s = self._get_attribute_from_table(s) 755 attributes.append(attribute) 756 return attributes, s 757 758 def _get_constants(self, s): 759 count = u2(s[0:2]) 760 return self._get_constants_from_table(count, s[2:]) 761 762 def _serialize_constants(self): 763 return su2(len(self.constants)+1)+"".join([self._encode_const(c) for c in self.constants]) 764 765 def _get_access_flags(self, s): 766 return u2(s[0:2]), s[2:] 767 768 def _serialize_access_flags(self): 769 return su2(self.access_flags) 770 771 def _get_this_class(self, s): 772 index = u2(s[0:2]) 773 return self.constants[index - 1], s[2:] 774 775 def _serialize_this_class(self): 776 return su2(self.constants.index(self.this_class)+1) 777 778 def _serialize_super_class(self): 779 return su2(self.constants.index(self.super_class)+1) 780 781 def _get_super_class(self, s): 782 index = u2(s[0:2]) 783 if index != 0: 784 return self.constants[index - 1], s[2:] 785 else: 786 return None, s[2:] 787 788 def _get_interfaces(self, s): 789 interfaces = [] 790 number = u2(s[0:2]) 791 s = s[2:] 792 for i in range(0, number): 793 index = u2(s[0:2]) 794 interfaces.append(self.constants[index - 1]) 795 s = s[2:] 796 return interfaces, s 797 798 def _serialize_interfaces(self): 799 return su2(len(self.interfaces))+"".join([su2(self.interfaces.index(interf)+1) for interf in self.interfaces]) 800 801 def _get_fields(self, s): 802 number = u2(s[0:2]) 803 return self._get_fields_from_table(number, s[2:]) 804 805 def _serialize_fields(self): 806 od = su2(len(self.fields)) 807 od += "".join([f.serialize() for f in self.fields]) 808 return od 809 810 def _get_attributes(self, s): 811 number = u2(s[0:2]) 812 return self._get_attributes_from_table(number, s[2:]) 813 814 def _serialize_attributes(self, attrs): 815 od = su2(len(attrs)) 816 if len(attrs) == 0: return od 817 if self.attribute_class_to_index == None: 818 self.attribute_class_to_index = {} 819 attr_names_to_class = {"SourceFile":SourceFileAttributeInfo, "ConstantValue":ConstantValueAttributeInfo, 820 "Code":CodeAttributeInfo, "Exceptions":ExceptionsAttributeInfo, 821 "InnerClasses":InnerClassesAttributeInfo, "Synthetic":SyntheticAttributeInfo, 822 "LineNumberTable":LineNumberAttributeInfo, "LocalVariableTable":LocalVariableAttributeInfo, 823 "Deprecated":DeprecatedAttributeInfo} 824 index = 0 825 for c in self.constants: 826 index += 1 827 if isinstance(c, Utf8Info) and str(c) in attr_names_to_class.keys(): 828 self.attribute_class_to_index[attr_names_to_class[str(c)]]=index 829 for attribute in attrs: 830 for (classtype,name_index) in self.attribute_class_to_index.iteritems(): 831 if isinstance(attribute, classtype): 832 od += su2(name_index) 833 break 834 od += attribute.serialize() 835 return od 836 837 def _get_methods(self, s): 838 number = u2(s[0:2]) 839 return self._get_methods_from_table(number, s[2:]) 840 841 def _serialize_methods(self): 842 od = su2(len(self.methods)) 843 od += "".join([m.serialize() for m in self.methods]) 844 return od 845 846 847 if __name__ == "__main__": 848 import sys 849 f = open(sys.argv[1], "rb") 850 c = ClassFile(f.read()) 851 f.close() 852 853 # vim: tabstop=4 expandtab shiftwidth=4