44def loads (object ):
55 """
66 Deserializes Java primitive data and objects serialized by ObjectOutputStream
7+ from a string.
78 """
89 f = StringIO .StringIO (object )
9- marshaller = JavaObjectMarshaller (f )
10- return marshaller .readObject ( )
10+ marshaller = JavaObjectMarshaller ()
11+ return marshaller .load_stream ( f )
1112# ba = f.read(4)
1213# (magic, version) = struct.unpack(">HH", ba)
1314# print magic
@@ -18,6 +19,33 @@ def loads(object):
1819#
1920# print type(object), Magic
2021
22+ def dumps (object ):
23+ """
24+ Serializes Java primitive data and objects unmarshaled by load(s) before into string.
25+ """
26+ marshaller = JavaObjectMarshaller ()
27+ return marshaller .dump (object )
28+
29+
30+ class JavaClass (object ):
31+ def __init__ (self ):
32+ self .name = None
33+ self .serialVersionUID = None
34+ self .flags = None
35+ self .fields_names = []
36+ self .fields_types = []
37+
38+ def __str__ (self ):
39+ return "[%s:0x%X]" % (self .name , self .serialVersionUID )
40+
41+
42+ class JavaObject (object ):
43+ classdesc = None
44+
45+ def get_class (self ):
46+ return self .classdesc
47+
48+
2149class JavaObjectMarshaller :
2250
2351 STREAM_MAGIC = 0xaced
@@ -40,7 +68,14 @@ class JavaObjectMarshaller:
4068 TC_ENUM = 0x7E
4169 TC_MAX = 0x7E
4270
43- def __init__ (self , stream ):
71+ # classDescFlags
72+ SC_WRITE_METHOD = 0x01 # if SC_SERIALIZABLE
73+ SC_BLOCK_DATA = 0x08 # if SC_EXTERNALIZABLE
74+ SC_SERIALIZABLE = 0x02
75+ SC_EXTERNALIZABLE = 0x04
76+ SC_ENUM = 0x10
77+
78+ def __init__ (self ):
4479 self .opmap = {
4580 self .TC_NULL : self .do_null ,
4681 self .TC_CLASSDESC : self .do_classdesc ,
@@ -50,26 +85,33 @@ def __init__(self, stream):
5085 self .TC_BLOCKDATA : self .do_blockdata ,
5186 self .TC_REFERENCE : self .do_reference
5287 }
88+ self .current_object = None
89+
90+ def load_stream (self , stream ):
5391 self .object_stream = stream
5492 self ._readStreamHeader ()
55- self .finalValue = True
56- self .current_object = None
93+ return self .readObject ()
5794
5895 def _readStreamHeader (self ):
5996 (magic , version ) = self ._readStruct (">HH" , 4 )
6097 if magic != self .STREAM_MAGIC or version != self .STREAM_VERSION :
6198 raise IOError ("The stream is not java serialized object. Invalid stream header: %04X%04X" % (magic , version ))
6299
63100 def readObject (self ):
64- (opid , ) = self ._readStruct (">B" , 1 )
65- print "OpCode: 0x%X" % opid
66- res = self .opmap .get (opid , self .do_default_stuff )()
101+ res = self .read_and_exec_opcode (ident = 0 ) # TODO: add expects
102+
103+ the_rest = self .object_stream .read ()
104+ if len (the_rest ):
105+ print "Warning!!!!: Stream still has %s bytes left." % str (the_rest )
106+
67107 return res
68108
69- def read_and_exec_opcode (self ):
109+ def read_and_exec_opcode (self , ident = 0 , expect = None ):
70110 (opid , ) = self ._readStruct (">B" , 1 )
71- print "OpCode: 0x%X" % opid
72- return self .opmap .get (opid , self .do_default_stuff )()
111+ self .print_ident ("OpCode: 0x%X" % opid , ident )
112+ if expect and opid not in expect :
113+ raise IOError ("Unexpected opcode 0x%X" % opid )
114+ return self .opmap .get (opid , self .do_default_stuff )(ident = ident )
73115
74116 def _readStruct (self , unpack , length ):
75117 ba = self .object_stream .read (length )
@@ -80,7 +122,7 @@ def _readString(self):
80122 ba = self .object_stream .read (length )
81123 return ba
82124
83- def do_classdesc (self , parent = None ):
125+ def do_classdesc (self , parent = None , ident = 0 ):
84126 # TC_CLASSDESC className serialVersionUID newHandle classDescInfo
85127 # classDescInfo:
86128 # classDescFlags fields classAnnotation superClassDesc
@@ -96,99 +138,176 @@ def do_classdesc(self, parent=None):
96138 # prim_typecode fieldName
97139 # objectDesc:
98140 # obj_typecode fieldName className1
99- class JavaClass (object ):
100- def __init__ (self ):
101- self .name = None
102- self .serialVersionUID = None
103- self .flags = None
104- self .fields_names = []
105- self .fields_types = []
106-
107- def __str__ (self ):
108- return "[%s:0x%X]" % (self .name , self .serialVersionUID )
109-
110141 clazz = JavaClass ()
111- print "[classdesc]"
142+ self . print_ident ( "[classdesc]" , ident )
112143 ba = self ._readString ()
113144 clazz .name = ba
114- print "Class name:" , ba
145+ self . print_ident ( "Class name: %s" % ba , ident )
115146 (serialVersionUID , newHandle , classDescFlags ) = self ._readStruct (">LLB" , 4 + 4 + 1 )
116147 clazz .serialVersionUID = serialVersionUID
117148 clazz .flags = classDescFlags
118- print "Serial: 0x%X newHanle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID , newHandle , classDescFlags )
149+ self . print_ident ( "Serial: 0x%X newHanle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID , newHandle , classDescFlags ), ident )
119150 (length , ) = self ._readStruct (">H" , 2 )
120- print "Fields num: 0x%X" % length
151+ self . print_ident ( "Fields num: 0x%X" % length , ident )
121152
122- fields_names = []
123- fields_types = []
153+ clazz . fields_names = []
154+ clazz . fields_types = []
124155 for fieldId in range (length ):
125156 (type , ) = self ._readStruct (">B" , 1 )
126- ba = self ._readString ()
127- print "FieldType: 0x%X" % type , ba
128- (opid , ) = self ._readStruct (">B" , 1 )
129- print "OpCode: 0x%X" % opid
130- res = self .opmap .get (opid , self .do_default_stuff )()
131- fields_names .append (ba )
132- fields_types .append (res )
157+ field_name = self ._readString ()
158+ field_type = None
159+ if type == 0x44 : # 'D': Double
160+ field_type = "double"
161+ elif type == 0x49 : # 'I': Integer
162+ field_type = "integer"
163+ elif type == 0x4A : # 'J': Long
164+ field_type = "long"
165+ elif type == 0x5A : # 'Z': Boolean
166+ field_type = "boolean"
167+ elif type == 0x5B : # '[': Array
168+ field_type = self .read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_STRING , self .TC_REFERENCE ])
169+ field_type = "array of " + field_type
170+ elif type == 0x42 : # 'B': Byte
171+ field_type = "byte"
172+ elif type == 0x4C : # 'L': Object
173+ field_type = self .read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_STRING , self .TC_REFERENCE ])
174+ else :
175+ raise NotImplementedError ("type 0x%X isn't implemented yet" % type )
176+ self .print_ident ("FieldName: 0x%X" % type + " " + str (field_name ) + " " + str (field_type ), ident )
177+ clazz .fields_names .append (field_name )
178+ clazz .fields_types .append (field_type )
133179 if parent :
134- parent .__fields = fields_names
135- parent .__types = fields_types
180+ parent .__fields = clazz . fields_names
181+ parent .__types = clazz . fields_types
136182 # classAnnotation
137183 (opid , ) = self ._readStruct (">B" , 1 )
138184 if opid != self .TC_ENDBLOCKDATA :
139185 raise NotImplementedError ("classAnnotation isn't implemented yet" )
140- print "OpCode: 0x%X" % opid
186+ self . print_ident ( "OpCode: 0x%X" % opid , ident )
141187 # superClassDesc
142- (opid , ) = self ._readStruct (">B" , 1 )
143- print "OpCode: 0x%X" % opid
144- self .opmap .get (opid , self .do_default_stuff )()
188+ superclassdesc = self .read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_NULL ])
189+ print superclassdesc
145190
146191 return clazz
147192
148- def do_blockdata (self , parent = None ):
193+ def do_blockdata (self , parent = None , ident = 0 ):
149194 # TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
150- print "[blockdata]"
195+ self . print_ident ( "[blockdata]" , ident )
151196 (length , ) = self ._readStruct (">B" , 1 )
152197 ba = self .object_stream .read (length )
153198 return ba
154199
155- def do_class (self , parent = None ):
200+ def do_class (self , parent = None , ident = 0 ):
156201 # TC_CLASS classDesc newHandle
157- print "[class]"
158- clazz = self .read_and_exec_opcode ()
159- print "Class:" , clazz
160- return clazz
202+ self .print_ident ("[class]" , ident )
161203
162- def do_object (self , parent = None ):
204+ # TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
205+ classdesc = self .read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_PROXYCLASSDESC , self .TC_NULL ])
206+ self .print_ident ("Classdesc: %s" % classdesc , ident )
207+ return classdesc
208+
209+ def do_object (self , parent = None , ident = 0 ):
163210 # TC_OBJECT classDesc newHandle classdata[] // data for each class
164- class JavaObject (object ):
165- pass
166- self .current_object = JavaObject ()
167- print "[object]"
168- (opid , ) = self ._readStruct (">B" , 1 )
169- print "OpCode: 0x%X" % opid
170- res = self .opmap .get (opid , self .do_default_stuff )(self .current_object )
171- self .finalValue = res
211+ java_object = JavaObject ()
212+ self .print_ident ("[object]" , ident )
213+
214+ # TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
215+ classdesc = self .read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_PROXYCLASSDESC , self .TC_NULL ])
216+
172217 # classdata[]
173218
174- for field_name in self .current_object .__fields :
175- (opid , ) = self ._readStruct (">B" , 1 )
176- print "OpCode: 0x%X" % opid
177- res = self .opmap .get (opid , self .do_default_stuff )(self .current_object )
178- self .current_object .__setattr__ (field_name , res )
179- return self .current_object
219+ # Store classdesc of this object
220+ java_object .classdesc = classdesc
180221
181- def do_string (self , parent = None ):
182- print "[string]"
222+ # classdata[]
223+ # TODO: nowrclass, wrclass, externalContents, objectAnnotation
224+ if classdesc .flags & self .SC_SERIALIZABLE and not (classdesc .flags & self .SC_WRITE_METHOD ):
225+ pass
226+ else :
227+ raise NotImplementedError ("only nowrclass is implemented." )
228+ for field_name in classdesc .fields_names :
229+ res = self .read_and_exec_opcode (ident = ident + 1 )
230+ java_object .__setattr__ (field_name , res )
231+ return java_object
232+
233+ def do_string (self , parent = None , ident = 0 ):
234+ self .print_ident ("[string]" , ident )
183235 ba = self ._readString ()
184236# (handle, ) = self._readStruct(">B", 1)
185237 return str (ba )
186238
187- def do_reference (self , parent = None ):
239+ def do_reference (self , parent = None , ident = 0 ):
188240 (handle , reference ) = self ._readStruct (">HH" , 4 )
189241
190- def do_null (self , parent = None ):
242+ def do_null (self , parent = None , ident = 0 ):
191243 return None
192244
193- def do_default_stuff (self , parent = None ):
245+ def do_default_stuff (self , parent = None , ident = 0 ):
194246 raise RuntimeError ("Unknown opcode" )
247+
248+ def print_ident (self , message , ident ):
249+ print " " * ident + str (message )
250+ # =====================================================================================
251+
252+ def dump (self , obj ):
253+ self .object_obj = obj
254+ self .object_stream = StringIO .StringIO ()
255+ self ._writeStreamHeader ()
256+ self .writeObject (obj )
257+ return self .object_stream .getvalue ()
258+
259+ def _writeStreamHeader (self ):
260+ self ._writeStruct (">HH" , 4 , (self .STREAM_MAGIC , self .STREAM_VERSION ))
261+
262+ def writeObject (self , obj ):
263+ print type (obj )
264+ print obj
265+ if type (obj ) is JavaObject :
266+ print "This is java object!"
267+ self .write_object (obj )
268+ elif type (obj ) is str :
269+ print "This is string."
270+ self .write_blockdata (obj )
271+ # (opid, ) = self._readStruct(">B", 1)
272+ # print "OpCode: 0x%X" % opid
273+ # res = self.opmap.get(opid, self.do_default_stuff)()
274+ # return res
275+
276+ def _writeStruct (self , unpack , length , args ):
277+ ba = struct .pack (unpack , * args )
278+ self .object_stream .write (ba )
279+
280+ def _writeString (self , string ):
281+ len = len (string )
282+ self ._writeStruct (">H" , 2 , (len , ))
283+ self .object_stream .write (string )
284+
285+ def write_blockdata (self , obj , parent = None ):
286+ self ._writeStruct (">B" , 1 , (self .TC_BLOCKDATA , ))
287+ # TC_BLOCKDATA (unsigned byte)<size> (byte)[size]
288+ if type (obj ) is str :
289+ print "This is string."
290+ self ._writeStruct (">B" , 1 , (len (obj ), ))
291+ self .object_stream .write (obj )
292+
293+ def write_object (self , obj , parent = None ):
294+ # TC_OBJECT classDesc newHandle classdata[] // data for each class
295+ # self.current_object = JavaObject()
296+ # print "[object]"
297+ self ._writeStruct (">B" , 1 , (self .TC_OBJECT , ))
298+ self ._writeStruct (">B" , 1 , (self .TC_CLASSDESC , ))
299+
300+ # print "OpCode: 0x%X" % opid
301+ # classdesc = self.opmap.get(opid, self.do_default_stuff)(self.current_object)
302+ # self.finalValue = classdesc
303+ # # classdata[]
304+ #
305+ # # Store classdesc of this object
306+ # self.current_object.classdesc = classdesc
307+ #
308+ # for field_name in self.current_object.__fields:
309+ # (opid, ) = self._readStruct(">B", 1)
310+ # print "OpCode: 0x%X" % opid
311+ # res = self.opmap.get(opid, self.do_default_stuff)(self.current_object)
312+ # self.current_object.__setattr__(field_name, res)
313+ # return self.current_object
0 commit comments