OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [io/] [ObjectInputStream.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* ObjectInputStream.java -- Class used to read serialized objects
2
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GNU Classpath.
6
 
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING.  If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301 USA.
21
 
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library.  Thus, the terms and
24
conditions of the GNU General Public License cover the whole
25
combination.
26
 
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module.  An independent module is a module which is not derived from
34
or based on this library.  If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so.  If you do not wish to do so, delete this
37
exception statement from your version. */
38
 
39
 
40
package java.io;
41
 
42
import gnu.classpath.Pair;
43
import gnu.classpath.VMStackWalker;
44
 
45
import java.lang.reflect.Array;
46
import java.lang.reflect.Constructor;
47
import java.lang.reflect.Field;
48
import java.lang.reflect.InvocationTargetException;
49
import java.lang.reflect.Method;
50
import java.lang.reflect.Modifier;
51
import java.lang.reflect.Proxy;
52
import java.security.AccessController;
53
import java.security.PrivilegedAction;
54
import java.util.HashMap;
55
import java.util.Hashtable;
56
import java.util.Iterator;
57
import java.util.Map;
58
import java.util.TreeSet;
59
 
60
/**
61
 * @author Tom Tromey (tromey@redhat.com)
62
 * @author Jeroen Frijters (jeroen@frijters.net)
63
 * @author Guilhem Lavaux (guilhem@kaffe.org)
64
 * @author Michael Koch (konqueror@gmx.de)
65
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
66
 */
67
public class ObjectInputStream extends InputStream
68
  implements ObjectInput, ObjectStreamConstants
69
{
70
  /**
71
   * Creates a new <code>ObjectInputStream</code> that will do all of
72
   * its reading from <code>in</code>.  This method also checks
73
   * the stream by reading the header information (stream magic number
74
   * and stream version).
75
   *
76
   * @exception IOException Reading stream header from underlying
77
   * stream cannot be completed.
78
   *
79
   * @exception StreamCorruptedException An invalid stream magic
80
   * number or stream version was read from the stream.
81
   *
82
   * @see #readStreamHeader()
83
   */
84
  public ObjectInputStream(InputStream in)
85
    throws IOException, StreamCorruptedException
86
  {
87
    if (DEBUG)
88
      {
89
        String val = System.getProperty("gcj.dumpobjects");
90
        if (dump == false && val != null && !val.equals(""))
91
          {
92
            dump = true;
93
            System.out.println ("Serialization debugging enabled");
94
          }
95
        else if (dump == true && (val == null || val.equals("")))
96
          {
97
            dump = false;
98
            System.out.println ("Serialization debugging disabled");
99
          }
100
      }
101
 
102
    this.resolveEnabled = false;
103
    this.blockDataPosition = 0;
104
    this.blockDataBytes = 0;
105
    this.blockData = new byte[BUFFER_SIZE];
106
    this.blockDataInput = new DataInputStream(this);
107
    this.realInputStream = new DataInputStream(in);
108
    this.nextOID = baseWireHandle;
109
    handles = new HashMap<Integer,Pair<Boolean,Object>>();
110
    this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
111
    setBlockDataMode(true);
112
    readStreamHeader();
113
  }
114
 
115
 
116
  /**
117
   * Returns the next deserialized object read from the underlying stream.
118
   *
119
   * This method can be overriden by a class by implementing
120
   * <code>private void readObject (ObjectInputStream)</code>.
121
   *
122
   * If an exception is thrown from this method, the stream is left in
123
   * an undefined state. This method can also throw Errors and
124
   * RuntimeExceptions if caused by existing readResolve() user code.
125
   *
126
   * @return The object read from the underlying stream.
127
   *
128
   * @exception ClassNotFoundException The class that an object being
129
   * read in belongs to cannot be found.
130
   *
131
   * @exception IOException Exception from underlying
132
   * <code>InputStream</code>.
133
   */
134
  public final Object readObject()
135
    throws ClassNotFoundException, IOException
136
  {
137
    return readObject(true);
138
  }
139
 
140
  /**
141
   * <p>
142
   * Returns the next deserialized object read from the
143
   * underlying stream in an unshared manner.  Any object
144
   * returned by this method will not be returned by
145
   * subsequent calls to either this method or {@link #readObject()}.
146
   * </p>
147
   * <p>
148
   * This behaviour is achieved by:
149
   * </p>
150
   * <ul>
151
   * <li>Marking the handles created by successful calls to this
152
   * method, so that future calls to {@link #readObject()} or
153
   * {@link #readUnshared()} will throw an {@link ObjectStreamException}
154
   * rather than returning the same object reference.</li>
155
   * <li>Throwing an {@link ObjectStreamException} if the next
156
   * element in the stream is a reference to an earlier object.</li>
157
   * </ul>
158
   *
159
   * @return a reference to the deserialized object.
160
   * @throws ClassNotFoundException if the class of the object being
161
   *                                deserialized can not be found.
162
   * @throws StreamCorruptedException if information in the stream
163
   *                                  is inconsistent.
164
   * @throws ObjectStreamException if the next object has already been
165
   *                               returned by an earlier call to this
166
   *                               method or {@link #readObject()}.
167
   * @throws OptionalDataException if primitive data occurs next in the stream.
168
   * @throws IOException if an I/O error occurs from the stream.
169
   * @since 1.4
170
   * @see #readObject()
171
   */
172
  public Object readUnshared()
173
    throws IOException, ClassNotFoundException
174
  {
175
    return readObject(false);
176
  }
177
 
178
  /**
179
   * Returns the next deserialized object read from the underlying stream.
180
   *
181
   * This method can be overriden by a class by implementing
182
   * <code>private void readObject (ObjectInputStream)</code>.
183
   *
184
   * If an exception is thrown from this method, the stream is left in
185
   * an undefined state. This method can also throw Errors and
186
   * RuntimeExceptions if caused by existing readResolve() user code.
187
   *
188
   * @param shared true if handles created by this call should be shared
189
   *               with later calls.
190
   * @return The object read from the underlying stream.
191
   *
192
   * @exception ClassNotFoundException The class that an object being
193
   * read in belongs to cannot be found.
194
   *
195
   * @exception IOException Exception from underlying
196
   * <code>InputStream</code>.
197
   */
198
  private final Object readObject(boolean shared)
199
    throws ClassNotFoundException, IOException
200
  {
201
    if (this.useSubclassMethod)
202
      return readObjectOverride();
203
 
204
    Object ret_val;
205
    boolean old_mode = setBlockDataMode(false);
206
    byte marker = this.realInputStream.readByte();
207
 
208
    if (DEBUG)
209
      depth += 2;
210
 
211
    if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
212
 
213
    try
214
      {
215
        ret_val = parseContent(marker, shared);
216
      }
217
    finally
218
      {
219
        setBlockDataMode(old_mode);
220
        if (DEBUG)
221
          depth -= 2;
222
      }
223
 
224
    return ret_val;
225
  }
226
 
227
   /**
228
    * Handles a content block within the stream, which begins with a marker
229
    * byte indicating its type.
230
    *
231
    * @param marker the byte marker.
232
    * @param shared true if handles created by this call should be shared
233
    *               with later calls.
234
    * @return an object which represents the parsed content.
235
    * @throws ClassNotFoundException if the class of an object being
236
    *                                read in cannot be found.
237
    * @throws IOException if invalid data occurs or one is thrown by the
238
    *                     underlying <code>InputStream</code>.
239
    */
240
   private Object parseContent(byte marker, boolean shared)
241
     throws ClassNotFoundException, IOException
242
   {
243
     Object ret_val;
244
     boolean is_consumed = false;
245
 
246
     switch (marker)
247
       {
248
       case TC_ENDBLOCKDATA:
249
        {
250
          ret_val = null;
251
          is_consumed = true;
252
          break;
253
        }
254
 
255
       case TC_BLOCKDATA:
256
       case TC_BLOCKDATALONG:
257
        {
258
          if (marker == TC_BLOCKDATALONG)
259
            { if(dump) dumpElementln("BLOCKDATALONG"); }
260
          else
261
            { if(dump) dumpElementln("BLOCKDATA"); }
262
          readNextBlock(marker);
263
        }
264
 
265
       case TC_NULL:
266
        {
267
          if(dump) dumpElementln("NULL");
268
          ret_val = null;
269
          break;
270
        }
271
 
272
       case TC_REFERENCE:
273
        {
274
          if(dump) dumpElement("REFERENCE ");
275
          int oid = realInputStream.readInt();
276
          if(dump) dumpElementln(Integer.toHexString(oid));
277
          ret_val = lookupHandle(oid);
278
          if (!shared)
279
            throw new
280
              InvalidObjectException("References can not be read unshared.");
281
          break;
282
        }
283
 
284
       case TC_CLASS:
285
        {
286
          if(dump) dumpElementln("CLASS");
287
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
288
          Class clazz = osc.forClass();
289
          assignNewHandle(clazz,shared);
290
          ret_val = clazz;
291
          break;
292
        }
293
 
294
       case TC_PROXYCLASSDESC:
295
        {
296
          if(dump) dumpElementln("PROXYCLASS");
297
 
298
/* GCJ LOCAL */
299
          // The grammar at this point is
300
          //   TC_PROXYCLASSDESC newHandle proxyClassDescInfo
301
          // i.e. we have to assign the handle immediately after
302
          // reading the marker.
303
          int handle = assignNewHandle("Dummy proxy",shared);
304
/* END GCJ LOCAL */
305
 
306
          int n_intf = this.realInputStream.readInt();
307
          String[] intfs = new String[n_intf];
308
          for (int i = 0; i < n_intf; i++)
309
            {
310
              intfs[i] = this.realInputStream.readUTF();
311
            }
312
 
313
          boolean oldmode = setBlockDataMode(true);
314
          Class cl = resolveProxyClass(intfs);
315
          setBlockDataMode(oldmode);
316
 
317
          ObjectStreamClass osc = lookupClass(cl);
318
          if (osc.firstNonSerializableParentConstructor == null)
319
            {
320
              osc.realClassIsSerializable = true;
321
              osc.fields = osc.fieldMapping = new ObjectStreamField[0];
322
              try
323
                {
324
                  osc.firstNonSerializableParentConstructor =
325
                    Object.class.getConstructor(new Class[0]);
326
                }
327
              catch (NoSuchMethodException x)
328
                {
329
                  throw (InternalError)
330
                    new InternalError("Object ctor missing").initCause(x);
331
                }
332
            }
333
/* GCJ LOCAL */
334
          rememberHandle(osc,shared,handle);
335
/* END GCJ LOCAL */
336
 
337
          if (!is_consumed)
338
            {
339
              byte b = this.realInputStream.readByte();
340
              if (b != TC_ENDBLOCKDATA)
341
                throw new IOException("Data annotated to class was not consumed." + b);
342
            }
343
          else
344
            is_consumed = false;
345
          ObjectStreamClass superosc = (ObjectStreamClass)readObject();
346
          osc.setSuperclass(superosc);
347
          ret_val = osc;
348
          break;
349
        }
350
 
351
       case TC_CLASSDESC:
352
        {
353
          ObjectStreamClass osc = readClassDescriptor();
354
 
355
          if (!is_consumed)
356
            {
357
              byte b = this.realInputStream.readByte();
358
              if (b != TC_ENDBLOCKDATA)
359
                throw new IOException("Data annotated to class was not consumed." + b);
360
            }
361
          else
362
            is_consumed = false;
363
 
364
          osc.setSuperclass ((ObjectStreamClass)readObject());
365
          ret_val = osc;
366
          break;
367
        }
368
 
369
       case TC_STRING:
370
        {
371
          if(dump) dumpElement("STRING=");
372
          String s = this.realInputStream.readUTF();
373
          if(dump) dumpElementln(s);
374
          ret_val = processResolution(null, s, assignNewHandle(s,shared),
375
                                      shared);
376
          break;
377
        }
378
 
379
       case TC_LONGSTRING:
380
        {
381
          if(dump) dumpElement("STRING=");
382
          String s = this.realInputStream.readUTFLong();
383
          if(dump) dumpElementln(s);
384
          ret_val = processResolution(null, s, assignNewHandle(s,shared),
385
                                      shared);
386
          break;
387
        }
388
 
389
       case TC_ARRAY:
390
        {
391
          if(dump) dumpElementln("ARRAY");
392
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
393
          Class componentType = osc.forClass().getComponentType();
394
          if(dump) dumpElement("ARRAY LENGTH=");
395
          int length = this.realInputStream.readInt();
396
          if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
397
          Object array = Array.newInstance(componentType, length);
398
          int handle = assignNewHandle(array,shared);
399
          readArrayElements(array, componentType);
400
          if(dump)
401
            for (int i = 0, len = Array.getLength(array); i < len; i++)
402
              dumpElementln("  ELEMENT[" + i + "]=", Array.get(array, i));
403
          ret_val = processResolution(null, array, handle, shared);
404
          break;
405
        }
406
 
407
       case TC_OBJECT:
408
        {
409
          if(dump) dumpElementln("OBJECT");
410
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
411
          Class clazz = osc.forClass();
412
 
413
          if (!osc.realClassIsSerializable)
414
            throw new NotSerializableException
415
              (clazz + " is not Serializable, and thus cannot be deserialized.");
416
 
417
          if (osc.realClassIsExternalizable)
418
            {
419
              Externalizable obj = osc.newInstance();
420
 
421
              int handle = assignNewHandle(obj,shared);
422
 
423
              boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
424
 
425
              boolean oldmode = this.readDataFromBlock;
426
              if (read_from_blocks)
427
                setBlockDataMode(true);
428
 
429
              obj.readExternal(this);
430
 
431
              if (read_from_blocks)
432
                {
433
                  setBlockDataMode(oldmode);
434
                  if (!oldmode)
435
                    if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
436
                      throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
437
                }
438
 
439
              ret_val = processResolution(osc, obj, handle,shared);
440
              break;
441
 
442
            } // end if (osc.realClassIsExternalizable)
443
 
444
          Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
445
 
446
          int handle = assignNewHandle(obj,shared);
447
          Object prevObject = this.currentObject;
448
          ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
449
          TreeSet<ValidatorAndPriority> prevObjectValidators =
450
            this.currentObjectValidators;
451
 
452
          this.currentObject = obj;
453
          this.currentObjectValidators = null;
454
          ObjectStreamClass[] hierarchy = hierarchy(clazz);
455
 
456
          for (int i = 0; i < hierarchy.length; i++)
457
          {
458
              this.currentObjectStreamClass = hierarchy[i];
459
              if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
460
 
461
              // XXX: should initialize fields in classes in the hierarchy
462
              // that aren't in the stream
463
              // should skip over classes in the stream that aren't in the
464
              // real classes hierarchy
465
 
466
              Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
467
              if (readObjectMethod != null)
468
                {
469
                  fieldsAlreadyRead = false;
470
                  boolean oldmode = setBlockDataMode(true);
471
                  callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
472
                  setBlockDataMode(oldmode);
473
                }
474
              else
475
                {
476
                  readFields(obj, currentObjectStreamClass);
477
                }
478
 
479
              if (this.currentObjectStreamClass.hasWriteMethod())
480
                {
481
                  if(dump) dumpElement("ENDBLOCKDATA? ");
482
                  try
483
                    {
484
                      /* Read blocks until an end marker */
485
                      byte writeMarker = this.realInputStream.readByte();
486
                      while (writeMarker != TC_ENDBLOCKDATA)
487
                        {
488
                          parseContent(writeMarker, shared);
489
                          writeMarker = this.realInputStream.readByte();
490
                        }
491
                      if(dump) dumpElementln("yes");
492
                    }
493
                  catch (EOFException e)
494
                    {
495
                      throw (IOException) new IOException
496
                        ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
497
                    }
498
                }
499
            }
500
 
501
          this.currentObject = prevObject;
502
          this.currentObjectStreamClass = prevObjectStreamClass;
503
          ret_val = processResolution(osc, obj, handle, shared);
504
          if (currentObjectValidators != null)
505
            invokeValidators();
506
          this.currentObjectValidators = prevObjectValidators;
507
 
508
          break;
509
        }
510
 
511
       case TC_RESET:
512
        if(dump) dumpElementln("RESET");
513
        clearHandles();
514
        ret_val = readObject();
515
        break;
516
 
517
       case TC_EXCEPTION:
518
        {
519
          if(dump) dumpElement("EXCEPTION=");
520
          Exception e = (Exception)readObject();
521
          if(dump) dumpElementln(e.toString());
522
          clearHandles();
523
          throw new WriteAbortedException("Exception thrown during writing of stream", e);
524
        }
525
 
526
       case TC_ENUM:
527
         {
528
           /* TC_ENUM classDesc newHandle enumConstantName */
529
           if (dump)
530
             dumpElementln("ENUM=");
531
           ObjectStreamClass osc = (ObjectStreamClass) readObject();
532
           String constantName = (String) readObject();
533
           if (dump)
534
             dumpElementln("CONSTANT NAME = " + constantName);
535
           Class clazz = osc.forClass();
536
           Enum instance = Enum.valueOf(clazz, constantName);
537
           assignNewHandle(instance,shared);
538
           ret_val = instance;
539
           break;
540
         }
541
 
542
       default:
543
        throw new IOException("Unknown marker on stream: " + marker);
544
      }
545
    return ret_val;
546
  }
547
 
548
  /**
549
   * This method makes a partial check of types for the fields
550
   * contained given in arguments. It checks primitive types of
551
   * fields1 against non primitive types of fields2. This method
552
   * assumes the two lists has already been sorted according to
553
   * the Java specification.
554
   *
555
   * @param name Name of the class owning the given fields.
556
   * @param fields1 First list to check.
557
   * @param fields2 Second list to check.
558
   * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
559
   * in the non primitive part in fields2.
560
   */
561
  private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
562
    throws InvalidClassException
563
  {
564
    int nonPrimitive = 0;
565
 
566
    for (nonPrimitive = 0;
567
         nonPrimitive < fields1.length
568
           && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
569
      {
570
      }
571
 
572
    if (nonPrimitive == fields1.length)
573
      return;
574
 
575
    int i = 0;
576
    ObjectStreamField f1;
577
    ObjectStreamField f2;
578
 
579
    while (i < fields2.length
580
           && nonPrimitive < fields1.length)
581
      {
582
        f1 = fields1[nonPrimitive];
583
        f2 = fields2[i];
584
 
585
        if (!f2.isPrimitive())
586
          break;
587
 
588
        int compVal = f1.getName().compareTo (f2.getName());
589
 
590
        if (compVal < 0)
591
          {
592
            nonPrimitive++;
593
          }
594
        else if (compVal > 0)
595
          {
596
            i++;
597
          }
598
        else
599
          {
600
            throw new InvalidClassException
601
              ("invalid field type for " + f2.getName() +
602
               " in class " + name);
603
          }
604
      }
605
  }
606
 
607
  /**
608
   * This method reads a class descriptor from the real input stream
609
   * and use these data to create a new instance of ObjectStreamClass.
610
   * Fields are sorted and ordered for the real read which occurs for
611
   * each instance of the described class. Be aware that if you call that
612
   * method you must ensure that the stream is synchronized, in the other
613
   * case it may be completely desynchronized.
614
   *
615
   * @return A new instance of ObjectStreamClass containing the freshly
616
   * created descriptor.
617
   * @throws ClassNotFoundException if the required class to build the
618
   * descriptor has not been found in the system.
619
   * @throws IOException An input/output error occured.
620
   * @throws InvalidClassException If there was a compatibility problem
621
   * between the class present in the system and the serialized class.
622
   */
623
  protected ObjectStreamClass readClassDescriptor()
624
    throws ClassNotFoundException, IOException
625
  {
626
    if(dump) dumpElement("CLASSDESC NAME=");
627
    String name = this.realInputStream.readUTF();
628
    if(dump) dumpElement(name + "; UID=");
629
    long uid = this.realInputStream.readLong ();
630
    if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
631
    byte flags = this.realInputStream.readByte ();
632
    if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
633
    short field_count = this.realInputStream.readShort();
634
    if(dump) dumpElementln(Short.toString(field_count));
635
    ObjectStreamField[] fields = new ObjectStreamField[field_count];
636
    ObjectStreamClass osc = new ObjectStreamClass(name, uid,
637
                                                  flags, fields);
638
    assignNewHandle(osc,true);
639
 
640
    for (int i = 0; i < field_count; i++)
641
      {
642
        if(dump) dumpElement("  TYPE CODE=");
643
        char type_code = (char)this.realInputStream.readByte();
644
        if(dump) dumpElement(type_code + "; FIELD NAME=");
645
        String field_name = this.realInputStream.readUTF();
646
        if(dump) dumpElementln(field_name);
647
        String class_name;
648
 
649
        // If the type code is an array or an object we must
650
        // decode a String here. In the other case we convert
651
        // the type code and pass it to ObjectStreamField.
652
        // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
653
        if (type_code == 'L' || type_code == '[')
654
          class_name = (String)readObject();
655
        else
656
          class_name = String.valueOf(type_code);
657
 
658
        fields[i] =
659
          new ObjectStreamField(field_name, class_name);
660
      }
661
 
662
    /* Now that fields have been read we may resolve the class
663
     * (and read annotation if needed). */
664
    Class clazz = resolveClass(osc);
665
    ClassLoader loader = clazz.getClassLoader();
666
    for (int i = 0; i < field_count; i++)
667
      {
668
        fields[i].resolveType(loader);
669
      }
670
    boolean oldmode = setBlockDataMode(true);
671
    osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
672
    classLookupTable.put(clazz, osc);
673
    setBlockDataMode(oldmode);
674
 
675
    // find the first non-serializable class in clazz's inheritance hierarchy
676
    Class first_nonserial = clazz.getSuperclass();
677
    // Maybe it is a primitive class, those don't have a super class,
678
    // or Object itself.  Otherwise we can keep getting the superclass
679
    // till we hit the Object class, or some other non-serializable class.
680
 
681
    if (first_nonserial == null)
682
      first_nonserial = clazz;
683
    else
684
      while (Serializable.class.isAssignableFrom(first_nonserial))
685
        first_nonserial = first_nonserial.getSuperclass();
686
 
687
    final Class local_constructor_class = first_nonserial;
688
 
689
    osc.firstNonSerializableParentConstructor =
690
        (Constructor)AccessController.doPrivileged(new PrivilegedAction()
691
          {
692
            public Object run()
693
            {
694
              try
695
                {
696
                  Constructor c = local_constructor_class.
697
                                    getDeclaredConstructor(new Class[0]);
698
                  if (Modifier.isPrivate(c.getModifiers()))
699
                    return null;
700
                  return c;
701
                }
702
              catch (NoSuchMethodException e)
703
                {
704
                  // error will be reported later, in newObject()
705
                  return null;
706
                }
707
            }
708
          });
709
 
710
    osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
711
    osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
712
 
713
    ObjectStreamField[] stream_fields = osc.fields;
714
    ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
715
    ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
716
 
717
    int stream_idx = 0;
718
    int real_idx = 0;
719
    int map_idx = 0;
720
 
721
    /*
722
     * Check that there is no type inconsistencies between the lists.
723
     * A special checking must be done for the two groups: primitive types and
724
     * not primitive types.
725
     */
726
    checkTypeConsistency(name, real_fields, stream_fields);
727
    checkTypeConsistency(name, stream_fields, real_fields);
728
 
729
 
730
    while (stream_idx < stream_fields.length
731
           || real_idx < real_fields.length)
732
      {
733
        ObjectStreamField stream_field = null;
734
        ObjectStreamField real_field = null;
735
 
736
        if (stream_idx == stream_fields.length)
737
          {
738
            real_field = real_fields[real_idx++];
739
          }
740
        else if (real_idx == real_fields.length)
741
          {
742
            stream_field = stream_fields[stream_idx++];
743
          }
744
        else
745
          {
746
            int comp_val =
747
              real_fields[real_idx].compareTo (stream_fields[stream_idx]);
748
 
749
            if (comp_val < 0)
750
              {
751
                real_field = real_fields[real_idx++];
752
              }
753
            else if (comp_val > 0)
754
              {
755
                stream_field = stream_fields[stream_idx++];
756
              }
757
            else
758
              {
759
                stream_field = stream_fields[stream_idx++];
760
                real_field = real_fields[real_idx++];
761
                if (stream_field.getType() != real_field.getType())
762
                  throw new InvalidClassException
763
                    ("invalid field type for " + real_field.getName() +
764
                     " in class " + name);
765
              }
766
          }
767
 
768
        /* If some of stream_fields does not correspond to any of real_fields,
769
         * or the opposite, then fieldmapping will go short.
770
         */
771
        if (map_idx == fieldmapping.length)
772
          {
773
            ObjectStreamField[] newfieldmapping =
774
              new ObjectStreamField[fieldmapping.length + 2];
775
            System.arraycopy(fieldmapping, 0,
776
                             newfieldmapping, 0, fieldmapping.length);
777
            fieldmapping = newfieldmapping;
778
          }
779
        fieldmapping[map_idx++] = stream_field;
780
        fieldmapping[map_idx++] = real_field;
781
      }
782
    osc.fieldMapping = fieldmapping;
783
 
784
    return osc;
785
  }
786
 
787
  /**
788
   * Reads the current objects non-transient, non-static fields from
789
   * the current class from the underlying output stream.
790
   *
791
   * This method is intended to be called from within a object's
792
   * <code>private void readObject (ObjectInputStream)</code>
793
   * method.
794
   *
795
   * @exception ClassNotFoundException The class that an object being
796
   * read in belongs to cannot be found.
797
   *
798
   * @exception NotActiveException This method was called from a
799
   * context other than from the current object's and current class's
800
   * <code>private void readObject (ObjectInputStream)</code>
801
   * method.
802
   *
803
   * @exception IOException Exception from underlying
804
   * <code>OutputStream</code>.
805
   */
806
  public void defaultReadObject()
807
    throws ClassNotFoundException, IOException, NotActiveException
808
  {
809
    if (this.currentObject == null || this.currentObjectStreamClass == null)
810
      throw new NotActiveException("defaultReadObject called by non-active"
811
                                   + " class and/or object");
812
 
813
    if (fieldsAlreadyRead)
814
      throw new NotActiveException("defaultReadObject called but fields "
815
                                   + "already read from stream (by "
816
                                   + "defaultReadObject or readFields)");
817
 
818
    boolean oldmode = setBlockDataMode(false);
819
    readFields(this.currentObject, this.currentObjectStreamClass);
820
    setBlockDataMode(oldmode);
821
 
822
    fieldsAlreadyRead = true;
823
  }
824
 
825
 
826
  /**
827
   * Registers a <code>ObjectInputValidation</code> to be carried out
828
   * on the object graph currently being deserialized before it is
829
   * returned to the original caller of <code>readObject ()</code>.
830
   * The order of validation for multiple
831
   * <code>ObjectInputValidation</code>s can be controled using
832
   * <code>priority</code>.  Validators with higher priorities are
833
   * called first.
834
   *
835
   * @see java.io.ObjectInputValidation
836
   *
837
   * @exception InvalidObjectException <code>validator</code> is
838
   * <code>null</code>
839
   *
840
   * @exception NotActiveException an attempt was made to add a
841
   * validator outside of the <code>readObject</code> method of the
842
   * object currently being deserialized
843
   */
844
  public void registerValidation(ObjectInputValidation validator,
845
                                 int priority)
846
    throws InvalidObjectException, NotActiveException
847
  {
848
    if (this.currentObject == null || this.currentObjectStreamClass == null)
849
      throw new NotActiveException("registerValidation called by non-active "
850
                                   + "class and/or object");
851
 
852
    if (validator == null)
853
      throw new InvalidObjectException("attempt to add a null "
854
                                       + "ObjectInputValidation object");
855
 
856
    if (currentObjectValidators == null)
857
      currentObjectValidators = new TreeSet<ValidatorAndPriority>();
858
 
859
    currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
860
  }
861
 
862
 
863
  /**
864
   * Called when a class is being deserialized.  This is a hook to
865
   * allow subclasses to read in information written by the
866
   * <code>annotateClass (Class)</code> method of an
867
   * <code>ObjectOutputStream</code>.
868
   *
869
   * This implementation looks up the active call stack for a
870
   * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
871
   * it is used to load the class associated with <code>osc</code>,
872
   * otherwise, the default system <code>ClassLoader</code> is used.
873
   *
874
   * @exception IOException Exception from underlying
875
   * <code>OutputStream</code>.
876
   *
877
   * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
878
   */
879
  protected Class<?> resolveClass(ObjectStreamClass osc)
880
    throws ClassNotFoundException, IOException
881
  {
882
    String name = osc.getName();
883
    try
884
      {
885
        return Class.forName(name, true, currentLoader());
886
      }
887
    catch(ClassNotFoundException x)
888
      {
889
        if (name.equals("void"))
890
          return Void.TYPE;
891
        else if (name.equals("boolean"))
892
          return Boolean.TYPE;
893
        else if (name.equals("byte"))
894
          return Byte.TYPE;
895
        else if (name.equals("char"))
896
          return Character.TYPE;
897
        else if (name.equals("short"))
898
          return Short.TYPE;
899
        else if (name.equals("int"))
900
          return Integer.TYPE;
901
        else if (name.equals("long"))
902
          return Long.TYPE;
903
        else if (name.equals("float"))
904
          return Float.TYPE;
905
        else if (name.equals("double"))
906
          return Double.TYPE;
907
        else
908
          throw x;
909
      }
910
  }
911
 
912
  /**
913
   * Returns the most recent user defined ClassLoader on the execution stack
914
   * or null if none is found.
915
   */
916
  private ClassLoader currentLoader()
917
  {
918
    return VMStackWalker.firstNonNullClassLoader();
919
  }
920
 
921
  /**
922
   * Lookup a class stored in the local hashtable. If it is not
923
   * use the global lookup function in ObjectStreamClass to build
924
   * the ObjectStreamClass. This method is requested according to
925
   * the behaviour detected in the JDK by Kaffe's team.
926
   *
927
   * @param clazz Class to lookup in the hash table or for which
928
   * we must build a descriptor.
929
   * @return A valid instance of ObjectStreamClass corresponding
930
   * to the specified class.
931
   */
932
  private ObjectStreamClass lookupClass(Class clazz)
933
  {
934
    if (clazz == null)
935
      return null;
936
 
937
    ObjectStreamClass oclazz;
938
    oclazz = classLookupTable.get(clazz);
939
    if (oclazz == null)
940
      return ObjectStreamClass.lookup(clazz);
941
    else
942
      return oclazz;
943
  }
944
 
945
  /**
946
   * Reconstruct class hierarchy the same way {@link
947
   * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
948
   * instead of ObjectStreamClass.lookup.
949
   *
950
   * @param clazz This is the class for which we want the hierarchy.
951
   *
952
   * @return An array of valid {@link java.io.ObjectStreamClass} instances which
953
   * represent the class hierarchy for clazz.
954
   */
955
  private ObjectStreamClass[] hierarchy(Class clazz)
956
  {
957
    ObjectStreamClass osc = lookupClass(clazz);
958
 
959
    return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
960
  }
961
 
962
  /**
963
   * Allows subclasses to resolve objects that are read from the
964
   * stream with other objects to be returned in their place.  This
965
   * method is called the first time each object is encountered.
966
   *
967
   * This method must be enabled before it will be called in the
968
   * serialization process.
969
   *
970
   * @exception IOException Exception from underlying
971
   * <code>OutputStream</code>.
972
   *
973
   * @see #enableResolveObject(boolean)
974
   */
975
  protected Object resolveObject(Object obj) throws IOException
976
  {
977
    return obj;
978
  }
979
 
980
 
981
  protected Class<?> resolveProxyClass(String[] intfs)
982
    throws IOException, ClassNotFoundException
983
  {
984
    ClassLoader cl = currentLoader();
985
 
986
    Class<?>[] clss = new Class<?>[intfs.length];
987
    if(cl == null)
988
      {
989
        for (int i = 0; i < intfs.length; i++)
990
          clss[i] = Class.forName(intfs[i]);
991
        cl = ClassLoader.getSystemClassLoader();
992
      }
993
    else
994
      for (int i = 0; i < intfs.length; i++)
995
        clss[i] = Class.forName(intfs[i], false, cl);
996
    try
997
      {
998
        return Proxy.getProxyClass(cl, clss);
999
      }
1000
    catch (IllegalArgumentException e)
1001
      {
1002
        throw new ClassNotFoundException(null, e);
1003
      }
1004
  }
1005
 
1006
  /**
1007
   * If <code>enable</code> is <code>true</code> and this object is
1008
   * trusted, then <code>resolveObject (Object)</code> will be called
1009
   * in subsequent calls to <code>readObject (Object)</code>.
1010
   * Otherwise, <code>resolveObject (Object)</code> will not be called.
1011
   *
1012
   * @exception SecurityException This class is not trusted.
1013
   */
1014
  protected boolean enableResolveObject (boolean enable)
1015
    throws SecurityException
1016
  {
1017
    if (enable)
1018
      {
1019
        SecurityManager sm = System.getSecurityManager();
1020
        if (sm != null)
1021
          sm.checkPermission(new SerializablePermission("enableSubstitution"));
1022
      }
1023
 
1024
    boolean old_val = this.resolveEnabled;
1025
    this.resolveEnabled = enable;
1026
    return old_val;
1027
  }
1028
 
1029
  /**
1030
   * Reads stream magic and stream version information from the
1031
   * underlying stream.
1032
   *
1033
   * @exception IOException Exception from underlying stream.
1034
   *
1035
   * @exception StreamCorruptedException An invalid stream magic
1036
   * number or stream version was read from the stream.
1037
   */
1038
  protected void readStreamHeader()
1039
    throws IOException, StreamCorruptedException
1040
  {
1041
    if(dump) dumpElement("STREAM MAGIC ");
1042
    if (this.realInputStream.readShort() != STREAM_MAGIC)
1043
      throw new StreamCorruptedException("Invalid stream magic number");
1044
 
1045
    if(dump) dumpElementln("STREAM VERSION ");
1046
    if (this.realInputStream.readShort() != STREAM_VERSION)
1047
      throw new StreamCorruptedException("Invalid stream version number");
1048
  }
1049
 
1050
  public int read() throws IOException
1051
  {
1052
    if (this.readDataFromBlock)
1053
      {
1054
        if (this.blockDataPosition >= this.blockDataBytes)
1055
          readNextBlock();
1056
        return (this.blockData[this.blockDataPosition++] & 0xff);
1057
      }
1058
    else
1059
      return this.realInputStream.read();
1060
  }
1061
 
1062
  public int read(byte[] data, int offset, int length) throws IOException
1063
  {
1064
    if (this.readDataFromBlock)
1065
      {
1066
        int remain = this.blockDataBytes - this.blockDataPosition;
1067
        if (remain == 0)
1068
          {
1069
            readNextBlock();
1070
            remain = this.blockDataBytes - this.blockDataPosition;
1071
          }
1072
        length = Math.min(length, remain);
1073
        System.arraycopy(this.blockData, this.blockDataPosition,
1074
                         data, offset, length);
1075
        this.blockDataPosition += length;
1076
 
1077
        return length;
1078
      }
1079
    else
1080
      return this.realInputStream.read(data, offset, length);
1081
  }
1082
 
1083
  public int available() throws IOException
1084
  {
1085
    if (this.readDataFromBlock)
1086
      {
1087
        if (this.blockDataPosition >= this.blockDataBytes)
1088
          readNextBlock ();
1089
 
1090
        return this.blockDataBytes - this.blockDataPosition;
1091
      }
1092
    else
1093
      return this.realInputStream.available();
1094
  }
1095
 
1096
  public void close() throws IOException
1097
  {
1098
    this.realInputStream.close();
1099
  }
1100
 
1101
  public boolean readBoolean() throws IOException
1102
  {
1103
    boolean switchmode = true;
1104
    boolean oldmode = this.readDataFromBlock;
1105
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1106
      switchmode = false;
1107
    if (switchmode)
1108
      oldmode = setBlockDataMode (true);
1109
    boolean value = this.dataInputStream.readBoolean ();
1110
    if (switchmode)
1111
      setBlockDataMode (oldmode);
1112
    return value;
1113
  }
1114
 
1115
  public byte readByte() throws IOException
1116
  {
1117
    boolean switchmode = true;
1118
    boolean oldmode = this.readDataFromBlock;
1119
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1120
      switchmode = false;
1121
    if (switchmode)
1122
      oldmode = setBlockDataMode(true);
1123
    byte value = this.dataInputStream.readByte();
1124
    if (switchmode)
1125
      setBlockDataMode(oldmode);
1126
    return value;
1127
  }
1128
 
1129
  public int readUnsignedByte() throws IOException
1130
  {
1131
    boolean switchmode = true;
1132
    boolean oldmode = this.readDataFromBlock;
1133
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1134
      switchmode = false;
1135
    if (switchmode)
1136
      oldmode = setBlockDataMode(true);
1137
    int value = this.dataInputStream.readUnsignedByte();
1138
    if (switchmode)
1139
      setBlockDataMode(oldmode);
1140
    return value;
1141
  }
1142
 
1143
  public short readShort() throws IOException
1144
  {
1145
    boolean switchmode = true;
1146
    boolean oldmode = this.readDataFromBlock;
1147
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1148
      switchmode = false;
1149
    if (switchmode)
1150
      oldmode = setBlockDataMode(true);
1151
    short value = this.dataInputStream.readShort();
1152
    if (switchmode)
1153
      setBlockDataMode(oldmode);
1154
    return value;
1155
  }
1156
 
1157
  public int readUnsignedShort() throws IOException
1158
  {
1159
    boolean switchmode = true;
1160
    boolean oldmode = this.readDataFromBlock;
1161
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1162
      switchmode = false;
1163
    if (switchmode)
1164
      oldmode = setBlockDataMode(true);
1165
    int value = this.dataInputStream.readUnsignedShort();
1166
    if (switchmode)
1167
      setBlockDataMode(oldmode);
1168
    return value;
1169
  }
1170
 
1171
  public char readChar() throws IOException
1172
  {
1173
    boolean switchmode = true;
1174
    boolean oldmode = this.readDataFromBlock;
1175
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1176
      switchmode = false;
1177
    if (switchmode)
1178
      oldmode = setBlockDataMode(true);
1179
    char value = this.dataInputStream.readChar();
1180
    if (switchmode)
1181
      setBlockDataMode(oldmode);
1182
    return value;
1183
  }
1184
 
1185
  public int readInt() throws IOException
1186
  {
1187
    boolean switchmode = true;
1188
    boolean oldmode = this.readDataFromBlock;
1189
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1190
      switchmode = false;
1191
    if (switchmode)
1192
      oldmode = setBlockDataMode(true);
1193
    int value = this.dataInputStream.readInt();
1194
    if (switchmode)
1195
      setBlockDataMode(oldmode);
1196
    return value;
1197
  }
1198
 
1199
  public long readLong() throws IOException
1200
  {
1201
    boolean switchmode = true;
1202
    boolean oldmode = this.readDataFromBlock;
1203
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1204
      switchmode = false;
1205
    if (switchmode)
1206
      oldmode = setBlockDataMode(true);
1207
    long value = this.dataInputStream.readLong();
1208
    if (switchmode)
1209
      setBlockDataMode(oldmode);
1210
    return value;
1211
  }
1212
 
1213
  public float readFloat() throws IOException
1214
  {
1215
    boolean switchmode = true;
1216
    boolean oldmode = this.readDataFromBlock;
1217
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1218
      switchmode = false;
1219
    if (switchmode)
1220
      oldmode = setBlockDataMode(true);
1221
    float value = this.dataInputStream.readFloat();
1222
    if (switchmode)
1223
      setBlockDataMode(oldmode);
1224
    return value;
1225
  }
1226
 
1227
  public double readDouble() throws IOException
1228
  {
1229
    boolean switchmode = true;
1230
    boolean oldmode = this.readDataFromBlock;
1231
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1232
      switchmode = false;
1233
    if (switchmode)
1234
      oldmode = setBlockDataMode(true);
1235
    double value = this.dataInputStream.readDouble();
1236
    if (switchmode)
1237
      setBlockDataMode(oldmode);
1238
    return value;
1239
  }
1240
 
1241
  public void readFully(byte data[]) throws IOException
1242
  {
1243
    this.dataInputStream.readFully(data);
1244
  }
1245
 
1246
  public void readFully(byte data[], int offset, int size)
1247
    throws IOException
1248
  {
1249
    this.dataInputStream.readFully(data, offset, size);
1250
  }
1251
 
1252
  public int skipBytes(int len) throws IOException
1253
  {
1254
    return this.dataInputStream.skipBytes(len);
1255
  }
1256
 
1257
  /**
1258
   * @deprecated
1259
   * @see java.io.DataInputStream#readLine ()
1260
   */
1261
  public String readLine() throws IOException
1262
  {
1263
    return this.dataInputStream.readLine();
1264
  }
1265
 
1266
  public String readUTF() throws IOException
1267
  {
1268
    return this.dataInputStream.readUTF();
1269
  }
1270
 
1271
  /**
1272
   * This class allows a class to specify exactly which fields should
1273
   * be read, and what values should be read for these fields.
1274
   *
1275
   * XXX: finish up comments
1276
   */
1277
  public abstract static class GetField
1278
  {
1279
    public abstract ObjectStreamClass getObjectStreamClass();
1280
 
1281
    public abstract boolean defaulted(String name)
1282
      throws IOException, IllegalArgumentException;
1283
 
1284
    public abstract boolean get(String name, boolean defvalue)
1285
      throws IOException, IllegalArgumentException;
1286
 
1287
    public abstract char get(String name, char defvalue)
1288
      throws IOException, IllegalArgumentException;
1289
 
1290
    public abstract byte get(String name, byte defvalue)
1291
      throws IOException, IllegalArgumentException;
1292
 
1293
    public abstract short get(String name, short defvalue)
1294
      throws IOException, IllegalArgumentException;
1295
 
1296
    public abstract int get(String name, int defvalue)
1297
      throws IOException, IllegalArgumentException;
1298
 
1299
    public abstract long get(String name, long defvalue)
1300
      throws IOException, IllegalArgumentException;
1301
 
1302
    public abstract float get(String name, float defvalue)
1303
      throws IOException, IllegalArgumentException;
1304
 
1305
    public abstract double get(String name, double defvalue)
1306
      throws IOException, IllegalArgumentException;
1307
 
1308
    public abstract Object get(String name, Object defvalue)
1309
      throws IOException, IllegalArgumentException;
1310
  }
1311
 
1312
  /**
1313
   * This method should be called by a method called 'readObject' in the
1314
   * deserializing class (if present). It cannot (and should not)be called
1315
   * outside of it. Its goal is to read all fields in the real input stream
1316
   * and keep them accessible through the {@link GetField} class. Calling
1317
   * this method will not alter the deserializing object.
1318
   *
1319
   * @return A valid freshly created 'GetField' instance to get access to
1320
   * the deserialized stream.
1321
   * @throws IOException An input/output exception occured.
1322
   * @throws ClassNotFoundException
1323
   * @throws NotActiveException
1324
   */
1325
  public GetField readFields()
1326
    throws IOException, ClassNotFoundException, NotActiveException
1327
  {
1328
    if (this.currentObject == null || this.currentObjectStreamClass == null)
1329
      throw new NotActiveException("readFields called by non-active class and/or object");
1330
 
1331
    if (prereadFields != null)
1332
      return prereadFields;
1333
 
1334
    if (fieldsAlreadyRead)
1335
      throw new NotActiveException("readFields called but fields already read from"
1336
                                   + " stream (by defaultReadObject or readFields)");
1337
 
1338
    final ObjectStreamClass clazz = this.currentObjectStreamClass;
1339
    final byte[] prim_field_data = new byte[clazz.primFieldSize];
1340
    final Object[] objs = new Object[clazz.objectFieldCount];
1341
 
1342
    // Apparently Block data is not used with GetField as per
1343
    // empirical evidence against JDK 1.2.  Also see Mauve test
1344
    // java.io.ObjectInputOutput.Test.GetPutField.
1345
    boolean oldmode = setBlockDataMode(false);
1346
    readFully(prim_field_data);
1347
    for (int i = 0; i < objs.length; ++ i)
1348
      objs[i] = readObject();
1349
    setBlockDataMode(oldmode);
1350
 
1351
    prereadFields = new GetField()
1352
      {
1353
        public ObjectStreamClass getObjectStreamClass()
1354
        {
1355
          return clazz;
1356
        }
1357
 
1358
        public boolean defaulted(String name)
1359
          throws IOException, IllegalArgumentException
1360
        {
1361
          ObjectStreamField f = clazz.getField(name);
1362
 
1363
          /* First if we have a serialized field use the descriptor */
1364
          if (f != null)
1365
            {
1366
              /* It is in serialPersistentFields but setClass tells us
1367
               * it should not be set. This value is defaulted.
1368
               */
1369
              if (f.isPersistent() && !f.isToSet())
1370
                return true;
1371
 
1372
              return false;
1373
            }
1374
 
1375
          /* This is not a serialized field. There should be
1376
           * a default value only if the field really exists.
1377
           */
1378
          try
1379
            {
1380
              return (clazz.forClass().getDeclaredField (name) != null);
1381
            }
1382
          catch (NoSuchFieldException e)
1383
            {
1384
              throw new IllegalArgumentException(e);
1385
            }
1386
        }
1387
 
1388
        public boolean get(String name, boolean defvalue)
1389
          throws IOException, IllegalArgumentException
1390
        {
1391
          ObjectStreamField field = getField(name, Boolean.TYPE);
1392
 
1393
          if (field == null)
1394
            return defvalue;
1395
 
1396
          return prim_field_data[field.getOffset()] == 0 ? false : true;
1397
        }
1398
 
1399
        public char get(String name, char defvalue)
1400
          throws IOException, IllegalArgumentException
1401
        {
1402
          ObjectStreamField field = getField(name, Character.TYPE);
1403
 
1404
          if (field == null)
1405
            return defvalue;
1406
 
1407
          int off = field.getOffset();
1408
 
1409
          return (char)(((prim_field_data[off++] & 0xFF) << 8)
1410
                        | (prim_field_data[off] & 0xFF));
1411
        }
1412
 
1413
        public byte get(String name, byte defvalue)
1414
          throws IOException, IllegalArgumentException
1415
        {
1416
          ObjectStreamField field = getField(name, Byte.TYPE);
1417
 
1418
          if (field == null)
1419
            return defvalue;
1420
 
1421
          return prim_field_data[field.getOffset()];
1422
        }
1423
 
1424
        public short get(String name, short defvalue)
1425
          throws IOException, IllegalArgumentException
1426
        {
1427
          ObjectStreamField field = getField(name, Short.TYPE);
1428
 
1429
          if (field == null)
1430
            return defvalue;
1431
 
1432
          int off = field.getOffset();
1433
 
1434
          return (short)(((prim_field_data[off++] & 0xFF) << 8)
1435
                         | (prim_field_data[off] & 0xFF));
1436
        }
1437
 
1438
        public int get(String name, int defvalue)
1439
          throws IOException, IllegalArgumentException
1440
        {
1441
          ObjectStreamField field = getField(name, Integer.TYPE);
1442
 
1443
          if (field == null)
1444
            return defvalue;
1445
 
1446
          int off = field.getOffset();
1447
 
1448
          return ((prim_field_data[off++] & 0xFF) << 24)
1449
            | ((prim_field_data[off++] & 0xFF) << 16)
1450
            | ((prim_field_data[off++] & 0xFF) << 8)
1451
            | (prim_field_data[off] & 0xFF);
1452
        }
1453
 
1454
        public long get(String name, long defvalue)
1455
          throws IOException, IllegalArgumentException
1456
        {
1457
          ObjectStreamField field = getField(name, Long.TYPE);
1458
 
1459
          if (field == null)
1460
            return defvalue;
1461
 
1462
          int off = field.getOffset();
1463
 
1464
          return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1465
                        | ((prim_field_data[off++] & 0xFFL) << 48)
1466
                        | ((prim_field_data[off++] & 0xFFL) << 40)
1467
                        | ((prim_field_data[off++] & 0xFFL) << 32)
1468
                        | ((prim_field_data[off++] & 0xFF) << 24)
1469
                        | ((prim_field_data[off++] & 0xFF) << 16)
1470
                        | ((prim_field_data[off++] & 0xFF) << 8)
1471
                        | (prim_field_data[off] & 0xFF));
1472
        }
1473
 
1474
        public float get(String name, float defvalue)
1475
          throws IOException, IllegalArgumentException
1476
        {
1477
          ObjectStreamField field = getField(name, Float.TYPE);
1478
 
1479
          if (field == null)
1480
            return defvalue;
1481
 
1482
          int off = field.getOffset();
1483
 
1484
          return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1485
                                      | ((prim_field_data[off++] & 0xFF) << 16)
1486
                                      | ((prim_field_data[off++] & 0xFF) << 8)
1487
                                      | (prim_field_data[off] & 0xFF));
1488
        }
1489
 
1490
        public double get(String name, double defvalue)
1491
          throws IOException, IllegalArgumentException
1492
        {
1493
          ObjectStreamField field = getField(name, Double.TYPE);
1494
 
1495
          if (field == null)
1496
            return defvalue;
1497
 
1498
          int off = field.getOffset();
1499
 
1500
          return Double.longBitsToDouble
1501
            ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1502
                      | ((prim_field_data[off++] & 0xFFL) << 48)
1503
                      | ((prim_field_data[off++] & 0xFFL) << 40)
1504
                      | ((prim_field_data[off++] & 0xFFL) << 32)
1505
                      | ((prim_field_data[off++] & 0xFF) << 24)
1506
                      | ((prim_field_data[off++] & 0xFF) << 16)
1507
                      | ((prim_field_data[off++] & 0xFF) << 8)
1508
                      | (prim_field_data[off] & 0xFF)));
1509
        }
1510
 
1511
        public Object get(String name, Object defvalue)
1512
          throws IOException, IllegalArgumentException
1513
        {
1514
          ObjectStreamField field =
1515
            getField(name, defvalue == null ? null : defvalue.getClass ());
1516
 
1517
          if (field == null)
1518
            return defvalue;
1519
 
1520
          return objs[field.getOffset()];
1521
        }
1522
 
1523
        private ObjectStreamField getField(String name, Class type)
1524
          throws IllegalArgumentException
1525
        {
1526
          ObjectStreamField field = clazz.getField(name);
1527
          boolean illegal = false;
1528
 
1529
          // XXX This code is horrible and needs to be rewritten!
1530
          try
1531
            {
1532
              try
1533
                {
1534
                  Class field_type = field.getType();
1535
 
1536
                  if (type == field_type ||
1537
                      (type == null && !field_type.isPrimitive()))
1538
                    {
1539
                      /* See defaulted */
1540
                      return field;
1541
                    }
1542
 
1543
                  illegal = true;
1544
                  throw new IllegalArgumentException
1545
                    ("Field requested is of type "
1546
                     + field_type.getName()
1547
                     + ", but requested type was "
1548
                     + (type == null ?  "Object" : type.getName()));
1549
                }
1550
              catch (NullPointerException _)
1551
                {
1552
                  /* Here we catch NullPointerException, because it may
1553
                     only come from the call 'field.getType()'. If field
1554
                     is null, we have to return null and classpath ethic
1555
                     say we must try to avoid 'if (xxx == null)'.
1556
                  */
1557
                }
1558
              catch (IllegalArgumentException e)
1559
                {
1560
                  throw e;
1561
                }
1562
 
1563
              return null;
1564
            }
1565
          finally
1566
            {
1567
              /* If this is an unassigned field we should return
1568
               * the default value.
1569
               */
1570
              if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1571
                return null;
1572
 
1573
              /* We do not want to modify transient fields. They should
1574
               * be left to 0.
1575
               */
1576
              try
1577
                {
1578
                  Field f = clazz.forClass().getDeclaredField(name);
1579
                  if (Modifier.isTransient(f.getModifiers()))
1580
                    throw new IllegalArgumentException
1581
                      ("no such field (non transient) " + name);
1582
                  if (field == null && f.getType() != type)
1583
                    throw new IllegalArgumentException
1584
                      ("Invalid requested type for field " + name);
1585
                }
1586
              catch (NoSuchFieldException e)
1587
                {
1588
                  if (field == null)
1589
                    throw new IllegalArgumentException(e);
1590
                }
1591
 
1592
            }
1593
        }
1594
      };
1595
 
1596
    fieldsAlreadyRead = true;
1597
    return prereadFields;
1598
  }
1599
 
1600
  /**
1601
   * Protected constructor that allows subclasses to override
1602
   * deserialization.  This constructor should be called by subclasses
1603
   * that wish to override <code>readObject (Object)</code>.  This
1604
   * method does a security check <i>NOTE: currently not
1605
   * implemented</i>, then sets a flag that informs
1606
   * <code>readObject (Object)</code> to call the subclasses
1607
   * <code>readObjectOverride (Object)</code> method.
1608
   *
1609
   * @see #readObjectOverride()
1610
   */
1611
  protected ObjectInputStream()
1612
    throws IOException, SecurityException
1613
  {
1614
    SecurityManager sec_man = System.getSecurityManager();
1615
    if (sec_man != null)
1616
      sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1617
    this.useSubclassMethod = true;
1618
  }
1619
 
1620
  /**
1621
   * This method allows subclasses to override the default
1622
   * de serialization mechanism provided by
1623
   * <code>ObjectInputStream</code>.  To make this method be used for
1624
   * writing objects, subclasses must invoke the 0-argument
1625
   * constructor on this class from their constructor.
1626
   *
1627
   * @see #ObjectInputStream()
1628
   */
1629
  protected Object readObjectOverride()
1630
    throws ClassNotFoundException, IOException, OptionalDataException
1631
  {
1632
    throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1633
  }
1634
 
1635
  /**
1636
   * Assigns the next available handle to <code>obj</code>.
1637
   *
1638
   * @param obj The object for which we want a new handle.
1639
   * @param shared True if the handle should be shared
1640
   *               with later calls.
1641
   * @return A valid handle for the specified object.
1642
   */
1643
  private int assignNewHandle(Object obj, boolean shared)
1644
  {
1645
    int handle = this.nextOID;
1646
    this.nextOID = handle + 1;
1647
    rememberHandle(obj,shared,handle);
1648
    return handle;
1649
  }
1650
 
1651
  /**
1652
   * Remember the object associated with the given handle.
1653
   *
1654
   * @param obj an object
1655
   * @param shared true if the reference should be shared
1656
   *               with later calls.
1657
   * @param handle a handle, must be >= baseWireHandle
1658
   *
1659
   * @see #lookupHandle
1660
   */
1661
  private void rememberHandle(Object obj, boolean shared,
1662
                              int handle)
1663
  {
1664
    handles.put(handle, new Pair<Boolean,Object>(shared, obj));
1665
  }
1666
 
1667
  /**
1668
   * Look up the object associated with a given handle.
1669
   *
1670
   * @param handle a handle, must be >= baseWireHandle
1671
   * @return the object remembered for handle or null if none.
1672
   * @throws StreamCorruptedException if the handle is invalid.
1673
   * @throws InvalidObjectException if the reference is not shared.
1674
   * @see #rememberHandle
1675
   */
1676
  private Object lookupHandle(int handle)
1677
    throws ObjectStreamException
1678
  {
1679
    Pair<Boolean,Object> result = handles.get(handle);
1680
    if (result == null)
1681
      throw new StreamCorruptedException("The handle, " +
1682
                                         Integer.toHexString(handle) +
1683
                                         ", is invalid.");
1684
    if (!result.getLeft())
1685
      throw new InvalidObjectException("The handle, " +
1686
                                       Integer.toHexString(handle) +
1687
                                       ", is not shared.");
1688
    return result.getRight();
1689
  }
1690
 
1691
  private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
1692
                                   boolean shared)
1693
    throws IOException
1694
  {
1695
    if (osc != null && obj instanceof Serializable)
1696
      {
1697
        try
1698
          {
1699
            Method m = osc.readResolveMethod;
1700
            if(m != null)
1701
            {
1702
                obj = m.invoke(obj, new Object[] {});
1703
            }
1704
          }
1705
        catch (IllegalAccessException ignore)
1706
          {
1707
          }
1708
        catch (InvocationTargetException exception)
1709
          {
1710
            Throwable cause = exception.getCause();
1711
            if (cause instanceof ObjectStreamException)
1712
              throw (ObjectStreamException) cause;
1713
            else if (cause instanceof RuntimeException)
1714
              throw (RuntimeException) cause;
1715
            else if (cause instanceof Error)
1716
              throw (Error) cause;
1717
          }
1718
      }
1719
 
1720
    if (this.resolveEnabled)
1721
      obj = resolveObject(obj);
1722
 
1723
    rememberHandle(obj, shared, handle);
1724
    if (!shared)
1725
      {
1726
        if (obj instanceof byte[])
1727
          return ((byte[]) obj).clone();
1728
        if (obj instanceof short[])
1729
          return ((short[]) obj).clone();
1730
        if (obj instanceof int[])
1731
          return ((int[]) obj).clone();
1732
        if (obj instanceof long[])
1733
          return ((long[]) obj).clone();
1734
        if (obj instanceof char[])
1735
          return ((char[]) obj).clone();
1736
        if (obj instanceof boolean[])
1737
          return ((boolean[]) obj).clone();
1738
        if (obj instanceof float[])
1739
          return ((float[]) obj).clone();
1740
        if (obj instanceof double[])
1741
          return ((double[]) obj).clone();
1742
        if (obj instanceof Object[])
1743
          return ((Object[]) obj).clone();
1744
      }
1745
    return obj;
1746
  }
1747
 
1748
  private void clearHandles()
1749
  {
1750
    handles.clear();
1751
    this.nextOID = baseWireHandle;
1752
  }
1753
 
1754
  private void readNextBlock() throws IOException
1755
  {
1756
    byte marker = this.realInputStream.readByte();
1757
    while (marker == TC_RESET)
1758
      {
1759
        if(dump) dumpElementln("RESET");
1760
        clearHandles();
1761
        marker = this.realInputStream.readByte();
1762
      }
1763
    readNextBlock(marker);
1764
  }
1765
 
1766
  private void readNextBlock(byte marker) throws IOException
1767
  {
1768
    if (marker == TC_BLOCKDATA)
1769
      {
1770
        if(dump) dumpElement("BLOCK DATA SIZE=");
1771
        this.blockDataBytes = this.realInputStream.readUnsignedByte();
1772
        if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1773
      }
1774
    else if (marker == TC_BLOCKDATALONG)
1775
      {
1776
        if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1777
        this.blockDataBytes = this.realInputStream.readInt();
1778
        if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1779
      }
1780
    else
1781
      {
1782
        throw new EOFException("Attempt to read primitive data, but no data block is active.");
1783
      }
1784
 
1785
    if (this.blockData.length < this.blockDataBytes)
1786
      this.blockData = new byte[this.blockDataBytes];
1787
 
1788
    this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1789
    this.blockDataPosition = 0;
1790
  }
1791
 
1792
  private void readArrayElements (Object array, Class clazz)
1793
    throws ClassNotFoundException, IOException
1794
  {
1795
    if (clazz.isPrimitive())
1796
      {
1797
        if (clazz == Boolean.TYPE)
1798
          {
1799
            boolean[] cast_array = (boolean[])array;
1800
            for (int i=0; i < cast_array.length; i++)
1801
              cast_array[i] = this.realInputStream.readBoolean();
1802
            return;
1803
          }
1804
        if (clazz == Byte.TYPE)
1805
          {
1806
            byte[] cast_array = (byte[])array;
1807
            for (int i=0; i < cast_array.length; i++)
1808
              cast_array[i] = this.realInputStream.readByte();
1809
            return;
1810
          }
1811
        if (clazz == Character.TYPE)
1812
          {
1813
            char[] cast_array = (char[])array;
1814
            for (int i=0; i < cast_array.length; i++)
1815
              cast_array[i] = this.realInputStream.readChar();
1816
            return;
1817
          }
1818
        if (clazz == Double.TYPE)
1819
          {
1820
            double[] cast_array = (double[])array;
1821
            for (int i=0; i < cast_array.length; i++)
1822
              cast_array[i] = this.realInputStream.readDouble();
1823
            return;
1824
          }
1825
        if (clazz == Float.TYPE)
1826
          {
1827
            float[] cast_array = (float[])array;
1828
            for (int i=0; i < cast_array.length; i++)
1829
              cast_array[i] = this.realInputStream.readFloat();
1830
            return;
1831
          }
1832
        if (clazz == Integer.TYPE)
1833
          {
1834
            int[] cast_array = (int[])array;
1835
            for (int i=0; i < cast_array.length; i++)
1836
              cast_array[i] = this.realInputStream.readInt();
1837
            return;
1838
          }
1839
        if (clazz == Long.TYPE)
1840
          {
1841
            long[] cast_array = (long[])array;
1842
            for (int i=0; i < cast_array.length; i++)
1843
              cast_array[i] = this.realInputStream.readLong();
1844
            return;
1845
          }
1846
        if (clazz == Short.TYPE)
1847
          {
1848
            short[] cast_array = (short[])array;
1849
            for (int i=0; i < cast_array.length; i++)
1850
              cast_array[i] = this.realInputStream.readShort();
1851
            return;
1852
          }
1853
      }
1854
    else
1855
      {
1856
        Object[] cast_array = (Object[])array;
1857
        for (int i=0; i < cast_array.length; i++)
1858
          cast_array[i] = readObject();
1859
      }
1860
  }
1861
 
1862
  private void readFields (Object obj, ObjectStreamClass stream_osc)
1863
    throws ClassNotFoundException, IOException
1864
  {
1865
    ObjectStreamField[] fields = stream_osc.fieldMapping;
1866
 
1867
    for (int i = 0; i < fields.length; i += 2)
1868
      {
1869
        ObjectStreamField stream_field = fields[i];
1870
        ObjectStreamField real_field = fields[i + 1];
1871
        boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1872
        boolean set_value = (real_field != null && real_field.isToSet());
1873
        String field_name;
1874
        char type;
1875
 
1876
        if (stream_field != null)
1877
          {
1878
            field_name = stream_field.getName();
1879
            type = stream_field.getTypeCode();
1880
          }
1881
        else
1882
          {
1883
            field_name = real_field.getName();
1884
            type = real_field.getTypeCode();
1885
          }
1886
 
1887
        switch(type)
1888
          {
1889
          case 'Z':
1890
            {
1891
              boolean value =
1892
                read_value ? this.realInputStream.readBoolean() : false;
1893
              if (dump && read_value && set_value)
1894
                dumpElementln("  " + field_name + ": " + value);
1895
              if (set_value)
1896
                real_field.setBooleanField(obj, value);
1897
              break;
1898
            }
1899
          case 'B':
1900
            {
1901
              byte value =
1902
                read_value ? this.realInputStream.readByte() : 0;
1903
              if (dump && read_value && set_value)
1904
                dumpElementln("  " + field_name + ": " + value);
1905
              if (set_value)
1906
                real_field.setByteField(obj, value);
1907
              break;
1908
            }
1909
          case 'C':
1910
            {
1911
              char value =
1912
                read_value ? this.realInputStream.readChar(): 0;
1913
              if (dump && read_value && set_value)
1914
                dumpElementln("  " + field_name + ": " + value);
1915
              if (set_value)
1916
                real_field.setCharField(obj, value);
1917
              break;
1918
            }
1919
          case 'D':
1920
            {
1921
              double value =
1922
                read_value ? this.realInputStream.readDouble() : 0;
1923
              if (dump && read_value && set_value)
1924
                dumpElementln("  " + field_name + ": " + value);
1925
              if (set_value)
1926
                real_field.setDoubleField(obj, value);
1927
              break;
1928
            }
1929
          case 'F':
1930
            {
1931
              float value =
1932
                read_value ? this.realInputStream.readFloat() : 0;
1933
              if (dump && read_value && set_value)
1934
                dumpElementln("  " + field_name + ": " + value);
1935
              if (set_value)
1936
                real_field.setFloatField(obj, value);
1937
              break;
1938
            }
1939
          case 'I':
1940
            {
1941
              int value =
1942
                read_value ? this.realInputStream.readInt() : 0;
1943
              if (dump && read_value && set_value)
1944
                dumpElementln("  " + field_name + ": " + value);
1945
              if (set_value)
1946
                real_field.setIntField(obj, value);
1947
              break;
1948
            }
1949
          case 'J':
1950
            {
1951
              long value =
1952
                read_value ? this.realInputStream.readLong() : 0;
1953
              if (dump && read_value && set_value)
1954
                dumpElementln("  " + field_name + ": " + value);
1955
              if (set_value)
1956
                real_field.setLongField(obj, value);
1957
              break;
1958
            }
1959
          case 'S':
1960
            {
1961
              short value =
1962
                read_value ? this.realInputStream.readShort() : 0;
1963
              if (dump && read_value && set_value)
1964
                dumpElementln("  " + field_name + ": " + value);
1965
              if (set_value)
1966
                real_field.setShortField(obj, value);
1967
              break;
1968
            }
1969
          case 'L':
1970
          case '[':
1971
            {
1972
              Object value =
1973
                read_value ? readObject() : null;
1974
              if (set_value)
1975
                real_field.setObjectField(obj, value);
1976
              break;
1977
            }
1978
          default:
1979
            throw new InternalError("Invalid type code: " + type);
1980
          }
1981
      }
1982
  }
1983
 
1984
  // Toggles writing primitive data to block-data buffer.
1985
  private boolean setBlockDataMode (boolean on)
1986
  {
1987
    boolean oldmode = this.readDataFromBlock;
1988
    this.readDataFromBlock = on;
1989
 
1990
    if (on)
1991
      this.dataInputStream = this.blockDataInput;
1992
    else
1993
      this.dataInputStream = this.realInputStream;
1994
    return oldmode;
1995
  }
1996
 
1997
  // returns a new instance of REAL_CLASS that has been constructed
1998
  // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1999
  private Object newObject (Class real_class, Constructor constructor)
2000
    throws ClassNotFoundException, IOException
2001
  {
2002
    if (constructor == null)
2003
        throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
2004
    try
2005
      {
2006
        return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
2007
      }
2008
    catch (InstantiationException e)
2009
      {
2010
        throw (ClassNotFoundException) new ClassNotFoundException
2011
          ("Instance of " + real_class + " could not be created").initCause(e);
2012
      }
2013
  }
2014
 
2015
  // runs all registered ObjectInputValidations in prioritized order
2016
  // on OBJ
2017
  private void invokeValidators() throws InvalidObjectException
2018
  {
2019
    try
2020
      {
2021
        Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
2022
        while(it.hasNext())
2023
          {
2024
            ValidatorAndPriority vap = it.next();
2025
            ObjectInputValidation validator = vap.validator;
2026
            validator.validateObject();
2027
          }
2028
      }
2029
    finally
2030
      {
2031
        currentObjectValidators = null;
2032
      }
2033
  }
2034
 
2035
  private void callReadMethod (Method readObject, Class klass, Object obj)
2036
    throws ClassNotFoundException, IOException
2037
  {
2038
    try
2039
      {
2040
        readObject.invoke(obj, new Object[] { this });
2041
      }
2042
    catch (InvocationTargetException x)
2043
      {
2044
        /* Rethrow if possible. */
2045
        Throwable exception = x.getTargetException();
2046
        if (exception instanceof RuntimeException)
2047
          throw (RuntimeException) exception;
2048
        if (exception instanceof IOException)
2049
          throw (IOException) exception;
2050
        if (exception instanceof ClassNotFoundException)
2051
          throw (ClassNotFoundException) exception;
2052
 
2053
        throw (IOException) new IOException(
2054
          "Exception thrown from readObject() on " + klass).initCause(x);
2055
      }
2056
    catch (Exception x)
2057
      {
2058
        throw (IOException) new IOException(
2059
          "Failure invoking readObject() on " + klass).initCause(x);
2060
      }
2061
 
2062
    // Invalidate fields which has been read through readFields.
2063
    prereadFields = null;
2064
  }
2065
 
2066
  private static final int BUFFER_SIZE = 1024;
2067
 
2068
  private DataInputStream realInputStream;
2069
  private DataInputStream dataInputStream;
2070
  private DataInputStream blockDataInput;
2071
  private int blockDataPosition;
2072
  private int blockDataBytes;
2073
  private byte[] blockData;
2074
  private boolean useSubclassMethod;
2075
  private int nextOID;
2076
  private boolean resolveEnabled;
2077
  private Map<Integer,Pair<Boolean,Object>> handles;
2078
  private Object currentObject;
2079
  private ObjectStreamClass currentObjectStreamClass;
2080
  private TreeSet<ValidatorAndPriority> currentObjectValidators;
2081
  private boolean readDataFromBlock;
2082
  private boolean fieldsAlreadyRead;
2083
  private Hashtable<Class,ObjectStreamClass> classLookupTable;
2084
  private GetField prereadFields;
2085
 
2086
  private static boolean dump;
2087
 
2088
  // The nesting depth for debugging output
2089
  private int depth = 0;
2090
 
2091
  private static final boolean DEBUG = false;
2092
 
2093
  private void dumpElement (String msg)
2094
  {
2095
    System.out.print(msg);
2096
  }
2097
 
2098
  private void dumpElementln (String msg)
2099
  {
2100
    System.out.println(msg);
2101
    for (int i = 0; i < depth; i++)
2102
      System.out.print (" ");
2103
    System.out.print (Thread.currentThread() + ": ");
2104
  }
2105
 
2106
  private void dumpElementln (String msg, Object obj)
2107
  {
2108
    try
2109
      {
2110
        System.out.print(msg);
2111
        if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
2112
          System.out.println(obj.getClass());
2113
        else
2114
        System.out.println(obj);
2115
      }
2116
    catch (Exception _)
2117
      {
2118
      }
2119
    for (int i = 0; i < depth; i++)
2120
      System.out.print (" ");
2121
    System.out.print (Thread.currentThread() + ": ");
2122
  }
2123
 
2124
  // used to keep a prioritized list of object validators
2125
  private static final class ValidatorAndPriority implements Comparable
2126
  {
2127
    int priority;
2128
    ObjectInputValidation validator;
2129
 
2130
    ValidatorAndPriority (ObjectInputValidation validator, int priority)
2131
    {
2132
      this.priority = priority;
2133
      this.validator = validator;
2134
    }
2135
 
2136
    public int compareTo (Object o)
2137
    {
2138
      ValidatorAndPriority vap = (ValidatorAndPriority)o;
2139
      return this.priority - vap.priority;
2140
    }
2141
  }
2142
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.