Source for java.io.ObjectInputStream

   1: /* 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:        int enumHandle = assignNewHandle(null, shared);
 533:            String constantName = (String) readObject();
 534:            if (dump)
 535:              dumpElementln("CONSTANT NAME = " + constantName);
 536:            Class clazz = osc.forClass();
 537:            Enum instance = Enum.valueOf(clazz, constantName);
 538:        rememberHandle(instance, shared, enumHandle);
 539:            ret_val = instance;
 540:            break;
 541:          }
 542: 
 543:        default:
 544:         throw new IOException("Unknown marker on stream: " + marker);
 545:       }
 546:     return ret_val;
 547:   }
 548: 
 549:   /**
 550:    * This method makes a partial check of types for the fields
 551:    * contained given in arguments. It checks primitive types of
 552:    * fields1 against non primitive types of fields2. This method
 553:    * assumes the two lists has already been sorted according to
 554:    * the Java specification.
 555:    *
 556:    * @param name Name of the class owning the given fields.
 557:    * @param fields1 First list to check.
 558:    * @param fields2 Second list to check.
 559:    * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
 560:    * in the non primitive part in fields2.
 561:    */
 562:   private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
 563:     throws InvalidClassException
 564:   {
 565:     int nonPrimitive = 0;
 566: 
 567:     for (nonPrimitive = 0;
 568:          nonPrimitive < fields1.length
 569:            && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
 570:       {
 571:       }
 572: 
 573:     if (nonPrimitive == fields1.length)
 574:       return;
 575: 
 576:     int i = 0;
 577:     ObjectStreamField f1;
 578:     ObjectStreamField f2;
 579: 
 580:     while (i < fields2.length
 581:            && nonPrimitive < fields1.length)
 582:       {
 583:         f1 = fields1[nonPrimitive];
 584:         f2 = fields2[i];
 585: 
 586:         if (!f2.isPrimitive())
 587:           break;
 588: 
 589:         int compVal = f1.getName().compareTo (f2.getName());
 590: 
 591:         if (compVal < 0)
 592:           {
 593:             nonPrimitive++;
 594:           }
 595:         else if (compVal > 0)
 596:           {
 597:             i++;
 598:           }
 599:         else
 600:           {
 601:             throw new InvalidClassException
 602:               ("invalid field type for " + f2.getName() +
 603:                " in class " + name);
 604:           }
 605:       }
 606:   }
 607: 
 608:   /**
 609:    * This method reads a class descriptor from the real input stream
 610:    * and use these data to create a new instance of ObjectStreamClass.
 611:    * Fields are sorted and ordered for the real read which occurs for
 612:    * each instance of the described class. Be aware that if you call that
 613:    * method you must ensure that the stream is synchronized, in the other
 614:    * case it may be completely desynchronized.
 615:    *
 616:    * @return A new instance of ObjectStreamClass containing the freshly
 617:    * created descriptor.
 618:    * @throws ClassNotFoundException if the required class to build the
 619:    * descriptor has not been found in the system.
 620:    * @throws IOException An input/output error occured.
 621:    * @throws InvalidClassException If there was a compatibility problem
 622:    * between the class present in the system and the serialized class.
 623:    */
 624:   protected ObjectStreamClass readClassDescriptor()
 625:     throws ClassNotFoundException, IOException
 626:   {
 627:     if(dump) dumpElement("CLASSDESC NAME=");
 628:     String name = this.realInputStream.readUTF();
 629:     if(dump) dumpElement(name + "; UID=");
 630:     long uid = this.realInputStream.readLong ();
 631:     if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
 632:     byte flags = this.realInputStream.readByte ();
 633:     if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
 634:     short field_count = this.realInputStream.readShort();
 635:     if(dump) dumpElementln(Short.toString(field_count));
 636:     ObjectStreamField[] fields = new ObjectStreamField[field_count];
 637:     ObjectStreamClass osc = new ObjectStreamClass(name, uid,
 638:                                                   flags, fields);
 639:     assignNewHandle(osc,true);
 640: 
 641:     for (int i = 0; i < field_count; i++)
 642:       {
 643:         if(dump) dumpElement("  TYPE CODE=");
 644:         char type_code = (char)this.realInputStream.readByte();
 645:         if(dump) dumpElement(type_code + "; FIELD NAME=");
 646:         String field_name = this.realInputStream.readUTF();
 647:         if(dump) dumpElementln(field_name);
 648:         String class_name;
 649: 
 650:         // If the type code is an array or an object we must
 651:         // decode a String here. In the other case we convert
 652:         // the type code and pass it to ObjectStreamField.
 653:         // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
 654:         if (type_code == 'L' || type_code == '[')
 655:           class_name = (String)readObject();
 656:         else
 657:           class_name = String.valueOf(type_code);
 658: 
 659:         fields[i] =
 660:           new ObjectStreamField(field_name, class_name);
 661:       }
 662: 
 663:     /* Now that fields have been read we may resolve the class
 664:      * (and read annotation if needed). */
 665:     Class clazz = resolveClass(osc);
 666:     ClassLoader loader = clazz.getClassLoader();
 667:     for (int i = 0; i < field_count; i++)
 668:       {
 669:         fields[i].resolveType(loader);
 670:       }
 671:     boolean oldmode = setBlockDataMode(true);
 672:     osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
 673:     classLookupTable.put(clazz, osc);
 674:     setBlockDataMode(oldmode);
 675: 
 676:     // find the first non-serializable class in clazz's inheritance hierarchy
 677:     Class first_nonserial = clazz.getSuperclass();
 678:     // Maybe it is a primitive class, those don't have a super class,
 679:     // or Object itself.  Otherwise we can keep getting the superclass
 680:     // till we hit the Object class, or some other non-serializable class.
 681: 
 682:     if (first_nonserial == null)
 683:       first_nonserial = clazz;
 684:     else
 685:       while (Serializable.class.isAssignableFrom(first_nonserial))
 686:         first_nonserial = first_nonserial.getSuperclass();
 687: 
 688:     final Class local_constructor_class = first_nonserial;
 689: 
 690:     osc.firstNonSerializableParentConstructor =
 691:         (Constructor)AccessController.doPrivileged(new PrivilegedAction()
 692:           {
 693:             public Object run()
 694:             {
 695:               try
 696:                 {
 697:                   Constructor c = local_constructor_class.
 698:                                     getDeclaredConstructor(new Class[0]);
 699:                   if (Modifier.isPrivate(c.getModifiers()))
 700:                     return null;
 701:                   return c;
 702:                 }
 703:               catch (NoSuchMethodException e)
 704:                 {
 705:                   // error will be reported later, in newObject()
 706:                   return null;
 707:                 }
 708:             }
 709:           });
 710: 
 711:     osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
 712:     osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
 713: 
 714:     ObjectStreamField[] stream_fields = osc.fields;
 715:     ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
 716:     ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
 717: 
 718:     int stream_idx = 0;
 719:     int real_idx = 0;
 720:     int map_idx = 0;
 721: 
 722:     /*
 723:      * Check that there is no type inconsistencies between the lists.
 724:      * A special checking must be done for the two groups: primitive types and
 725:      * not primitive types.
 726:      */
 727:     checkTypeConsistency(name, real_fields, stream_fields);
 728:     checkTypeConsistency(name, stream_fields, real_fields);
 729: 
 730: 
 731:     while (stream_idx < stream_fields.length
 732:            || real_idx < real_fields.length)
 733:       {
 734:         ObjectStreamField stream_field = null;
 735:         ObjectStreamField real_field = null;
 736: 
 737:         if (stream_idx == stream_fields.length)
 738:           {
 739:             real_field = real_fields[real_idx++];
 740:           }
 741:         else if (real_idx == real_fields.length)
 742:           {
 743:             stream_field = stream_fields[stream_idx++];
 744:           }
 745:         else
 746:           {
 747:             int comp_val =
 748:               real_fields[real_idx].compareTo (stream_fields[stream_idx]);
 749: 
 750:             if (comp_val < 0)
 751:               {
 752:                 real_field = real_fields[real_idx++];
 753:               }
 754:             else if (comp_val > 0)
 755:               {
 756:                 stream_field = stream_fields[stream_idx++];
 757:               }
 758:             else
 759:               {
 760:                 stream_field = stream_fields[stream_idx++];
 761:                 real_field = real_fields[real_idx++];
 762:                 if (stream_field.getType() != real_field.getType())
 763:                   throw new InvalidClassException
 764:                     ("invalid field type for " + real_field.getName() +
 765:                      " in class " + name);
 766:               }
 767:           }
 768: 
 769:         /* If some of stream_fields does not correspond to any of real_fields,
 770:          * or the opposite, then fieldmapping will go short.
 771:          */
 772:         if (map_idx == fieldmapping.length)
 773:           {
 774:             ObjectStreamField[] newfieldmapping =
 775:               new ObjectStreamField[fieldmapping.length + 2];
 776:             System.arraycopy(fieldmapping, 0,
 777:                              newfieldmapping, 0, fieldmapping.length);
 778:             fieldmapping = newfieldmapping;
 779:           }
 780:         fieldmapping[map_idx++] = stream_field;
 781:         fieldmapping[map_idx++] = real_field;
 782:       }
 783:     osc.fieldMapping = fieldmapping;
 784: 
 785:     return osc;
 786:   }
 787: 
 788:   /**
 789:    * Reads the current objects non-transient, non-static fields from
 790:    * the current class from the underlying output stream.
 791:    *
 792:    * This method is intended to be called from within a object's
 793:    * <code>private void readObject (ObjectInputStream)</code>
 794:    * method.
 795:    *
 796:    * @exception ClassNotFoundException The class that an object being
 797:    * read in belongs to cannot be found.
 798:    *
 799:    * @exception NotActiveException This method was called from a
 800:    * context other than from the current object's and current class's
 801:    * <code>private void readObject (ObjectInputStream)</code>
 802:    * method.
 803:    *
 804:    * @exception IOException Exception from underlying
 805:    * <code>OutputStream</code>.
 806:    */
 807:   public void defaultReadObject()
 808:     throws ClassNotFoundException, IOException, NotActiveException
 809:   {
 810:     if (this.currentObject == null || this.currentObjectStreamClass == null)
 811:       throw new NotActiveException("defaultReadObject called by non-active"
 812:                                    + " class and/or object");
 813: 
 814:     if (fieldsAlreadyRead)
 815:       throw new NotActiveException("defaultReadObject called but fields "
 816:                                    + "already read from stream (by "
 817:                                    + "defaultReadObject or readFields)");
 818: 
 819:     boolean oldmode = setBlockDataMode(false);
 820:     readFields(this.currentObject, this.currentObjectStreamClass);
 821:     setBlockDataMode(oldmode);
 822: 
 823:     fieldsAlreadyRead = true;
 824:   }
 825: 
 826: 
 827:   /**
 828:    * Registers a <code>ObjectInputValidation</code> to be carried out
 829:    * on the object graph currently being deserialized before it is
 830:    * returned to the original caller of <code>readObject ()</code>.
 831:    * The order of validation for multiple
 832:    * <code>ObjectInputValidation</code>s can be controled using
 833:    * <code>priority</code>.  Validators with higher priorities are
 834:    * called first.
 835:    *
 836:    * @see java.io.ObjectInputValidation
 837:    *
 838:    * @exception InvalidObjectException <code>validator</code> is
 839:    * <code>null</code>
 840:    *
 841:    * @exception NotActiveException an attempt was made to add a
 842:    * validator outside of the <code>readObject</code> method of the
 843:    * object currently being deserialized
 844:    */
 845:   public void registerValidation(ObjectInputValidation validator,
 846:                                  int priority)
 847:     throws InvalidObjectException, NotActiveException
 848:   {
 849:     if (this.currentObject == null || this.currentObjectStreamClass == null)
 850:       throw new NotActiveException("registerValidation called by non-active "
 851:                                    + "class and/or object");
 852: 
 853:     if (validator == null)
 854:       throw new InvalidObjectException("attempt to add a null "
 855:                                        + "ObjectInputValidation object");
 856: 
 857:     if (currentObjectValidators == null)
 858:       currentObjectValidators = new TreeSet<ValidatorAndPriority>();
 859: 
 860:     currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
 861:   }
 862: 
 863: 
 864:   /**
 865:    * Called when a class is being deserialized.  This is a hook to
 866:    * allow subclasses to read in information written by the
 867:    * <code>annotateClass (Class)</code> method of an
 868:    * <code>ObjectOutputStream</code>.
 869:    *
 870:    * This implementation looks up the active call stack for a
 871:    * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
 872:    * it is used to load the class associated with <code>osc</code>,
 873:    * otherwise, the default system <code>ClassLoader</code> is used.
 874:    *
 875:    * @exception IOException Exception from underlying
 876:    * <code>OutputStream</code>.
 877:    *
 878:    * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
 879:    */
 880:   protected Class<?> resolveClass(ObjectStreamClass osc)
 881:     throws ClassNotFoundException, IOException
 882:   {
 883:     String name = osc.getName();
 884:     try
 885:       {
 886:         return Class.forName(name, true, currentLoader());
 887:       }
 888:     catch(ClassNotFoundException x)
 889:       {
 890:         if (name.equals("void"))
 891:           return Void.TYPE;
 892:         else if (name.equals("boolean"))
 893:           return Boolean.TYPE;
 894:         else if (name.equals("byte"))
 895:           return Byte.TYPE;
 896:         else if (name.equals("char"))
 897:           return Character.TYPE;
 898:         else if (name.equals("short"))
 899:           return Short.TYPE;
 900:         else if (name.equals("int"))
 901:           return Integer.TYPE;
 902:         else if (name.equals("long"))
 903:           return Long.TYPE;
 904:         else if (name.equals("float"))
 905:           return Float.TYPE;
 906:         else if (name.equals("double"))
 907:           return Double.TYPE;
 908:         else
 909:           throw x;
 910:       }
 911:   }
 912: 
 913:   /**
 914:    * Returns the most recent user defined ClassLoader on the execution stack
 915:    * or null if none is found.
 916:    */
 917:   private ClassLoader currentLoader()
 918:   {
 919:     return VMStackWalker.firstNonNullClassLoader();
 920:   }
 921: 
 922:   /**
 923:    * Lookup a class stored in the local hashtable. If it is not
 924:    * use the global lookup function in ObjectStreamClass to build
 925:    * the ObjectStreamClass. This method is requested according to
 926:    * the behaviour detected in the JDK by Kaffe's team.
 927:    *
 928:    * @param clazz Class to lookup in the hash table or for which
 929:    * we must build a descriptor.
 930:    * @return A valid instance of ObjectStreamClass corresponding
 931:    * to the specified class.
 932:    */
 933:   private ObjectStreamClass lookupClass(Class clazz)
 934:   {
 935:     if (clazz == null)
 936:       return null;
 937: 
 938:     ObjectStreamClass oclazz;
 939:     oclazz = classLookupTable.get(clazz);
 940:     if (oclazz == null)
 941:       return ObjectStreamClass.lookup(clazz);
 942:     else
 943:       return oclazz;
 944:   }
 945: 
 946:   /**
 947:    * Reconstruct class hierarchy the same way {@link
 948:    * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
 949:    * instead of ObjectStreamClass.lookup.
 950:    *
 951:    * @param clazz This is the class for which we want the hierarchy.
 952:    *
 953:    * @return An array of valid {@link java.io.ObjectStreamClass} instances which
 954:    * represent the class hierarchy for clazz.
 955:    */
 956:   private ObjectStreamClass[] hierarchy(Class clazz)
 957:   {
 958:     ObjectStreamClass osc = lookupClass(clazz);
 959: 
 960:     return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
 961:   }
 962: 
 963:   /**
 964:    * Allows subclasses to resolve objects that are read from the
 965:    * stream with other objects to be returned in their place.  This
 966:    * method is called the first time each object is encountered.
 967:    *
 968:    * This method must be enabled before it will be called in the
 969:    * serialization process.
 970:    *
 971:    * @exception IOException Exception from underlying
 972:    * <code>OutputStream</code>.
 973:    *
 974:    * @see #enableResolveObject(boolean)
 975:    */
 976:   protected Object resolveObject(Object obj) throws IOException
 977:   {
 978:     return obj;
 979:   }
 980: 
 981: 
 982:   protected Class<?> resolveProxyClass(String[] intfs)
 983:     throws IOException, ClassNotFoundException
 984:   {
 985:     ClassLoader cl = currentLoader();
 986: 
 987:     Class<?>[] clss = new Class<?>[intfs.length];
 988:     if(cl == null)
 989:       {
 990:         for (int i = 0; i < intfs.length; i++)
 991:           clss[i] = Class.forName(intfs[i]);
 992:         cl = ClassLoader.getSystemClassLoader();
 993:       }
 994:     else
 995:       for (int i = 0; i < intfs.length; i++)
 996:         clss[i] = Class.forName(intfs[i], false, cl);
 997:     try
 998:       {
 999:         return Proxy.getProxyClass(cl, clss);
1000:       }
1001:     catch (IllegalArgumentException e)
1002:       {
1003:         throw new ClassNotFoundException(null, e);
1004:       }
1005:   }
1006: 
1007:   /**
1008:    * If <code>enable</code> is <code>true</code> and this object is
1009:    * trusted, then <code>resolveObject (Object)</code> will be called
1010:    * in subsequent calls to <code>readObject (Object)</code>.
1011:    * Otherwise, <code>resolveObject (Object)</code> will not be called.
1012:    *
1013:    * @exception SecurityException This class is not trusted.
1014:    */
1015:   protected boolean enableResolveObject (boolean enable)
1016:     throws SecurityException
1017:   {
1018:     if (enable)
1019:       {
1020:         SecurityManager sm = System.getSecurityManager();
1021:         if (sm != null)
1022:           sm.checkPermission(new SerializablePermission("enableSubstitution"));
1023:       }
1024: 
1025:     boolean old_val = this.resolveEnabled;
1026:     this.resolveEnabled = enable;
1027:     return old_val;
1028:   }
1029: 
1030:   /**
1031:    * Reads stream magic and stream version information from the
1032:    * underlying stream.
1033:    *
1034:    * @exception IOException Exception from underlying stream.
1035:    *
1036:    * @exception StreamCorruptedException An invalid stream magic
1037:    * number or stream version was read from the stream.
1038:    */
1039:   protected void readStreamHeader()
1040:     throws IOException, StreamCorruptedException
1041:   {
1042:     if(dump) dumpElement("STREAM MAGIC ");
1043:     if (this.realInputStream.readShort() != STREAM_MAGIC)
1044:       throw new StreamCorruptedException("Invalid stream magic number");
1045: 
1046:     if(dump) dumpElementln("STREAM VERSION ");
1047:     if (this.realInputStream.readShort() != STREAM_VERSION)
1048:       throw new StreamCorruptedException("Invalid stream version number");
1049:   }
1050: 
1051:   public int read() throws IOException
1052:   {
1053:     if (this.readDataFromBlock)
1054:       {
1055:         if (this.blockDataPosition >= this.blockDataBytes)
1056:           readNextBlock();
1057:         return (this.blockData[this.blockDataPosition++] & 0xff);
1058:       }
1059:     else
1060:       return this.realInputStream.read();
1061:   }
1062: 
1063:   public int read(byte[] data, int offset, int length) throws IOException
1064:   {
1065:     if (this.readDataFromBlock)
1066:       {
1067:         int remain = this.blockDataBytes - this.blockDataPosition;
1068:         if (remain == 0)
1069:           {
1070:             readNextBlock();
1071:             remain = this.blockDataBytes - this.blockDataPosition;
1072:           }
1073:         length = Math.min(length, remain);
1074:         System.arraycopy(this.blockData, this.blockDataPosition,
1075:                          data, offset, length);
1076:         this.blockDataPosition += length;
1077: 
1078:         return length;
1079:       }
1080:     else
1081:       return this.realInputStream.read(data, offset, length);
1082:   }
1083: 
1084:   public int available() throws IOException
1085:   {
1086:     if (this.readDataFromBlock)
1087:       {
1088:         if (this.blockDataPosition >= this.blockDataBytes)
1089:           readNextBlock ();
1090: 
1091:         return this.blockDataBytes - this.blockDataPosition;
1092:       }
1093:     else
1094:       return this.realInputStream.available();
1095:   }
1096: 
1097:   public void close() throws IOException
1098:   {
1099:     this.realInputStream.close();
1100:   }
1101: 
1102:   public boolean readBoolean() throws IOException
1103:   {
1104:     boolean switchmode = true;
1105:     boolean oldmode = this.readDataFromBlock;
1106:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1107:       switchmode = false;
1108:     if (switchmode)
1109:       oldmode = setBlockDataMode (true);
1110:     boolean value = this.dataInputStream.readBoolean ();
1111:     if (switchmode)
1112:       setBlockDataMode (oldmode);
1113:     return value;
1114:   }
1115: 
1116:   public byte readByte() throws IOException
1117:   {
1118:     boolean switchmode = true;
1119:     boolean oldmode = this.readDataFromBlock;
1120:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1121:       switchmode = false;
1122:     if (switchmode)
1123:       oldmode = setBlockDataMode(true);
1124:     byte value = this.dataInputStream.readByte();
1125:     if (switchmode)
1126:       setBlockDataMode(oldmode);
1127:     return value;
1128:   }
1129: 
1130:   public int readUnsignedByte() throws IOException
1131:   {
1132:     boolean switchmode = true;
1133:     boolean oldmode = this.readDataFromBlock;
1134:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1135:       switchmode = false;
1136:     if (switchmode)
1137:       oldmode = setBlockDataMode(true);
1138:     int value = this.dataInputStream.readUnsignedByte();
1139:     if (switchmode)
1140:       setBlockDataMode(oldmode);
1141:     return value;
1142:   }
1143: 
1144:   public short readShort() throws IOException
1145:   {
1146:     boolean switchmode = true;
1147:     boolean oldmode = this.readDataFromBlock;
1148:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1149:       switchmode = false;
1150:     if (switchmode)
1151:       oldmode = setBlockDataMode(true);
1152:     short value = this.dataInputStream.readShort();
1153:     if (switchmode)
1154:       setBlockDataMode(oldmode);
1155:     return value;
1156:   }
1157: 
1158:   public int readUnsignedShort() throws IOException
1159:   {
1160:     boolean switchmode = true;
1161:     boolean oldmode = this.readDataFromBlock;
1162:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1163:       switchmode = false;
1164:     if (switchmode)
1165:       oldmode = setBlockDataMode(true);
1166:     int value = this.dataInputStream.readUnsignedShort();
1167:     if (switchmode)
1168:       setBlockDataMode(oldmode);
1169:     return value;
1170:   }
1171: 
1172:   public char readChar() throws IOException
1173:   {
1174:     boolean switchmode = true;
1175:     boolean oldmode = this.readDataFromBlock;
1176:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1177:       switchmode = false;
1178:     if (switchmode)
1179:       oldmode = setBlockDataMode(true);
1180:     char value = this.dataInputStream.readChar();
1181:     if (switchmode)
1182:       setBlockDataMode(oldmode);
1183:     return value;
1184:   }
1185: 
1186:   public int readInt() throws IOException
1187:   {
1188:     boolean switchmode = true;
1189:     boolean oldmode = this.readDataFromBlock;
1190:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1191:       switchmode = false;
1192:     if (switchmode)
1193:       oldmode = setBlockDataMode(true);
1194:     int value = this.dataInputStream.readInt();
1195:     if (switchmode)
1196:       setBlockDataMode(oldmode);
1197:     return value;
1198:   }
1199: 
1200:   public long readLong() throws IOException
1201:   {
1202:     boolean switchmode = true;
1203:     boolean oldmode = this.readDataFromBlock;
1204:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1205:       switchmode = false;
1206:     if (switchmode)
1207:       oldmode = setBlockDataMode(true);
1208:     long value = this.dataInputStream.readLong();
1209:     if (switchmode)
1210:       setBlockDataMode(oldmode);
1211:     return value;
1212:   }
1213: 
1214:   public float readFloat() throws IOException
1215:   {
1216:     boolean switchmode = true;
1217:     boolean oldmode = this.readDataFromBlock;
1218:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1219:       switchmode = false;
1220:     if (switchmode)
1221:       oldmode = setBlockDataMode(true);
1222:     float value = this.dataInputStream.readFloat();
1223:     if (switchmode)
1224:       setBlockDataMode(oldmode);
1225:     return value;
1226:   }
1227: 
1228:   public double readDouble() throws IOException
1229:   {
1230:     boolean switchmode = true;
1231:     boolean oldmode = this.readDataFromBlock;
1232:     if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1233:       switchmode = false;
1234:     if (switchmode)
1235:       oldmode = setBlockDataMode(true);
1236:     double value = this.dataInputStream.readDouble();
1237:     if (switchmode)
1238:       setBlockDataMode(oldmode);
1239:     return value;
1240:   }
1241: 
1242:   public void readFully(byte data[]) throws IOException
1243:   {
1244:     this.dataInputStream.readFully(data);
1245:   }
1246: 
1247:   public void readFully(byte data[], int offset, int size)
1248:     throws IOException
1249:   {
1250:     this.dataInputStream.readFully(data, offset, size);
1251:   }
1252: 
1253:   public int skipBytes(int len) throws IOException
1254:   {
1255:     return this.dataInputStream.skipBytes(len);
1256:   }
1257: 
1258:   /**
1259:    * @deprecated
1260:    * @see java.io.DataInputStream#readLine ()
1261:    */
1262:   public String readLine() throws IOException
1263:   {
1264:     return this.dataInputStream.readLine();
1265:   }
1266: 
1267:   public String readUTF() throws IOException
1268:   {
1269:     return this.dataInputStream.readUTF();
1270:   }
1271: 
1272:   /**
1273:    * This class allows a class to specify exactly which fields should
1274:    * be read, and what values should be read for these fields.
1275:    *
1276:    * XXX: finish up comments
1277:    */
1278:   public abstract static class GetField
1279:   {
1280:     public abstract ObjectStreamClass getObjectStreamClass();
1281: 
1282:     public abstract boolean defaulted(String name)
1283:       throws IOException, IllegalArgumentException;
1284: 
1285:     public abstract boolean get(String name, boolean defvalue)
1286:       throws IOException, IllegalArgumentException;
1287: 
1288:     public abstract char get(String name, char defvalue)
1289:       throws IOException, IllegalArgumentException;
1290: 
1291:     public abstract byte get(String name, byte defvalue)
1292:       throws IOException, IllegalArgumentException;
1293: 
1294:     public abstract short get(String name, short defvalue)
1295:       throws IOException, IllegalArgumentException;
1296: 
1297:     public abstract int get(String name, int defvalue)
1298:       throws IOException, IllegalArgumentException;
1299: 
1300:     public abstract long get(String name, long defvalue)
1301:       throws IOException, IllegalArgumentException;
1302: 
1303:     public abstract float get(String name, float defvalue)
1304:       throws IOException, IllegalArgumentException;
1305: 
1306:     public abstract double get(String name, double defvalue)
1307:       throws IOException, IllegalArgumentException;
1308: 
1309:     public abstract Object get(String name, Object defvalue)
1310:       throws IOException, IllegalArgumentException;
1311:   }
1312: 
1313:   /**
1314:    * This method should be called by a method called 'readObject' in the
1315:    * deserializing class (if present). It cannot (and should not)be called
1316:    * outside of it. Its goal is to read all fields in the real input stream
1317:    * and keep them accessible through the {@link GetField} class. Calling
1318:    * this method will not alter the deserializing object.
1319:    *
1320:    * @return A valid freshly created 'GetField' instance to get access to
1321:    * the deserialized stream.
1322:    * @throws IOException An input/output exception occured.
1323:    * @throws ClassNotFoundException
1324:    * @throws NotActiveException
1325:    */
1326:   public GetField readFields()
1327:     throws IOException, ClassNotFoundException, NotActiveException
1328:   {
1329:     if (this.currentObject == null || this.currentObjectStreamClass == null)
1330:       throw new NotActiveException("readFields called by non-active class and/or object");
1331: 
1332:     if (prereadFields != null)
1333:       return prereadFields;
1334: 
1335:     if (fieldsAlreadyRead)
1336:       throw new NotActiveException("readFields called but fields already read from"
1337:                                    + " stream (by defaultReadObject or readFields)");
1338: 
1339:     final ObjectStreamClass clazz = this.currentObjectStreamClass;
1340:     final byte[] prim_field_data = new byte[clazz.primFieldSize];
1341:     final Object[] objs = new Object[clazz.objectFieldCount];
1342: 
1343:     // Apparently Block data is not used with GetField as per
1344:     // empirical evidence against JDK 1.2.  Also see Mauve test
1345:     // java.io.ObjectInputOutput.Test.GetPutField.
1346:     boolean oldmode = setBlockDataMode(false);
1347:     readFully(prim_field_data);
1348:     for (int i = 0; i < objs.length; ++ i)
1349:       objs[i] = readObject();
1350:     setBlockDataMode(oldmode);
1351: 
1352:     prereadFields = new GetField()
1353:       {
1354:         public ObjectStreamClass getObjectStreamClass()
1355:         {
1356:           return clazz;
1357:         }
1358: 
1359:         public boolean defaulted(String name)
1360:           throws IOException, IllegalArgumentException
1361:         {
1362:           ObjectStreamField f = clazz.getField(name);
1363: 
1364:           /* First if we have a serialized field use the descriptor */
1365:           if (f != null)
1366:             {
1367:               /* It is in serialPersistentFields but setClass tells us
1368:                * it should not be set. This value is defaulted.
1369:                */
1370:               if (f.isPersistent() && !f.isToSet())
1371:                 return true;
1372: 
1373:               return false;
1374:             }
1375: 
1376:           /* This is not a serialized field. There should be
1377:            * a default value only if the field really exists.
1378:            */
1379:           try
1380:             {
1381:               return (clazz.forClass().getDeclaredField (name) != null);
1382:             }
1383:           catch (NoSuchFieldException e)
1384:             {
1385:               throw new IllegalArgumentException(e);
1386:             }
1387:         }
1388: 
1389:         public boolean get(String name, boolean defvalue)
1390:           throws IOException, IllegalArgumentException
1391:         {
1392:           ObjectStreamField field = getField(name, Boolean.TYPE);
1393: 
1394:           if (field == null)
1395:             return defvalue;
1396: 
1397:           return prim_field_data[field.getOffset()] == 0 ? false : true;
1398:         }
1399: 
1400:         public char get(String name, char defvalue)
1401:           throws IOException, IllegalArgumentException
1402:         {
1403:           ObjectStreamField field = getField(name, Character.TYPE);
1404: 
1405:           if (field == null)
1406:             return defvalue;
1407: 
1408:           int off = field.getOffset();
1409: 
1410:           return (char)(((prim_field_data[off++] & 0xFF) << 8)
1411:                         | (prim_field_data[off] & 0xFF));
1412:         }
1413: 
1414:         public byte get(String name, byte defvalue)
1415:           throws IOException, IllegalArgumentException
1416:         {
1417:           ObjectStreamField field = getField(name, Byte.TYPE);
1418: 
1419:           if (field == null)
1420:             return defvalue;
1421: 
1422:           return prim_field_data[field.getOffset()];
1423:         }
1424: 
1425:         public short get(String name, short defvalue)
1426:           throws IOException, IllegalArgumentException
1427:         {
1428:           ObjectStreamField field = getField(name, Short.TYPE);
1429: 
1430:           if (field == null)
1431:             return defvalue;
1432: 
1433:           int off = field.getOffset();
1434: 
1435:           return (short)(((prim_field_data[off++] & 0xFF) << 8)
1436:                          | (prim_field_data[off] & 0xFF));
1437:         }
1438: 
1439:         public int get(String name, int defvalue)
1440:           throws IOException, IllegalArgumentException
1441:         {
1442:           ObjectStreamField field = getField(name, Integer.TYPE);
1443: 
1444:           if (field == null)
1445:             return defvalue;
1446: 
1447:           int off = field.getOffset();
1448: 
1449:           return ((prim_field_data[off++] & 0xFF) << 24)
1450:             | ((prim_field_data[off++] & 0xFF) << 16)
1451:             | ((prim_field_data[off++] & 0xFF) << 8)
1452:             | (prim_field_data[off] & 0xFF);
1453:         }
1454: 
1455:         public long get(String name, long defvalue)
1456:           throws IOException, IllegalArgumentException
1457:         {
1458:           ObjectStreamField field = getField(name, Long.TYPE);
1459: 
1460:           if (field == null)
1461:             return defvalue;
1462: 
1463:           int off = field.getOffset();
1464: 
1465:           return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1466:                         | ((prim_field_data[off++] & 0xFFL) << 48)
1467:                         | ((prim_field_data[off++] & 0xFFL) << 40)
1468:                         | ((prim_field_data[off++] & 0xFFL) << 32)
1469:                         | ((prim_field_data[off++] & 0xFF) << 24)
1470:                         | ((prim_field_data[off++] & 0xFF) << 16)
1471:                         | ((prim_field_data[off++] & 0xFF) << 8)
1472:                         | (prim_field_data[off] & 0xFF));
1473:         }
1474: 
1475:         public float get(String name, float defvalue)
1476:           throws IOException, IllegalArgumentException
1477:         {
1478:           ObjectStreamField field = getField(name, Float.TYPE);
1479: 
1480:           if (field == null)
1481:             return defvalue;
1482: 
1483:           int off = field.getOffset();
1484: 
1485:           return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1486:                                       | ((prim_field_data[off++] & 0xFF) << 16)
1487:                                       | ((prim_field_data[off++] & 0xFF) << 8)
1488:                                       | (prim_field_data[off] & 0xFF));
1489:         }
1490: 
1491:         public double get(String name, double defvalue)
1492:           throws IOException, IllegalArgumentException
1493:         {
1494:           ObjectStreamField field = getField(name, Double.TYPE);
1495: 
1496:           if (field == null)
1497:             return defvalue;
1498: 
1499:           int off = field.getOffset();
1500: 
1501:           return Double.longBitsToDouble
1502:             ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1503:                       | ((prim_field_data[off++] & 0xFFL) << 48)
1504:                       | ((prim_field_data[off++] & 0xFFL) << 40)
1505:                       | ((prim_field_data[off++] & 0xFFL) << 32)
1506:                       | ((prim_field_data[off++] & 0xFF) << 24)
1507:                       | ((prim_field_data[off++] & 0xFF) << 16)
1508:                       | ((prim_field_data[off++] & 0xFF) << 8)
1509:                       | (prim_field_data[off] & 0xFF)));
1510:         }
1511: 
1512:         public Object get(String name, Object defvalue)
1513:           throws IOException, IllegalArgumentException
1514:         {
1515:           ObjectStreamField field =
1516:             getField(name, defvalue == null ? null : defvalue.getClass ());
1517: 
1518:           if (field == null)
1519:             return defvalue;
1520: 
1521:           return objs[field.getOffset()];
1522:         }
1523: 
1524:         private ObjectStreamField getField(String name, Class type)
1525:           throws IllegalArgumentException
1526:         {
1527:           ObjectStreamField field = clazz.getField(name);
1528:           boolean illegal = false;
1529: 
1530:           // XXX This code is horrible and needs to be rewritten!
1531:           try
1532:             {
1533:               try
1534:                 {
1535:                   Class field_type = field.getType();
1536: 
1537:                   if (type == field_type ||
1538:                       (type == null && !field_type.isPrimitive()))
1539:                     {
1540:                       /* See defaulted */
1541:                       return field;
1542:                     }
1543: 
1544:                   illegal = true;
1545:                   throw new IllegalArgumentException
1546:                     ("Field requested is of type "
1547:                      + field_type.getName()
1548:                      + ", but requested type was "
1549:                      + (type == null ?  "Object" : type.getName()));
1550:                 }
1551:               catch (NullPointerException _)
1552:                 {
1553:                   /* Here we catch NullPointerException, because it may
1554:                      only come from the call 'field.getType()'. If field
1555:                      is null, we have to return null and classpath ethic
1556:                      say we must try to avoid 'if (xxx == null)'.
1557:                   */
1558:                 }
1559:               catch (IllegalArgumentException e)
1560:                 {
1561:                   throw e;
1562:                 }
1563: 
1564:               return null;
1565:             }
1566:           finally
1567:             {
1568:               /* If this is an unassigned field we should return
1569:                * the default value.
1570:                */
1571:               if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1572:                 return null;
1573: 
1574:               /* We do not want to modify transient fields. They should
1575:                * be left to 0.
1576:                */
1577:               try
1578:                 {
1579:                   Field f = clazz.forClass().getDeclaredField(name);
1580:                   if (Modifier.isTransient(f.getModifiers()))
1581:                     throw new IllegalArgumentException
1582:                       ("no such field (non transient) " + name);
1583:                   if (field == null && f.getType() != type)
1584:                     throw new IllegalArgumentException
1585:                       ("Invalid requested type for field " + name);
1586:                 }
1587:               catch (NoSuchFieldException e)
1588:                 {
1589:                   if (field == null)
1590:                     throw new IllegalArgumentException(e);
1591:                 }
1592: 
1593:             }
1594:         }
1595:       };
1596: 
1597:     fieldsAlreadyRead = true;
1598:     return prereadFields;
1599:   }
1600: 
1601:   /**
1602:    * Protected constructor that allows subclasses to override
1603:    * deserialization.  This constructor should be called by subclasses
1604:    * that wish to override <code>readObject (Object)</code>.  This
1605:    * method does a security check <i>NOTE: currently not
1606:    * implemented</i>, then sets a flag that informs
1607:    * <code>readObject (Object)</code> to call the subclasses
1608:    * <code>readObjectOverride (Object)</code> method.
1609:    *
1610:    * @see #readObjectOverride()
1611:    */
1612:   protected ObjectInputStream()
1613:     throws IOException, SecurityException
1614:   {
1615:     SecurityManager sec_man = System.getSecurityManager();
1616:     if (sec_man != null)
1617:       sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1618:     this.useSubclassMethod = true;
1619:   }
1620: 
1621:   /**
1622:    * This method allows subclasses to override the default
1623:    * de serialization mechanism provided by
1624:    * <code>ObjectInputStream</code>.  To make this method be used for
1625:    * writing objects, subclasses must invoke the 0-argument
1626:    * constructor on this class from their constructor.
1627:    *
1628:    * @see #ObjectInputStream()
1629:    */
1630:   protected Object readObjectOverride()
1631:     throws ClassNotFoundException, IOException, OptionalDataException
1632:   {
1633:     throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1634:   }
1635: 
1636:   /**
1637:    * Assigns the next available handle to <code>obj</code>.
1638:    *
1639:    * @param obj The object for which we want a new handle.
1640:    * @param shared True if the handle should be shared
1641:    *               with later calls.
1642:    * @return A valid handle for the specified object.
1643:    */
1644:   private int assignNewHandle(Object obj, boolean shared)
1645:   {
1646:     int handle = this.nextOID;
1647:     this.nextOID = handle + 1;
1648:     rememberHandle(obj,shared,handle);
1649:     return handle;
1650:   }
1651: 
1652:   /**
1653:    * Remember the object associated with the given handle.
1654:    *
1655:    * @param obj an object
1656:    * @param shared true if the reference should be shared
1657:    *               with later calls.
1658:    * @param handle a handle, must be >= baseWireHandle
1659:    *
1660:    * @see #lookupHandle
1661:    */
1662:   private void rememberHandle(Object obj, boolean shared,
1663:                               int handle)
1664:   {
1665:     handles.put(handle, new Pair<Boolean,Object>(shared, obj));
1666:   }
1667: 
1668:   /**
1669:    * Look up the object associated with a given handle.
1670:    *
1671:    * @param handle a handle, must be >= baseWireHandle
1672:    * @return the object remembered for handle or null if none.
1673:    * @throws StreamCorruptedException if the handle is invalid.
1674:    * @throws InvalidObjectException if the reference is not shared.
1675:    * @see #rememberHandle
1676:    */
1677:   private Object lookupHandle(int handle)
1678:     throws ObjectStreamException
1679:   {
1680:     Pair<Boolean,Object> result = handles.get(handle);
1681:     if (result == null)
1682:       throw new StreamCorruptedException("The handle, " +
1683:                                          Integer.toHexString(handle) +
1684:                                          ", is invalid.");
1685:     if (!result.getLeft())
1686:       throw new InvalidObjectException("The handle, " +
1687:                                        Integer.toHexString(handle) +
1688:                                        ", is not shared.");
1689:     return result.getRight();
1690:   }
1691: 
1692:   private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
1693:                                    boolean shared)
1694:     throws IOException
1695:   {
1696:     if (osc != null && obj instanceof Serializable)
1697:       {
1698:         try
1699:           {
1700:             Method m = osc.readResolveMethod;
1701:             if(m != null)
1702:             {
1703:                 obj = m.invoke(obj, new Object[] {});
1704:             }
1705:           }
1706:         catch (IllegalAccessException ignore)
1707:           {
1708:           }
1709:         catch (InvocationTargetException exception)
1710:           {
1711:             Throwable cause = exception.getCause();
1712:             if (cause instanceof ObjectStreamException)
1713:               throw (ObjectStreamException) cause;
1714:             else if (cause instanceof RuntimeException)
1715:               throw (RuntimeException) cause;
1716:             else if (cause instanceof Error)
1717:               throw (Error) cause;
1718:           }
1719:       }
1720: 
1721:     if (this.resolveEnabled)
1722:       obj = resolveObject(obj);
1723: 
1724:     rememberHandle(obj, shared, handle);
1725:     if (!shared)
1726:       {
1727:         if (obj instanceof byte[])
1728:           return ((byte[]) obj).clone();
1729:         if (obj instanceof short[])
1730:           return ((short[]) obj).clone();
1731:         if (obj instanceof int[])
1732:           return ((int[]) obj).clone();
1733:         if (obj instanceof long[])
1734:           return ((long[]) obj).clone();
1735:         if (obj instanceof char[])
1736:           return ((char[]) obj).clone();
1737:         if (obj instanceof boolean[])
1738:           return ((boolean[]) obj).clone();
1739:         if (obj instanceof float[])
1740:           return ((float[]) obj).clone();
1741:         if (obj instanceof double[])
1742:           return ((double[]) obj).clone();
1743:         if (obj instanceof Object[])
1744:           return ((Object[]) obj).clone();
1745:       }
1746:     return obj;
1747:   }
1748: 
1749:   private void clearHandles()
1750:   {
1751:     handles.clear();
1752:     this.nextOID = baseWireHandle;
1753:   }
1754: 
1755:   private void readNextBlock() throws IOException
1756:   {
1757:     byte marker = this.realInputStream.readByte();
1758:     while (marker == TC_RESET)
1759:       {
1760:         if(dump) dumpElementln("RESET");
1761:         clearHandles();
1762:         marker = this.realInputStream.readByte();
1763:       }
1764:     readNextBlock(marker);
1765:   }
1766: 
1767:   private void readNextBlock(byte marker) throws IOException
1768:   {
1769:     if (marker == TC_BLOCKDATA)
1770:       {
1771:         if(dump) dumpElement("BLOCK DATA SIZE=");
1772:         this.blockDataBytes = this.realInputStream.readUnsignedByte();
1773:         if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1774:       }
1775:     else if (marker == TC_BLOCKDATALONG)
1776:       {
1777:         if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1778:         this.blockDataBytes = this.realInputStream.readInt();
1779:         if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1780:       }
1781:     else
1782:       {
1783:         throw new EOFException("Attempt to read primitive data, but no data block is active.");
1784:       }
1785: 
1786:     if (this.blockData.length < this.blockDataBytes)
1787:       this.blockData = new byte[this.blockDataBytes];
1788: 
1789:     this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1790:     this.blockDataPosition = 0;
1791:   }
1792: 
1793:   private void readArrayElements (Object array, Class clazz)
1794:     throws ClassNotFoundException, IOException
1795:   {
1796:     if (clazz.isPrimitive())
1797:       {
1798:         if (clazz == Boolean.TYPE)
1799:           {
1800:             boolean[] cast_array = (boolean[])array;
1801:             for (int i=0; i < cast_array.length; i++)
1802:               cast_array[i] = this.realInputStream.readBoolean();
1803:             return;
1804:           }
1805:         if (clazz == Byte.TYPE)
1806:           {
1807:             byte[] cast_array = (byte[])array;
1808:             for (int i=0; i < cast_array.length; i++)
1809:               cast_array[i] = this.realInputStream.readByte();
1810:             return;
1811:           }
1812:         if (clazz == Character.TYPE)
1813:           {
1814:             char[] cast_array = (char[])array;
1815:             for (int i=0; i < cast_array.length; i++)
1816:               cast_array[i] = this.realInputStream.readChar();
1817:             return;
1818:           }
1819:         if (clazz == Double.TYPE)
1820:           {
1821:             double[] cast_array = (double[])array;
1822:             for (int i=0; i < cast_array.length; i++)
1823:               cast_array[i] = this.realInputStream.readDouble();
1824:             return;
1825:           }
1826:         if (clazz == Float.TYPE)
1827:           {
1828:             float[] cast_array = (float[])array;
1829:             for (int i=0; i < cast_array.length; i++)
1830:               cast_array[i] = this.realInputStream.readFloat();
1831:             return;
1832:           }
1833:         if (clazz == Integer.TYPE)
1834:           {
1835:             int[] cast_array = (int[])array;
1836:             for (int i=0; i < cast_array.length; i++)
1837:               cast_array[i] = this.realInputStream.readInt();
1838:             return;
1839:           }
1840:         if (clazz == Long.TYPE)
1841:           {
1842:             long[] cast_array = (long[])array;
1843:             for (int i=0; i < cast_array.length; i++)
1844:               cast_array[i] = this.realInputStream.readLong();
1845:             return;
1846:           }
1847:         if (clazz == Short.TYPE)
1848:           {
1849:             short[] cast_array = (short[])array;
1850:             for (int i=0; i < cast_array.length; i++)
1851:               cast_array[i] = this.realInputStream.readShort();
1852:             return;
1853:           }
1854:       }
1855:     else
1856:       {
1857:         Object[] cast_array = (Object[])array;
1858:         for (int i=0; i < cast_array.length; i++)
1859:           cast_array[i] = readObject();
1860:       }
1861:   }
1862: 
1863:   private void readFields (Object obj, ObjectStreamClass stream_osc)
1864:     throws ClassNotFoundException, IOException
1865:   {
1866:     ObjectStreamField[] fields = stream_osc.fieldMapping;
1867: 
1868:     for (int i = 0; i < fields.length; i += 2)
1869:       {
1870:         ObjectStreamField stream_field = fields[i];
1871:         ObjectStreamField real_field = fields[i + 1];
1872:         boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1873:         boolean set_value = (real_field != null && real_field.isToSet());
1874:         String field_name;
1875:         char type;
1876: 
1877:         if (stream_field != null)
1878:           {
1879:             field_name = stream_field.getName();
1880:             type = stream_field.getTypeCode();
1881:           }
1882:         else
1883:           {
1884:             field_name = real_field.getName();
1885:             type = real_field.getTypeCode();
1886:           }
1887: 
1888:         switch(type)
1889:           {
1890:           case 'Z':
1891:             {
1892:               boolean value =
1893:                 read_value ? this.realInputStream.readBoolean() : false;
1894:               if (dump && read_value && set_value)
1895:                 dumpElementln("  " + field_name + ": " + value);
1896:               if (set_value)
1897:                 real_field.setBooleanField(obj, value);
1898:               break;
1899:             }
1900:           case 'B':
1901:             {
1902:               byte value =
1903:                 read_value ? this.realInputStream.readByte() : 0;
1904:               if (dump && read_value && set_value)
1905:                 dumpElementln("  " + field_name + ": " + value);
1906:               if (set_value)
1907:                 real_field.setByteField(obj, value);
1908:               break;
1909:             }
1910:           case 'C':
1911:             {
1912:               char value =
1913:                 read_value ? this.realInputStream.readChar(): 0;
1914:               if (dump && read_value && set_value)
1915:                 dumpElementln("  " + field_name + ": " + value);
1916:               if (set_value)
1917:                 real_field.setCharField(obj, value);
1918:               break;
1919:             }
1920:           case 'D':
1921:             {
1922:               double value =
1923:                 read_value ? this.realInputStream.readDouble() : 0;
1924:               if (dump && read_value && set_value)
1925:                 dumpElementln("  " + field_name + ": " + value);
1926:               if (set_value)
1927:                 real_field.setDoubleField(obj, value);
1928:               break;
1929:             }
1930:           case 'F':
1931:             {
1932:               float value =
1933:                 read_value ? this.realInputStream.readFloat() : 0;
1934:               if (dump && read_value && set_value)
1935:                 dumpElementln("  " + field_name + ": " + value);
1936:               if (set_value)
1937:                 real_field.setFloatField(obj, value);
1938:               break;
1939:             }
1940:           case 'I':
1941:             {
1942:               int value =
1943:                 read_value ? this.realInputStream.readInt() : 0;
1944:               if (dump && read_value && set_value)
1945:                 dumpElementln("  " + field_name + ": " + value);
1946:               if (set_value)
1947:                 real_field.setIntField(obj, value);
1948:               break;
1949:             }
1950:           case 'J':
1951:             {
1952:               long value =
1953:                 read_value ? this.realInputStream.readLong() : 0;
1954:               if (dump && read_value && set_value)
1955:                 dumpElementln("  " + field_name + ": " + value);
1956:               if (set_value)
1957:                 real_field.setLongField(obj, value);
1958:               break;
1959:             }
1960:           case 'S':
1961:             {
1962:               short value =
1963:                 read_value ? this.realInputStream.readShort() : 0;
1964:               if (dump && read_value && set_value)
1965:                 dumpElementln("  " + field_name + ": " + value);
1966:               if (set_value)
1967:                 real_field.setShortField(obj, value);
1968:               break;
1969:             }
1970:           case 'L':
1971:           case '[':
1972:             {
1973:               Object value =
1974:                 read_value ? readObject() : null;
1975:               if (set_value)
1976:                 real_field.setObjectField(obj, value);
1977:               break;
1978:             }
1979:           default:
1980:             throw new InternalError("Invalid type code: " + type);
1981:           }
1982:       }
1983:   }
1984: 
1985:   // Toggles writing primitive data to block-data buffer.
1986:   private boolean setBlockDataMode (boolean on)
1987:   {
1988:     boolean oldmode = this.readDataFromBlock;
1989:     this.readDataFromBlock = on;
1990: 
1991:     if (on)
1992:       this.dataInputStream = this.blockDataInput;
1993:     else
1994:       this.dataInputStream = this.realInputStream;
1995:     return oldmode;
1996:   }
1997: 
1998:   // returns a new instance of REAL_CLASS that has been constructed
1999:   // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
2000:   private Object newObject (Class real_class, Constructor constructor)
2001:     throws ClassNotFoundException, IOException
2002:   {
2003:     if (constructor == null)
2004:         throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
2005:     try
2006:       {
2007:         return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
2008:       }
2009:     catch (InstantiationException e)
2010:       {
2011:         throw (ClassNotFoundException) new ClassNotFoundException
2012:           ("Instance of " + real_class + " could not be created").initCause(e);
2013:       }
2014:   }
2015: 
2016:   // runs all registered ObjectInputValidations in prioritized order
2017:   // on OBJ
2018:   private void invokeValidators() throws InvalidObjectException
2019:   {
2020:     try
2021:       {
2022:         Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
2023:         while(it.hasNext())
2024:           {
2025:             ValidatorAndPriority vap = it.next();
2026:             ObjectInputValidation validator = vap.validator;
2027:             validator.validateObject();
2028:           }
2029:       }
2030:     finally
2031:       {
2032:         currentObjectValidators = null;
2033:       }
2034:   }
2035: 
2036:   private void callReadMethod (Method readObject, Class klass, Object obj)
2037:     throws ClassNotFoundException, IOException
2038:   {
2039:     try
2040:       {
2041:         readObject.invoke(obj, new Object[] { this });
2042:       }
2043:     catch (InvocationTargetException x)
2044:       {
2045:         /* Rethrow if possible. */
2046:         Throwable exception = x.getTargetException();
2047:         if (exception instanceof RuntimeException)
2048:           throw (RuntimeException) exception;
2049:         if (exception instanceof IOException)
2050:           throw (IOException) exception;
2051:         if (exception instanceof ClassNotFoundException)
2052:           throw (ClassNotFoundException) exception;
2053: 
2054:         throw (IOException) new IOException(
2055:           "Exception thrown from readObject() on " + klass).initCause(x);
2056:       }
2057:     catch (Exception x)
2058:       {
2059:         throw (IOException) new IOException(
2060:           "Failure invoking readObject() on " + klass).initCause(x);
2061:       }
2062: 
2063:     // Invalidate fields which has been read through readFields.
2064:     prereadFields = null;
2065:   }
2066: 
2067:   private static final int BUFFER_SIZE = 1024;
2068: 
2069:   private DataInputStream realInputStream;
2070:   private DataInputStream dataInputStream;
2071:   private DataInputStream blockDataInput;
2072:   private int blockDataPosition;
2073:   private int blockDataBytes;
2074:   private byte[] blockData;
2075:   private boolean useSubclassMethod;
2076:   private int nextOID;
2077:   private boolean resolveEnabled;
2078:   private Map<Integer,Pair<Boolean,Object>> handles;
2079:   private Object currentObject;
2080:   private ObjectStreamClass currentObjectStreamClass;
2081:   private TreeSet<ValidatorAndPriority> currentObjectValidators;
2082:   private boolean readDataFromBlock;
2083:   private boolean fieldsAlreadyRead;
2084:   private Hashtable<Class,ObjectStreamClass> classLookupTable;
2085:   private GetField prereadFields;
2086: 
2087:   private static boolean dump;
2088: 
2089:   // The nesting depth for debugging output
2090:   private int depth = 0;
2091: 
2092:   private static final boolean DEBUG = false;
2093: 
2094:   private void dumpElement (String msg)
2095:   {
2096:     System.out.print(msg);
2097:   }
2098: 
2099:   private void dumpElementln (String msg)
2100:   {
2101:     System.out.println(msg);
2102:     for (int i = 0; i < depth; i++)
2103:       System.out.print (" ");
2104:     System.out.print (Thread.currentThread() + ": ");
2105:   }
2106: 
2107:   private void dumpElementln (String msg, Object obj)
2108:   {
2109:     try
2110:       {
2111:         System.out.print(msg);
2112:         if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
2113:           System.out.println(obj.getClass());
2114:         else
2115:         System.out.println(obj);
2116:       }
2117:     catch (Exception _)
2118:       {
2119:       }
2120:     for (int i = 0; i < depth; i++)
2121:       System.out.print (" ");
2122:     System.out.print (Thread.currentThread() + ": ");
2123:   }
2124: 
2125:   // used to keep a prioritized list of object validators
2126:   private static final class ValidatorAndPriority implements Comparable
2127:   {
2128:     int priority;
2129:     ObjectInputValidation validator;
2130: 
2131:     ValidatorAndPriority (ObjectInputValidation validator, int priority)
2132:     {
2133:       this.priority = priority;
2134:       this.validator = validator;
2135:     }
2136: 
2137:     public int compareTo (Object o)
2138:     {
2139:       ValidatorAndPriority vap = (ValidatorAndPriority)o;
2140:       return this.priority - vap.priority;
2141:     }
2142:   }
2143: }