Save This Page
Home » apache-harmony-6.0-src-r917296-snapshot » java » io » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package java.io;
   19   
   20   import java.io.EmulatedFields.ObjectSlot;
   21   import java.lang.reflect.Array;
   22   import java.lang.reflect.Constructor;
   23   import java.lang.reflect.InvocationTargetException;
   24   import java.lang.reflect.Method;
   25   import java.lang.reflect.Modifier;
   26   import java.lang.reflect.Proxy;
   27   import java.security.AccessController;
   28   import java.security.PrivilegedAction;
   29   import java.util.ArrayList;
   30   import java.util.HashMap;
   31   import java.util.Iterator;
   32   
   33   import org.apache.harmony.misc.accessors.ObjectAccessor;
   34   import org.apache.harmony.misc.accessors.AccessorFactory;
   35   
   36   import org.apache.harmony.kernel.vm.VM;
   37   import org.apache.harmony.luni.internal.nls.Messages;
   38   import org.apache.harmony.luni.internal.nls.Messages;
   39   import org.apache.harmony.luni.util.PriviAction;
   40   
   41   /**
   42    * A specialized {@link InputStream} that is able to read (deserialize) Java
   43    * objects as well as primitive data types (int, byte, char etc.). The data has
   44    * typically been saved using an ObjectOutputStream.
   45    * 
   46    * @see ObjectOutputStream
   47    * @see ObjectInput
   48    * @see Serializable
   49    * @see Externalizable
   50    */
   51   public class ObjectInputStream extends InputStream implements ObjectInput,
   52           ObjectStreamConstants {
   53   
   54       private InputStream emptyStream = new ByteArrayInputStream(
   55               new byte[0]);
   56   
   57       // To put into objectsRead when reading unsharedObject
   58       private static final Object UNSHARED_OBJ = new Object(); // $NON-LOCK-1$
   59   
   60       // If the receiver has already read & not consumed a TC code
   61       private boolean hasPushbackTC;
   62   
   63       // Push back TC code if the variable above is true
   64       private byte pushbackTC;
   65   
   66       // How many nested levels to readObject. When we reach 0 we have to validate
   67       // the graph then reset it
   68       private int nestedLevels;
   69   
   70       // All objects are assigned an ID (integer handle)
   71       private int currentHandle;
   72   
   73       // Where we read from
   74       private DataInputStream input;
   75   
   76       // Where we read primitive types from
   77       private DataInputStream primitiveTypes;
   78   
   79       // Where we keep primitive type data
   80       private InputStream primitiveData = emptyStream;
   81   
   82       // Resolve object is a mechanism for replacement
   83       private boolean enableResolve;
   84   
   85       // Table mapping Integer (handle) -> Object
   86       private HashMap<Integer, Object> objectsRead;
   87   
   88       // Used by defaultReadObject
   89       private Object currentObject;
   90   
   91       // Used by defaultReadObject
   92       private ObjectStreamClass currentClass;
   93   
   94       // All validations to be executed when the complete graph is read. See inner
   95       // type below.
   96       private InputValidationDesc[] validations;
   97   
   98       // Allows the receiver to decide if it needs to call readObjectOverride
   99       private boolean subclassOverridingImplementation;
  100   
  101       // Original caller's class loader, used to perform class lookups
  102       private ClassLoader callerClassLoader;
  103   
  104       // false when reading missing fields
  105       private boolean mustResolve = true;
  106   
  107       // Handle for the current class descriptor
  108       private Integer descriptorHandle;
  109   
  110       private static final HashMap<String, Class<?>> PRIMITIVE_CLASSES =
  111           new HashMap<String, Class<?>>();
  112   
  113       static {
  114           PRIMITIVE_CLASSES.put("byte", byte.class); //$NON-NLS-1$
  115           PRIMITIVE_CLASSES.put("short", short.class); //$NON-NLS-1$
  116           PRIMITIVE_CLASSES.put("int", int.class); //$NON-NLS-1$
  117           PRIMITIVE_CLASSES.put("long", long.class); //$NON-NLS-1$
  118           PRIMITIVE_CLASSES.put("boolean", boolean.class); //$NON-NLS-1$
  119           PRIMITIVE_CLASSES.put("char", char.class); //$NON-NLS-1$
  120           PRIMITIVE_CLASSES.put("float", float.class); //$NON-NLS-1$
  121           PRIMITIVE_CLASSES.put("double", double.class); //$NON-NLS-1$
  122       }
  123   
  124       private ObjectAccessor accessor = AccessorFactory.getObjectAccessor();
  125   
  126       // Internal type used to keep track of validators & corresponding priority
  127       static class InputValidationDesc {
  128           ObjectInputValidation validator;
  129   
  130           int priority;
  131       }
  132   
  133       /**
  134        * GetField is an inner class that provides access to the persistent fields
  135        * read from the source stream.
  136        */
  137       public abstract static class GetField {
  138           /**
  139            * Gets the ObjectStreamClass that describes a field.
  140            *
  141            * @return the descriptor class for a serialized field.
  142            */
  143           public abstract ObjectStreamClass getObjectStreamClass();
  144   
  145           /**
  146            * Indicates if the field identified by {@code name} is defaulted. This
  147            * means that it has no value in this stream.
  148            *
  149            * @param name
  150            *            the name of the field to check.
  151            * @return {@code true} if the field is defaulted, {@code false}
  152            *         otherwise.
  153            * @throws IllegalArgumentException
  154            *             if {@code name} does not identify a serializable field.
  155            * @throws IOException
  156            *             if an error occurs while reading from the source input
  157            *             stream.
  158            */
  159           public abstract boolean defaulted(String name) throws IOException,
  160                   IllegalArgumentException;
  161   
  162           /**
  163            * Gets the value of the boolean field identified by {@code name} from
  164            * the persistent field.
  165            *
  166            * @param name
  167            *            the name of the field to get.
  168            * @param defaultValue
  169            *            the default value that is used if the field does not have
  170            *            a value when read from the source stream.
  171            * @return the value of the field identified by {@code name}.
  172            * @throws IOException
  173            *             if an error occurs while reading from the source input
  174            *             stream.
  175            * @throws IllegalArgumentException
  176            *             if the type of the field identified by {@code name} is
  177            *             not {@code boolean}.
  178            */
  179           public abstract boolean get(String name, boolean defaultValue)
  180                   throws IOException, IllegalArgumentException;
  181   
  182           /**
  183            * Gets the value of the character field identified by {@code name} from
  184            * the persistent field.
  185            *
  186            * @param name
  187            *            the name of the field to get.
  188            * @param defaultValue
  189            *            the default value that is used if the field does not have
  190            *            a value when read from the source stream.
  191            * @return the value of the field identified by {@code name}.
  192            * @throws IOException
  193            *             if an error occurs while reading from the source input
  194            *             stream.
  195            * @throws IllegalArgumentException
  196            *             if the type of the field identified by {@code name} is
  197            *             not {@code char}.
  198            */
  199           public abstract char get(String name, char defaultValue)
  200                   throws IOException, IllegalArgumentException;
  201   
  202           /**
  203            * Gets the value of the byte field identified by {@code name} from the
  204            * persistent field.
  205            *
  206            * @param name
  207            *            the name of the field to get.
  208            * @param defaultValue
  209            *            the default value that is used if the field does not have
  210            *            a value when read from the source stream.
  211            * @return the value of the field identified by {@code name}.
  212            * @throws IOException
  213            *             if an error occurs while reading from the source input
  214            *             stream.
  215            * @throws IllegalArgumentException
  216            *             if the type of the field identified by {@code name} is
  217            *             not {@code byte}.
  218            */
  219           public abstract byte get(String name, byte defaultValue)
  220                   throws IOException, IllegalArgumentException;
  221   
  222           /**
  223            * Gets the value of the short field identified by {@code name} from the
  224            * persistent field.
  225            *
  226            * @param name
  227            *            the name of the field to get.
  228            * @param defaultValue
  229            *            the default value that is used if the field does not have
  230            *            a value when read from the source stream.
  231            * @return the value of the field identified by {@code name}.
  232            * @throws IOException
  233            *             if an error occurs while reading from the source input
  234            *             stream.
  235            * @throws IllegalArgumentException
  236            *             if the type of the field identified by {@code name} is
  237            *             not {@code short}.
  238            */
  239           public abstract short get(String name, short defaultValue)
  240                   throws IOException, IllegalArgumentException;
  241   
  242           /**
  243            * Gets the value of the integer field identified by {@code name} from
  244            * the persistent field.
  245            *
  246            * @param name
  247            *            the name of the field to get.
  248            * @param defaultValue
  249            *            the default value that is used if the field does not have
  250            *            a value when read from the source stream.
  251            * @return the value of the field identified by {@code name}.
  252            * @throws IOException
  253            *             if an error occurs while reading from the source input
  254            *             stream.
  255            * @throws IllegalArgumentException
  256            *             if the type of the field identified by {@code name} is
  257            *             not {@code int}.
  258            */
  259           public abstract int get(String name, int defaultValue)
  260                   throws IOException, IllegalArgumentException;
  261   
  262           /**
  263            * Gets the value of the long field identified by {@code name} from the
  264            * persistent field.
  265            *
  266            * @param name
  267            *            the name of the field to get.
  268            * @param defaultValue
  269            *            the default value that is used if the field does not have
  270            *            a value when read from the source stream.
  271            * @return the value of the field identified by {@code name}.
  272            * @throws IOException
  273            *             if an error occurs while reading from the source input
  274            *             stream.
  275            * @throws IllegalArgumentException
  276            *             if the type of the field identified by {@code name} is
  277            *             not {@code long}.
  278            */
  279           public abstract long get(String name, long defaultValue)
  280                   throws IOException, IllegalArgumentException;
  281   
  282           /**
  283            * Gets the value of the float field identified by {@code name} from the
  284            * persistent field.
  285            *
  286            * @param name
  287            *            the name of the field to get.
  288            * @param defaultValue
  289            *            the default value that is used if the field does not have
  290            *            a value when read from the source stream.
  291            * @return the value of the field identified by {@code name}.
  292            * @throws IOException
  293            *             if an error occurs while reading from the source input
  294            *             stream.
  295            * @throws IllegalArgumentException
  296            *             if the type of the field identified by {@code float} is
  297            *             not {@code char}.
  298            */
  299           public abstract float get(String name, float defaultValue)
  300                   throws IOException, IllegalArgumentException;
  301   
  302           /**
  303            * Gets the value of the double field identified by {@code name} from
  304            * the persistent field.
  305            *
  306            * @param name
  307            *            the name of the field to get.
  308            * @param defaultValue
  309            *            the default value that is used if the field does not have
  310            *            a value when read from the source stream.
  311            * @return the value of the field identified by {@code name}.
  312            * @throws IOException
  313            *             if an error occurs while reading from the source input
  314            *             stream.
  315            * @throws IllegalArgumentException
  316            *             if the type of the field identified by {@code name} is
  317            *             not {@code double}.
  318            */
  319           public abstract double get(String name, double defaultValue)
  320                   throws IOException, IllegalArgumentException;
  321   
  322           /**
  323            * Gets the value of the object field identified by {@code name} from
  324            * the persistent field.
  325            *
  326            * @param name
  327            *            the name of the field to get.
  328            * @param defaultValue
  329            *            the default value that is used if the field does not have
  330            *            a value when read from the source stream.
  331            * @return the value of the field identified by {@code name}.
  332            * @throws IOException
  333            *             if an error occurs while reading from the source input
  334            *             stream.
  335            * @throws IllegalArgumentException
  336            *             if the type of the field identified by {@code name} is
  337            *             not {@code Object}.
  338            */
  339           public abstract Object get(String name, Object defaultValue)
  340                   throws IOException, IllegalArgumentException;
  341       }
  342   
  343       /**
  344        * Constructs a new ObjectInputStream. This default constructor can be used
  345        * by subclasses that do not want to use the public constructor if it
  346        * allocates unneeded data.
  347        * 
  348        * @throws IOException
  349        *             if an error occurs when creating this stream.
  350        * @throws SecurityException
  351        *             if a security manager is installed and it denies subclassing
  352        *             this class.
  353        * @see SecurityManager#checkPermission(java.security.Permission)
  354        */
  355       protected ObjectInputStream() throws IOException, SecurityException {
  356           super();
  357           SecurityManager currentManager = System.getSecurityManager();
  358           if (currentManager != null) {
  359               currentManager.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  360           }
  361           // WARNING - we should throw IOException if not called from a subclass
  362           // according to the JavaDoc. Add the test.
  363           this.subclassOverridingImplementation = true;
  364       }
  365   
  366       /**
  367        * Constructs a new ObjectInputStream that reads from the InputStream
  368        * {@code input}.
  369        * 
  370        * @param input
  371        *            the non-null source InputStream to filter reads on.
  372        * @throws IOException
  373        *             if an error occurs while reading the stream header.
  374        * @throws StreamCorruptedException
  375        *             if the source stream does not contain serialized objects that
  376        *             can be read.
  377        * @throws SecurityException
  378        *             if a security manager is installed and it denies subclassing
  379        *             this class.
  380        */
  381       public ObjectInputStream(InputStream input)
  382               throws StreamCorruptedException, IOException {
  383           final Class<?> implementationClass = getClass();
  384           final Class<?> thisClass = ObjectInputStream.class;
  385           SecurityManager sm = System.getSecurityManager();
  386           if (sm != null && implementationClass != thisClass) {
  387               boolean mustCheck = (AccessController
  388                       .doPrivileged(new PrivilegedAction<Boolean>() {
  389                           public Boolean run() {
  390                               try {
  391                                   Method method = implementationClass
  392                                           .getMethod(
  393                                                   "readFields", //$NON-NLS-1$
  394                                                   ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
  395                                   if (method.getDeclaringClass() != thisClass) {
  396                                       return Boolean.TRUE;
  397                                   }
  398                               } catch (NoSuchMethodException e) {
  399                               }
  400                               try {
  401                                   Method method = implementationClass
  402                                           .getMethod(
  403                                                   "readUnshared", //$NON-NLS-1$
  404                                                   ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
  405                                   if (method.getDeclaringClass() != thisClass) {
  406                                       return Boolean.TRUE;
  407                                   }
  408                               } catch (NoSuchMethodException e) {
  409                               }
  410                               return Boolean.FALSE;
  411                           }
  412                       })).booleanValue();
  413               if (mustCheck) {
  414                   sm
  415                           .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
  416               }
  417           }
  418           this.input = (input instanceof DataInputStream) ? (DataInputStream) input
  419                   : new DataInputStream(input);
  420           primitiveTypes = new DataInputStream(this);
  421           enableResolve = false;
  422           this.subclassOverridingImplementation = false;
  423           resetState();
  424           nestedLevels = 0;
  425           // So read...() methods can be used by
  426           // subclasses during readStreamHeader()
  427           primitiveData = this.input;
  428           // Has to be done here according to the specification
  429           readStreamHeader();
  430           primitiveData = emptyStream;
  431       }
  432   
  433       /**
  434        * Returns the number of bytes of primitive data that can be read from this
  435        * stream without blocking. This method should not be used at any arbitrary
  436        * position; just when reading primitive data types (int, char etc).
  437        * 
  438        * @return the number of available primitive data bytes.
  439        * @throws IOException
  440        *             if any I/O problem occurs while computing the available
  441        *             bytes.
  442        */
  443       @Override
  444       public int available() throws IOException {
  445           // returns 0 if next data is an object, or N if reading primitive types
  446           checkReadPrimitiveTypes();
  447           return primitiveData.available();
  448       }
  449   
  450       /**
  451        * Checks to if it is ok to read primitive types from this stream at
  452        * this point. One is not supposed to read primitive types when about to
  453        * read an object, for example, so an exception has to be thrown.
  454        * 
  455        * @throws IOException
  456        *             If any IO problem occurred when trying to read primitive type
  457        *             or if it is illegal to read primitive types
  458        */
  459       private void checkReadPrimitiveTypes() throws IOException {
  460           // If we still have primitive data, it is ok to read primitive data
  461           if (primitiveData == input || primitiveData.available() > 0) {
  462               return;
  463           }
  464   
  465           // If we got here either we had no Stream previously created or
  466           // we no longer have data in that one, so get more bytes
  467           do {
  468               int next = 0;
  469               if (hasPushbackTC) {
  470                   hasPushbackTC = false;
  471               } else {
  472                   next = input.read();
  473                   pushbackTC = (byte) next;
  474               }
  475               switch (pushbackTC) {
  476                   case TC_BLOCKDATA:
  477                       primitiveData = new ByteArrayInputStream(readBlockData());
  478                       return;
  479                   case TC_BLOCKDATALONG:
  480                       primitiveData = new ByteArrayInputStream(
  481                               readBlockDataLong());
  482                       return;
  483                   case TC_RESET:
  484                       resetState();
  485                       break;
  486                   default:
  487                       if (next != -1) {
  488                           pushbackTC();
  489                       }
  490                       return;
  491               }
  492               // Only TC_RESET falls through
  493           } while (true);
  494       }
  495   
  496       /**
  497        * Closes this stream. This implementation closes the source stream.
  498        * 
  499        * @throws IOException
  500        *             if an error occurs while closing this stream.
  501        */
  502       @Override
  503       public void close() throws IOException {
  504           input.close();
  505       }
  506   
  507       /**
  508        * Default method to read objects from this stream. Serializable fields
  509        * defined in the object's class and superclasses are read from the source
  510        * stream.
  511        * 
  512        * @throws ClassNotFoundException
  513        *             if the object's class cannot be found.
  514        * @throws IOException
  515        *             if an I/O error occurs while reading the object data.
  516        * @throws NotActiveException
  517        *             if this method is not called from {@code readObject()}.
  518        * @see ObjectOutputStream#defaultWriteObject
  519        */
  520       public void defaultReadObject() throws IOException, ClassNotFoundException,
  521               NotActiveException {
  522           // We can't be called from just anywhere. There are rules.
  523           if (currentObject != null || !mustResolve) {
  524               readFieldValues(currentObject, currentClass);
  525           } else {
  526               throw new NotActiveException();
  527           }
  528       }
  529   
  530       /**
  531        * Enables object replacement for this stream. By default this is not
  532        * enabled. Only trusted subclasses (loaded with system class loader) are
  533        * allowed to change this status.
  534        * 
  535        * @param enable
  536        *            {@code true} to enable object replacement; {@code false} to
  537        *            disable it.
  538        * @return the previous setting.
  539        * @throws SecurityException
  540        *             if a security manager is installed and it denies enabling
  541        *             object replacement for this stream.
  542        * @see #resolveObject
  543        * @see ObjectOutputStream#enableReplaceObject
  544        */
  545       protected boolean enableResolveObject(boolean enable)
  546               throws SecurityException {
  547           if (enable) {
  548               // The Stream has to be trusted for this feature to be enabled.
  549               // trusted means the stream's classloader has to be null
  550               SecurityManager currentManager = System.getSecurityManager();
  551               if (currentManager != null) {
  552                   currentManager.checkPermission(SUBSTITUTION_PERMISSION);
  553               }
  554           }
  555           boolean originalValue = enableResolve;
  556           enableResolve = enable;
  557           return originalValue;
  558       }
  559   
  560       /**
  561        * Checks if two classes belong to the same package.
  562        * 
  563        * @param c1
  564        *            one of the classes to test.
  565        * @param c2
  566        *            the other class to test.
  567        * @return {@code true} if the two classes belong to the same package,
  568        *         {@code false} otherwise.
  569        */
  570       private boolean inSamePackage(Class<?> c1, Class<?> c2) {
  571           String nameC1 = c1.getName();
  572           String nameC2 = c2.getName();
  573           int indexDotC1 = nameC1.lastIndexOf('.');
  574           int indexDotC2 = nameC2.lastIndexOf('.');
  575           if (indexDotC1 != indexDotC2) {
  576               return false; // cannot be in the same package if indices are not
  577           }
  578           // the same
  579           if (indexDotC1 < 0) {
  580               return true; // both of them are in default package
  581           }
  582           return nameC1.substring(0, indexDotC1).equals(
  583                   nameC2.substring(0, indexDotC2));
  584       }
  585   
  586       /**
  587        * Return the next {@code int} handle to be used to indicate cyclic
  588        * references being loaded from the stream.
  589        * 
  590        * @return the next handle to represent the next cyclic reference
  591        */
  592       private Integer nextHandle() {
  593           return Integer.valueOf(this.currentHandle++);
  594       }
  595   
  596       /**
  597        * Return the next token code (TC) from the receiver, which indicates what
  598        * kind of object follows
  599        * 
  600        * @return the next TC from the receiver
  601        * 
  602        * @throws IOException
  603        *             If an IO error occurs
  604        * 
  605        * @see ObjectStreamConstants
  606        */
  607       private byte nextTC() throws IOException {
  608           if (hasPushbackTC) {
  609               hasPushbackTC = false; // We are consuming it
  610           } else {
  611               // Just in case a later call decides to really push it back,
  612               // we don't require the caller to pass it as parameter
  613               pushbackTC = input.readByte();
  614           }
  615           return pushbackTC;
  616       }
  617   
  618       /**
  619        * Pushes back the last TC code read
  620        */
  621       private void pushbackTC() {
  622           hasPushbackTC = true;
  623       }
  624   
  625       /**
  626        * Reads a single byte from the source stream and returns it as an integer
  627        * in the range from 0 to 255. Returns -1 if the end of the source stream
  628        * has been reached. Blocks if no input is available.
  629        * 
  630        * @return the byte read or -1 if the end of the source stream has been
  631        *         reached.
  632        * @throws IOException
  633        *             if an error occurs while reading from this stream.
  634        */
  635       @Override
  636       public int read() throws IOException {
  637           checkReadPrimitiveTypes();
  638           return primitiveData.read();
  639       }
  640   
  641       /**
  642        * Reads at most {@code length} bytes from the source stream and stores them
  643        * in byte array {@code buffer} starting at offset {@code count}. Blocks
  644        * until {@code count} bytes have been read, the end of the source stream is
  645        * detected or an exception is thrown.
  646        * 
  647        * @param buffer
  648        *            the array in which to store the bytes read.
  649        * @param offset
  650        *            the initial position in {@code buffer} to store the bytes
  651        *            read from the source stream.
  652        * @param length
  653        *            the maximum number of bytes to store in {@code buffer}.
  654        * @return the number of bytes read or -1 if the end of the source input
  655        *         stream has been reached.
  656        * @throws IndexOutOfBoundsException
  657        *             if {@code offset < 0} or {@code length < 0}, or if
  658        *             {@code offset + length} is greater than the length of
  659        *             {@code buffer}.
  660        * @throws IOException
  661        *             if an error occurs while reading from this stream.
  662        * @throws NullPointerException
  663        *             if {@code buffer} is {@code null}.
  664        */
  665       @Override
  666       public int read(byte[] buffer, int offset, int length) throws IOException {
  667           // Force buffer null check first!
  668           if (offset > buffer.length || offset < 0) {
  669               // luni.12=Offset out of bounds \: {0}
  670               throw new ArrayIndexOutOfBoundsException(Messages.getString("luni.12", offset)); //$NON-NLS-1$
  671           }
  672           if (length < 0 || length > buffer.length - offset) {
  673               // luni.18=Length out of bounds \: {0}
  674               throw new ArrayIndexOutOfBoundsException(Messages.getString("luni.18", length)); //$NON-NLS-1$
  675           }
  676           if (length == 0) {
  677               return 0;
  678           }
  679           checkReadPrimitiveTypes();
  680           return primitiveData.read(buffer, offset, length);
  681       }
  682   
  683       /**
  684        * Reads and returns an array of raw bytes with primitive data. The array
  685        * will have up to 255 bytes. The primitive data will be in the format
  686        * described by {@code DataOutputStream}.
  687        * 
  688        * @return The primitive data read, as raw bytes
  689        * 
  690        * @throws IOException
  691        *             If an IO exception happened when reading the primitive data.
  692        */
  693       private byte[] readBlockData() throws IOException {
  694           byte[] result = new byte[input.readByte() & 0xff];
  695           input.readFully(result);
  696           return result;
  697       }
  698   
  699       /**
  700        * Reads and returns an array of raw bytes with primitive data. The array
  701        * will have more than 255 bytes. The primitive data will be in the format
  702        * described by {@code DataOutputStream}.
  703        * 
  704        * @return The primitive data read, as raw bytes
  705        * 
  706        * @throws IOException
  707        *             If an IO exception happened when reading the primitive data.
  708        */
  709       private byte[] readBlockDataLong() throws IOException {
  710           byte[] result = new byte[input.readInt()];
  711           input.readFully(result);
  712           return result;
  713       }
  714   
  715       /**
  716        * Reads a boolean from the source stream.
  717        * 
  718        * @return the boolean value read from the source stream.
  719        * @throws EOFException
  720        *             if the end of the input is reached before the read
  721        *             request can be satisfied.
  722        * @throws IOException
  723        *             if an error occurs while reading from the source stream.
  724        */
  725       public boolean readBoolean() throws IOException {
  726           return primitiveTypes.readBoolean();
  727       }
  728   
  729       /**
  730        * Reads a byte (8 bit) from the source stream.
  731        * 
  732        * @return the byte value read from the source stream.
  733        * @throws EOFException
  734        *             if the end of the input is reached before the read
  735        *             request can be satisfied.
  736        * @throws IOException
  737        *             if an error occurs while reading from the source stream.
  738        */
  739       public byte readByte() throws IOException {
  740           return primitiveTypes.readByte();
  741       }
  742   
  743       /**
  744        * Reads a character (16 bit) from the source stream.
  745        * 
  746        * @return the char value read from the source stream.
  747        * @throws EOFException
  748        *             if the end of the input is reached before the read
  749        *             request can be satisfied.
  750        * @throws IOException
  751        *             if an error occurs while reading from the source stream.
  752        */
  753       public char readChar() throws IOException {
  754           return primitiveTypes.readChar();
  755       }
  756   
  757       /**
  758        * Reads and discards block data and objects until TC_ENDBLOCKDATA is found.
  759        * 
  760        * @throws IOException
  761        *             If an IO exception happened when reading the optional class
  762        *             annotation.
  763        * @throws ClassNotFoundException
  764        *             If the class corresponding to the class descriptor could not
  765        *             be found.
  766        */
  767       private void discardData() throws ClassNotFoundException, IOException {
  768           primitiveData = emptyStream;
  769           boolean resolve = mustResolve;
  770           mustResolve = false;
  771           do {
  772               byte tc = nextTC();
  773               if (tc == TC_ENDBLOCKDATA) {
  774                   mustResolve = resolve;
  775                   return; // End of annotation
  776               }
  777               readContent(tc);
  778           } while (true);
  779       }
  780   
  781       /**
  782        * Reads a class descriptor (an {@code ObjectStreamClass}) from the
  783        * stream.
  784        * 
  785        * @return the class descriptor read from the stream
  786        * 
  787        * @throws IOException
  788        *             If an IO exception happened when reading the class
  789        *             descriptor.
  790        * @throws ClassNotFoundException
  791        *             If the class corresponding to the class descriptor could not
  792        *             be found.
  793        */
  794       private ObjectStreamClass readClassDesc() throws ClassNotFoundException,
  795               IOException {
  796           byte tc = nextTC();
  797           switch (tc) {
  798               case TC_CLASSDESC:
  799                   return readNewClassDesc(false);
  800               case TC_PROXYCLASSDESC:
  801                   Class<?> proxyClass = readNewProxyClassDesc();
  802                   ObjectStreamClass streamClass = ObjectStreamClass
  803                           .lookup(proxyClass);
  804                   streamClass.setLoadFields(new ObjectStreamField[0]);
  805                   registerObjectRead(streamClass, nextHandle(), false);
  806                   checkedSetSuperClassDesc(streamClass, readClassDesc());
  807                   return streamClass;
  808               case TC_REFERENCE:
  809                   return (ObjectStreamClass) readCyclicReference();
  810               case TC_NULL:
  811                   return null;
  812               default:
  813                   throw new StreamCorruptedException(Messages.getString(
  814                           "luni.BC", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
  815           }
  816       }
  817   
  818       /**
  819        * Reads the content of the receiver based on the previously read token
  820        * {@code tc}.
  821        * 
  822        * @param tc
  823        *            The token code for the next item in the stream
  824        * @return the object read from the stream
  825        * 
  826        * @throws IOException
  827        *             If an IO exception happened when reading the class
  828        *             descriptor.
  829        * @throws ClassNotFoundException
  830        *             If the class corresponding to the object being read could not
  831        *             be found.
  832        */
  833       private Object readContent(byte tc) throws ClassNotFoundException,
  834               IOException {
  835           switch (tc) {
  836               case TC_BLOCKDATA:
  837                   return readBlockData();
  838               case TC_BLOCKDATALONG:
  839                   return readBlockDataLong();
  840               case TC_CLASS:
  841                   return readNewClass(false);
  842               case TC_CLASSDESC:
  843                   return readNewClassDesc(false);
  844               case TC_ARRAY:
  845                   return readNewArray(false);
  846               case TC_OBJECT:
  847                   return readNewObject(false);
  848               case TC_STRING:
  849                   return readNewString(false);
  850               case TC_LONGSTRING:
  851                   return readNewLongString(false);
  852               case TC_REFERENCE:
  853                   return readCyclicReference();
  854               case TC_NULL:
  855                   return null;
  856               case TC_EXCEPTION:
  857                   Exception exc = readException();
  858                   throw new WriteAbortedException(Messages.getString("luni.BD"), exc); //$NON-NLS-1$
  859               case TC_RESET:
  860                   resetState();
  861                   return null;
  862               default:
  863                   throw new StreamCorruptedException(Messages.getString(
  864                           "luni.BC", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
  865           }
  866       }
  867   
  868       /**
  869        * Reads the content of the receiver based on the previously read token
  870        * {@code tc}. Primitive data content is considered an error.
  871        * 
  872        * @param unshared
  873        *            read the object unshared
  874        * @return the object read from the stream
  875        * 
  876        * @throws IOException
  877        *             If an IO exception happened when reading the class
  878        *             descriptor.
  879        * @throws ClassNotFoundException
  880        *             If the class corresponding to the object being read could not
  881        *             be found.
  882        */
  883       private Object readNonPrimitiveContent(boolean unshared)
  884               throws ClassNotFoundException, IOException {
  885           checkReadPrimitiveTypes();
  886           if (primitiveData.available() > 0) {
  887               OptionalDataException e = new OptionalDataException();
  888               e.length = primitiveData.available();
  889               throw e;
  890           }
  891   
  892           do {
  893               byte tc = nextTC();
  894               switch (tc) {
  895                   case TC_CLASS:
  896                       return readNewClass(unshared);
  897                   case TC_CLASSDESC:
  898                       return readNewClassDesc(unshared);
  899                   case TC_ARRAY:
  900                       return readNewArray(unshared);
  901                   case TC_OBJECT:
  902                       return readNewObject(unshared);
  903                   case TC_STRING:
  904                       return readNewString(unshared);
  905                   case TC_LONGSTRING:
  906                       return readNewLongString(unshared);
  907                   case TC_ENUM:
  908                       return readEnum(unshared);
  909                   case TC_REFERENCE:
  910                       if (unshared) {
  911                           readNewHandle();
  912                           throw new InvalidObjectException(Messages.getString("luni.BE")); //$NON-NLS-1$
  913                       }
  914                       return readCyclicReference();
  915                   case TC_NULL:
  916                       return null;
  917                   case TC_EXCEPTION:
  918                       Exception exc = readException();
  919                       throw new WriteAbortedException(Messages.getString("luni.BD"), exc); //$NON-NLS-1$
  920                   case TC_RESET:
  921                       resetState();
  922                       break;
  923                   case TC_ENDBLOCKDATA: // Can occur reading class annotation
  924                       pushbackTC();
  925                       OptionalDataException e = new OptionalDataException();
  926                       e.eof = true;
  927                       throw e;
  928                   default:
  929                       throw new StreamCorruptedException(Messages.getString(
  930                               "luni.BC", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
  931               }
  932               // Only TC_RESET falls through
  933           } while (true);
  934       }
  935   
  936       /**
  937        * Reads the next item from the stream assuming it is a cyclic reference to
  938        * an object previously read. Return the actual object previously read.
  939        * 
  940        * @return the object previously read from the stream
  941        * 
  942        * @throws IOException
  943        *             If an IO exception happened when reading the class
  944        *             descriptor.
  945        * @throws InvalidObjectException
  946        *             If the cyclic reference is not valid.
  947        */
  948       private Object readCyclicReference() throws InvalidObjectException,
  949               IOException {
  950           return registeredObjectRead(readNewHandle());
  951       }
  952   
  953       /**
  954        * Reads a double (64 bit) from the source stream.
  955        * 
  956        * @return the double value read from the source stream.
  957        * @throws EOFException
  958        *             if the end of the input is reached before the read
  959        *             request can be satisfied.
  960        * @throws IOException
  961        *             if an error occurs while reading from the source stream.
  962        */
  963       public double readDouble() throws IOException {
  964           return primitiveTypes.readDouble();
  965       }
  966   
  967       /**
  968        * Read the next item assuming it is an exception. The exception is not a
  969        * regular instance in the object graph, but the exception instance that
  970        * happened (if any) when dumping the original object graph. The set of seen
  971        * objects will be reset just before and just after loading this exception
  972        * object.
  973        * <p>
  974        * When exceptions are found normally in the object graph, they are loaded
  975        * as a regular object, and not by this method. In that case, the set of
  976        * "known objects" is not reset.
  977        * 
  978        * @return the exception read
  979        * 
  980        * @throws IOException
  981        *             If an IO exception happened when reading the exception
  982        *             object.
  983        * @throws ClassNotFoundException
  984        *             If a class could not be found when reading the object graph
  985        *             for the exception
  986        * @throws OptionalDataException
  987        *             If optional data could not be found when reading the
  988        *             exception graph
  989        * @throws WriteAbortedException
  990        *             If another exception was caused when dumping this exception
  991        */
  992       private Exception readException() throws WriteAbortedException,
  993               OptionalDataException, ClassNotFoundException, IOException {
  994   
  995           resetSeenObjects();
  996   
  997           // Now we read the Throwable object that was saved
  998           // WARNING - the grammar says it is a Throwable, but the
  999           // WriteAbortedException constructor takes an Exception. So, we read an
 1000           // Exception from the stream
 1001           Exception exc = (Exception) readObject();
 1002   
 1003           // We reset the receiver's state (the grammar has "reset" in normal
 1004           // font)
 1005           resetSeenObjects();
 1006           return exc;
 1007       }
 1008   
 1009       /**
 1010        * Reads a collection of field descriptors (name, type name, etc) for the
 1011        * class descriptor {@code cDesc} (an {@code ObjectStreamClass})
 1012        * 
 1013        * @param cDesc
 1014        *            The class descriptor (an {@code ObjectStreamClass})
 1015        *            for which to write field information
 1016        * 
 1017        * @throws IOException
 1018        *             If an IO exception happened when reading the field
 1019        *             descriptors.
 1020        * @throws ClassNotFoundException
 1021        *             If a class for one of the field types could not be found
 1022        * 
 1023        * @see #readObject()
 1024        */
 1025       private void readFieldDescriptors(ObjectStreamClass cDesc)
 1026               throws ClassNotFoundException, IOException {
 1027           short numFields = input.readShort();
 1028           ObjectStreamField[] fields = new ObjectStreamField[numFields];
 1029   
 1030           // We set it now, but each element will be inserted in the array further
 1031           // down
 1032           cDesc.setLoadFields(fields);
 1033   
 1034           // Check ObjectOutputStream.writeFieldDescriptors
 1035           for (short i = 0; i < numFields; i++) {
 1036               char typecode = (char) input.readByte();
 1037               String fieldName = input.readUTF();
 1038               boolean isPrimType = ObjectStreamClass.isPrimitiveType(typecode);
 1039               String classSig;
 1040               if (isPrimType) {
 1041                   classSig = String.valueOf(typecode);
 1042               } else {
 1043                   // The spec says it is a UTF, but experience shows they dump
 1044                   // this String using writeObject (unlike the field name, which
 1045                   // is saved with writeUTF).
 1046                   // And if resolveObject is enabled, the classSig may be modified
 1047                   // so that the original class descriptor cannot be read
 1048                   // properly, so it is disabled.
 1049                   boolean old = enableResolve;
 1050                   try {
 1051                       enableResolve = false;
 1052                       classSig = (String) readObject();
 1053                   } finally {
 1054                       enableResolve = old;
 1055                   }
 1056               }
 1057               
 1058               classSig = formatClassSig(classSig);
 1059               ObjectStreamField f = new ObjectStreamField(classSig, fieldName);
 1060               fields[i] = f;
 1061           }
 1062       }
 1063       
 1064       /*
 1065        * Format the class signature for ObjectStreamField, for example,
 1066        * "[L[Ljava.lang.String;;" is converted to "[Ljava.lang.String;"
 1067        */
 1068       private static String formatClassSig(String classSig) {
 1069           int start = 0;
 1070           int end = classSig.length();
 1071   
 1072           if (end <= 0) {
 1073               return classSig;
 1074           }
 1075   
 1076           while (classSig.startsWith("[L", start) //$NON-NLS-1$
 1077                   && classSig.charAt(end - 1) == ';') {
 1078               start += 2;
 1079               end--;
 1080           }
 1081   
 1082           if (start > 0) {
 1083               start -= 2;
 1084               end++;
 1085               return classSig.substring(start, end);
 1086           }
 1087           return classSig;
 1088       }
 1089   
 1090       /**
 1091        * Reads the persistent fields of the object that is currently being read
 1092        * from the source stream. The values read are stored in a GetField object
 1093        * that provides access to the persistent fields. This GetField object is
 1094        * then returned.
 1095        * 
 1096        * @return the GetField object from which persistent fields can be accessed
 1097        *         by name.
 1098        * @throws ClassNotFoundException
 1099        *             if the class of an object being deserialized can not be
 1100        *             found.
 1101        * @throws IOException
 1102        *             if an error occurs while reading from this stream.
 1103        * @throws NotActiveException
 1104        *             if this stream is currently not reading an object.
 1105        */
 1106       public GetField readFields() throws IOException, ClassNotFoundException,
 1107               NotActiveException {
 1108           // We can't be called from just anywhere. There are rules.
 1109           if (currentObject == null) {
 1110               throw new NotActiveException();
 1111           }
 1112           EmulatedFieldsForLoading result = new EmulatedFieldsForLoading(
 1113                   currentClass);
 1114           readFieldValues(result);
 1115           return result;
 1116       }
 1117   
 1118       /**
 1119        * Reads a collection of field values for the emulated fields
 1120        * {@code emulatedFields}
 1121        * 
 1122        * @param emulatedFields
 1123        *            an {@code EmulatedFieldsForLoading}, concrete subclass
 1124        *            of {@code GetField}
 1125        * 
 1126        * @throws IOException
 1127        *             If an IO exception happened when reading the field values.
 1128        * @throws InvalidClassException
 1129        *             If an incompatible type is being assigned to an emulated
 1130        *             field.
 1131        * @throws OptionalDataException
 1132        *             If optional data could not be found when reading the
 1133        *             exception graph
 1134        * 
 1135        * @see #readFields
 1136        * @see #readObject()
 1137        */
 1138       private void readFieldValues(EmulatedFieldsForLoading emulatedFields)
 1139               throws OptionalDataException, InvalidClassException, IOException {
 1140           EmulatedFields.ObjectSlot[] slots = emulatedFields.emulatedFields()
 1141                   .slots();
 1142           for (ObjectSlot element : slots) {
 1143               element.defaulted = false;
 1144               Class<?> type = element.field.getType();
 1145               if (type == Integer.TYPE) {
 1146                   element.fieldValue = Integer.valueOf(input.readInt());
 1147               } else if (type == Byte.TYPE) {
 1148                   element.fieldValue = Byte.valueOf(input.readByte());
 1149               } else if (type == Character.TYPE) {
 1150                   element.fieldValue = Character.valueOf(input.readChar());
 1151               } else if (type == Short.TYPE) {
 1152                   element.fieldValue = Short.valueOf(input.readShort());
 1153               } else if (type == Boolean.TYPE) {
 1154                   element.fieldValue = Boolean.valueOf(input.readBoolean());
 1155               } else if (type == Long.TYPE) {
 1156                   element.fieldValue = Long.valueOf(input.readLong());
 1157               } else if (type == Float.TYPE) {
 1158                   element.fieldValue = Float.valueOf(input.readFloat());
 1159               } else if (type == Double.TYPE) {
 1160                   element.fieldValue = Double.valueOf(input.readDouble());
 1161               } else {
 1162                   // Either array or Object
 1163                   try {
 1164                       element.fieldValue = readObject();
 1165                   } catch (ClassNotFoundException cnf) {
 1166                       // WARNING- Not sure this is the right thing to do. Write
 1167                       // test case.
 1168                       throw new InvalidClassException(cnf.toString());
 1169                   }
 1170               }
 1171           }
 1172       }
 1173   
 1174       /**
 1175        * Reads a collection of field values for the class descriptor
 1176        * {@code classDesc} (an {@code ObjectStreamClass}). The
 1177        * values will be used to set instance fields in object {@code obj}.
 1178        * This is the default mechanism, when emulated fields (an
 1179        * {@code GetField}) are not used. Actual values to load are stored
 1180        * directly into the object {@code obj}.
 1181        * 
 1182        * @param obj
 1183        *            Instance in which the fields will be set.
 1184        * @param classDesc
 1185        *            A class descriptor (an {@code ObjectStreamClass})
 1186        *            defining which fields should be loaded.
 1187        * 
 1188        * @throws IOException
 1189        *             If an IO exception happened when reading the field values.
 1190        * @throws InvalidClassException
 1191        *             If an incompatible type is being assigned to an emulated
 1192        *             field.
 1193        * @throws OptionalDataException
 1194        *             If optional data could not be found when reading the
 1195        *             exception graph
 1196        * @throws ClassNotFoundException
 1197        *             If a class of an object being de-serialized can not be found
 1198        * 
 1199        * @see #readFields
 1200        * @see #readObject()
 1201        */
 1202       private void readFieldValues(Object obj, ObjectStreamClass classDesc)
 1203               throws OptionalDataException, ClassNotFoundException, IOException {
 1204           // Now we must read all fields and assign them to the receiver
 1205           ObjectStreamField[] fields = classDesc.getLoadFields();
 1206           fields = (null == fields ? new ObjectStreamField[] {} : fields);
 1207           Class<?> declaringClass = classDesc.forClass();
 1208           if (declaringClass == null && mustResolve) {
 1209               throw new ClassNotFoundException(classDesc.getName());
 1210           }
 1211   
 1212           for (ObjectStreamField fieldDesc : fields) {
 1213   
 1214               // get associated Field 
 1215               long fieldID = fieldDesc.getFieldID(accessor, declaringClass);
 1216   
 1217               // Code duplication starts, just because Java is typed
 1218               if (fieldDesc.isPrimitive()) {
 1219                   try {
 1220                       switch (fieldDesc.getTypeCode()) {
 1221                           case 'B':
 1222                               byte srcByte = input.readByte();
 1223                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1224                                   accessor.setByte(obj, fieldID, srcByte);
 1225                               }
 1226                               break;
 1227                           case 'C':
 1228                               char srcChar = input.readChar();
 1229                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1230                                   accessor.setChar(obj, fieldID, srcChar);
 1231                               }
 1232                               break;
 1233                           case 'D':
 1234                               double srcDouble = input.readDouble();
 1235                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1236                                   accessor.setDouble(obj, fieldID, srcDouble);
 1237                               }
 1238                               break;
 1239                           case 'F':
 1240                               float srcFloat = input.readFloat();
 1241                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1242                                   accessor.setFloat(obj, fieldID, srcFloat);
 1243                               }
 1244                               break;
 1245                           case 'I':
 1246                               int srcInt = input.readInt();
 1247                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1248                                   accessor.setInt(obj, fieldID, srcInt);
 1249                               }
 1250                               break;
 1251                           case 'J':
 1252                               long srcLong = input.readLong();
 1253                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1254                                   accessor.setLong(obj, fieldID, srcLong);
 1255                               }
 1256                               break;
 1257                           case 'S':
 1258                               short srcShort = input.readShort();
 1259                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1260                                   accessor.setShort(obj, fieldID, srcShort);
 1261                               }
 1262                               break;
 1263                           case 'Z':
 1264                               boolean srcBoolean = input.readBoolean();
 1265                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1266                                   accessor.setBoolean(obj, fieldID, srcBoolean);
 1267                               }
 1268                               break;
 1269                           default:
 1270                               throw new StreamCorruptedException(Messages.getString(
 1271                                       "luni.BF", fieldDesc.getTypeCode())); //$NON-NLS-1$
 1272                       }
 1273                   } catch (NoSuchFieldError err) {
 1274                   }
 1275               } else {
 1276                   // Object type (array included).
 1277                   String fieldName = fieldDesc.getName();
 1278                   boolean setBack = false;
 1279                   if (mustResolve && fieldDesc == null) {
 1280                       setBack = true;
 1281                       mustResolve = false;
 1282                   }
 1283                   Object toSet;
 1284                   if (fieldDesc != null && fieldDesc.isUnshared()) {
 1285                       toSet = readUnshared();
 1286                   } else {
 1287                       toSet = readObject();
 1288                   }
 1289                   if (setBack) {
 1290                       mustResolve = true;
 1291                   }
 1292                   if (fieldDesc != null) {
 1293                       if (toSet != null) {
 1294                           Class<?> fieldType = fieldDesc.getType();
 1295                           Class<?> valueType = toSet.getClass();
 1296                           if (!fieldType.isAssignableFrom(valueType)) {
 1297                               throw new ClassCastException(Messages.getString(
 1298                                       "luni.C0", new String[] { //$NON-NLS-1$
 1299                                       fieldType.toString(), valueType.toString(),
 1300                                               classDesc.getName() + "." //$NON-NLS-1$
 1301                                                       + fieldName }));
 1302                           }
 1303                           try {
 1304                               if (fieldID != ObjectStreamField.FIELD_IS_ABSENT) { 
 1305                                   accessor.setObject(obj, fieldID, toSet);
 1306                               }
 1307                           } catch (NoSuchFieldError e) {
 1308                               // Ignored
 1309                           }
 1310                       }
 1311                   }
 1312               }
 1313           }
 1314       }
 1315   
 1316       /**
 1317        * Reads a float (32 bit) from the source stream.
 1318        * 
 1319        * @return the float value read from the source stream.
 1320        * @throws EOFException
 1321        *             if the end of the input is reached before the read
 1322        *             request can be satisfied.
 1323        * @throws IOException
 1324        *             if an error occurs while reading from the source stream.
 1325        */
 1326       public float readFloat() throws IOException {
 1327           return primitiveTypes.readFloat();
 1328       }
 1329   
 1330       /**
 1331        * Reads bytes from the source stream into the byte array {@code buffer}.
 1332        * This method will block until {@code buffer.length} bytes have been read.
 1333        * 
 1334        * @param buffer
 1335        *            the array in which to store the bytes read.
 1336        * @throws EOFException
 1337        *             if the end of the input is reached before the read
 1338        *             request can be satisfied.
 1339        * @throws IOException
 1340        *             if an error occurs while reading from the source stream.
 1341        */
 1342       public void readFully(byte[] buffer) throws IOException {
 1343           primitiveTypes.readFully(buffer);
 1344       }
 1345   
 1346       /**
 1347        * Reads bytes from the source stream into the byte array {@code buffer}.
 1348        * This method will block until {@code length} number of bytes have been
 1349        * read.
 1350        * 
 1351        * @param buffer
 1352        *            the byte array in which to store the bytes read.
 1353        * @param offset
 1354        *            the initial position in {@code buffer} to store the bytes
 1355        *            read from the source stream.
 1356        * @param length
 1357        *            the maximum number of bytes to store in {@code buffer}.
 1358        * @throws EOFException
 1359        *             if the end of the input is reached before the read
 1360        *             request can be satisfied.
 1361        * @throws IOException
 1362        *             if an error occurs while reading from the source stream.
 1363        */
 1364       public void readFully(byte[] buffer, int offset, int length)
 1365               throws IOException {
 1366           primitiveTypes.readFully(buffer, offset, length);
 1367       }
 1368   
 1369       /**
 1370        * Walks the hierarchy of classes described by class descriptor
 1371        * {@code classDesc} and reads the field values corresponding to
 1372        * fields declared by the corresponding class descriptor. The instance to
 1373        * store field values into is {@code object}. If the class
 1374        * (corresponding to class descriptor {@code classDesc}) defines
 1375        * private instance method {@code readObject} it will be used to load
 1376        * field values.
 1377        * 
 1378        * @param object
 1379        *            Instance into which stored field values loaded.
 1380        * @param classDesc
 1381        *            A class descriptor (an {@code ObjectStreamClass})
 1382        *            defining which fields should be loaded.
 1383        * 
 1384        * @throws IOException
 1385        *             If an IO exception happened when reading the field values in
 1386        *             the hierarchy.
 1387        * @throws ClassNotFoundException
 1388        *             If a class for one of the field types could not be found
 1389        * @throws NotActiveException
 1390        *             If {@code defaultReadObject} is called from the wrong
 1391        *             context.
 1392        * 
 1393        * @see #defaultReadObject
 1394        * @see #readObject()
 1395        */
 1396       private void readHierarchy(Object object, ObjectStreamClass classDesc)
 1397               throws IOException, ClassNotFoundException, NotActiveException {
 1398           // We can't be called from just anywhere. There are rules.
 1399           if (object == null && mustResolve) {
 1400               throw new NotActiveException();
 1401           }
 1402   
 1403           ArrayList<ObjectStreamClass> streamClassList = new ArrayList<ObjectStreamClass>(
 1404                   32);
 1405           ObjectStreamClass nextStreamClass = classDesc;
 1406           while (nextStreamClass != null) {
 1407               streamClassList.add(0, nextStreamClass);
 1408               nextStreamClass = nextStreamClass.getSuperclass();
 1409           }
 1410           if (object == null) {
 1411               Iterator<ObjectStreamClass> streamIt = streamClassList.iterator();
 1412               while (streamIt.hasNext()) {
 1413                   ObjectStreamClass streamClass = streamIt.next();
 1414                   readObjectForClass(null, streamClass);
 1415               }
 1416           } else {
 1417               ArrayList<Class<?>> classList = new ArrayList<Class<?>>(32);
 1418               Class<?> nextClass = object.getClass();
 1419               while (nextClass != null) {
 1420                   Class<?> testClass = nextClass.getSuperclass();
 1421                   if (testClass != null) {
 1422                       classList.add(0, nextClass);
 1423                   }
 1424                   nextClass = testClass;
 1425               }
 1426               int lastIndex = 0;
 1427               for (int i = 0; i < classList.size(); i++) {
 1428                   Class<?> superclass = classList.get(i);
 1429                   int index = findStreamSuperclass(superclass, streamClassList,
 1430                           lastIndex);
 1431                   if (index == -1) {
 1432                       readObjectNoData(object, superclass, ObjectStreamClass.lookupStreamClass(superclass));
 1433                   } else {
 1434                       for (int j = lastIndex; j <= index; j++) {
 1435                           readObjectForClass(object, streamClassList.get(j));
 1436                       }
 1437                       lastIndex = index + 1;
 1438                   }
 1439               }
 1440           }
 1441       }
 1442   
 1443       private int findStreamSuperclass(Class<?> cl,
 1444               ArrayList<ObjectStreamClass> classList, int lastIndex) {
 1445           ObjectStreamClass objCl;
 1446           String forName;
 1447   
 1448           for (int i = lastIndex; i < classList.size(); i++) {
 1449               objCl = classList.get(i);
 1450               forName = objCl.forClass().getName();
 1451   
 1452               if (objCl.getName().equals(forName)) {
 1453                   if (cl.getName().equals(objCl.getName())) {
 1454                       return i;
 1455                   }
 1456               } else {
 1457                   // there was a class replacement
 1458                   if (cl.getName().equals(forName)) {
 1459                       return i;
 1460                   }
 1461               }
 1462           }
 1463           return -1;
 1464       }
 1465   
 1466       private void readObjectNoData(Object object, Class<?> cl, ObjectStreamClass classDesc)
 1467               throws ObjectStreamException {
 1468           if (!classDesc.isSerializable()) {
 1469               return;
 1470           }
 1471           if (classDesc.hasMethodReadObjectNoData()){
 1472               final Method readMethod = classDesc.getMethodReadObjectNoData();
 1473               try {
 1474                   readMethod.invoke(object, new Object[0]);
 1475               } catch (InvocationTargetException e) {
 1476                   Throwable ex = e.getTargetException();
 1477                   if (ex instanceof RuntimeException) {
 1478                       throw (RuntimeException) ex;
 1479                   } else if (ex instanceof Error) {
 1480                       throw (Error) ex;
 1481                   }
 1482                   throw (ObjectStreamException) ex;
 1483               } catch (IllegalAccessException e) {
 1484                   throw new RuntimeException(e.toString());
 1485               }
 1486           }
 1487   
 1488       }
 1489   
 1490       private void readObjectForClass(Object object, ObjectStreamClass classDesc)
 1491               throws IOException, ClassNotFoundException, NotActiveException {
 1492           // Have to do this before calling defaultReadObject or anything that
 1493           // calls defaultReadObject
 1494           currentObject = object;
 1495           currentClass = classDesc;
 1496   
 1497           boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) > 0;
 1498           Class<?> targetClass = classDesc.forClass();
 1499   
 1500           final Method readMethod;
 1501           if (targetClass == null || !mustResolve) {
 1502               readMethod = null;
 1503           } else {
 1504               readMethod = classDesc.getMethodReadObject();
 1505           }
 1506           try {
 1507               if (readMethod != null) {
 1508                   // We have to be able to fetch its value, even if it is private
 1509                   AccessController.doPrivileged(new PriviAction<Object>(
 1510                           readMethod));
 1511                   try {
 1512                       readMethod.invoke(object, new Object[] { this });
 1513                   } catch (InvocationTargetException e) {
 1514                       Throwable ex = e.getTargetException();
 1515                       if (ex instanceof ClassNotFoundException) {
 1516                           throw (ClassNotFoundException) ex;
 1517                       } else if (ex instanceof RuntimeException) {
 1518                           throw (RuntimeException) ex;
 1519                       } else if (ex instanceof Error) {
 1520                           throw (Error) ex;
 1521                       }
 1522                       throw (IOException) ex;
 1523                   } catch (IllegalAccessException e) {
 1524                       throw new RuntimeException(e.toString());
 1525                   }
 1526               } else {
 1527                   defaultReadObject();
 1528               }
 1529               if (hadWriteMethod) {
 1530                   discardData();
 1531               }
 1532           } finally {
 1533               // Cleanup, needs to run always so that we can later detect invalid
 1534               // calls to defaultReadObject
 1535               currentObject = null; // We did not set this, so we do not need to
 1536               // clean it
 1537               currentClass = null;
 1538           }
 1539       }
 1540   
 1541       /**
 1542        * Reads an integer (32 bit) from the source stream.
 1543        * 
 1544        * @return the integer value read from the source stream.
 1545        * @throws EOFException
 1546        *             if the end of the input is reached before the read
 1547        *             request can be satisfied.
 1548        * @throws IOException
 1549        *             if an error occurs while reading from the source stream.
 1550        */
 1551       public int readInt() throws IOException {
 1552           return primitiveTypes.readInt();
 1553       }
 1554   
 1555       /**
 1556        * Reads the next line from the source stream. Lines are terminated by
 1557        * {@code '\r'}, {@code '\n'}, {@code "\r\n"} or an {@code EOF}.
 1558        * 
 1559        * @return the string read from the source stream.
 1560        * @throws IOException
 1561        *             if an error occurs while reading from the source stream.
 1562        * @deprecated Use {@link BufferedReader}
 1563        */
 1564       @Deprecated
 1565       public String readLine() throws IOException {
 1566           return primitiveTypes.readLine();
 1567       }
 1568   
 1569       /**
 1570        * Reads a long (64 bit) from the source stream.
 1571        * 
 1572        * @return the long value read from the source stream.
 1573        * @throws EOFException
 1574        *             if the end of the input is reached before the read
 1575        *             request can be satisfied.
 1576        * @throws IOException
 1577        *             if an error occurs while reading from the source stream.
 1578        */
 1579       public long readLong() throws IOException {
 1580           return primitiveTypes.readLong();
 1581       }
 1582   
 1583       /**
 1584        * Read a new array from the receiver. It is assumed the array has not been
 1585        * read yet (not a cyclic reference). Return the array read.
 1586        * 
 1587        * @param unshared
 1588        *            read the object unshared
 1589        * @return the array read
 1590        * 
 1591        * @throws IOException
 1592        *             If an IO exception happened when reading the array.
 1593        * @throws ClassNotFoundException
 1594        *             If a class for one of the objects could not be found
 1595        * @throws OptionalDataException
 1596        *             If optional data could not be found when reading the array.
 1597        */
 1598       private Object readNewArray(boolean unshared) throws OptionalDataException,
 1599               ClassNotFoundException, IOException {
 1600           ObjectStreamClass classDesc = readClassDesc();
 1601   
 1602           if (classDesc == null) {
 1603               throw new InvalidClassException(Messages.getString("luni.C1")); //$NON-NLS-1$
 1604           }
 1605   
 1606           Integer newHandle = nextHandle();
 1607   
 1608           // Array size
 1609           int size = input.readInt();
 1610           Class<?> arrayClass = classDesc.forClass();
 1611           Class<?> componentType = arrayClass.getComponentType();
 1612           Object result = Array.newInstance(componentType, size);
 1613   
 1614           registerObjectRead(result, newHandle, unshared);
 1615   
 1616           // Now we have code duplication just because Java is typed. We have to
 1617           // read N elements and assign to array positions, but we must typecast
 1618           // the array first, and also call different methods depending on the
 1619           // elements.
 1620           if (componentType.isPrimitive()) {
 1621               if (componentType == Integer.TYPE) {
 1622                   int[] intArray = (int[]) result;
 1623                   for (int i = 0; i < size; i++) {
 1624                       intArray[i] = input.readInt();
 1625                   }
 1626               } else if (componentType == Byte.TYPE) {
 1627                   byte[] byteArray = (byte[]) result;
 1628                   input.readFully(byteArray, 0, size);
 1629               } else if (componentType == Character.TYPE) {
 1630                   char[] charArray = (char[]) result;
 1631                   for (int i = 0; i < size; i++) {
 1632                       charArray[i] = input.readChar();
 1633                   }
 1634               } else if (componentType == Short.TYPE) {
 1635                   short[] shortArray = (short[]) result;
 1636                   for (int i = 0; i < size; i++) {
 1637                       shortArray[i] = input.readShort();
 1638                   }
 1639               } else if (componentType == Boolean.TYPE) {
 1640                   boolean[] booleanArray = (boolean[]) result;
 1641                   for (int i = 0; i < size; i++) {
 1642                       booleanArray[i] = input.readBoolean();
 1643                   }
 1644               } else if (componentType == Long.TYPE) {
 1645                   long[] longArray = (long[]) result;
 1646                   for (int i = 0; i < size; i++) {
 1647                       longArray[i] = input.readLong();
 1648                   }
 1649               } else if (componentType == Float.TYPE) {
 1650                   float[] floatArray = (float[]) result;
 1651                   for (int i = 0; i < size; i++) {
 1652                       floatArray[i] = input.readFloat();
 1653                   }
 1654               } else if (componentType == Double.TYPE) {
 1655                   double[] doubleArray = (double[]) result;
 1656                   for (int i = 0; i < size; i++) {
 1657                       doubleArray[i] = input.readDouble();
 1658                   }
 1659               } else {
 1660                   throw new ClassNotFoundException(Messages.getString(
 1661                           "luni.C2", classDesc.getName())); //$NON-NLS-1$
 1662               }
 1663           } else {
 1664               // Array of Objects
 1665               Object[] objectArray = (Object[]) result;
 1666               for (int i = 0; i < size; i++) {
 1667                   // TODO: This place is the opportunity for enhancement
 1668                   //      We can implement writing elements through fast-path,
 1669                   //      without setting up the context (see readObject()) for 
 1670                   //      each element with public API
 1671                   objectArray[i] = readObject();
 1672               }
 1673           }
 1674           if (enableResolve) {
 1675               result = resolveObject(result);
 1676               registerObjectRead(result, newHandle, false);
 1677           }
 1678           return result;
 1679       }
 1680   
 1681       /**
 1682        * Reads a new class from the receiver. It is assumed the class has not been
 1683        * read yet (not a cyclic reference). Return the class read.
 1684        * 
 1685        * @param unshared
 1686        *            read the object unshared
 1687        * @return The {@code java.lang.Class} read from the stream.
 1688        * 
 1689        * @throws IOException
 1690        *             If an IO exception happened when reading the class.
 1691        * @throws ClassNotFoundException
 1692        *             If a class for one of the objects could not be found
 1693        */
 1694       private Class<?> readNewClass(boolean unshared)
 1695               throws ClassNotFoundException, IOException {
 1696           ObjectStreamClass classDesc = readClassDesc();
 1697   
 1698           if (classDesc != null) {
 1699               Class<?> localClass = classDesc.forClass();
 1700               if (localClass != null) {
 1701                   registerObjectRead(localClass, nextHandle(), unshared);
 1702               }
 1703               return localClass;
 1704           }
 1705           throw new InvalidClassException(Messages.getString("luni.C1")); //$NON-NLS-1$
 1706       }
 1707   
 1708       /*
 1709        * read class type for Enum, note there's difference between enum and normal
 1710        * classes
 1711        */
 1712       private ObjectStreamClass readEnumDesc() throws IOException,
 1713               ClassNotFoundException {
 1714           byte tc = nextTC();
 1715           switch (tc) {
 1716               case TC_CLASSDESC:
 1717                   return readEnumDescInternal();
 1718               case TC_REFERENCE:
 1719                   return (ObjectStreamClass) readCyclicReference();
 1720               case TC_NULL:
 1721                   return null;
 1722               default:
 1723                   throw new StreamCorruptedException(Messages.getString(
 1724                           "luni.BC", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
 1725           }
 1726       }
 1727   
 1728       private ObjectStreamClass readEnumDescInternal() throws IOException,
 1729               ClassNotFoundException {
 1730           ObjectStreamClass classDesc;
 1731           primitiveData = input;
 1732           Integer oldHandle = descriptorHandle;
 1733           descriptorHandle = nextHandle();
 1734           classDesc = readClassDescriptor();
 1735           registerObjectRead(classDesc, descriptorHandle, false);
 1736           descriptorHandle = oldHandle;
 1737           primitiveData = emptyStream;
 1738           classDesc.setClass(resolveClass(classDesc));
 1739           // Consume unread class annotation data and TC_ENDBLOCKDATA
 1740           discardData();
 1741           ObjectStreamClass superClass = readClassDesc();
 1742           checkedSetSuperClassDesc(classDesc, superClass);
 1743           // Check SUIDs, note all SUID for Enum is 0L
 1744           if (0L != classDesc.getSerialVersionUID()
 1745                   || 0L != superClass.getSerialVersionUID()) {
 1746               throw new InvalidClassException(superClass.getName(), Messages
 1747                       .getString("luni.C3", superClass, //$NON-NLS-1$
 1748                               superClass));
 1749           }
 1750           byte tc = nextTC();
 1751           // discard TC_ENDBLOCKDATA after classDesc if any
 1752           if (tc == TC_ENDBLOCKDATA) {
 1753               // read next parent class. For enum, it may be null
 1754               superClass.setSuperclass(readClassDesc());
 1755           } else {
 1756               // not TC_ENDBLOCKDATA, push back for next read
 1757               pushbackTC();
 1758           }
 1759           return classDesc;
 1760       }
 1761   
 1762       @SuppressWarnings("unchecked")// For the Enum.valueOf call
 1763       private Object readEnum(boolean unshared) throws OptionalDataException,
 1764               ClassNotFoundException, IOException {
 1765           // read classdesc for Enum first
 1766           ObjectStreamClass classDesc = readEnumDesc();
 1767           Integer newHandle = nextHandle();
 1768           // read name after class desc
 1769           String name;
 1770           byte tc = nextTC();
 1771           switch (tc) {
 1772               case TC_REFERENCE:
 1773                   if (unshared) {
 1774                       readNewHandle();
 1775                       throw new InvalidObjectException(Messages.getString("luni.BE")); //$NON-NLS-1$
 1776                   }
 1777                   name = (String) readCyclicReference();
 1778                   break;
 1779               case TC_STRING:
 1780                   name = (String) readNewString(unshared);
 1781                   break;
 1782               default:
 1783                   throw new StreamCorruptedException(Messages.getString("luni.BC"));//$NON-NLS-1$
 1784           }
 1785   
 1786           Enum<?> result = Enum.valueOf((Class) classDesc.forClass(), name);
 1787           registerObjectRead(result, newHandle, unshared);
 1788   
 1789           return result;
 1790       }
 1791   
 1792       /**
 1793        * Reads a new class descriptor from the receiver. It is assumed the class
 1794        * descriptor has not been read yet (not a cyclic reference). Return the
 1795        * class descriptor read.
 1796        * 
 1797        * @param unshared
 1798        *            read the object unshared
 1799        * @return The {@code ObjectStreamClass} read from the stream.
 1800        * 
 1801        * @throws IOException
 1802        *             If an IO exception happened when reading the class
 1803        *             descriptor.
 1804        * @throws ClassNotFoundException
 1805        *             If a class for one of the objects could not be found
 1806        */
 1807       private ObjectStreamClass readNewClassDesc(boolean unshared)
 1808               throws ClassNotFoundException, IOException {
 1809           // So read...() methods can be used by
 1810           // subclasses during readClassDescriptor()
 1811           primitiveData = input;
 1812           Integer oldHandle = descriptorHandle;
 1813           descriptorHandle = nextHandle();
 1814           ObjectStreamClass newClassDesc = readClassDescriptor();
 1815           registerObjectRead(newClassDesc, descriptorHandle, unshared);
 1816           descriptorHandle = oldHandle;
 1817           primitiveData = emptyStream;
 1818   
 1819           // We need to map classDesc to class.
 1820           try {
 1821               newClassDesc.setClass(resolveClass(newClassDesc));
 1822               // Check SUIDs & base name of the class
 1823               verifyAndInit(newClassDesc);
 1824           } catch (ClassNotFoundException e) {
 1825               if (mustResolve) {
 1826                   throw e;
 1827                   // Just continue, the class may not be required
 1828               }
 1829           }
 1830   
 1831           // Resolve the field signatures using the class loader of the
 1832           // resolved class
 1833           ObjectStreamField[] fields = newClassDesc.getLoadFields();
 1834           fields = (null == fields ? new ObjectStreamField[] {} : fields);
 1835           ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader
 1836                   : newClassDesc.forClass().getClassLoader();
 1837           for (ObjectStreamField element : fields) {
 1838               element.resolve(loader);
 1839           }
 1840   
 1841           // Consume unread class annotation data and TC_ENDBLOCKDATA
 1842           discardData();
 1843           checkedSetSuperClassDesc(newClassDesc, readClassDesc());
 1844           return newClassDesc;
 1845       }
 1846   
 1847       /**
 1848        * Reads a new proxy class descriptor from the receiver. It is assumed the
 1849        * proxy class descriptor has not been read yet (not a cyclic reference).
 1850        * Return the proxy class descriptor read.
 1851        * 
 1852        * @return The {@code Class} read from the stream.
 1853        * 
 1854        * @throws IOException
 1855        *             If an IO exception happened when reading the class
 1856        *             descriptor.
 1857        * @throws ClassNotFoundException
 1858        *             If a class for one of the objects could not be found
 1859        */
 1860       private Class<?> readNewProxyClassDesc() throws ClassNotFoundException,
 1861               IOException {
 1862           int count = input.readInt();
 1863           String[] interfaceNames = new String[count];
 1864           for (int i = 0; i < count; i++) {
 1865               interfaceNames[i] = input.readUTF();
 1866           }
 1867           Class<?> proxy = resolveProxyClass(interfaceNames);
 1868           // Consume unread class annotation data and TC_ENDBLOCKDATA
 1869           discardData();
 1870           return proxy;
 1871       }
 1872   
 1873       /**
 1874        * Reads a class descriptor from the source stream.
 1875        * 
 1876        * @return the class descriptor read from the source stream.
 1877        * @throws ClassNotFoundException
 1878        *             if a class for one of the objects cannot be found.
 1879        * @throws IOException
 1880        *             if an error occurs while reading from the source stream.
 1881        */
 1882       protected ObjectStreamClass readClassDescriptor() throws IOException,
 1883               ClassNotFoundException {
 1884   
 1885           ObjectStreamClass newClassDesc = new ObjectStreamClass();
 1886           String name = input.readUTF();
 1887           if (name.length() == 0) {
 1888               // luni.07 = The stream is corrupted
 1889               throw new IOException(Messages.getString("luni.07")); //$NON-NLS-1$
 1890           }
 1891           newClassDesc.setName(name);
 1892           newClassDesc.setSerialVersionUID(input.readLong());
 1893           newClassDesc.setFlags(input.readByte());
 1894   
 1895           /*
 1896            * We must register the class descriptor before reading field
 1897            * descriptors. If called outside of readObject, the descriptorHandle
 1898            * might be null.
 1899            */
 1900           descriptorHandle = (null == descriptorHandle ? nextHandle() : descriptorHandle);
 1901           registerObjectRead(newClassDesc, descriptorHandle, false);
 1902   
 1903           readFieldDescriptors(newClassDesc);
 1904           return newClassDesc;
 1905       }
 1906   
 1907       /**
 1908        * Creates the proxy class that implements the interfaces specified in
 1909        * {@code interfaceNames}.
 1910        * 
 1911        * @param interfaceNames
 1912        *            the interfaces used to create the proxy class.
 1913        * @return the proxy class.
 1914        * @throws ClassNotFoundException
 1915        *             if the proxy class or any of the specified interfaces cannot
 1916        *             be created.
 1917        * @throws IOException
 1918        *             if an error occurs while reading from the source stream.
 1919        * @see ObjectOutputStream#annotateProxyClass(Class)
 1920        */
 1921       protected Class<?> resolveProxyClass(String[] interfaceNames)
 1922               throws IOException, ClassNotFoundException {
 1923               
 1924           // TODO: This method is opportunity for performance enhancement
 1925           //       We can cache the classloader and recently used interfaces.        
 1926           ClassLoader loader = VM.getNonBootstrapClassLoader();
 1927           Class<?>[] interfaces = new Class<?>[interfaceNames.length];
 1928           for (int i = 0; i < interfaceNames.length; i++) {
 1929               interfaces[i] = Class.forName(interfaceNames[i], false, loader);
 1930           }
 1931           try {
 1932               return Proxy.getProxyClass(loader, interfaces);
 1933           } catch (IllegalArgumentException e) {
 1934               throw new ClassNotFoundException(e.toString(), e);
 1935           }
 1936       }
 1937   
 1938       /**
 1939        * Write a new handle describing a cyclic reference from the stream.
 1940        * 
 1941        * @return the handle read
 1942        * 
 1943        * @throws IOException
 1944        *             If an IO exception happened when reading the handle
 1945        */
 1946       private int readNewHandle() throws IOException {
 1947           return input.readInt();
 1948       }
 1949   
 1950       private Class<?> resolveConstructorClass(Class<?> objectClass, boolean wasSerializable, boolean wasExternalizable)
 1951           throws OptionalDataException, ClassNotFoundException, IOException {
 1952   
 1953               // The class of the instance may not be the same as the class of the
 1954               // constructor to run
 1955               // This is the constructor to run if Externalizable
 1956               Class<?> constructorClass = objectClass;
 1957   
 1958               // WARNING - What if the object is serializable and externalizable ?
 1959               // Is that possible ?
 1960               if (wasSerializable) {
 1961                   // Now we must run the constructor of the class just above the
 1962                   // one that implements Serializable so that slots that were not
 1963                   // dumped can be initialized properly
 1964                   while (constructorClass != null
 1965                           && ObjectStreamClass.isSerializable(constructorClass)) {
 1966                       constructorClass = constructorClass.getSuperclass();
 1967                   }
 1968               }
 1969   
 1970               // Fetch the empty constructor, or null if none.
 1971               Constructor<?> constructor = null;
 1972               if (constructorClass != null) {
 1973                   try {
 1974                       constructor = constructorClass
 1975                               .getDeclaredConstructor(ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
 1976                   } catch (NoSuchMethodException nsmEx) {
 1977                       // Ignored
 1978                   }
 1979               }
 1980   
 1981               // Has to have an empty constructor
 1982               if (constructor == null) {
 1983                   throw new InvalidClassException(constructorClass.getName(), Messages
 1984                           .getString("luni.C4")); //$NON-NLS-1$
 1985               }
 1986   
 1987               int constructorModifiers = constructor.getModifiers();
 1988   
 1989               // Now we must check if the empty constructor is visible to the
 1990               // instantiation class
 1991               if (Modifier.isPrivate(constructorModifiers)
 1992                       || (wasExternalizable && !Modifier
 1993                               .isPublic(constructorModifiers))) {
 1994                   throw new InvalidClassException(constructorClass.getName(), Messages
 1995                           .getString("luni.C4")); //$NON-NLS-1$
 1996               }
 1997   
 1998               // We know we are testing from a subclass, so the only other case
 1999               // where the visibility is not allowed is when the constructor has
 2000               // default visibility and the instantiation class is in a different
 2001               // package than the constructor class
 2002               if (!Modifier.isPublic(constructorModifiers)
 2003                       && !Modifier.isProtected(constructorModifiers)) {
 2004                   // Not public, not private and not protected...means default
 2005                   // visibility. Check if same package
 2006                   if (!inSamePackage(constructorClass, objectClass)) {
 2007                       throw new InvalidClassException(constructorClass.getName(),
 2008                               Messages.getString("luni.C4")); //$NON-NLS-1$
 2009                   }
 2010               }
 2011   
 2012               return constructorClass;
 2013       }
 2014   
 2015       /**
 2016        * Read a new object from the stream. It is assumed the object has not been
 2017        * loaded yet (not a cyclic reference). Return the object read.
 2018        * 
 2019        * If the object implements <code>Externalizable</code> its
 2020        * <code>readExternal</code> is called. Otherwise, all fields described by
 2021        * the class hierarchy are loaded. Each class can define how its declared
 2022        * instance fields are loaded by defining a private method
 2023        * <code>readObject</code>
 2024        * 
 2025        * @param unshared
 2026        *            read the object unshared
 2027        * @return the object read
 2028        * 
 2029        * @throws IOException
 2030        *             If an IO exception happened when reading the object.
 2031        * @throws OptionalDataException
 2032        *             If optional data could not be found when reading the object
 2033        *             graph
 2034        * @throws ClassNotFoundException
 2035        *             If a class for one of the objects could not be found
 2036        */
 2037       private Object readNewObject(boolean unshared)
 2038               throws OptionalDataException, ClassNotFoundException, IOException {
 2039           ObjectStreamClass classDesc = readClassDesc();
 2040   
 2041           if (classDesc == null) {
 2042               throw new InvalidClassException(Messages.getString("luni.C1")); //$NON-NLS-1$
 2043           }
 2044   
 2045           Integer newHandle = nextHandle();
 2046   
 2047           // Note that these values come from the Stream, and in fact it could be
 2048           // that the classes have been changed so that the info below now
 2049           // conflicts with the newer class
 2050           boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) > 0;
 2051           boolean wasSerializable = (classDesc.getFlags() & SC_SERIALIZABLE) > 0;
 2052   
 2053   
 2054           // Maybe we should cache the values above in classDesc ? It may be the
 2055           // case that when reading classDesc we may need to read more stuff
 2056           // depending on the values above
 2057           Class<?> objectClass = classDesc.forClass();
 2058   
 2059           Object result, registeredResult = null;
 2060           if (objectClass != null) {
 2061   
 2062               long constructor = classDesc.getConstructor();
 2063               if (constructor == ObjectStreamClass.CONSTRUCTOR_IS_NOT_RESOLVED) {
 2064                   constructor = accessor.getMethodID(resolveConstructorClass(objectClass, wasSerializable, wasExternalizable), null, new Class[0]);
 2065                   classDesc.setConstructor(constructor);
 2066               }
 2067   
 2068               // Now we know which class to instantiate and which constructor to
 2069               // run. We are allowed to run the constructor.
 2070               result = accessor.newInstance(objectClass, constructor, null);
 2071   
 2072               registerObjectRead(result, newHandle, unshared);
 2073   
 2074               registeredResult = result;
 2075           } else {
 2076               result = null;
 2077           }
 2078   
 2079           try {
 2080               // This is how we know what to do in defaultReadObject. And it is
 2081               // also used by defaultReadObject to check if it was called from an
 2082               // invalid place. It also allows readExternal to call
 2083               // defaultReadObject and have it work.
 2084               currentObject = result;
 2085               currentClass = classDesc;
 2086   
 2087               // If Externalizable, just let the object read itself
 2088               if (wasExternalizable) {
 2089                   boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) > 0;
 2090                   if (!blockData) {
 2091                       primitiveData = input;
 2092                   }
 2093                   if (mustResolve) {
 2094                       Externalizable extern = (Externalizable) result;
 2095                       extern.readExternal(this);
 2096                   }
 2097                   if (blockData) {
 2098                       // Similar to readHierarchy. Anything not read by
 2099                       // readExternal has to be consumed here
 2100                       discardData();
 2101                   } else {
 2102                       primitiveData = emptyStream;
 2103                   }
 2104               } else {
 2105                   // If we got here, it is Serializable but not Externalizable.
 2106                   // Walk the hierarchy reading each class' slots
 2107                   readHierarchy(result, classDesc);
 2108               }
 2109           } finally {
 2110               // Cleanup, needs to run always so that we can later detect invalid
 2111               // calls to defaultReadObject
 2112               currentObject = null;
 2113               currentClass = null;
 2114           }
 2115   
 2116           if (objectClass != null) {
 2117   
 2118               if (classDesc.hasMethodReadResolve()){
 2119                   Method methodReadResolve = classDesc.getMethodReadResolve();
 2120                   try {
 2121                       result = methodReadResolve.invoke(result, (Object[]) null);
 2122                   } catch (IllegalAccessException iae) {
 2123                   } catch (InvocationTargetException ite) {
 2124                       Throwable target = ite.getTargetException();
 2125                       if (target instanceof ObjectStreamException) {
 2126                           throw (ObjectStreamException) target;
 2127                       } else if (target instanceof Error) {
 2128                           throw (Error) target;
 2129                       } else {
 2130                           throw (RuntimeException) target;
 2131                       }
 2132                   }
 2133   
 2134               }
 2135           }
 2136           // We get here either if class-based replacement was not needed or if it
 2137           // was needed but produced the same object or if it could not be
 2138           // computed.
 2139   
 2140           // The object to return is the one we instantiated or a replacement for
 2141           // it
 2142           if (result != null && enableResolve) {
 2143               result = resolveObject(result);
 2144           }
 2145           if (registeredResult != result) {
 2146               registerObjectRead(result, newHandle, unshared);
 2147           }
 2148           return result;
 2149       }
 2150   
 2151       /**
 2152        * Read a string encoded in {@link DataInput modified UTF-8} from the
 2153        * receiver. Return the string read.
 2154        * 
 2155        * @param unshared
 2156        *            read the object unshared
 2157        * @return the string just read.
 2158        * @throws IOException
 2159        *             If an IO exception happened when reading the String.
 2160        */
 2161       private Object readNewString(boolean unshared) throws IOException {
 2162           Object result = input.readUTF();
 2163           if (enableResolve) {
 2164               result = resolveObject(result);
 2165           }
 2166   		registerObjectRead(result, nextHandle(), unshared);
 2167   
 2168           return result;
 2169       }
 2170   
 2171       /**
 2172        * Read a new String in UTF format from the receiver. Return the string
 2173        * read.
 2174        * 
 2175        * @param unshared
 2176        *            read the object unshared
 2177        * @return the string just read.
 2178        * 
 2179        * @throws IOException
 2180        *             If an IO exception happened when reading the String.
 2181        */
 2182       private Object readNewLongString(boolean unshared) throws IOException {
 2183           long length = input.readLong();
 2184           Object result = input.decodeUTF((int) length);
 2185           if (enableResolve) {
 2186               result = resolveObject(result);
 2187           }
 2188           registerObjectRead(result, nextHandle(), unshared);
 2189   
 2190           return result;
 2191       }
 2192   
 2193       /**
 2194        * Reads the next object from the source stream.
 2195        * 
 2196        * @return the object read from the source stream.
 2197        * @throws ClassNotFoundException
 2198        *             if the class of one of the objects in the object graph cannot
 2199        *             be found.
 2200        * @throws IOException
 2201        *             if an error occurs while reading from the source stream.
 2202        * @throws OptionalDataException
 2203        *             if primitive data types were found instead of an object.
 2204        * @see ObjectOutputStream#writeObject(Object)
 2205        */
 2206       public final Object readObject() throws OptionalDataException,
 2207               ClassNotFoundException, IOException {
 2208           return readObject(false);
 2209       }
 2210   
 2211       /**
 2212        * Reads the next unshared object from the source stream.
 2213        * 
 2214        * @return the new object read.
 2215        * @throws ClassNotFoundException
 2216        *             if the class of one of the objects in the object graph cannot
 2217        *             be found.
 2218        * @throws IOException
 2219        *             if an error occurs while reading from the source stream.
 2220        * @see ObjectOutputStream#writeUnshared
 2221        */
 2222       public Object readUnshared() throws IOException, ClassNotFoundException {
 2223           return readObject(true);
 2224       }
 2225   
 2226       private Object readObject(boolean unshared) throws OptionalDataException,
 2227               ClassNotFoundException, IOException {
 2228           boolean restoreInput = (primitiveData == input);
 2229           if (restoreInput) {
 2230               primitiveData = emptyStream;
 2231           }
 2232   
 2233           // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
 2234           // behavior overriding.
 2235           if (subclassOverridingImplementation && !unshared) {
 2236               return readObjectOverride();
 2237           }
 2238   
 2239           // If we still had primitive types to read, should we discard them
 2240           // (reset the primitiveTypes stream) or leave as is, so that attempts to
 2241           // read primitive types won't read 'past data' ???
 2242           Object result;
 2243           try {
 2244               // We need this so we can tell when we are returning to the
 2245               // original/outside caller
 2246               if (++nestedLevels == 1) {
 2247                   // Remember the caller's class loader
 2248                   callerClassLoader = VM.getNonBootstrapClassLoader();
 2249               }
 2250   
 2251               result = readNonPrimitiveContent(unshared);
 2252               if (restoreInput) {
 2253                   primitiveData = input;
 2254               }
 2255           } finally {
 2256               // We need this so we can tell when we are returning to the
 2257               // original/outside caller
 2258               if (--nestedLevels == 0) {
 2259                   // We are going to return to the original caller, perform
 2260                   // cleanups.
 2261                   // No more need to remember the caller's class loader
 2262                   callerClassLoader = null;
 2263               }
 2264           }
 2265   
 2266           // Done reading this object. Is it time to return to the original
 2267           // caller? If so we need to perform validations first.
 2268           if (nestedLevels == 0 && validations != null) {
 2269               // We are going to return to the original caller. If validation is
 2270               // enabled we need to run them now and then cleanup the validation
 2271               // collection
 2272               try {
 2273                   for (InputValidationDesc element : validations) {
 2274                       element.validator.validateObject();
 2275                   }
 2276               } finally {
 2277                   // Validations have to be renewed, since they are only called
 2278                   // from readObject
 2279                   validations = null;
 2280               }
 2281           }
 2282           return result;
 2283       }
 2284   
 2285       /**
 2286        * Method to be overriden by subclasses to read the next object from the
 2287        * source stream.
 2288        * 
 2289        * @return the object read from the source stream.
 2290        * @throws ClassNotFoundException
 2291        *             if the class of one of the objects in the object graph cannot
 2292        *             be found.
 2293        * @throws IOException
 2294        *             if an error occurs while reading from the source stream.
 2295        * @throws OptionalDataException
 2296        *             if primitive data types were found instead of an object.
 2297        * @see ObjectOutputStream#writeObjectOverride
 2298        */
 2299       protected Object readObjectOverride() throws OptionalDataException,
 2300               ClassNotFoundException, IOException {
 2301           if (input == null) {
 2302               return null;
 2303           }
 2304           // Subclasses must override.
 2305           throw new IOException();
 2306       }
 2307   
 2308       /**
 2309        * Reads a short (16 bit) from the source stream.
 2310        * 
 2311        * @return the short value read from the source stream.
 2312        * @throws IOException
 2313        *             if an error occurs while reading from the source stream.
 2314        */
 2315       public short readShort() throws IOException {
 2316           return primitiveTypes.readShort();
 2317       }
 2318   
 2319       /**
 2320        * Reads and validates the ObjectInputStream header from the source stream.
 2321        * 
 2322        * @throws IOException
 2323        *             if an error occurs while reading from the source stream.
 2324        * @throws StreamCorruptedException
 2325        *             if the source stream does not contain readable serialized
 2326        *             objects.
 2327        */
 2328       protected void readStreamHeader() throws IOException,
 2329               StreamCorruptedException {
 2330           if (input.readShort() == STREAM_MAGIC
 2331                   && input.readShort() == STREAM_VERSION) {
 2332               return;
 2333           }
 2334           throw new StreamCorruptedException();
 2335       }
 2336   
 2337       /**
 2338        * Reads an unsigned byte (8 bit) from the source stream.
 2339        * 
 2340        * @return the unsigned byte value read from the source stream packaged in
 2341        *         an integer.
 2342        * @throws EOFException
 2343        *             if the end of the input is reached before the read
 2344        *             request can be satisfied.
 2345        * @throws IOException
 2346        *             if an error occurs while reading from the source stream.
 2347        */
 2348       public int readUnsignedByte() throws IOException {
 2349           return primitiveTypes.readUnsignedByte();
 2350       }
 2351   
 2352       /**
 2353        * Reads an unsigned short (16 bit) from the source stream.
 2354        * 
 2355        * @return the unsigned short value read from the source stream packaged in
 2356        *         an integer.
 2357        * @throws EOFException
 2358        *             if the end of the input is reached before the read
 2359        *             request can be satisfied.
 2360        * @throws IOException
 2361        *             if an error occurs while reading from the source stream.
 2362        */
 2363       public int readUnsignedShort() throws IOException {
 2364           return primitiveTypes.readUnsignedShort();
 2365       }
 2366   
 2367       /**
 2368        * Reads a string encoded in {@link DataInput modified UTF-8} from the
 2369        * source stream.
 2370        * 
 2371        * @return the string encoded in {@link DataInput modified UTF-8} read from
 2372        *         the source stream.
 2373        * @throws EOFException
 2374        *             if the end of the input is reached before the read
 2375        *             request can be satisfied.
 2376        * @throws IOException
 2377        *             if an error occurs while reading from the source stream.
 2378        */
 2379       public String readUTF() throws IOException {
 2380           return primitiveTypes.readUTF();
 2381       }
 2382   
 2383       /**
 2384        * Return the object previously read tagged with handle {@code handle}.
 2385        * 
 2386        * @param handle
 2387        *            The handle that this object was assigned when it was read.
 2388        * @return the object previously read.
 2389        * 
 2390        * @throws InvalidObjectException
 2391        *             If there is no previously read object with this handle
 2392        */
 2393       private Object registeredObjectRead(Integer handle)
 2394               throws InvalidObjectException {
 2395           Object res = objectsRead.get(handle);
 2396   
 2397           if (res == UNSHARED_OBJ) {
 2398               throw new InvalidObjectException(Messages.getString("luni.C5")); //$NON-NLS-1$
 2399           }
 2400   
 2401           return res;
 2402       }
 2403   
 2404       /**
 2405        * Assume object {@code obj} has been read, and assign a handle to
 2406        * it, {@code handle}.
 2407        * 
 2408        * @param obj
 2409        *            Non-null object being loaded.
 2410        * @param handle
 2411        *            An Integer, the handle to this object
 2412        * @param unshared
 2413        *            Boolean, indicates that caller is reading in unshared mode
 2414        * 
 2415        * @see #nextHandle
 2416        */
 2417       private void registerObjectRead(Object obj, Integer handle, boolean unshared) {
 2418           objectsRead.put(handle, unshared ? UNSHARED_OBJ : obj);
 2419       }
 2420   
 2421       /**
 2422        * Registers a callback for post-deserialization validation of objects. It
 2423        * allows to perform additional consistency checks before the {@code
 2424        * readObject()} method of this class returns its result to the caller. This
 2425        * method can only be called from within the {@code readObject()} method of
 2426        * a class that implements "special" deserialization rules. It can be called
 2427        * multiple times. Validation callbacks are then done in order of decreasing
 2428        * priority, defined by {@code priority}.
 2429        * 
 2430        * @param object
 2431        *            an object that can validate itself by receiving a callback.
 2432        * @param priority
 2433        *            the validator's priority.
 2434        * @throws InvalidObjectException
 2435        *             if {@code object} is {@code null}.
 2436        * @throws NotActiveException
 2437        *             if this stream is currently not reading objects. In that
 2438        *             case, calling this method is not allowed.
 2439        * @see ObjectInputValidation#validateObject()
 2440        */
 2441       public synchronized void registerValidation(ObjectInputValidation object,
 2442               int priority) throws NotActiveException, InvalidObjectException {
 2443           // Validation can only be registered when inside readObject calls
 2444           Object instanceBeingRead = this.currentObject;
 2445   
 2446           // We can't be called from just anywhere. There are rules.
 2447           if (instanceBeingRead == null && nestedLevels == 0) {
 2448               throw new NotActiveException();
 2449           }
 2450           if (object == null) {
 2451               throw new InvalidObjectException(Messages.getString("luni.C6")); //$NON-NLS-1$
 2452           }
 2453           // From now on it is just insertion in a SortedCollection. Since
 2454           // the Java class libraries don't provide that, we have to
 2455           // implement it from scratch here.
 2456           InputValidationDesc desc = new InputValidationDesc();
 2457           desc.validator = object;
 2458           desc.priority = priority;
 2459           // No need for this, validateObject does not take a parameter
 2460           // desc.toValidate = instanceBeingRead;
 2461           if (validations == null) {
 2462               validations = new InputValidationDesc[1];
 2463               validations[0] = desc;
 2464           } else {
 2465               int i = 0;
 2466               for (; i < validations.length; i++) {
 2467                   InputValidationDesc validation = validations[i];
 2468                   // Sorted, higher priority first.
 2469                   if (priority >= validation.priority) {
 2470                       break; // Found the index where to insert
 2471                   }
 2472               }
 2473               InputValidationDesc[] oldValidations = validations;
 2474               int currentSize = oldValidations.length;
 2475               validations = new InputValidationDesc[currentSize + 1];
 2476               System.arraycopy(oldValidations, 0, validations, 0, i);
 2477               System.arraycopy(oldValidations, i, validations, i + 1, currentSize
 2478                       - i);
 2479               validations[i] = desc;
 2480           }
 2481       }
 2482   
 2483       /**
 2484        * Reset the collection of objects already loaded by the receiver.
 2485        */
 2486       private void resetSeenObjects() {
 2487           objectsRead = new HashMap<Integer, Object>();
 2488           currentHandle = baseWireHandle;
 2489           primitiveData = emptyStream;
 2490       }
 2491   
 2492       /**
 2493        * Reset the receiver. The collection of objects already read by the
 2494        * receiver is reset, and internal structures are also reset so that the
 2495        * receiver knows it is in a fresh clean state.
 2496        */
 2497       private void resetState() {
 2498           resetSeenObjects();
 2499           hasPushbackTC = false;
 2500           pushbackTC = 0;
 2501           // nestedLevels = 0;
 2502       }
 2503   
 2504       /**
 2505        * Loads the Java class corresponding to the class descriptor {@code
 2506        * osClass} that has just been read from the source stream.
 2507        * 
 2508        * @param osClass
 2509        *            an ObjectStreamClass read from the source stream.
 2510        * @return a Class corresponding to the descriptor {@code osClass}.
 2511        * @throws ClassNotFoundException
 2512        *             if the class for an object cannot be found.
 2513        * @throws IOException
 2514        *             if an I/O error occurs while creating the class.
 2515        * @see ObjectOutputStream#annotateClass(Class)
 2516        */
 2517       protected Class<?> resolveClass(ObjectStreamClass osClass)
 2518               throws IOException, ClassNotFoundException {
 2519           // fastpath: obtain cached value
 2520           Class<?> cls = osClass.forClass();
 2521           if (null == cls) {
 2522               // slowpath: resolve the class
 2523               String className = osClass.getName();
 2524   
 2525               // if it is primitive class, for example, long.class
 2526               cls = PRIMITIVE_CLASSES.get(className);
 2527   
 2528               if (null == cls) {
 2529                   // not primitive class
 2530                   // Use the first non-null ClassLoader on the stack. If null, use
 2531                   // the system class loader
 2532                   cls = Class.forName(className, true, callerClassLoader);
 2533               }
 2534           }
 2535           return cls;
 2536       }
 2537   
 2538       /**
 2539        * Allows trusted subclasses to substitute the specified original {@code
 2540        * object} with a new object. Object substitution has to be activated first
 2541        * with calling {@code enableResolveObject(true)}. This implementation just
 2542        * returns {@code object}.
 2543        * 
 2544        * @param object
 2545        *            the original object for which a replacement may be defined.
 2546        * @return the replacement object for {@code object}.
 2547        * @throws IOException
 2548        *             if any I/O error occurs while creating the replacement
 2549        *             object.
 2550        * @see #enableResolveObject
 2551        * @see ObjectOutputStream#enableReplaceObject
 2552        * @see ObjectOutputStream#replaceObject
 2553        */
 2554       protected Object resolveObject(Object object) throws IOException {
 2555           // By default no object replacement. Subclasses can override
 2556           return object;
 2557       }
 2558   
 2559       /**
 2560        * Skips {@code length} bytes on the source stream. This method should not
 2561        * be used to skip bytes at any arbitrary position, just when reading
 2562        * primitive data types (int, char etc).
 2563        *
 2564        * @param length
 2565        *            the number of bytes to skip.
 2566        * @return the number of bytes actually skipped.
 2567        * @throws IOException
 2568        *             if an error occurs while skipping bytes on the source stream.
 2569        * @throws NullPointerException
 2570        *             if the source stream is {@code null}.
 2571        */
 2572       public int skipBytes(int length) throws IOException {
 2573           // To be used with available. Ok to call if reading primitive buffer
 2574           if (input == null) {
 2575               throw new NullPointerException();
 2576           }
 2577   
 2578           int offset = 0;
 2579           while (offset < length) {
 2580               checkReadPrimitiveTypes();
 2581               long skipped = primitiveData.skip(length - offset);
 2582               if (skipped == 0) {
 2583                   return offset;
 2584               }
 2585               offset += (int) skipped;
 2586           }
 2587           return length;
 2588       }
 2589   
 2590       /**
 2591        * Verify if the SUID & the base name for descriptor
 2592        * <code>loadedStreamClass</code>matches
 2593        * the SUID & the base name of the corresponding loaded class and
 2594        * init private fields.
 2595        * 
 2596        * @param loadedStreamClass
 2597        *            An ObjectStreamClass that was loaded from the stream.
 2598        * 
 2599        * @throws InvalidClassException
 2600        *             If the SUID of the stream class does not match the VM class
 2601        */
 2602       private void verifyAndInit(ObjectStreamClass loadedStreamClass)
 2603               throws InvalidClassException {
 2604   
 2605           Class<?> localClass = loadedStreamClass.forClass();
 2606           ObjectStreamClass localStreamClass = ObjectStreamClass
 2607                   .lookupStreamClass(localClass);
 2608   
 2609           if (loadedStreamClass.getSerialVersionUID() != localStreamClass
 2610                   .getSerialVersionUID()) {
 2611               throw new InvalidClassException(loadedStreamClass.getName(), Messages
 2612                       .getString("luni.C3", loadedStreamClass, //$NON-NLS-1$
 2613                               localStreamClass));
 2614           }
 2615   
 2616           String loadedClassBaseName = getBaseName(loadedStreamClass.getName());
 2617           String localClassBaseName = getBaseName(localStreamClass.getName());
 2618   
 2619           if (!loadedClassBaseName.equals(localClassBaseName)) {
 2620               throw new InvalidClassException(loadedStreamClass.getName(), Messages
 2621                       .getString("luni.C7", loadedClassBaseName, //$NON-NLS-1$
 2622                               localClassBaseName));
 2623           }
 2624   
 2625           loadedStreamClass.initPrivateFields(localStreamClass);        
 2626       }
 2627   
 2628       private static String getBaseName(String fullName) {
 2629           int k = fullName.lastIndexOf('.');
 2630   
 2631           if (k == -1 || k == (fullName.length() - 1)) {
 2632               return fullName;
 2633           }
 2634           return fullName.substring(k + 1);
 2635       }
 2636   
 2637       // Avoid recursive defining.
 2638       private static void checkedSetSuperClassDesc(ObjectStreamClass desc,
 2639               ObjectStreamClass superDesc) throws StreamCorruptedException {
 2640           if (desc.equals(superDesc)) {
 2641               throw new StreamCorruptedException();
 2642           }
 2643           desc.setSuperclass(superDesc);
 2644       }
 2645   }

Save This Page
Home » apache-harmony-6.0-src-r917296-snapshot » java » io » [javadoc | source]