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