Skip to content

Commit 69c8c4e

Browse files
committed
Upgraded JavaObjectMarshaller according to the original repository
1 parent 5012626 commit 69c8c4e

File tree

1 file changed

+206
-7
lines changed

1 file changed

+206
-7
lines changed

javaobj.py

Lines changed: 206 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ def _oops_dump_state(self, ignore_remaining_data=False):
10461046

10471047
class 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}\nDir: {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

Comments
 (0)