@@ -221,9 +221,11 @@ def __init__(self, stream=None):
221221 self .TC_CLASSDESC : self .do_classdesc ,
222222 self .TC_OBJECT : self .do_object ,
223223 self .TC_STRING : self .do_string ,
224+ self .TC_LONGSTRING : self .do_string_long ,
224225 self .TC_ARRAY : self .do_array ,
225226 self .TC_CLASS : self .do_class ,
226227 self .TC_BLOCKDATA : self .do_blockdata ,
228+ self .TC_BLOCKDATALONG : self .do_blockdata_long ,
227229 self .TC_REFERENCE : self .do_reference ,
228230 self .TC_ENUM : self .do_enum ,
229231 self .TC_ENDBLOCKDATA : self .do_null , # note that we are reusing of do_null
@@ -234,6 +236,7 @@ def __init__(self, stream=None):
234236 self .object_stream = stream
235237 self ._readStreamHeader ()
236238 self .object_transformers = []
239+ self .data_left = True
237240
238241 def readObject (self ):
239242 try :
@@ -244,8 +247,10 @@ def readObject(self):
244247 if len (the_rest ):
245248 log_error ("Warning!!!!: Stream still has %s bytes left. Enable debug mode of logging to see the hexdump." % len (the_rest ))
246249 log_debug (self ._create_hexdump (the_rest ))
250+ self .data_left = True
247251 else :
248252 log_debug ("Java Object unmarshalled succesfully!" )
253+ self .data_left = False
249254 self .object_stream .seek (position_bak )
250255
251256 return res
@@ -275,11 +280,11 @@ def _readStruct(self, unpack):
275280 length = struct .calcsize (unpack )
276281 ba = self .object_stream .read (length )
277282 if len (ba ) != length :
278- raise RuntimeError ("Stream has been ended unexpectedly while unmarshaling." )
283+ raise RuntimeError ("Stream has been ended unexpectedly while unmarshaling. (%d vs %d)" % ( len ( ba ), length ) )
279284 return struct .unpack (unpack , ba )
280285
281- def _readString (self ):
282- (length , ) = self ._readStruct (">H" )
286+ def _readString (self , mod = "H" ):
287+ (length , ) = self ._readStruct (">" + mod )
283288 ba = self .object_stream .read (length )
284289 return ba
285290
@@ -307,8 +312,9 @@ def do_classdesc(self, parent=None, ident=0):
307312 (serialVersionUID , newHandle , classDescFlags ) = self ._readStruct (">LLB" )
308313 clazz .serialVersionUID = serialVersionUID
309314 clazz .flags = classDescFlags
315+ clazz .handle = newHandle
310316
311- self ._add_reference (clazz )
317+ self ._add_reference (clazz , ident )
312318
313319 log_debug ("Serial: 0x%X newHandle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID , newHandle , classDescFlags ), ident )
314320 (length , ) = self ._readStruct (">H" )
@@ -324,14 +330,14 @@ def do_classdesc(self, parent=None, ident=0):
324330
325331 if field_type == self .TYPE_ARRAY :
326332 opcode , field_type = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_STRING , self .TC_REFERENCE ])
327- assert type (field_type ) is str
333+ assert type (field_type ) is JavaString
328334# if field_type is not None:
329335# field_type = "array of " + field_type
330336# else:
331337# field_type = "array of None"
332338 elif field_type == self .TYPE_OBJECT :
333339 opcode , field_type = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_STRING , self .TC_REFERENCE ])
334- assert type (field_type ) is str
340+ assert type (field_type ) is JavaString
335341
336342 log_debug ("FieldName: 0x%X" % typecode + " " + str (field_name ) + " " + str (field_type ), ident )
337343 assert field_name is not None
@@ -361,14 +367,22 @@ def do_blockdata(self, parent=None, ident=0):
361367 ba = self .object_stream .read (length )
362368 return ba
363369
370+ def do_blockdata_long (self , parent = None , ident = 0 ):
371+ # TC_BLOCKDATALONG (int)<size> (byte)[size]
372+ log_debug ("[blockdata]" , ident )
373+ (length , ) = self ._readStruct (">I" )
374+ ba = self .object_stream .read (length )
375+ return ba
376+
377+
364378 def do_class (self , parent = None , ident = 0 ):
365379 # TC_CLASS classDesc newHandle
366380 log_debug ("[class]" , ident )
367381
368382 # TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
369383 opcode , classdesc = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_PROXYCLASSDESC , self .TC_NULL , self .TC_REFERENCE ])
370384 log_debug ("Classdesc: %s" % classdesc , ident )
371- self ._add_reference (classdesc )
385+ self ._add_reference (classdesc , ident )
372386 return classdesc
373387
374388 def do_object (self , parent = None , ident = 0 ):
@@ -381,7 +395,7 @@ def do_object(self, parent=None, ident=0):
381395 opcode , classdesc = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_PROXYCLASSDESC , self .TC_NULL , self .TC_REFERENCE ])
382396 # self.TC_REFERENCE hasn't shown in spec, but actually is here
383397
384- self ._add_reference (java_object )
398+ self ._add_reference (java_object , ident )
385399
386400 # classdata[]
387401
@@ -430,7 +444,7 @@ def do_object(self, parent=None, ident=0):
430444 # Transform object
431445 for transformer in self .object_transformers :
432446 tmp_object = transformer .transform (java_object )
433- if tmp_object != java_object :
447+ if tmp_object is not java_object :
434448 java_object = tmp_object
435449 break
436450
@@ -439,18 +453,24 @@ def do_object(self, parent=None, ident=0):
439453
440454 def do_string (self , parent = None , ident = 0 ):
441455 log_debug ("[string]" , ident )
442- ba = self ._readString ()
443- self ._add_reference (str (ba ))
444- return str (ba )
456+ ba = JavaString (self ._readString ())
457+ self ._add_reference (ba , ident )
458+ return ba
459+
460+ def do_string_long (self , parent = None , ident = 0 ):
461+ log_debug ("[long string]" , ident )
462+ ba = JavaString (self ._readString ("Q" ))
463+ self ._add_reference (ba , ident )
464+ return ba
445465
446466 def do_array (self , parent = None , ident = 0 ):
447467 # TC_ARRAY classDesc newHandle (int)<size> values[size]
448468 log_debug ("[array]" , ident )
449469 opcode , classdesc = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_PROXYCLASSDESC , self .TC_NULL , self .TC_REFERENCE ])
450470
451- array = []
471+ array = JavaArray ( classdesc )
452472
453- self ._add_reference (array )
473+ self ._add_reference (array , ident )
454474
455475 (size , ) = self ._readStruct (">i" )
456476 log_debug ("size: " + str (size ), ident )
@@ -482,11 +502,14 @@ def do_null(self, parent=None, ident=0):
482502
483503 def do_enum (self , parent = None , ident = 0 ):
484504 # TC_ENUM classDesc newHandle enumConstantName
485- enum = JavaObject ()
505+ enum = JavaEnum ()
486506 opcode , classdesc = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_CLASSDESC , self .TC_PROXYCLASSDESC , self .TC_NULL , self .TC_REFERENCE ])
487- self ._add_reference (enum )
507+ enum .classdesc = classdesc
508+ self ._add_reference (enum , ident )
488509 opcode , enumConstantName = self ._read_and_exec_opcode (ident = ident + 1 , expect = [self .TC_STRING , self .TC_REFERENCE ])
489- return enumConstantName
510+
511+ enum .constant = enumConstantName
512+ return enum
490513
491514 def _create_hexdump (self , src , length = 16 ):
492515 FILTER = '' .join ([(len (repr (chr (x )))== 3 ) and chr (x ) or '.' for x in range (256 )])
@@ -500,6 +523,7 @@ def _create_hexdump(self, src, length=16):
500523
501524 def _read_value (self , field_type , ident , name = "" ):
502525 if len (field_type ) > 1 :
526+ cls = field_type [1 :]
503527 field_type = field_type [0 ] # We don't need details for arrays and objects
504528
505529 if field_type == self .TYPE_BOOLEAN :
@@ -518,7 +542,13 @@ def _read_value(self, field_type, ident, name = ""):
518542 elif field_type == self .TYPE_DOUBLE :
519543 (res , ) = self ._readStruct (">d" )
520544 elif field_type == self .TYPE_OBJECT or field_type == self .TYPE_ARRAY :
521- opcode , res = self ._read_and_exec_opcode (ident = ident + 1 )
545+ try :
546+ opcode , res = self ._read_and_exec_opcode (ident = ident + 1 )
547+ except RuntimeError :
548+ if cls == 'java/lang/String;' :
549+ res = JavaString (self ._readString ())
550+ else :
551+ raise
522552 else :
523553 raise RuntimeError ("Unknown typecode: %s" % field_type )
524554 log_debug ("* %s %s: " % (field_type , name ) + str (res ), ident )
@@ -534,14 +564,15 @@ def _convert_char_to_type(self, type_char):
534564 else :
535565 raise RuntimeError ("Typecode %s (%s) isn't supported." % (type_char , typecode ))
536566
537- def _add_reference (self , obj ):
567+ def _add_reference (self , obj , ident = 0 ):
568+ log_debug ('## New reference handle 0x%X' % (len (self .references ) + self .BASE_REFERENCE_IDX ,), ident )
538569 self .references .append (obj )
539570
540571 def _oops_dump_state (self ):
541572 log_error ("==Oops state dump" + "=" * (30 - 17 ))
542573 log_error ("References: %s" % str (self .references ))
543574 log_error ("Stream seeking back at -16 byte (2nd line is an actual position!):" )
544- self .object_stream .seek (- 16 , mode = 1 )
575+ self .object_stream .seek (- 16 , 1 )
545576 the_rest = self .object_stream .read ()
546577 if len (the_rest ):
547578 log_error ("Warning!!!!: Stream still has %s bytes left." % len (the_rest ))
0 commit comments