mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			222 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
## Copyright (C) 2004, 2005 Free Software Foundation
 | 
						|
## Written by Gary Benson <gbenson@redhat.com>
 | 
						|
##
 | 
						|
## This program is free software; you can redistribute it and/or modify
 | 
						|
## it under the terms of the GNU General Public License as published by
 | 
						|
## the Free Software Foundation; either version 2 of the License, or
 | 
						|
## (at your option) any later version.
 | 
						|
##
 | 
						|
## This program is distributed in the hope that it will be useful,
 | 
						|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
## GNU General Public License for more details.
 | 
						|
 | 
						|
"""Read Java(TM) class files."""
 | 
						|
 | 
						|
import cStringIO as StringIO
 | 
						|
import struct
 | 
						|
 | 
						|
class Class:
 | 
						|
    def __init__(self, arg):
 | 
						|
        if hasattr(arg, "read"):
 | 
						|
            self.fp = arg
 | 
						|
        elif type(arg) == type(""):
 | 
						|
            if arg.startswith("\xca\xfe\xba\xbe"):
 | 
						|
                self.fp = StringIO.StringIO(arg)
 | 
						|
            else:
 | 
						|
                self.fp = open(arg, "r")
 | 
						|
        else:
 | 
						|
            raise TypeError, type(arg)
 | 
						|
 | 
						|
        magic = self._read_int()
 | 
						|
        assert magic == 0xcafebabeL
 | 
						|
        minor, major = self._read(">HH")        
 | 
						|
        self.version = (major, minor)
 | 
						|
 | 
						|
        self.pool_integrity_checks = None
 | 
						|
        try:
 | 
						|
            assert False
 | 
						|
        except AssertionError:
 | 
						|
            self.pool_integrity_checks = []
 | 
						|
 | 
						|
        self._read_constants_pool()
 | 
						|
 | 
						|
        self.access_flags = self._read_short()
 | 
						|
        self.name = self._read_reference_Class()
 | 
						|
        self.super = self._read_reference_Class()
 | 
						|
 | 
						|
        self.interfaces = self._read_interfaces()
 | 
						|
        self.fields = self._read_fieldsormethods()
 | 
						|
        self.methods = self._read_fieldsormethods()
 | 
						|
        self.attributes = self._read_attributes()
 | 
						|
 | 
						|
        if self.pool_integrity_checks is not None:
 | 
						|
            for index, tag in self.pool_integrity_checks:
 | 
						|
                assert self.constants[index][0] == tag
 | 
						|
 | 
						|
        del self.fp, self.pool_integrity_checks
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        result = []
 | 
						|
        attrs = [attr for attr in dir(self)
 | 
						|
                 if not attr.startswith("_") and attr != "Member"]
 | 
						|
        attrs.sort()
 | 
						|
        for attr in attrs:
 | 
						|
            result.append("%-13s %s" % (
 | 
						|
                attr + ":", attr == "constants" and
 | 
						|
                "<ELIDED>" or repr(getattr(self, attr))))
 | 
						|
        return "\n".join(result)
 | 
						|
 | 
						|
    def _read_constants_pool(self):
 | 
						|
        self.constants = {}
 | 
						|
        skip = False
 | 
						|
        for i in xrange(1, self._read_short()):
 | 
						|
            if skip:
 | 
						|
                skip = False
 | 
						|
                continue
 | 
						|
            tag = {
 | 
						|
                1: "Utf8", 3: "Integer", 4: "Float", 5: "Long",
 | 
						|
                6: "Double", 7: "Class", 8: "String", 9: "Fieldref",
 | 
						|
                10: "Methodref", 11: "InterfaceMethodref",
 | 
						|
                12: "NameAndType"}[self._read_byte()]
 | 
						|
            skip = tag in ("Long", "Double") # crack crack crack!
 | 
						|
            self.constants[i] = (tag, getattr(self, "_read_constant_" + tag)())
 | 
						|
 | 
						|
    def _read_interfaces(self):
 | 
						|
        result = []
 | 
						|
        for i in xrange(self._read_short()):
 | 
						|
            result.append(self._read_reference_Class())
 | 
						|
        return result
 | 
						|
 | 
						|
    def _read_fieldsormethods(self):
 | 
						|
        result = []
 | 
						|
        for i in xrange(self._read_short()):
 | 
						|
            result.append(self.Member(self))
 | 
						|
        return result
 | 
						|
 | 
						|
    class Member:
 | 
						|
        def __init__(self, source):
 | 
						|
            self.access_flags = source._read_short()
 | 
						|
            self.name = source._read_reference_Utf8()
 | 
						|
            self.descriptor = source._read_reference_Utf8()
 | 
						|
            self.attributes = source._read_attributes()
 | 
						|
 | 
						|
        def __repr__(self):
 | 
						|
            result = []
 | 
						|
            attrs = [attr for attr in dir(self) if not attr.startswith("_")]
 | 
						|
            attrs.sort()
 | 
						|
            for attr in attrs:
 | 
						|
                value = getattr(self, attr)
 | 
						|
                if attr == "attributes" and value.has_key("Code"):
 | 
						|
                    value = value.copy()
 | 
						|
                    value.update({"Code": "<ELIDED>"})
 | 
						|
                result.append("%-13s %s" % (
 | 
						|
                    attr + ":", repr(value).replace(
 | 
						|
                        "'Code': '<ELIDED>'", "'Code': <ELIDED>")))
 | 
						|
            return ("\n%s" % (15 * " ")).join(result)
 | 
						|
 | 
						|
    def _read_attributes(self):
 | 
						|
        result = {}
 | 
						|
        for i in xrange(self._read_short()):
 | 
						|
            name = self._read_reference_Utf8()
 | 
						|
            data = self.fp.read(self._read_int())
 | 
						|
            assert not result.has_key(name)
 | 
						|
            result[name] = data
 | 
						|
        return result
 | 
						|
 | 
						|
    # Constants pool reference reader convenience functions
 | 
						|
 | 
						|
    def _read_reference_Utf8(self):
 | 
						|
        return self._read_references("Utf8")[0]
 | 
						|
 | 
						|
    def _read_reference_Class(self):
 | 
						|
        return self._read_references("Class")[0]
 | 
						|
 | 
						|
    def _read_reference_Class_NameAndType(self):
 | 
						|
        return self._read_references("Class", "NameAndType")
 | 
						|
 | 
						|
    def _read_references(self, *args):
 | 
						|
        result = []
 | 
						|
        for arg in args:
 | 
						|
            index = self._read_short()
 | 
						|
            if self.pool_integrity_checks is not None:
 | 
						|
                self.pool_integrity_checks.append((index, arg))
 | 
						|
            result.append(index)
 | 
						|
        return result
 | 
						|
 | 
						|
    # Constants pool constant reader functions
 | 
						|
 | 
						|
    def _read_constant_Utf8(self):
 | 
						|
        constant = self.fp.read(self._read_short())
 | 
						|
        try:
 | 
						|
            constant = constant.decode("utf-8")
 | 
						|
        except UnicodeError:
 | 
						|
            constant = _bork_utf8_decode(constant)
 | 
						|
        try:
 | 
						|
            constant = constant.encode("us-ascii")
 | 
						|
        except UnicodeError:
 | 
						|
            pass
 | 
						|
        return constant
 | 
						|
 | 
						|
    def _read_constant_Integer(self):
 | 
						|
        return self._read_int()
 | 
						|
 | 
						|
    def _read_constant_Float(self):
 | 
						|
        return self._read(">f")[0]
 | 
						|
 | 
						|
    def _read_constant_Long(self):
 | 
						|
        return self._read(">q")[0]
 | 
						|
 | 
						|
    def _read_constant_Double(self):
 | 
						|
        return self._read(">d")[0]
 | 
						|
 | 
						|
    _read_constant_Class = _read_reference_Utf8
 | 
						|
    _read_constant_String = _read_reference_Utf8
 | 
						|
    _read_constant_Fieldref = _read_reference_Class_NameAndType
 | 
						|
    _read_constant_Methodref = _read_reference_Class_NameAndType
 | 
						|
    _read_constant_InterfaceMethodref = _read_reference_Class_NameAndType
 | 
						|
 | 
						|
    def _read_constant_NameAndType(self):
 | 
						|
        return self._read_reference_Utf8(), self._read_reference_Utf8()
 | 
						|
 | 
						|
    # Generic reader functions
 | 
						|
 | 
						|
    def _read_int(self):
 | 
						|
        # XXX how else to read 32 bits on a 64-bit box?
 | 
						|
        h, l = map(long, self._read(">HH"))
 | 
						|
        return (h << 16) + l
 | 
						|
 | 
						|
    def _read_short(self):
 | 
						|
        return self._read(">H")[0]
 | 
						|
 | 
						|
    def _read_byte(self):
 | 
						|
        return self._read("B")[0]
 | 
						|
 | 
						|
    def _read(self, fmt):
 | 
						|
        return struct.unpack(fmt, self.fp.read(struct.calcsize(fmt)))
 | 
						|
 | 
						|
def _bork_utf8_decode(data):
 | 
						|
    # more crack!
 | 
						|
    bytes, unicode = map(ord, data), ""
 | 
						|
    while bytes:
 | 
						|
        b1 = bytes.pop(0)
 | 
						|
        if b1 & 0x80:
 | 
						|
            assert b1 & 0x40
 | 
						|
            b2 = bytes.pop(0)
 | 
						|
            assert b2 & 0xC0 == 0x80
 | 
						|
            if b1 & 0x20:
 | 
						|
                assert not b1 & 0x10
 | 
						|
                b3 = bytes.pop(0)
 | 
						|
                assert b3 & 0xC0 == 0x80
 | 
						|
                unicode += unichr(
 | 
						|
                    ((b1 & 0x0f) << 12) + ((b2 & 0x3f) << 6) + (b3 & 0x3f))
 | 
						|
            else:
 | 
						|
                unicode += unichr(((b1 & 0x1f) << 6) + (b2 & 0x3f))
 | 
						|
        else:
 | 
						|
            unicode += unichr(b1)
 | 
						|
    return unicode
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    print Class("/usr/share/katana/build/ListDependentClasses.class")
 | 
						|
 |