source: trunk/src/gcc/libjava/java/io/ObjectInputStream.java@ 1213

Last change on this file since 1213 was 2, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 42.4 KB
Line 
1/* ObjectInputStream.java -- Class used to read serialized objects
2 Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1902111-1307 USA.
20
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library. Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module. An independent module is a module which is not derived from
33or based on this library. If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so. If you do not wish to do so, delete this
36exception statement from your version. */
37
38
39package java.io;
40
41import gnu.classpath.Configuration;
42
43import java.lang.reflect.Array;
44import java.lang.reflect.Modifier;
45import java.util.Arrays;
46import java.util.Hashtable;
47import java.util.Vector;
48
49import gnu.java.io.ObjectIdentityWrapper;
50import gnu.java.lang.reflect.TypeSignature;
51import java.lang.reflect.Field;
52import java.lang.reflect.Method;
53import java.lang.reflect.InvocationTargetException;
54
55
56
57public class ObjectInputStream extends InputStream
58 implements ObjectInput, ObjectStreamConstants
59{
60 /**
61 Creates a new <code>ObjectInputStream</code> that will do all of
62 its reading from <code>in</code>. This method also checks
63 the stream by reading the header information (stream magic number
64 and stream version).
65
66 @exception IOException Reading stream header from underlying
67 stream cannot be completed.
68
69 @exception StreamCorruptedException An invalid stream magic
70 number or stream version was read from the stream.
71
72 @see readStreamHeader ()
73 */
74 public ObjectInputStream (InputStream in)
75 throws IOException, StreamCorruptedException
76 {
77 if (Configuration.DEBUG)
78 {
79 String val = System.getProperty("gcj.dumpobjects");
80 if (dump == false && val != null && !val.equals(""))
81 {
82 dump = true;
83 System.out.println ("Serialization debugging enabled");
84 }
85 else if (dump == true && (val == null || val.equals("")))
86 {
87 dump = false;
88 System.out.println ("Serialization debugging disabled");
89 }
90 }
91
92 this.resolveEnabled = false;
93 this.isDeserializing = false;
94 this.blockDataPosition = 0;
95 this.blockDataBytes = 0;
96 this.blockData = new byte[BUFFER_SIZE];
97 this.blockDataInput = new DataInputStream (this);
98 this.realInputStream = new DataInputStream (in);
99 this.nextOID = baseWireHandle;
100 this.objectLookupTable = new Hashtable ();
101 this.validators = new Vector ();
102 setBlockDataMode (true);
103 readStreamHeader ();
104 }
105
106
107 /**
108 Returns the next deserialized object read from the underlying stream.
109
110 This method can be overriden by a class by implementing
111 <code>private void readObject (ObjectInputStream)</code>.
112
113 If an exception is thrown from this method, the stream is left in
114 an undefined state.
115
116 @exception ClassNotFoundException The class that an object being
117 read in belongs to cannot be found.
118
119 @exception IOException Exception from underlying
120 <code>InputStream</code>.
121 */
122 public final Object readObject () throws ClassNotFoundException, IOException
123 {
124 if (this.useSubclassMethod)
125 return readObjectOverride ();
126
127 boolean was_deserializing;
128
129 Object ret_val;
130 was_deserializing = this.isDeserializing;
131
132 if (! was_deserializing)
133 setBlockDataMode (false);
134
135 this.isDeserializing = true;
136
137 byte marker = this.realInputStream.readByte ();
138 dumpElement ("MARKER: 0x" + Integer.toHexString(marker) + " ");
139
140 switch (marker)
141 {
142 case TC_BLOCKDATA:
143 case TC_BLOCKDATALONG:
144 if (marker == TC_BLOCKDATALONG)
145 dumpElementln ("BLOCKDATALONG");
146 else
147 dumpElementln ("BLOCKDATA");
148 readNextBlock (marker);
149 throw new StreamCorruptedException ("Unexpected blockData");
150
151 case TC_NULL:
152 dumpElementln ("NULL");
153 ret_val = null;
154 break;
155
156 case TC_REFERENCE:
157 {
158 dumpElement ("REFERENCE ");
159 Integer oid = new Integer (this.realInputStream.readInt ());
160 dumpElementln (Integer.toHexString(oid.intValue()));
161 ret_val = ((ObjectIdentityWrapper)
162 this.objectLookupTable.get (oid)).object;
163 break;
164 }
165
166 case TC_CLASS:
167 {
168 dumpElementln ("CLASS");
169 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
170 Class clazz = osc.forClass ();
171 assignNewHandle (clazz);
172 ret_val = clazz;
173 break;
174 }
175
176 case TC_CLASSDESC:
177 {
178 dumpElement ("CLASSDESC NAME=");
179 String name = this.realInputStream.readUTF ();
180 dumpElement (name + "; UID=");
181 long uid = this.realInputStream.readLong ();
182 dumpElement (Long.toHexString(uid) + "; FLAGS=");
183 byte flags = this.realInputStream.readByte ();
184 dumpElement (Integer.toHexString(flags) + "; FIELD COUNT=");
185 short field_count = this.realInputStream.readShort ();
186 dumpElementln (Short.toString(field_count));
187 ObjectStreamField[] fields = new ObjectStreamField[field_count];
188
189 ObjectStreamClass osc = new ObjectStreamClass (name, uid,
190 flags, fields);
191 assignNewHandle (osc);
192
193 for (int i=0; i < field_count; i++)
194 {
195 dumpElement (" TYPE CODE=");
196 char type_code = (char)this.realInputStream.readByte ();
197 dumpElement (type_code + "; FIELD NAME=");
198 String field_name = this.realInputStream.readUTF ();
199 dumpElementln (field_name);
200 String class_name;
201
202 if (type_code == 'L' || type_code == '[')
203 class_name = (String)readObject ();
204 else
205 class_name = String.valueOf (type_code);
206
207 fields[i] =
208 new ObjectStreamField (field_name,
209 TypeSignature.getClassForEncoding
210 (class_name));
211 }
212
213 Class cl = resolveClass (osc);
214 osc.setClass (cl);
215 setBlockDataMode (false);
216
217 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
218 throw new IOException ("Data annotated to class was not consumed.");
219 dumpElementln ("ENDBLOCKDATA ");
220
221 osc.setSuperclass ((ObjectStreamClass)readObject ());
222 ret_val = osc;
223 break;
224 }
225
226 case TC_STRING:
227 {
228 dumpElement ("STRING=");
229 String s = this.realInputStream.readUTF ();
230 dumpElementln (s);
231 ret_val = processResolution (s, assignNewHandle (s));
232 break;
233 }
234
235 case TC_ARRAY:
236 {
237 dumpElementln ("ARRAY");
238 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
239 Class componentType = osc.forClass ().getComponentType ();
240 dumpElement ("ARRAY LENGTH=");
241 int length = this.realInputStream.readInt ();
242 dumpElementln (length + "; COMPONENT TYPE=" + componentType);
243 Object array = Array.newInstance (componentType, length);
244 int handle = assignNewHandle (array);
245 readArrayElements (array, componentType);
246 for (int i=0, len=Array.getLength(array); i < len; i++)
247 dumpElementln (" ELEMENT[" + i + "]=" + Array.get(array, i).toString());
248 ret_val = processResolution (array, handle);
249 break;
250 }
251
252 case TC_OBJECT:
253 {
254 dumpElementln ("OBJECT");
255 ObjectStreamClass osc = (ObjectStreamClass)readObject ();
256 Class clazz = osc.forClass ();
257
258 if (!Serializable.class.isAssignableFrom (clazz))
259 throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
260
261 if (Externalizable.class.isAssignableFrom (clazz))
262 {
263 Externalizable obj = null;
264
265 try
266 {
267 obj = (Externalizable)clazz.newInstance ();
268 }
269 catch (InstantiationException e)
270 {
271 throw new ClassNotFoundException ("Instance of " + clazz
272 + " could not be created");
273 }
274 catch (IllegalAccessException e)
275 {
276 throw new ClassNotFoundException ("Instance of " + clazz
277 + " could not be created because class or zero-argument constructor is not accessible");
278 }
279 catch (NoSuchMethodError e)
280 {
281 throw new ClassNotFoundException ("Instance of " + clazz
282 + " could not be created because zero-argument constructor is not defined");
283 }
284
285 int handle = assignNewHandle (obj);
286
287 boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
288
289 if (read_from_blocks)
290 setBlockDataMode (true);
291
292 obj.readExternal (this);
293
294 if (read_from_blocks)
295 setBlockDataMode (false);
296
297 ret_val = processResolution (obj, handle);
298 break;
299 } // end if (Externalizable.class.isAssignableFrom (clazz))
300
301 // find the first non-serializable, non-abstract
302 // class in clazz's inheritance hierarchy
303 Class first_nonserial = clazz.getSuperclass ();
304 while (Serializable.class.isAssignableFrom (first_nonserial)
305 || Modifier.isAbstract (first_nonserial.getModifiers ()))
306 first_nonserial = first_nonserial.getSuperclass ();
307
308// DEBUGln ("Using " + first_nonserial
309// + " as starting point for constructing " + clazz);
310
311 Object obj = null;
312 obj = newObject (clazz, first_nonserial);
313
314 if (obj == null)
315 throw new ClassNotFoundException ("Instance of " + clazz +
316 " could not be created");
317
318 int handle = assignNewHandle (obj);
319 this.currentObject = obj;
320 ObjectStreamClass[] hierarchy =
321 ObjectStreamClass.getObjectStreamClasses (clazz);
322
323// DEBUGln ("Got class hierarchy of depth " + hierarchy.length);
324
325 boolean has_read;
326 for (int i=0; i < hierarchy.length; i++)
327 {
328 this.currentObjectStreamClass = hierarchy[i];
329
330 dumpElementln ("Reading fields of "
331 + this.currentObjectStreamClass.getName ());
332
333 has_read = true;
334
335 try
336 {
337 this.currentObjectStreamClass.forClass ().
338 getDeclaredMethod ("readObject", readObjectParams);
339 }
340 catch (NoSuchMethodException e)
341 {
342 has_read = false;
343 }
344
345 // XXX: should initialize fields in classes in the hierarchy
346 // that aren't in the stream
347 // should skip over classes in the stream that aren't in the
348 // real classes hierarchy
349 readFields (obj, this.currentObjectStreamClass.fields,
350 has_read, this.currentObjectStreamClass);
351
352 if (has_read)
353 {
354 dumpElement ("ENDBLOCKDATA? ");
355 try
356 {
357 // FIXME: XXX: This try block is to catch EOF which is
358 // thrown for some objects. That indicates a bug in the logic.
359 if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
360 throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
361 dumpElementln ("yes");
362 }
363 catch (EOFException e)
364 {
365 dumpElementln ("no, got EOFException");
366 }
367 catch (IOException e)
368 {
369 dumpElementln ("no, got IOException");
370 }
371 }
372 }
373
374 this.currentObject = null;
375 this.currentObjectStreamClass = null;
376 ret_val = processResolution (obj, handle);
377 break;
378 }
379
380 case TC_RESET:
381 dumpElementln ("RESET");
382 clearHandles ();
383 ret_val = readObject ();
384 break;
385
386 case TC_EXCEPTION:
387 {
388 dumpElement ("EXCEPTION=");
389 Exception e = (Exception)readObject ();
390 dumpElementln (e.toString());
391 clearHandles ();
392 throw new WriteAbortedException ("Exception thrown during writing of stream", e);
393 }
394
395 default:
396 throw new IOException ("Unknown marker on stream");
397 }
398
399 this.isDeserializing = was_deserializing;
400
401 if (! was_deserializing)
402 {
403 setBlockDataMode (true);
404
405 if (validators.size () > 0)
406 invokeValidators ();
407 }
408
409 return ret_val;
410 }
411
412
413 /**
414 Reads the current objects non-transient, non-static fields from
415 the current class from the underlying output stream.
416
417 This method is intended to be called from within a object's
418 <code>private void readObject (ObjectInputStream)</code>
419 method.
420
421 @exception ClassNotFoundException The class that an object being
422 read in belongs to cannot be found.
423
424 @exception NotActiveException This method was called from a
425 context other than from the current object's and current class's
426 <code>private void readObject (ObjectInputStream)</code>
427 method.
428
429 @exception IOException Exception from underlying
430 <code>OutputStream</code>.
431 */
432 public void defaultReadObject ()
433 throws ClassNotFoundException, IOException, NotActiveException
434 {
435 if (this.currentObject == null || this.currentObjectStreamClass == null)
436 throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
437
438 if (fieldsAlreadyRead)
439 throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
440
441 readFields (this.currentObject,
442 this.currentObjectStreamClass.fields,
443 false, this.currentObjectStreamClass);
444
445 fieldsAlreadyRead = true;
446 }
447
448
449 /**
450 Registers a <code>ObjectInputValidation</code> to be carried out
451 on the object graph currently being deserialized before it is
452 returned to the original caller of <code>readObject ()</code>.
453 The order of validation for multiple
454 <code>ObjectInputValidation</code>s can be controled using
455 <code>priority</code>. Validators with higher priorities are
456 called first.
457
458 @see java.io.ObjectInputValidation
459
460 @exception InvalidObjectException <code>validator</code> is
461 <code>null</code>
462
463 @exception NotActiveException an attempt was made to add a
464 validator outside of the <code>readObject</code> method of the
465 object currently being deserialized
466 */
467 public void registerValidation (ObjectInputValidation validator,
468 int priority)
469 throws InvalidObjectException, NotActiveException
470 {
471 if (this.currentObject == null || this.currentObjectStreamClass == null)
472 throw new NotActiveException ("registerValidation called by non-active class and/or object");
473
474 if (validator == null)
475 throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
476
477 this.validators.addElement (new ValidatorAndPriority (validator,
478 priority));
479 }
480
481
482 /**
483 Called when a class is being deserialized. This is a hook to
484 allow subclasses to read in information written by the
485 <code>annotateClass (Class)</code> method of an
486 <code>ObjectOutputStream</code>.
487
488 This implementation looks up the active call stack for a
489 <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
490 it is used to load the class associated with <code>osc</code>,
491 otherwise, the default system <code>ClassLoader</code> is used.
492
493 @exception IOException Exception from underlying
494 <code>OutputStream</code>.
495
496 @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
497 */
498 protected Class resolveClass (ObjectStreamClass osc)
499 throws ClassNotFoundException, IOException
500 {
501 SecurityManager sm = System.getSecurityManager ();
502
503 // FIXME: currentClassLoader doesn't yet do anything useful. We need
504 // to call forName() with the classloader of the class which called
505 // readObject(). See SecurityManager.getClassContext().
506 ClassLoader cl = currentClassLoader (sm);
507
508 return Class.forName (osc.getName (), true, cl);
509 }
510
511 /**
512 Allows subclasses to resolve objects that are read from the
513 stream with other objects to be returned in their place. This
514 method is called the first time each object is encountered.
515
516 This method must be enabled before it will be called in the
517 serialization process.
518
519 @exception IOException Exception from underlying
520 <code>OutputStream</code>.
521
522 @see enableResolveObject (boolean)
523 */
524 protected Object resolveObject (Object obj) throws IOException
525 {
526 return obj;
527 }
528
529
530 /**
531 If <code>enable</code> is <code>true</code> and this object is
532 trusted, then <code>resolveObject (Object)</code> will be called
533 in subsequent calls to <code>readObject (Object)</code>.
534 Otherwise, <code>resolveObject (Object)</code> will not be called.
535
536 @exception SecurityException This class is not trusted.
537 */
538 protected boolean enableResolveObject (boolean enable)
539 throws SecurityException
540 {
541 if (enable)
542 {
543 SecurityManager sm = System.getSecurityManager ();
544 if (sm != null)
545 sm.checkPermission (new SerializablePermission ("enableSubtitution"));
546 }
547
548 boolean old_val = this.resolveEnabled;
549 this.resolveEnabled = enable;
550 return old_val;
551 }
552
553
554 /**
555 Reads stream magic and stream version information from the
556 underlying stream.
557
558 @exception IOException Exception from underlying stream.
559
560 @exception StreamCorruptedException An invalid stream magic
561 number or stream version was read from the stream.
562 */
563 protected void readStreamHeader ()
564 throws IOException, StreamCorruptedException
565 {
566 dumpElement ("STREAM MAGIC ");
567 if (this.realInputStream.readShort () != STREAM_MAGIC)
568 throw new StreamCorruptedException ("Invalid stream magic number");
569
570 dumpElementln ("STREAM VERSION ");
571 if (this.realInputStream.readShort () != STREAM_VERSION)
572 throw new StreamCorruptedException ("Invalid stream version number");
573 }
574
575
576 public int read () throws IOException
577 {
578 if (this.readDataFromBlock)
579 {
580 if (this.blockDataPosition >= this.blockDataBytes)
581 readNextBlock ();
582 return (this.blockData[this.blockDataPosition++] & 0xff);
583 }
584 else
585 return this.realInputStream.read ();
586 }
587
588 public int read (byte[] data, int offset, int length) throws IOException
589 {
590 if (this.readDataFromBlock)
591 {
592 if (this.blockDataPosition + length > this.blockDataBytes)
593 readNextBlock ();
594
595 System.arraycopy (this.blockData, this.blockDataPosition,
596 data, offset, length);
597 blockDataPosition += length;
598
599 return length;
600 }
601 else
602 return this.realInputStream.read (data, offset, length);
603 }
604
605 public int available () throws IOException
606 {
607 if (this.readDataFromBlock)
608 {
609 if (this.blockDataPosition >= this.blockDataBytes)
610 readNextBlock ();
611
612 return this.blockDataBytes - this.blockDataPosition;
613 }
614 else
615 return this.realInputStream.available ();
616 }
617
618 public void close () throws IOException
619 {
620 this.realInputStream.close ();
621 }
622
623 public boolean readBoolean () throws IOException
624 {
625 return this.dataInputStream.readBoolean ();
626 }
627
628 public byte readByte () throws IOException
629 {
630 return this.dataInputStream.readByte ();
631 }
632
633 public int readUnsignedByte () throws IOException
634 {
635 return this.dataInputStream.readUnsignedByte ();
636 }
637
638 public short readShort () throws IOException
639 {
640 return this.dataInputStream.readShort ();
641 }
642
643 public int readUnsignedShort () throws IOException
644 {
645 return this.dataInputStream.readUnsignedShort ();
646 }
647
648 public char readChar () throws IOException
649 {
650 return this.dataInputStream.readChar ();
651 }
652
653 public int readInt () throws IOException
654 {
655 return this.dataInputStream.readInt ();
656 }
657
658 public long readLong () throws IOException
659 {
660 return this.dataInputStream.readLong ();
661 }
662
663 public float readFloat () throws IOException
664 {
665 return this.dataInputStream.readFloat ();
666 }
667
668 public double readDouble () throws IOException
669 {
670 return this.dataInputStream.readDouble ();
671 }
672
673 public void readFully (byte data[]) throws IOException
674 {
675 this.dataInputStream.readFully (data);
676 }
677
678 public void readFully (byte data[], int offset, int size)
679 throws IOException
680 {
681 this.dataInputStream.readFully (data, offset, size);
682 }
683
684 public int skipBytes (int len) throws IOException
685 {
686 return this.dataInputStream.skipBytes (len);
687 }
688
689 /**
690 @deprecated
691 @see java.io.DataInputStream#readLine ()
692 */
693 public String readLine () throws IOException
694 {
695 return this.dataInputStream.readLine ();
696 }
697
698 public String readUTF () throws IOException
699 {
700 return this.dataInputStream.readUTF ();
701 }
702
703
704 /**
705 This class allows a class to specify exactly which fields should
706 be read, and what values should be read for these fields.
707
708 XXX: finish up comments
709 */
710 public static abstract class GetField
711 {
712 public abstract ObjectStreamClass getObjectStreamClass ();
713
714 public abstract boolean defaulted (String name)
715 throws IOException, IllegalArgumentException;
716
717 public abstract boolean get (String name, boolean defvalue)
718 throws IOException, IllegalArgumentException;
719
720 public abstract char get (String name, char defvalue)
721 throws IOException, IllegalArgumentException;
722
723 public abstract byte get (String name, byte defvalue)
724 throws IOException, IllegalArgumentException;
725
726 public abstract short get (String name, short defvalue)
727 throws IOException, IllegalArgumentException;
728
729 public abstract int get (String name, int defvalue)
730 throws IOException, IllegalArgumentException;
731
732 public abstract long get (String name, long defvalue)
733 throws IOException, IllegalArgumentException;
734
735 public abstract float get (String name, float defvalue)
736 throws IOException, IllegalArgumentException;
737
738 public abstract double get (String name, double defvalue)
739 throws IOException, IllegalArgumentException;
740
741 public abstract Object get (String name, Object defvalue)
742 throws IOException, IllegalArgumentException;
743 }
744
745 public GetField readFields ()
746 throws IOException, ClassNotFoundException, NotActiveException
747 {
748 if (this.currentObject == null || this.currentObjectStreamClass == null)
749 throw new NotActiveException ("readFields called by non-active class and/or object");
750
751 if (fieldsAlreadyRead)
752 throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
753
754 final ObjectStreamClass clazz = this.currentObjectStreamClass;
755 final byte[] prim_field_data = new byte[clazz.primFieldSize];
756 final Object[] objs = new Object[clazz.objectFieldCount];
757
758 // Apparently Block data is not used with GetField as per
759 // empirical evidence against JDK 1.2. Also see Mauve test
760 // java.io.ObjectInputOutput.Test.GetPutField.
761 setBlockDataMode (false);
762 readFully (prim_field_data);
763 for (int i = 0; i < objs.length; ++ i)
764 objs[i] = readObject ();
765 setBlockDataMode (true);
766
767 return new GetField ()
768 {
769 public ObjectStreamClass getObjectStreamClass ()
770 {
771 return clazz;
772 }
773
774 public boolean defaulted (String name)
775 throws IOException, IllegalArgumentException
776 {
777 return clazz.getField (name) == null;
778 }
779
780 public boolean get (String name, boolean defvalue)
781 throws IOException, IllegalArgumentException
782 {
783 ObjectStreamField field = getField (name, Boolean.TYPE);
784
785 if (field == null)
786 return defvalue;
787
788 return prim_field_data[field.getOffset ()] == 0 ? false : true;
789 }
790
791 public char get (String name, char defvalue)
792 throws IOException, IllegalArgumentException
793 {
794 ObjectStreamField field = getField (name, Character.TYPE);
795
796 if (field == null)
797 return defvalue;
798
799 int off = field.getOffset ();
800
801 return (char)(((prim_field_data[off++] & 0xFF) << 8)
802 | (prim_field_data[off] & 0xFF));
803 }
804
805 public byte get (String name, byte defvalue)
806 throws IOException, IllegalArgumentException
807 {
808 ObjectStreamField field = getField (name, Byte.TYPE);
809
810 if (field == null)
811 return defvalue;
812
813 return prim_field_data[field.getOffset ()];
814 }
815
816 public short get (String name, short defvalue)
817 throws IOException, IllegalArgumentException
818 {
819 ObjectStreamField field = getField (name, Short.TYPE);
820
821 if (field == null)
822 return defvalue;
823
824 int off = field.getOffset ();
825
826 return (short)(((prim_field_data[off++] & 0xFF) << 8)
827 | (prim_field_data[off] & 0xFF));
828 }
829
830 public int get (String name, int defvalue)
831 throws IOException, IllegalArgumentException
832 {
833 ObjectStreamField field = getField (name, Integer.TYPE);
834
835 if (field == null)
836 return defvalue;
837
838 int off = field.getOffset ();
839
840 return ((prim_field_data[off++] & 0xFF) << 24)
841 | ((prim_field_data[off++] & 0xFF) << 16)
842 | ((prim_field_data[off++] & 0xFF) << 8)
843 | (prim_field_data[off] & 0xFF);
844 }
845
846 public long get (String name, long defvalue)
847 throws IOException, IllegalArgumentException
848 {
849 ObjectStreamField field = getField (name, Long.TYPE);
850
851 if (field == null)
852 return defvalue;
853
854 int off = field.getOffset ();
855
856 return (long)(((prim_field_data[off++] & 0xFF) << 56)
857 | ((prim_field_data[off++] & 0xFF) << 48)
858 | ((prim_field_data[off++] & 0xFF) << 40)
859 | ((prim_field_data[off++] & 0xFF) << 32)
860 | ((prim_field_data[off++] & 0xFF) << 24)
861 | ((prim_field_data[off++] & 0xFF) << 16)
862 | ((prim_field_data[off++] & 0xFF) << 8)
863 | (prim_field_data[off] & 0xFF));
864 }
865
866 public float get (String name, float defvalue)
867 throws IOException, IllegalArgumentException
868 {
869 ObjectStreamField field = getField (name, Float.TYPE);
870
871 if (field == null)
872 return defvalue;
873
874 int off = field.getOffset ();
875
876 return Float.intBitsToFloat (((prim_field_data[off++] & 0xFF) << 24)
877 | ((prim_field_data[off++] & 0xFF) << 16)
878 | ((prim_field_data[off++] & 0xFF) << 8)
879 | (prim_field_data[off] & 0xFF));
880 }
881
882 public double get (String name, double defvalue)
883 throws IOException, IllegalArgumentException
884 {
885 ObjectStreamField field = getField (name, Double.TYPE);
886
887 if (field == null)
888 return defvalue;
889
890 int off = field.getOffset ();
891
892 return Double.longBitsToDouble (
893 (long)(((prim_field_data[off++] & 0xFF) << 56)
894 | ((prim_field_data[off++] & 0xFF) << 48)
895 | ((prim_field_data[off++] & 0xFF) << 40)
896 | ((prim_field_data[off++] & 0xFF) << 32)
897 | ((prim_field_data[off++] & 0xFF) << 24)
898 | ((prim_field_data[off++] & 0xFF) << 16)
899 | ((prim_field_data[off++] & 0xFF) << 8)
900 | (prim_field_data[off] & 0xFF)));
901 }
902
903 public Object get (String name, Object defvalue)
904 throws IOException, IllegalArgumentException
905 {
906 ObjectStreamField field =
907 getField (name, defvalue == null ? null : defvalue.getClass ());
908
909 if (field == null)
910 return defvalue;
911
912 return objs[field.getOffset ()];
913 }
914
915 private ObjectStreamField getField (String name, Class type)
916 throws IllegalArgumentException
917 {
918 ObjectStreamField field = clazz.getField (name);
919
920 if (field == null)
921 return null;
922
923 Class field_type = field.getType ();
924
925 if (type == field_type ||
926 (type == null && ! field_type.isPrimitive ()))
927 return field;
928
929 throw new IllegalArgumentException ("Field requested is of type "
930 + field_type.getName ()
931 + ", but requested type was "
932 + (type == null ?
933 "Object" : type.getName ()));
934 }
935 };
936
937 }
938
939
940 /**
941 Protected constructor that allows subclasses to override
942 deserialization. This constructor should be called by subclasses
943 that wish to override <code>readObject (Object)</code>. This
944 method does a security check <i>NOTE: currently not
945 implemented</i>, then sets a flag that informs
946 <code>readObject (Object)</code> to call the subclasses
947 <code>readObjectOverride (Object)</code> method.
948
949 @see readObjectOverride (Object)
950 */
951 protected ObjectInputStream ()
952 throws IOException, SecurityException
953 {
954 SecurityManager sec_man = System.getSecurityManager ();
955 if (sec_man != null)
956 sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
957 this.useSubclassMethod = true;
958 }
959
960
961 /**
962 This method allows subclasses to override the default
963 de serialization mechanism provided by
964 <code>ObjectInputStream</code>. To make this method be used for
965 writing objects, subclasses must invoke the 0-argument
966 constructor on this class from there constructor.
967
968 @see ObjectInputStream ()
969 */
970 protected Object readObjectOverride ()
971 throws ClassNotFoundException, IOException, OptionalDataException
972 {
973 throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
974 }
975
976
977 // assigns the next availible handle to OBJ
978 private int assignNewHandle (Object obj)
979 {
980 this.objectLookupTable.put (new Integer (this.nextOID),
981 new ObjectIdentityWrapper (obj));
982
983// try
984// {
985// DEBUG ("Assigning handle " + this.nextOID);
986// DEBUGln (" to " + obj);
987// }
988// catch (Throwable t) {}
989
990 return this.nextOID++;
991 }
992
993
994 private Object processResolution (Object obj, int handle)
995 throws IOException
996 {
997 if (obj instanceof Serializable)
998 {
999 Method m = null;
1000 try
1001 {
1002 Class classArgs[] = {};
1003 m = obj.getClass ().getDeclaredMethod ("readResolve", classArgs);
1004 // m can't be null by definition since an exception would
1005 // have been thrown so a check for null is not needed.
1006 obj = m.invoke (obj, new Object[] {});
1007 }
1008 catch (NoSuchMethodException ignore)
1009 {
1010 }
1011 catch (IllegalAccessException ignore)
1012 {
1013 }
1014 catch (InvocationTargetException ignore)
1015 {
1016 }
1017 }
1018
1019 if (this.resolveEnabled)
1020 obj = resolveObject (obj);
1021
1022 this.objectLookupTable.put (new Integer (handle),
1023 new ObjectIdentityWrapper (obj));
1024
1025 return obj;
1026 }
1027
1028
1029 private void clearHandles ()
1030 {
1031 this.objectLookupTable.clear ();
1032 this.nextOID = baseWireHandle;
1033 }
1034
1035
1036 private void readNextBlock () throws IOException
1037 {
1038// DEBUGln ("In readNextBlock ");
1039 readNextBlock (this.realInputStream.readByte ());
1040 }
1041
1042
1043 private void readNextBlock (byte marker) throws IOException
1044 {
1045 if (marker == TC_BLOCKDATA)
1046 {
1047 dumpElement ("BLOCK DATA SIZE=");
1048 this.blockDataBytes = this.realInputStream.readUnsignedByte ();
1049 dumpElementln (Integer.toString(this.blockDataBytes));
1050 }
1051 else if (marker == TC_BLOCKDATALONG)
1052 {
1053 dumpElement ("BLOCK DATA LONG SIZE=");
1054 this.blockDataBytes = this.realInputStream.readInt ();
1055 dumpElementln (Integer.toString(this.blockDataBytes));
1056 }
1057 else
1058 {
1059 throw new EOFException ("Attempt to read primitive data, but no data block is active.");
1060 }
1061
1062 if (this.blockData.length < this.blockDataBytes)
1063 this.blockData = new byte[this.blockDataBytes];
1064
1065 this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1066 this.blockDataPosition = 0;
1067 }
1068
1069
1070 private void readArrayElements (Object array, Class clazz)
1071 throws ClassNotFoundException, IOException
1072 {
1073 if (clazz.isPrimitive ())
1074 {
1075 if (clazz == Boolean.TYPE)
1076 {
1077 boolean[] cast_array = (boolean[])array;
1078 for (int i=0; i < cast_array.length; i++)
1079 cast_array[i] = this.realInputStream.readBoolean ();
1080 return;
1081 }
1082 if (clazz == Byte.TYPE)
1083 {
1084 byte[] cast_array = (byte[])array;
1085 for (int i=0; i < cast_array.length; i++)
1086 cast_array[i] = this.realInputStream.readByte ();
1087 return;
1088 }
1089 if (clazz == Character.TYPE)
1090 {
1091 char[] cast_array = (char[])array;
1092 for (int i=0; i < cast_array.length; i++)
1093 cast_array[i] = this.realInputStream.readChar ();
1094 return;
1095 }
1096 if (clazz == Double.TYPE)
1097 {
1098 double[] cast_array = (double[])array;
1099 for (int i=0; i < cast_array.length; i++)
1100 cast_array[i] = this.realInputStream.readDouble ();
1101 return;
1102 }
1103 if (clazz == Float.TYPE)
1104 {
1105 float[] cast_array = (float[])array;
1106 for (int i=0; i < cast_array.length; i++)
1107 cast_array[i] = this.realInputStream.readFloat ();
1108 return;
1109 }
1110 if (clazz == Integer.TYPE)
1111 {
1112 int[] cast_array = (int[])array;
1113 for (int i=0; i < cast_array.length; i++)
1114 cast_array[i] = this.realInputStream.readInt ();
1115 return;
1116 }
1117 if (clazz == Long.TYPE)
1118 {
1119 long[] cast_array = (long[])array;
1120 for (int i=0; i < cast_array.length; i++)
1121 cast_array[i] = this.realInputStream.readLong ();
1122 return;
1123 }
1124 if (clazz == Short.TYPE)
1125 {
1126 short[] cast_array = (short[])array;
1127 for (int i=0; i < cast_array.length; i++)
1128 cast_array[i] = this.realInputStream.readShort ();
1129 return;
1130 }
1131 }
1132 else
1133 {
1134 Object[] cast_array = (Object[])array;
1135 for (int i=0; i < cast_array.length; i++)
1136 cast_array[i] = readObject ();
1137 }
1138 }
1139
1140
1141 private void readFields (Object obj, ObjectStreamField[] stream_fields,
1142 boolean call_read_method,
1143 ObjectStreamClass stream_osc)
1144 throws ClassNotFoundException, IOException
1145 {
1146// DEBUGln ("In readFields");
1147 if (call_read_method)
1148 {
1149// DEBUGln (" call_read_method is true");
1150 fieldsAlreadyRead = false;
1151 setBlockDataMode (true);
1152 callReadMethod (obj, stream_osc.forClass ());
1153 setBlockDataMode (false);
1154 return;
1155 }
1156
1157 ObjectStreamField[] real_fields =
1158 ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
1159
1160 boolean default_initialize, set_value;
1161 String field_name = null;
1162 Class type = null;
1163 ObjectStreamField stream_field = null;
1164 ObjectStreamField real_field = null;
1165 int stream_idx = 0;
1166 int real_idx = 0;
1167
1168 while (stream_idx < stream_fields.length
1169 && real_idx < real_fields.length)
1170 {
1171 default_initialize = false;
1172 set_value = true;
1173
1174 if (stream_idx == stream_fields.length)
1175 default_initialize = true;
1176 else
1177 {
1178 stream_field = stream_fields[stream_idx];
1179 type = stream_field.getType ();
1180 }
1181
1182 if (real_idx == real_fields.length)
1183 set_value = false;
1184 else
1185 {
1186 real_field = real_fields[real_idx];
1187 type = real_field.getType ();
1188 field_name = real_field.getName ();
1189 }
1190
1191 if (set_value && !default_initialize)
1192 {
1193 int comp_val =
1194 real_field.compareTo (stream_field);
1195
1196 if (comp_val < 0)
1197 {
1198 default_initialize = true;
1199 real_idx++;
1200 }
1201 else if (comp_val > 0)
1202 {
1203 set_value = false;
1204 stream_idx++;
1205 }
1206 else
1207 {
1208 real_idx++;
1209 stream_idx++;
1210 }
1211 }
1212
1213 if (type == Boolean.TYPE)
1214 {
1215 boolean value =
1216 default_initialize ? false : this.realInputStream.readBoolean ();
1217 if (!default_initialize && set_value)
1218 dumpElementln (" " + field_name + ": " + value);
1219 if (set_value)
1220 setBooleanField (obj, field_name, value);
1221 }
1222 else if (type == Byte.TYPE)
1223 {
1224 byte value =
1225 default_initialize ? 0 : this.realInputStream.readByte ();
1226 if (!default_initialize && set_value)
1227 dumpElementln (" " + field_name + ": " + value);
1228 if (set_value)
1229 setByteField (obj, field_name, value);
1230 }
1231 else if (type == Character.TYPE)
1232 {
1233 char value =
1234 default_initialize ? (char)0 : this.realInputStream.readChar ();
1235 if (!default_initialize && set_value)
1236 dumpElementln (" " + field_name + ": " + value);
1237 if (set_value)
1238 setCharField (obj, field_name, value);
1239 }
1240 else if (type == Double.TYPE)
1241 {
1242 double value =
1243 default_initialize ? 0 : this.realInputStream.readDouble ();
1244 if (!default_initialize && set_value)
1245 dumpElementln (" " + field_name + ": " + value);
1246 if (set_value)
1247 setDoubleField (obj, field_name, value);
1248 }
1249 else if (type == Float.TYPE)
1250 {
1251 float value =
1252 default_initialize ? 0 : this.realInputStream.readFloat ();
1253 if (!default_initialize && set_value)
1254 dumpElementln (" " + field_name + ": " + value);
1255 if (set_value)
1256 setFloatField (obj, field_name, value);
1257 }
1258 else if (type == Integer.TYPE)
1259 {
1260 int value =
1261 default_initialize ? 0 : this.realInputStream.readInt ();
1262 if (!default_initialize && set_value)
1263 dumpElementln (" " + field_name + ": " + value);
1264 if (set_value)
1265 setIntField (obj, field_name, value);
1266 }
1267 else if (type == Long.TYPE)
1268 {
1269 long value =
1270 default_initialize ? 0 : this.realInputStream.readLong ();
1271 if (!default_initialize && set_value)
1272 dumpElementln (" " + field_name + ": " + value);
1273 if (set_value)
1274 setLongField (obj, field_name, value);
1275 }
1276 else if (type == Short.TYPE)
1277 {
1278 short value =
1279 default_initialize ? (short)0 : this.realInputStream.readShort ();
1280 if (!default_initialize && set_value)
1281 dumpElementln (" " + field_name + ": " + value);
1282 if (set_value)
1283 setShortField (obj, field_name, value);
1284 }
1285 else
1286 {
1287 Object value =
1288 default_initialize ? null : readObject ();
1289 if (set_value)
1290 setObjectField (obj, field_name,
1291 real_field.getTypeString (), value);
1292 }
1293 }
1294 }
1295
1296
1297 // Toggles writing primitive data to block-data buffer.
1298 private void setBlockDataMode (boolean on)
1299 {
1300// DEBUGln ("Setting block data mode to " + on);
1301
1302 this.readDataFromBlock = on;
1303
1304 if (on)
1305 this.dataInputStream = this.blockDataInput;
1306 else
1307 this.dataInputStream = this.realInputStream;
1308 }
1309
1310
1311 // returns a new instance of REAL_CLASS that has been constructed
1312 // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1313 private Object newObject (Class real_class, Class constructor_class)
1314 {
1315 try
1316 {
1317 Object obj = allocateObject (real_class);
1318 callConstructor (constructor_class, obj);
1319 return obj;
1320 }
1321 catch (InstantiationException e)
1322 {
1323 return null;
1324 }
1325 }
1326
1327
1328 // runs all registered ObjectInputValidations in prioritized order
1329 // on OBJ
1330 private void invokeValidators () throws InvalidObjectException
1331 {
1332 Object[] validators = new Object[this.validators.size ()];
1333 this.validators.copyInto (validators);
1334 Arrays.sort (validators);
1335
1336 try
1337 {
1338 for (int i=0; i < validators.length; i++)
1339 ((ObjectInputValidation)validators[i]).validateObject ();
1340 }
1341 finally
1342 {
1343 this.validators.removeAllElements ();
1344 }
1345 }
1346
1347
1348 // this native method is used to get access to the protected method
1349 // of the same name in SecurityManger
1350 private static ClassLoader currentClassLoader (SecurityManager sm)
1351 {
1352 // FIXME: This is too simple.
1353 return ClassLoader.getSystemClassLoader ();
1354 }
1355
1356 private static native Field getField (Class klass, String name)
1357 throws java.lang.NoSuchFieldException;
1358
1359 private static native Method getMethod (Class klass, String name, Class args[])
1360 throws java.lang.NoSuchMethodException;
1361
1362 private void callReadMethod (Object obj, Class klass) throws IOException
1363 {
1364 try
1365 {
1366 Class classArgs[] = {ObjectInputStream.class};
1367 Method m = getMethod (klass, "readObject", classArgs);
1368 if (m == null)
1369 return;
1370 Object args[] = {this};
1371 m.invoke (obj, args);
1372 }
1373 catch (InvocationTargetException x)
1374 {
1375 /* Rethrow if possible. */
1376 Throwable exception = x.getTargetException();
1377 if (exception instanceof RuntimeException)
1378 throw (RuntimeException) exception;
1379 if (exception instanceof IOException)
1380 throw (IOException) exception;
1381
1382 throw new IOException ("Exception thrown from readObject() on " +
1383 klass + ": " + exception.getClass().getName());
1384 }
1385 catch (Exception x)
1386 {
1387 throw new IOException ("Failure invoking readObject() on " +
1388 klass + ": " + x.getClass().getName());
1389 }
1390 }
1391
1392 private native Object allocateObject (Class clazz)
1393 throws InstantiationException;
1394
1395 private native void callConstructor (Class clazz, Object obj);
1396
1397 private void setBooleanField (Object obj, String field_name,
1398 boolean val)
1399 {
1400 try
1401 {
1402 Class klass = obj.getClass ();
1403 Field f = getField (klass, field_name);
1404 f.setBoolean (obj, val);
1405 }
1406 catch (Exception _)
1407 {
1408 }
1409 }
1410
1411 private void setByteField (Object obj, String field_name,
1412 byte val)
1413 {
1414 try
1415 {
1416 Class klass = obj.getClass ();
1417 Field f = getField (klass, field_name);
1418 f.setByte (obj, val);
1419 }
1420 catch (Exception _)
1421 {
1422 }
1423 }
1424
1425 private void setCharField (Object obj, String field_name,
1426 char val)
1427 {
1428 try
1429 {
1430 Class klass = obj.getClass ();
1431 Field f = getField (klass, field_name);
1432 f.setChar (obj, val);
1433 }
1434 catch (Exception _)
1435 {
1436 }
1437 }
1438
1439 private void setDoubleField (Object obj, String field_name,
1440 double val)
1441 {
1442 try
1443 {
1444 Class klass = obj.getClass ();
1445 Field f = getField (klass, field_name);
1446 f.setDouble (obj, val);
1447 }
1448 catch (Exception _)
1449 {
1450 }
1451 }
1452
1453 private void setFloatField (Object obj, String field_name,
1454 float val)
1455 {
1456 try
1457 {
1458 Class klass = obj.getClass ();
1459 Field f = getField (klass, field_name);
1460 f.setFloat (obj, val);
1461 }
1462 catch (Exception _)
1463 {
1464 }
1465 }
1466
1467 private void setIntField (Object obj, String field_name,
1468 int val)
1469 {
1470 try
1471 {
1472 Class klass = obj.getClass ();
1473 Field f = getField (klass, field_name);
1474 f.setInt (obj, val);
1475 }
1476 catch (Exception _)
1477 {
1478 }
1479 }
1480
1481
1482 private void setLongField (Object obj, String field_name,
1483 long val)
1484 {
1485 try
1486 {
1487 Class klass = obj.getClass ();
1488 Field f = getField (klass, field_name);
1489 f.setLong (obj, val);
1490 }
1491 catch (Exception _)
1492 {
1493 }
1494 }
1495
1496
1497 private void setShortField (Object obj, String field_name,
1498 short val)
1499 {
1500 try
1501 {
1502 Class klass = obj.getClass ();
1503 Field f = getField (klass, field_name);
1504 f.setShort (obj, val);
1505 }
1506 catch (Exception _)
1507 {
1508 }
1509 }
1510
1511
1512 private void setObjectField (Object obj, String field_name, String type_code,
1513 Object val)
1514 {
1515 try
1516 {
1517 Class klass = obj.getClass ();
1518 Field f = getField (klass, field_name);
1519 // FIXME: We should check the type_code here
1520 f.set (obj, val);
1521 }
1522 catch (Exception _)
1523 {
1524 }
1525 }
1526
1527 private static final int BUFFER_SIZE = 1024;
1528 private static final Class[] readObjectParams = { ObjectInputStream.class };
1529
1530 private DataInputStream realInputStream;
1531 private DataInputStream dataInputStream;
1532 private DataInputStream blockDataInput;
1533 private int blockDataPosition;
1534 private int blockDataBytes;
1535 private byte[] blockData;
1536 private boolean useSubclassMethod;
1537 private int nextOID;
1538 private boolean resolveEnabled;
1539 private Hashtable objectLookupTable;
1540 private Object currentObject;
1541 private ObjectStreamClass currentObjectStreamClass;
1542 private boolean readDataFromBlock;
1543 private boolean isDeserializing;
1544 private boolean fieldsAlreadyRead;
1545 private Vector validators;
1546
1547 private static boolean dump;
1548
1549 private void dumpElement (String msg)
1550 {
1551 if (Configuration.DEBUG && dump)
1552 System.out.print(msg);
1553 }
1554
1555 private void dumpElementln (String msg)
1556 {
1557 if (Configuration.DEBUG && dump)
1558 System.out.println(msg);
1559 }
1560}
1561
1562
1563// used to keep a prioritized list of object validators
1564class ValidatorAndPriority implements Comparable
1565{
1566 int priority;
1567 ObjectInputValidation validator;
1568
1569 ValidatorAndPriority (ObjectInputValidation validator, int priority)
1570 {
1571 this.priority = priority;
1572 this.validator = validator;
1573 }
1574
1575 public int compareTo (Object o)
1576 {
1577 ValidatorAndPriority vap = (ValidatorAndPriority)o;
1578 return this.priority - vap.priority;
1579 }
1580}
Note: See TracBrowser for help on using the repository browser.