@@ -1046,7 +1046,7 @@ def _oops_dump_state(self, ignore_remaining_data=False):
10461046
10471047class JavaObjectMarshaller (JavaObjectConstants ):
10481048 """
1049- UNUSABLE: Serializes objects into Java serialization format
1049+ Serializes objects into Java serialization format
10501050 """
10511051 def __init__ (self , stream = None ):
10521052 """
@@ -1090,9 +1090,21 @@ def writeObject(self, obj):
10901090 :raise RuntimeError: Unsupported type
10911091 """
10921092 log_debug ("Writing object of type {0}" .format (type (obj ).__name__ ))
1093- if type (obj ) is JavaObject :
1093+ if isinstance (obj , JavaArray ):
1094+ # Deserialized Java array
1095+ self .write_array (obj )
1096+ elif isinstance (obj , JavaEnum ):
1097+ # Deserialized Java Enum
1098+ self .write_enum (obj )
1099+ elif isinstance (obj , JavaObject ):
10941100 # Deserialized Java object
10951101 self .write_object (obj )
1102+ elif isinstance (obj , JavaClass ):
1103+ # Java class
1104+ self .write_class (obj )
1105+ elif obj is None :
1106+ # Null
1107+ self .write_null ()
10961108 elif type (obj ) is str :
10971109 # String value
10981110 self .write_blockdata (obj )
@@ -1121,21 +1133,54 @@ def _writeString(self, string):
11211133 self ._writeStruct (">H" , 2 , (len (string ),))
11221134 self .object_stream .write (string )
11231135
1136+ def write_string (self , obj ):
1137+ """
1138+ Writes a Java string with the TC_STRING type marker
1139+
1140+ :param obj: The string to print
1141+ """
1142+ self ._writeStruct (">B" , 1 , (self .TC_STRING ,))
1143+ self ._writeString (obj )
1144+
1145+ def write_enum (self , obj ):
1146+ """
1147+ Writes an Enum value
1148+
1149+ :param obj: A JavaEnum object
1150+ """
1151+ self ._writeStruct (">B" , 1 , (self .TC_ENUM ,))
1152+ self .write_classdesc (obj .get_class ())
1153+ self .write_string (obj .constant )
1154+
11241155 def write_blockdata (self , obj , parent = None ):
11251156 """
11261157 Appends a block of data to the serialization stream
11271158
11281159 :param obj: String form of the data block
11291160 """
1130- # TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
1131- self ._writeStruct (">B" , 1 , (self .TC_BLOCKDATA ,))
11321161 if type (obj ) is str :
11331162 # Latin-1: keep bytes as is
11341163 obj = to_bytes (obj , "latin-1" )
1135- self ._writeStruct (">B" , 1 , (len (obj ),))
1136- self .object_stream .write (obj )
1164+
1165+ length = len (obj )
1166+ if length <= 256 :
1167+ # Small block data
1168+ # TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
1169+ self ._writeStruct (">B" , 1 , (self .TC_BLOCKDATA ,))
1170+ self ._writeStruct (">B" , 1 , (length ,))
11371171 else :
1138- log_error ("Not a str blockdata: {0:r}" .format (obj ))
1172+ # Large block data
1173+ # TC_BLOCKDATALONG (unsigned int)<size> (byte)[size]
1174+ self ._writeStruct (">B" , 1 , (self .TC_BLOCKDATALONG ,))
1175+ self ._writeStruct (">I" , 1 , (length ,))
1176+
1177+ self .object_stream .write (obj )
1178+
1179+ def write_null (self ):
1180+ """
1181+ Writes a "null" value
1182+ """
1183+ self ._writeStruct (">B" , 1 , (self .TC_NULL ,))
11391184
11401185 def write_object (self , obj , parent = None ):
11411186 """
@@ -1152,7 +1197,161 @@ def write_object(self, obj, parent=None):
11521197 break
11531198
11541199 self ._writeStruct (">B" , 1 , (self .TC_OBJECT ,))
1200+ cls = obj .get_class ()
1201+ self .write_classdesc (cls )
1202+
1203+ all_names = []
1204+ all_types = []
1205+ tmpcls = cls
1206+ while tmpcls :
1207+ all_names .extend (tmpcls .fields_names )
1208+ all_types .extend (tmpcls .fields_types )
1209+ tmpcls = tmpcls .superclass
1210+ del tmpcls
1211+
1212+ for field_name , field_type in zip (all_names , all_types ):
1213+ try :
1214+ self ._write_value (field_type , getattr (obj , field_name ))
1215+ except AttributeError as ex :
1216+ log_error ("No attribute {0} for object {1}\n Dir: {2}"
1217+ .format (ex , repr (obj ), dir (obj )))
1218+ raise
1219+ del all_names , all_types
1220+
1221+ if cls .flags & self .SC_SERIALIZABLE \
1222+ and cls .flags & self .SC_WRITE_METHOD \
1223+ or cls .flags & self .SC_EXTERNALIZABLE \
1224+ and cls .flags & self .SC_BLOCK_DATA :
1225+ for annotation in obj .annotations :
1226+ log_debug ("Write annotation {0} for {1}"
1227+ .format (repr (annotation ), repr (obj )))
1228+ if annotation is None :
1229+ self .write_null ()
1230+ else :
1231+ self .writeObject (annotation )
1232+ self ._writeStruct ('>B' , 1 , (self .TC_ENDBLOCKDATA ,))
1233+
1234+ def write_class (self , obj , parent = None ):
1235+ """
1236+ Writes a class to the stream
1237+
1238+ :param obj: A JavaClass object
1239+ :param parent:
1240+ """
1241+ self ._writeStruct (">B" , 1 , (self .TC_CLASS ,))
1242+ self .write_classdesc (obj )
1243+
1244+ def write_classdesc (self , obj , parent = None ):
1245+ """
1246+ Writes a class description
1247+
1248+ :param obj: Class description to write
1249+ :param parent:
1250+ """
11551251 self ._writeStruct (">B" , 1 , (self .TC_CLASSDESC ,))
1252+ self ._writeString (obj .name )
1253+ self ._writeStruct (">qB" , 1 , (obj .serialVersionUID , obj .flags ))
1254+ self ._writeStruct (">H" , 1 , (len (obj .fields_names ),))
1255+
1256+ for field_name , field_type in zip (obj .fields_names , obj .fields_types ):
1257+ self ._writeStruct (
1258+ ">B" , 1 , (self ._convert_type_to_char (field_type ),))
1259+ self ._writeString (field_name )
1260+ if field_type [0 ] in (self .TYPE_OBJECT , self .TYPE_ARRAY ):
1261+ self .write_string (field_type )
1262+
1263+ self ._writeStruct (">B" , 1 , (self .TC_ENDBLOCKDATA ,))
1264+ if obj .superclass :
1265+ self .write_classdesc (obj .superclass )
1266+ else :
1267+ self .write_null ()
1268+
1269+ def write_array (self , obj ):
1270+ """
1271+ Writes a JavaArray
1272+
1273+ :param obj: A JavaArray object
1274+ """
1275+ self ._writeStruct (">B" , 1 , (self .TC_ARRAY ,))
1276+ self .write_classdesc (obj .get_class ())
1277+ self ._writeStruct (">i" , 1 , (len (obj ),))
1278+
1279+ classdesc = obj .get_class ()
1280+
1281+ type_char = classdesc .name [0 ]
1282+ assert type_char == self .TYPE_ARRAY
1283+ type_char = classdesc .name [1 ]
1284+
1285+ if type_char == self .TYPE_OBJECT :
1286+ for o in obj :
1287+ self .write_object (o )
1288+ elif type_char == self .TYPE_ARRAY :
1289+ for a in obj :
1290+ self .write_array (a )
1291+ else :
1292+ log_debug ("Write array of type %s" % type_char )
1293+ for v in obj :
1294+ self ._write_value (type_char , v )
1295+
1296+ def _write_value (self , field_type , value ):
1297+ """
1298+ Writes an item of an array
1299+
1300+ :param field_type: Value type
1301+ :param value: The value itself
1302+ """
1303+ if len (field_type ) > 1 :
1304+ # We don't need details for arrays and objects
1305+ field_type = field_type [0 ]
1306+
1307+ if field_type == self .TYPE_BOOLEAN :
1308+ self ._writeStruct (">B" , 1 , (1 if value else 0 ,))
1309+ elif field_type == self .TYPE_BYTE :
1310+ self ._writeStruct (">B" , 1 , (value ,))
1311+ elif field_type == self .TYPE_SHORT :
1312+ self ._writeStruct (">h" , 1 , (value ,))
1313+ elif field_type == self .TYPE_INTEGER :
1314+ self ._writeStruct (">i" , 1 , (value ,))
1315+ elif field_type == self .TYPE_LONG :
1316+ self ._writeStruct (">q" , 1 , (value ,))
1317+ elif field_type == self .TYPE_FLOAT :
1318+ self ._writeStruct (">f" , 1 , (value ,))
1319+ elif field_type == self .TYPE_DOUBLE :
1320+ self ._writeStruct (">d" , 1 , (value ,))
1321+ elif field_type == self .TYPE_OBJECT or field_type == self .TYPE_ARRAY :
1322+ if value is None :
1323+ self .write_null ()
1324+ elif isinstance (value , JavaEnum ):
1325+ self .write_enum (value )
1326+ elif isinstance (value , JavaObject ):
1327+ self .write_object (value )
1328+ elif isinstance (value , str ):
1329+ self .write_blockdata (value )
1330+ else :
1331+ raise RuntimeError ("Unknown typecode: {0}" .format (field_type ))
1332+ else :
1333+ raise RuntimeError ("Unknown typecode: {0}" .format (field_type ))
1334+
1335+ def _convert_type_to_char (self , type_char ):
1336+ """
1337+ Converts the given type code to an int
1338+
1339+ :param type_char: A type code character
1340+ """
1341+ typecode = type_char
1342+ if type (type_char ) is int :
1343+ typecode = chr (type_char )
1344+
1345+ if typecode in self .TYPECODES_LIST :
1346+ return ord (typecode )
1347+ elif len (typecode ) > 1 :
1348+ if typecode [0 ] == 'L' :
1349+ return ord (self .TYPE_OBJECT )
1350+ elif typecode [0 ] == '[' :
1351+ return ord (self .TYPE_ARRAY )
1352+
1353+ raise RuntimeError ("Typecode {0} ({1}) isn't supported."
1354+ .format (type_char , typecode ))
11561355
11571356# ------------------------------------------------------------------------------
11581357
0 commit comments