javaclass

Changeset

185:407b443fcc73
2011-03-24 Paul Boddie raw files shortlog changelog graph Added Braden Thomas' class file serialisation patches.
javaclass/classfile.py (file)
     1.1 --- a/javaclass/classfile.py	Wed Mar 23 23:15:41 2011 +0100
     1.2 +++ b/javaclass/classfile.py	Thu Mar 24 00:54:11 2011 +0100
     1.3 @@ -33,6 +33,30 @@
     1.4  def f8(data):
     1.5      return struct.unpack(">d", data[0:8])[0]
     1.6  
     1.7 +def su1(value):
     1.8 +    return struct.pack(">B", value)
     1.9 +
    1.10 +def su2(value):
    1.11 +    return struct.pack(">H", value)
    1.12 +
    1.13 +def ss2(value):
    1.14 +    return struct.pack(">h", value)
    1.15 +
    1.16 +def su4(value):
    1.17 +    return struct.pack(">L", value)
    1.18 +
    1.19 +def ss4(value):
    1.20 +    return struct.pack(">l", value)
    1.21 +
    1.22 +def ss8(value):
    1.23 +    return struct.pack(">q", value)
    1.24 +
    1.25 +def sf4(value):
    1.26 +    return struct.pack(">f", value)
    1.27 +
    1.28 +def sf8(value):
    1.29 +    return struct.pack(">d", value)
    1.30 +
    1.31  # Useful tables and constants.
    1.32  
    1.33  descriptor_base_type_mapping = {
    1.34 @@ -221,6 +245,8 @@
    1.35          self.class_file = class_file
    1.36          self.name_index = u2(data[0:2])
    1.37          return data[2:]
    1.38 +    def serialize(self):
    1.39 +        return su2(self.name_index)
    1.40  
    1.41  class RefInfo(NameAndTypeUtils):
    1.42      def init(self, data, class_file):
    1.43 @@ -228,6 +254,8 @@
    1.44          self.class_index = u2(data[0:2])
    1.45          self.name_and_type_index = u2(data[2:4])
    1.46          return data[4:]
    1.47 +    def serialize(self):
    1.48 +        return su2(self.class_index)+su2(self.name_and_type_index)
    1.49  
    1.50  class FieldRefInfo(RefInfo, PythonNameUtils):
    1.51      def get_descriptor(self):
    1.52 @@ -247,6 +275,9 @@
    1.53          self.descriptor_index = u2(data[2:4])
    1.54          return data[4:]
    1.55  
    1.56 +    def serialize(self):
    1.57 +        return su2(self.name_index)+su2(self.descriptor_index)
    1.58 +
    1.59      def get_field_descriptor(self):
    1.60          return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
    1.61  
    1.62 @@ -260,6 +291,9 @@
    1.63          self.bytes = data[2:2+self.length]
    1.64          return data[2+self.length:]
    1.65  
    1.66 +    def serialize(self):
    1.67 +        return su2(self.length)+self.bytes
    1.68 +
    1.69      def __str__(self):
    1.70          return self.bytes
    1.71  
    1.72 @@ -275,6 +309,9 @@
    1.73          self.string_index = u2(data[0:2])
    1.74          return data[2:]
    1.75  
    1.76 +    def serialize(self):
    1.77 +        return su2(self.string_index)
    1.78 +
    1.79      def __str__(self):
    1.80          return str(self.class_file.constants[self.string_index - 1])
    1.81  
    1.82 @@ -289,6 +326,8 @@
    1.83          self.class_file = class_file
    1.84          self.bytes = data[0:4]
    1.85          return data[4:]
    1.86 +    def serialize(self):
    1.87 +        return self.bytes
    1.88  
    1.89  class IntegerInfo(SmallNumInfo):
    1.90      def get_value(self):
    1.91 @@ -304,6 +343,9 @@
    1.92          self.high_bytes = data[0:4]
    1.93          self.low_bytes = data[4:8]
    1.94          return data[8:]
    1.95 +    def serialize(self):
    1.96 +        return self.high_bytes+self.low_bytes
    1.97 +
    1.98  
    1.99  class LongInfo(LargeNumInfo):
   1.100      def get_value(self):
   1.101 @@ -324,6 +366,10 @@
   1.102          self.descriptor_index = u2(data[4:6])
   1.103          self.attributes, data = self.class_file._get_attributes(data[6:])
   1.104          return data
   1.105 +    def serialize(self):
   1.106 +        od = su2(self.access_flags)+su2(self.name_index)+su2(self.descriptor_index)
   1.107 +        od += self.class_file._serialize_attributes(self.attributes)
   1.108 +        return od
   1.109  
   1.110  class FieldInfo(ItemInfo, PythonNameUtils):
   1.111      def get_descriptor(self):
   1.112 @@ -338,6 +384,8 @@
   1.113          self.attribute_length = u4(data[0:4])
   1.114          self.info = data[4:4+self.attribute_length]
   1.115          return data[4+self.attribute_length:]
   1.116 +    def serialize(self):
   1.117 +        return su4(self.attribute_length)+self.info
   1.118  
   1.119  # NOTE: Decode the different attribute formats.
   1.120  
   1.121 @@ -348,6 +396,8 @@
   1.122          # Permit the NameUtils mix-in.
   1.123          self.name_index = self.sourcefile_index = u2(data[4:6])
   1.124          return data[6:]
   1.125 +    def serialize(self):
   1.126 +        return su4(self.attribute_length)+su2(self.name_index)
   1.127  
   1.128  class ConstantValueAttributeInfo(AttributeInfo):
   1.129      def init(self, data, class_file):
   1.130 @@ -360,6 +410,9 @@
   1.131      def get_value(self):
   1.132          return self.class_file.constants[self.constant_value_index - 1].get_value()
   1.133  
   1.134 +    def serialize(self):
   1.135 +        return su4(self.attribute_length)+su2(self.constant_value_index)
   1.136 +
   1.137  class CodeAttributeInfo(AttributeInfo):
   1.138      def init(self, data, class_file):
   1.139          self.class_file = class_file
   1.140 @@ -378,6 +431,13 @@
   1.141              self.exception_table.append(exception)
   1.142          self.attributes, data = self.class_file._get_attributes(data)
   1.143          return data
   1.144 +    def serialize(self):
   1.145 +        od = su4(self.attribute_length)+su2(self.max_stack)+su2(self.max_locals)+su4(self.code_length)+self.code
   1.146 +        od += su2(self.exception_table_length)
   1.147 +        for e in self.exception_table:
   1.148 +            od += e.serialize()
   1.149 +        od += self.class_file._serialize_attributes(self.attributes)
   1.150 +        return od
   1.151  
   1.152  class ExceptionsAttributeInfo(AttributeInfo):
   1.153      def init(self, data, class_file):
   1.154 @@ -394,6 +454,12 @@
   1.155      def get_exception(self, i):
   1.156          exception_index = self.exception_index_table[i]
   1.157          return self.class_file.constants[exception_index - 1]
   1.158 +        
   1.159 +    def serialize(self):
   1.160 +        od = su4(self.attribute_length)+su2(self.number_of_exceptions)
   1.161 +        for ei in self.exception_index_table:
   1.162 +            od += su2(ei)
   1.163 +        return od
   1.164  
   1.165  class InnerClassesAttributeInfo(AttributeInfo):
   1.166      def init(self, data, class_file):
   1.167 @@ -408,6 +474,12 @@
   1.168              self.classes.append(inner_class)
   1.169          return data
   1.170  
   1.171 +    def serialize(self):
   1.172 +        od = su4(self.attribute_length)+su2(self.number_of_classes)
   1.173 +        for c in self.classes:
   1.174 +            od += c.serialize()
   1.175 +        return od
   1.176 +
   1.177  class SyntheticAttributeInfo(AttributeInfo):
   1.178      pass
   1.179  
   1.180 @@ -423,6 +495,12 @@
   1.181              data = line_number.init(data)
   1.182              self.line_number_table.append(line_number)
   1.183          return data
   1.184 +        
   1.185 +    def serialize(self):
   1.186 +        od = su4(self.attribute_length)+su2(self.line_number_table_length)
   1.187 +        for ln in self.line_number_table:
   1.188 +            od += ln.serialize()
   1.189 +        return od
   1.190  
   1.191  class LocalVariableAttributeInfo(AttributeInfo):
   1.192      def init(self, data, class_file):
   1.193 @@ -437,6 +515,12 @@
   1.194              self.local_variable_table.append(local_variable)
   1.195          return data
   1.196  
   1.197 +    def serialize(self):
   1.198 +        od = su4(self.attribute_length)+su2(self.local_variable_table_length)
   1.199 +        for lv in self.local_variable_table:
   1.200 +            od += lv.serialize()
   1.201 +        return od
   1.202 +
   1.203  class DeprecatedAttributeInfo(AttributeInfo):
   1.204      pass
   1.205  
   1.206 @@ -449,6 +533,8 @@
   1.207          self.handler_pc = u2(data[4:6])
   1.208          self.catch_type = u2(data[6:8])
   1.209          return data[8:]
   1.210 +    def serialize(self):
   1.211 +        return su2(self.start_pc)+su2(self.end_pc)+su2(self.handler_pc)+su2(self.catch_type)
   1.212  
   1.213  class InnerClassInfo(NameUtils):
   1.214      def init(self, data, class_file):
   1.215 @@ -459,12 +545,17 @@
   1.216          self.name_index = self.inner_name_index = u2(data[4:6])
   1.217          self.inner_class_access_flags = u2(data[6:8])
   1.218          return data[8:]
   1.219 +    def serialize(self):
   1.220 +        return su2(self.inner_class_info_index)+su2(self.outer_class_info_index)+su2(self.name_index)+su2(self.inner_class_access_flags)
   1.221  
   1.222  class LineNumberInfo:
   1.223      def init(self, data):
   1.224          self.start_pc = u2(data[0:2])
   1.225          self.line_number = u2(data[2:4])
   1.226          return data[4:]
   1.227 +        
   1.228 +    def serialize(self):
   1.229 +        return su2(self.start_pc)+su2(self.line_number)
   1.230  
   1.231  class LocalVariableInfo(NameUtils, PythonNameUtils):
   1.232      def init(self, data, class_file):
   1.233 @@ -478,6 +569,9 @@
   1.234  
   1.235      def get_descriptor(self):
   1.236          return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
   1.237 +        
   1.238 +    def serialize(self):
   1.239 +        return su2(self.start_pc)+su2(self.length)+su2(self.name_index)+su2(self.descriptor_index)+su2(self.index)
   1.240  
   1.241  # Exceptions.
   1.242  
   1.243 @@ -500,6 +594,8 @@
   1.244          file's details.
   1.245          """
   1.246  
   1.247 +        self.attribute_class_to_index = None
   1.248 +        self.minorv,self.majorv = u2(s[4:]),u2(s[6:])
   1.249          self.constants, s = self._get_constants(s[8:])
   1.250          self.access_flags, s = self._get_access_flags(s)
   1.251          self.this_class, s = self._get_this_class(s)
   1.252 @@ -509,6 +605,47 @@
   1.253          self.methods, s = self._get_methods(s)
   1.254          self.attributes, s = self._get_attributes(s)
   1.255  
   1.256 +    def serialize(self):
   1.257 +        od = su4(0xCAFEBABE)+su2(self.minorv)+su2(self.majorv)
   1.258 +        od += self._serialize_constants()
   1.259 +        od += self._serialize_access_flags()
   1.260 +        od += self._serialize_this_class()
   1.261 +        od += self._serialize_super_class()
   1.262 +        od += self._serialize_interfaces()
   1.263 +        od += self._serialize_fields()
   1.264 +        od += self._serialize_methods()
   1.265 +        od += self._serialize_attributes(self.attributes)
   1.266 +        return od
   1.267 +
   1.268 +    def _encode_const(self, c):
   1.269 +        od = ''
   1.270 +        if isinstance(c, Utf8Info):
   1.271 +            od += su1(1)
   1.272 +        elif isinstance(c, IntegerInfo):
   1.273 +            od += su1(3)
   1.274 +        elif isinstance(c, FloatInfo):
   1.275 +            od += su1(4)
   1.276 +        elif isinstance(c, LongInfo):
   1.277 +            od += su1(5)
   1.278 +        elif isinstance(c, DoubleInfo):
   1.279 +            od += su1(6)
   1.280 +        elif isinstance(c, ClassInfo):
   1.281 +            od += su1(7)
   1.282 +        elif isinstance(c, StringInfo):
   1.283 +            od += su1(8)
   1.284 +        elif isinstance(c, FieldRefInfo):
   1.285 +            od += su1(9)
   1.286 +        elif isinstance(c, MethodRefInfo):
   1.287 +            od += su1(10)
   1.288 +        elif isinstance(c, InterfaceMethodRefInfo):
   1.289 +            od += su1(11)
   1.290 +        elif isinstance(c, NameAndTypeInfo):
   1.291 +            od += su1(12)
   1.292 +        else:
   1.293 +            return od
   1.294 +        od += c.serialize()
   1.295 +        return od
   1.296 +
   1.297      def _decode_const(self, s):
   1.298          tag = u1(s[0:1])
   1.299          if tag == 1:
   1.300 @@ -606,13 +743,25 @@
   1.301          count = u2(s[0:2])
   1.302          return self._get_constants_from_table(count, s[2:])
   1.303  
   1.304 +    def _serialize_constants(self):
   1.305 +        return su2(len(self.constants)+1)+"".join([self._encode_const(c) for c in self.constants])
   1.306 +
   1.307      def _get_access_flags(self, s):
   1.308          return u2(s[0:2]), s[2:]
   1.309 +        
   1.310 +    def _serialize_access_flags(self):
   1.311 +        return su2(self.access_flags)
   1.312  
   1.313      def _get_this_class(self, s):
   1.314          index = u2(s[0:2])
   1.315          return self.constants[index - 1], s[2:]
   1.316  
   1.317 +    def _serialize_this_class(self):
   1.318 +        return su2(self.constants.index(self.this_class)+1)
   1.319 +
   1.320 +    def _serialize_super_class(self):
   1.321 +        return su2(self.constants.index(self.super_class)+1)
   1.322 +
   1.323      def _get_super_class(self, s):
   1.324          index = u2(s[0:2])
   1.325          if index != 0:
   1.326 @@ -630,18 +779,55 @@
   1.327              s = s[2:]
   1.328          return interfaces, s
   1.329  
   1.330 +    def _serialize_interfaces(self):
   1.331 +        return su2(len(self.interfaces))+"".join([su2(self.interfaces.index(interf)+1) for interf in self.interfaces])
   1.332 +
   1.333      def _get_fields(self, s):
   1.334          number = u2(s[0:2])
   1.335          return self._get_fields_from_table(number, s[2:])
   1.336  
   1.337 +    def _serialize_fields(self):
   1.338 +        od = su2(len(self.fields))
   1.339 +        od += "".join([f.serialize() for f in self.fields])
   1.340 +        return od
   1.341 +
   1.342      def _get_attributes(self, s):
   1.343          number = u2(s[0:2])
   1.344          return self._get_attributes_from_table(number, s[2:])
   1.345  
   1.346 +    def _serialize_attributes(self, attrs):
   1.347 +        od = su2(len(attrs))
   1.348 +        if len(attrs) == 0: return od
   1.349 +        if self.attribute_class_to_index == None:
   1.350 +            self.attribute_class_to_index = {}
   1.351 +            attr_names_to_class = {"SourceFile":SourceFileAttributeInfo, "ConstantValue":ConstantValueAttributeInfo, 
   1.352 +                            "Code":CodeAttributeInfo, "Exceptions":ExceptionsAttributeInfo,
   1.353 +                            "InnerClasses":InnerClassesAttributeInfo, "Synthetic":SyntheticAttributeInfo,
   1.354 +                            "LineNumberTable":LineNumberAttributeInfo, "LocalVariableTable":LocalVariableAttributeInfo, 
   1.355 +                            "Deprecated":DeprecatedAttributeInfo}
   1.356 +            index = 0
   1.357 +            for c in self.constants:
   1.358 +                index += 1
   1.359 +                if isinstance(c, Utf8Info) and str(c) in attr_names_to_class.keys():
   1.360 +                    self.attribute_class_to_index[attr_names_to_class[str(c)]]=index
   1.361 +        for attribute in attrs:
   1.362 +            for (classtype,name_index) in self.attribute_class_to_index.iteritems():
   1.363 +                if isinstance(attribute, classtype):
   1.364 +                    od += su2(name_index)
   1.365 +                    break
   1.366 +            od += attribute.serialize()
   1.367 +        return od
   1.368 +
   1.369      def _get_methods(self, s):
   1.370          number = u2(s[0:2])
   1.371          return self._get_methods_from_table(number, s[2:])
   1.372  
   1.373 +    def _serialize_methods(self):
   1.374 +        od = su2(len(self.methods))
   1.375 +        od += "".join([m.serialize() for m in self.methods])
   1.376 +        return od
   1.377 +
   1.378 +
   1.379  if __name__ == "__main__":
   1.380      import sys
   1.381      f = open(sys.argv[1], "rb")