javaclass

Annotated classfile.py

133:3e197ad55b82
2005-01-18 Paul Boddie Added more test programs.
paul@0 1
#!/usr/bin/env python
paul@0 2
paul@0 3
"""
paul@0 4
Java class file decoder. Specification found at the following URL:
paul@0 5
http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html
paul@0 6
"""
paul@0 7
paul@4 8
import struct # for general decoding of class files
paul@0 9
paul@1 10
# Utility functions.
paul@1 11
paul@1 12
def u1(data):
paul@1 13
    return struct.unpack(">B", data[0:1])[0]
paul@1 14
paul@1 15
def u2(data):
paul@1 16
    return struct.unpack(">H", data[0:2])[0]
paul@1 17
paul@61 18
def s2(data):
paul@61 19
    return struct.unpack(">h", data[0:2])[0]
paul@61 20
paul@1 21
def u4(data):
paul@1 22
    return struct.unpack(">L", data[0:4])[0]
paul@1 23
paul@4 24
def s4(data):
paul@4 25
    return struct.unpack(">l", data[0:4])[0]
paul@4 26
paul@4 27
def s8(data):
paul@4 28
    return struct.unpack(">q", data[0:8])[0]
paul@4 29
paul@4 30
def f4(data):
paul@4 31
    return struct.unpack(">f", data[0:4])[0]
paul@4 32
paul@4 33
def f8(data):
paul@4 34
    return struct.unpack(">d", data[0:8])[0]
paul@4 35
paul@55 36
# Useful tables and constants.
paul@55 37
paul@37 38
descriptor_base_type_mapping = {
paul@37 39
    "B" : "int",
paul@37 40
    "C" : "str",
paul@37 41
    "D" : "float",
paul@37 42
    "F" : "float",
paul@37 43
    "I" : "int",
paul@37 44
    "J" : "int",
paul@37 45
    "L" : "object",
paul@37 46
    "S" : "int",
paul@37 47
    "Z" : "bool",
paul@37 48
    "[" : "list"
paul@37 49
    }
paul@37 50
paul@55 51
PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL,  SUPER,  SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE, INTERFACE, ABSTRACT, STRICT = \
paul@55 52
0x0001, 0x0002,  0x0004,    0x0008, 0x0010, 0x0020, 0x0020,       0x0040,   0x0080,    0x0100, 0x0200,    0x0400,   0x0800
paul@55 53
paul@55 54
def has_flags(flags, desired):
paul@55 55
    desired_flags = reduce(lambda a, b: a | b, desired, 0)
paul@55 56
    return (flags & desired_flags) == desired_flags
paul@55 57
paul@2 58
# Useful mix-ins.
paul@2 59
paul@33 60
class PythonMethodUtils:
paul@79 61
    symbol_sep = "___" # was "$"
paul@79 62
    type_sep = "__" # replaces "/"
paul@79 63
    array_sep = "_array_" # was "[]"
paul@79 64
    base_seps = ("_", "_") # was "<" and ">"
paul@79 65
paul@95 66
    def get_unqualified_python_name(self):
paul@12 67
        name = self.get_name()
paul@12 68
        if str(name) == "<init>":
paul@95 69
            return "__init__"
paul@55 70
        elif str(name) == "<clinit>":
paul@55 71
            return "__clinit__"
paul@12 72
        else:
paul@95 73
            return str(name)
paul@95 74
paul@95 75
    def get_python_name(self):
paul@95 76
        name = self.get_unqualified_python_name()
paul@95 77
        if name == "__clinit__":
paul@95 78
            return name
paul@79 79
        return name + self.symbol_sep + self._get_descriptor_as_name()
paul@33 80
paul@33 81
    def _get_descriptor_as_name(self):
paul@33 82
        l = []
paul@33 83
        for descriptor_type in self.get_descriptor()[0]:
paul@33 84
            l.append(self._get_type_as_name(descriptor_type))
paul@79 85
        return self.symbol_sep.join(l)
paul@12 86
paul@33 87
    def _get_type_as_name(self, descriptor_type, s=""):
paul@33 88
        base_type, object_type, array_type = descriptor_type
paul@33 89
        if base_type == "L":
paul@79 90
            return object_type.replace("/", self.type_sep) + s
paul@33 91
        elif base_type == "[":
paul@79 92
            return self._get_type_as_name(array_type, s + self.array_sep)
paul@33 93
        else:
paul@79 94
            return self.base_seps[0] + base_type + self.base_seps[1] + s
paul@33 95
paul@33 96
class PythonNameUtils:
paul@33 97
    def get_python_name(self):
paul@69 98
        # NOTE: This may not be comprehensive.
paul@69 99
        if not str(self.get_name()).startswith("["):
paul@69 100
            return str(self.get_name()).replace("/", ".")
paul@69 101
        else:
paul@69 102
            return self._get_type_name(
paul@69 103
                get_field_descriptor(
paul@69 104
                    str(self.get_name())
paul@69 105
                    )
paul@69 106
                ).replace("/", ".")
paul@69 107
paul@69 108
    def _get_type_name(self, descriptor_type):
paul@69 109
        base_type, object_type, array_type = descriptor_type
paul@69 110
        if base_type == "L":
paul@69 111
            return object_type
paul@69 112
        elif base_type == "[":
paul@69 113
            return self._get_type_name(array_type)
paul@69 114
        else:
paul@69 115
            return descriptor_base_type_mapping[base_type]
paul@33 116
paul@33 117
class NameUtils:
paul@2 118
    def get_name(self):
paul@2 119
        if self.name_index != 0:
paul@10 120
            return self.class_file.constants[self.name_index - 1]
paul@2 121
        else:
paul@2 122
            # Some name indexes are zero to indicate special conditions.
paul@2 123
            return None
paul@2 124
paul@33 125
class NameAndTypeUtils:
paul@7 126
    def get_name(self):
paul@7 127
        if self.name_and_type_index != 0:
paul@7 128
            return self.class_file.constants[self.name_and_type_index - 1].get_name()
paul@7 129
        else:
paul@7 130
            # Some name indexes are zero to indicate special conditions.
paul@7 131
            return None
paul@7 132
paul@7 133
    def get_field_descriptor(self):
paul@7 134
        if self.name_and_type_index != 0:
paul@7 135
            return self.class_file.constants[self.name_and_type_index - 1].get_field_descriptor()
paul@7 136
        else:
paul@7 137
            # Some name indexes are zero to indicate special conditions.
paul@7 138
            return None
paul@7 139
paul@7 140
    def get_method_descriptor(self):
paul@7 141
        if self.name_and_type_index != 0:
paul@7 142
            return self.class_file.constants[self.name_and_type_index - 1].get_method_descriptor()
paul@7 143
        else:
paul@7 144
            # Some name indexes are zero to indicate special conditions.
paul@7 145
            return None
paul@7 146
paul@65 147
    def get_class(self):
paul@65 148
        return self.class_file.constants[self.class_index - 1]
paul@65 149
paul@69 150
# Symbol parsing.
paul@7 151
paul@69 152
def get_method_descriptor(s):
paul@69 153
    assert s[0] == "("
paul@69 154
    params = []
paul@69 155
    s = s[1:]
paul@69 156
    while s[0] != ")":
paul@69 157
        parameter_descriptor, s = _get_parameter_descriptor(s)
paul@69 158
        params.append(parameter_descriptor)
paul@69 159
    if s[1] != "V":
paul@69 160
        return_type, s = _get_field_type(s[1:])
paul@69 161
    else:
paul@69 162
        return_type, s = None, s[1:]
paul@69 163
    return params, return_type
paul@7 164
paul@69 165
def get_field_descriptor(s):
paul@69 166
    return _get_field_type(s)[0]
paul@7 167
paul@69 168
def _get_parameter_descriptor(s):
paul@69 169
    return _get_field_type(s)
paul@7 170
paul@69 171
def _get_component_type(s):
paul@69 172
    return _get_field_type(s)
paul@7 173
paul@69 174
def _get_field_type(s):
paul@69 175
    base_type, s = _get_base_type(s)
paul@69 176
    object_type = None
paul@69 177
    array_type = None
paul@69 178
    if base_type == "L":
paul@69 179
        object_type, s = _get_object_type(s)
paul@69 180
    elif base_type == "[":
paul@69 181
        array_type, s = _get_array_type(s)
paul@69 182
    return (base_type, object_type, array_type), s
paul@7 183
paul@69 184
def _get_base_type(s):
paul@69 185
    if len(s) > 0:
paul@69 186
        return s[0], s[1:]
paul@69 187
    else:
paul@69 188
        return None, s
paul@7 189
paul@69 190
def _get_object_type(s):
paul@69 191
    if len(s) > 0:
paul@69 192
        s_end = s.find(";")
paul@69 193
        assert s_end != -1
paul@69 194
        return s[:s_end], s[s_end+1:]
paul@69 195
    else:
paul@69 196
        return None, s
paul@7 197
paul@69 198
def _get_array_type(s):
paul@69 199
    if len(s) > 0:
paul@69 200
        return _get_component_type(s)
paul@69 201
    else:
paul@69 202
        return None, s
paul@7 203
paul@0 204
# Constant information.
paul@0 205
paul@33 206
class ClassInfo(NameUtils, PythonNameUtils):
paul@2 207
    def init(self, data, class_file):
paul@2 208
        self.class_file = class_file
paul@1 209
        self.name_index = u2(data[0:2])
paul@0 210
        return data[2:]
paul@0 211
paul@7 212
class RefInfo(NameAndTypeUtils):
paul@2 213
    def init(self, data, class_file):
paul@2 214
        self.class_file = class_file
paul@1 215
        self.class_index = u2(data[0:2])
paul@1 216
        self.name_and_type_index = u2(data[2:4])
paul@0 217
        return data[4:]
paul@0 218
paul@33 219
class FieldRefInfo(RefInfo, PythonNameUtils):
paul@7 220
    def get_descriptor(self):
paul@7 221
        return RefInfo.get_field_descriptor(self)
paul@0 222
paul@33 223
class MethodRefInfo(RefInfo, PythonMethodUtils):
paul@7 224
    def get_descriptor(self):
paul@7 225
        return RefInfo.get_method_descriptor(self)
paul@0 226
paul@33 227
class InterfaceMethodRefInfo(MethodRefInfo):
paul@33 228
    pass
paul@0 229
paul@69 230
class NameAndTypeInfo(NameUtils, PythonNameUtils):
paul@2 231
    def init(self, data, class_file):
paul@2 232
        self.class_file = class_file
paul@1 233
        self.name_index = u2(data[0:2])
paul@1 234
        self.descriptor_index = u2(data[2:4])
paul@0 235
        return data[4:]
paul@0 236
paul@7 237
    def get_field_descriptor(self):
paul@69 238
        return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
paul@7 239
paul@7 240
    def get_method_descriptor(self):
paul@69 241
        return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
paul@7 242
paul@0 243
class Utf8Info:
paul@2 244
    def init(self, data, class_file):
paul@2 245
        self.class_file = class_file
paul@1 246
        self.length = u2(data[0:2])
paul@0 247
        self.bytes = data[2:2+self.length]
paul@0 248
        return data[2+self.length:]
paul@0 249
paul@0 250
    def __str__(self):
paul@0 251
        return self.bytes
paul@0 252
paul@0 253
    def __unicode__(self):
paul@0 254
        return unicode(self.bytes, "utf-8")
paul@0 255
paul@61 256
    def get_value(self):
paul@61 257
        return str(self)
paul@61 258
paul@0 259
class StringInfo:
paul@2 260
    def init(self, data, class_file):
paul@2 261
        self.class_file = class_file
paul@1 262
        self.string_index = u2(data[0:2])
paul@0 263
        return data[2:]
paul@0 264
paul@61 265
    def __str__(self):
paul@61 266
        return str(self.class_file.constants[self.string_index - 1])
paul@61 267
paul@61 268
    def __unicode__(self):
paul@61 269
        return unicode(self.class_file.constants[self.string_index - 1])
paul@61 270
paul@61 271
    def get_value(self):
paul@61 272
        return str(self)
paul@61 273
paul@0 274
class SmallNumInfo:
paul@2 275
    def init(self, data, class_file):
paul@2 276
        self.class_file = class_file
paul@4 277
        self.bytes = data[0:4]
paul@0 278
        return data[4:]
paul@0 279
paul@0 280
class IntegerInfo(SmallNumInfo):
paul@4 281
    def get_value(self):
paul@4 282
        return s4(self.bytes)
paul@0 283
paul@0 284
class FloatInfo(SmallNumInfo):
paul@4 285
    def get_value(self):
paul@4 286
        return f4(self.bytes)
paul@0 287
paul@0 288
class LargeNumInfo:
paul@2 289
    def init(self, data, class_file):
paul@2 290
        self.class_file = class_file
paul@61 291
        self.high_bytes = data[0:4]
paul@61 292
        self.low_bytes = data[4:8]
paul@0 293
        return data[8:]
paul@0 294
paul@0 295
class LongInfo(LargeNumInfo):
paul@4 296
    def get_value(self):
paul@4 297
        return s8(self.high_bytes + self.low_bytes)
paul@0 298
paul@0 299
class DoubleInfo(LargeNumInfo):
paul@4 300
    def get_value(self):
paul@4 301
        return f8(self.high_bytes + self.low_bytes)
paul@0 302
paul@0 303
# Other information.
paul@1 304
# Objects of these classes are generally aware of the class they reside in.
paul@0 305
paul@69 306
class ItemInfo(NameUtils):
paul@0 307
    def init(self, data, class_file):
paul@0 308
        self.class_file = class_file
paul@1 309
        self.access_flags = u2(data[0:2])
paul@1 310
        self.name_index = u2(data[2:4])
paul@1 311
        self.descriptor_index = u2(data[4:6])
paul@0 312
        self.attributes, data = self.class_file._get_attributes(data[6:])
paul@0 313
        return data
paul@0 314
paul@34 315
class FieldInfo(ItemInfo, PythonNameUtils):
paul@0 316
    def get_descriptor(self):
paul@69 317
        return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
paul@0 318
paul@34 319
class MethodInfo(ItemInfo, PythonMethodUtils):
paul@0 320
    def get_descriptor(self):
paul@69 321
        return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
paul@0 322
paul@0 323
class AttributeInfo:
paul@0 324
    def init(self, data, class_file):
paul@1 325
        self.attribute_length = u4(data[0:4])
paul@0 326
        self.info = data[4:4+self.attribute_length]
paul@0 327
        return data[4+self.attribute_length:]
paul@0 328
paul@0 329
# NOTE: Decode the different attribute formats.
paul@0 330
paul@33 331
class SourceFileAttributeInfo(AttributeInfo, NameUtils, PythonNameUtils):
paul@2 332
    def init(self, data, class_file):
paul@2 333
        self.class_file = class_file
paul@2 334
        self.attribute_length = u4(data[0:4])
paul@2 335
        # Permit the NameUtils mix-in.
paul@2 336
        self.name_index = self.sourcefile_index = u2(data[4:6])
paul@61 337
        return data[6:]
paul@0 338
paul@0 339
class ConstantValueAttributeInfo(AttributeInfo):
paul@0 340
    def init(self, data, class_file):
paul@4 341
        self.class_file = class_file
paul@1 342
        self.attribute_length = u4(data[0:4])
paul@1 343
        self.constant_value_index = u2(data[4:6])
paul@0 344
        assert 4+self.attribute_length == 6
paul@0 345
        return data[4+self.attribute_length:]
paul@0 346
paul@4 347
    def get_value(self):
paul@4 348
        return self.class_file.constants[self.constant_value_index - 1].get_value()
paul@4 349
paul@0 350
class CodeAttributeInfo(AttributeInfo):
paul@0 351
    def init(self, data, class_file):
paul@0 352
        self.class_file = class_file
paul@1 353
        self.attribute_length = u4(data[0:4])
paul@1 354
        self.max_stack = u2(data[4:6])
paul@1 355
        self.max_locals = u2(data[6:8])
paul@1 356
        self.code_length = u4(data[8:12])
paul@0 357
        end_of_code = 12+self.code_length
paul@0 358
        self.code = data[12:end_of_code]
paul@1 359
        self.exception_table_length = u2(data[end_of_code:end_of_code+2])
paul@0 360
        self.exception_table = []
paul@0 361
        data = data[end_of_code + 2:]
paul@0 362
        for i in range(0, self.exception_table_length):
paul@0 363
            exception = ExceptionInfo()
paul@0 364
            data = exception.init(data)
paul@2 365
            self.exception_table.append(exception)
paul@0 366
        self.attributes, data = self.class_file._get_attributes(data)
paul@0 367
        return data
paul@0 368
paul@0 369
class ExceptionsAttributeInfo(AttributeInfo):
paul@1 370
    def init(self, data, class_file):
paul@1 371
        self.class_file = class_file
paul@1 372
        self.attribute_length = u4(data[0:4])
paul@1 373
        self.number_of_exceptions = u2(data[4:6])
paul@1 374
        self.exception_index_table = []
paul@1 375
        index = 6
paul@1 376
        for i in range(0, self.number_of_exceptions):
paul@1 377
            self.exception_index_table.append(u2(data[index:index+2]))
paul@1 378
            index += 2
paul@1 379
        return data[index:]
paul@1 380
paul@1 381
    def get_exception(self, i):
paul@1 382
        exception_index = self.exception_index_table[i]
paul@1 383
        return self.class_file.constants[exception_index - 1]
paul@0 384
paul@0 385
class InnerClassesAttributeInfo(AttributeInfo):
paul@2 386
    def init(self, data, class_file):
paul@2 387
        self.class_file = class_file
paul@2 388
        self.attribute_length = u4(data[0:4])
paul@2 389
        self.number_of_classes = u2(data[4:6])
paul@2 390
        self.classes = []
paul@2 391
        data = data[6:]
paul@2 392
        for i in range(0, self.number_of_classes):
paul@2 393
            inner_class = InnerClassInfo()
paul@2 394
            data = inner_class.init(data, self.class_file)
paul@2 395
            self.classes.append(inner_class)
paul@2 396
        return data
paul@0 397
paul@0 398
class SyntheticAttributeInfo(AttributeInfo):
paul@0 399
    pass
paul@0 400
paul@0 401
class LineNumberAttributeInfo(AttributeInfo):
paul@2 402
    def init(self, data, class_file):
paul@2 403
        self.class_file = class_file
paul@2 404
        self.attribute_length = u4(data[0:4])
paul@2 405
        self.line_number_table_length = u2(data[4:6])
paul@2 406
        self.line_number_table = []
paul@2 407
        data = data[6:]
paul@2 408
        for i in range(0, self.line_number_table_length):
paul@2 409
            line_number = LineNumberInfo()
paul@2 410
            data = line_number.init(data)
paul@2 411
            self.line_number_table.append(line_number)
paul@2 412
        return data
paul@0 413
paul@0 414
class LocalVariableAttributeInfo(AttributeInfo):
paul@2 415
    def init(self, data, class_file):
paul@2 416
        self.class_file = class_file
paul@2 417
        self.attribute_length = u4(data[0:4])
paul@2 418
        self.local_variable_table_length = u2(data[4:6])
paul@2 419
        self.local_variable_table = []
paul@2 420
        data = data[6:]
paul@2 421
        for i in range(0, self.local_variable_table_length):
paul@2 422
            local_variable = LocalVariableInfo()
paul@44 423
            data = local_variable.init(data, self.class_file)
paul@2 424
            self.local_variable_table.append(local_variable)
paul@2 425
        return data
paul@0 426
paul@0 427
class DeprecatedAttributeInfo(AttributeInfo):
paul@0 428
    pass
paul@0 429
paul@2 430
# Child classes of the attribute information classes.
paul@2 431
paul@0 432
class ExceptionInfo:
paul@0 433
    def init(self, data):
paul@1 434
        self.start_pc = u2(data[0:2])
paul@1 435
        self.end_pc = u2(data[2:4])
paul@1 436
        self.handler_pc = u2(data[4:6])
paul@1 437
        self.catch_type = u2(data[6:8])
paul@0 438
        return data[8:]
paul@0 439
paul@2 440
class InnerClassInfo(NameUtils):
paul@2 441
    def init(self, data, class_file):
paul@2 442
        self.class_file = class_file
paul@2 443
        self.inner_class_info_index = u2(data[0:2])
paul@2 444
        self.outer_class_info_index = u2(data[2:4])
paul@2 445
        # Permit the NameUtils mix-in.
paul@2 446
        self.name_index = self.inner_name_index = u2(data[4:6])
paul@2 447
        self.inner_class_access_flags = u2(data[6:8])
paul@2 448
        return data[8:]
paul@2 449
paul@2 450
class LineNumberInfo:
paul@2 451
    def init(self, data):
paul@2 452
        self.start_pc = u2(data[0:2])
paul@2 453
        self.line_number = u2(data[2:4])
paul@2 454
        return data[4:]
paul@2 455
paul@33 456
class LocalVariableInfo(NameUtils, PythonNameUtils):
paul@2 457
    def init(self, data, class_file):
paul@2 458
        self.class_file = class_file
paul@2 459
        self.start_pc = u2(data[0:2])
paul@2 460
        self.length = u2(data[2:4])
paul@2 461
        self.name_index = u2(data[4:6])
paul@2 462
        self.descriptor_index = u2(data[6:8])
paul@2 463
        self.index = u2(data[8:10])
paul@2 464
        return data[10:]
paul@2 465
paul@2 466
    def get_descriptor(self):
paul@69 467
        return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
paul@2 468
paul@2 469
# Exceptions.
paul@2 470
paul@0 471
class UnknownTag(Exception):
paul@0 472
    pass
paul@0 473
paul@0 474
class UnknownAttribute(Exception):
paul@0 475
    pass
paul@0 476
paul@0 477
# Abstractions for the main structures.
paul@0 478
paul@0 479
class ClassFile:
paul@0 480
paul@0 481
    "A class representing a Java class file."
paul@0 482
paul@0 483
    def __init__(self, s):
paul@0 484
paul@0 485
        """
paul@0 486
        Process the given string 's', populating the object with the class
paul@0 487
        file's details.
paul@0 488
        """
paul@0 489
paul@0 490
        self.constants, s = self._get_constants(s[8:])
paul@0 491
        self.access_flags, s = self._get_access_flags(s)
paul@0 492
        self.this_class, s = self._get_this_class(s)
paul@0 493
        self.super_class, s = self._get_super_class(s)
paul@0 494
        self.interfaces, s = self._get_interfaces(s)
paul@0 495
        self.fields, s = self._get_fields(s)
paul@0 496
        self.methods, s = self._get_methods(s)
paul@0 497
        self.attributes, s = self._get_attributes(s)
paul@0 498
paul@0 499
    def _decode_const(self, s):
paul@1 500
        tag = u1(s[0:1])
paul@0 501
        if tag == 1:
paul@0 502
            const = Utf8Info()
paul@0 503
        elif tag == 3:
paul@0 504
            const = IntegerInfo()
paul@0 505
        elif tag == 4:
paul@0 506
            const = FloatInfo()
paul@0 507
        elif tag == 5:
paul@0 508
            const = LongInfo()
paul@0 509
        elif tag == 6:
paul@0 510
            const = DoubleInfo()
paul@0 511
        elif tag == 7:
paul@0 512
            const = ClassInfo()
paul@0 513
        elif tag == 8:
paul@0 514
            const = StringInfo()
paul@0 515
        elif tag == 9:
paul@0 516
            const = FieldRefInfo()
paul@0 517
        elif tag == 10:
paul@0 518
            const = MethodRefInfo()
paul@0 519
        elif tag == 11:
paul@0 520
            const = InterfaceMethodRefInfo()
paul@0 521
        elif tag == 12:
paul@0 522
            const = NameAndTypeInfo()
paul@0 523
        else:
paul@0 524
            raise UnknownTag, tag
paul@2 525
paul@2 526
        # Initialise the constant object.
paul@2 527
paul@2 528
        s = const.init(s[1:], self)
paul@0 529
        return const, s
paul@0 530
paul@0 531
    def _get_constants_from_table(self, count, s):
paul@0 532
        l = []
paul@0 533
        # Have to skip certain entries specially.
paul@0 534
        i = 1
paul@0 535
        while i < count:
paul@0 536
            c, s = self._decode_const(s)
paul@0 537
            l.append(c)
paul@0 538
            # Add a blank entry after "large" entries.
paul@0 539
            if isinstance(c, LargeNumInfo):
paul@0 540
                l.append(None)
paul@0 541
                i += 1
paul@0 542
            i += 1
paul@0 543
        return l, s
paul@0 544
paul@0 545
    def _get_items_from_table(self, cls, number, s):
paul@0 546
        l = []
paul@0 547
        for i in range(0, number):
paul@0 548
            f = cls()
paul@0 549
            s = f.init(s, self)
paul@0 550
            l.append(f)
paul@0 551
        return l, s
paul@0 552
paul@0 553
    def _get_methods_from_table(self, number, s):
paul@0 554
        return self._get_items_from_table(MethodInfo, number, s)
paul@0 555
paul@0 556
    def _get_fields_from_table(self, number, s):
paul@0 557
        return self._get_items_from_table(FieldInfo, number, s)
paul@0 558
paul@0 559
    def _get_attribute_from_table(self, s):
paul@1 560
        attribute_name_index = u2(s[0:2])
paul@0 561
        constant_name = self.constants[attribute_name_index - 1].bytes
paul@0 562
        if constant_name == "SourceFile":
paul@0 563
            attribute = SourceFileAttributeInfo()
paul@0 564
        elif constant_name == "ConstantValue":
paul@0 565
            attribute = ConstantValueAttributeInfo()
paul@0 566
        elif constant_name == "Code":
paul@0 567
            attribute = CodeAttributeInfo()
paul@0 568
        elif constant_name == "Exceptions":
paul@0 569
            attribute = ExceptionsAttributeInfo()
paul@0 570
        elif constant_name == "InnerClasses":
paul@0 571
            attribute = InnerClassesAttributeInfo()
paul@0 572
        elif constant_name == "Synthetic":
paul@0 573
            attribute = SyntheticAttributeInfo()
paul@0 574
        elif constant_name == "LineNumberTable":
paul@0 575
            attribute = LineNumberAttributeInfo()
paul@0 576
        elif constant_name == "LocalVariableTable":
paul@0 577
            attribute = LocalVariableAttributeInfo()
paul@0 578
        elif constant_name == "Deprecated":
paul@0 579
            attribute = DeprecatedAttributeInfo()
paul@0 580
        else:
paul@0 581
            raise UnknownAttribute, constant_name
paul@0 582
        s = attribute.init(s[2:], self)
paul@0 583
        return attribute, s
paul@0 584
paul@0 585
    def _get_attributes_from_table(self, number, s):
paul@0 586
        attributes = []
paul@0 587
        for i in range(0, number):
paul@0 588
            attribute, s = self._get_attribute_from_table(s)
paul@0 589
            attributes.append(attribute)
paul@0 590
        return attributes, s
paul@0 591
paul@0 592
    def _get_constants(self, s):
paul@1 593
        count = u2(s[0:2])
paul@0 594
        return self._get_constants_from_table(count, s[2:])
paul@0 595
paul@0 596
    def _get_access_flags(self, s):
paul@1 597
        return u2(s[0:2]), s[2:]
paul@0 598
paul@0 599
    def _get_this_class(self, s):
paul@1 600
        index = u2(s[0:2])
paul@0 601
        return self.constants[index - 1], s[2:]
paul@0 602
paul@0 603
    _get_super_class = _get_this_class
paul@0 604
paul@0 605
    def _get_interfaces(self, s):
paul@0 606
        interfaces = []
paul@1 607
        number = u2(s[0:2])
paul@0 608
        s = s[2:]
paul@0 609
        for i in range(0, number):
paul@1 610
            index = u2(s[0:2])
paul@0 611
            interfaces.append(self.constants[index - 1])
paul@0 612
            s = s[2:]
paul@0 613
        return interfaces, s
paul@0 614
paul@0 615
    def _get_fields(self, s):
paul@1 616
        number = u2(s[0:2])
paul@0 617
        return self._get_fields_from_table(number, s[2:])
paul@0 618
paul@0 619
    def _get_attributes(self, s):
paul@1 620
        number = u2(s[0:2])
paul@0 621
        return self._get_attributes_from_table(number, s[2:])
paul@0 622
paul@0 623
    def _get_methods(self, s):
paul@1 624
        number = u2(s[0:2])
paul@0 625
        return self._get_methods_from_table(number, s[2:])
paul@0 626
paul@0 627
if __name__ == "__main__":
paul@0 628
    import sys
paul@95 629
    f = open(sys.argv[1], "rb")
paul@0 630
    c = ClassFile(f.read())
paul@95 631
    f.close()
paul@0 632
paul@0 633
# vim: tabstop=4 expandtab shiftwidth=4