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