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:            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: }