javaclass

Annotated javaclass/classfile.py

189:8391014fcbde
2011-10-08 Paul Boddie Minor formatting changes.
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