OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [io/] [ObjectInputStream.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* ObjectInputStream.java -- Class used to read serialized objects
2
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GNU Classpath.
6
 
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING.  If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301 USA.
21
 
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library.  Thus, the terms and
24
conditions of the GNU General Public License cover the whole
25
combination.
26
 
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module.  An independent module is a module which is not derived from
34
or based on this library.  If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so.  If you do not wish to do so, delete this
37
exception statement from your version. */
38
 
39
 
40
package java.io;
41
 
42
import gnu.java.io.ObjectIdentityWrapper;
43
 
44
import java.lang.reflect.Array;
45
import java.lang.reflect.Constructor;
46
import java.lang.reflect.Field;
47
import java.lang.reflect.InvocationTargetException;
48
import java.lang.reflect.Method;
49
import java.lang.reflect.Modifier;
50
import java.lang.reflect.Proxy;
51
import java.security.AccessController;
52
import java.security.PrivilegedAction;
53
import java.util.Arrays;
54
import java.util.Hashtable;
55
import java.util.Iterator;
56
import java.util.TreeSet;
57
import java.util.Vector;
58
 
59
public class ObjectInputStream extends InputStream
60
  implements ObjectInput, ObjectStreamConstants
61
{
62
  /**
63
   * Creates a new <code>ObjectInputStream</code> that will do all of
64
   * its reading from <code>in</code>.  This method also checks
65
   * the stream by reading the header information (stream magic number
66
   * and stream version).
67
   *
68
   * @exception IOException Reading stream header from underlying
69
   * stream cannot be completed.
70
   *
71
   * @exception StreamCorruptedException An invalid stream magic
72
   * number or stream version was read from the stream.
73
   *
74
   * @see #readStreamHeader()
75
   */
76
  public ObjectInputStream(InputStream in)
77
    throws IOException, StreamCorruptedException
78
  {
79
    if (DEBUG)
80
      {
81
        String val = System.getProperty("gcj.dumpobjects");
82
        if (dump == false && val != null && !val.equals(""))
83
          {
84
            dump = true;
85
            System.out.println ("Serialization debugging enabled");
86
          }
87
        else if (dump == true && (val == null || val.equals("")))
88
          {
89
            dump = false;
90
            System.out.println ("Serialization debugging disabled");
91
          }
92
      }
93
 
94
    this.resolveEnabled = false;
95
    this.blockDataPosition = 0;
96
    this.blockDataBytes = 0;
97
    this.blockData = new byte[BUFFER_SIZE];
98
    this.blockDataInput = new DataInputStream(this);
99
    this.realInputStream = new DataInputStream(in);
100
    this.nextOID = baseWireHandle;
101
    this.objectLookupTable = new Hashtable();
102
    this.classLookupTable = new Hashtable();
103
    setBlockDataMode(true);
104
    readStreamHeader();
105
  }
106
 
107
 
108
  /**
109
   * Returns the next deserialized object read from the underlying stream.
110
   *
111
   * This method can be overriden by a class by implementing
112
   * <code>private void readObject (ObjectInputStream)</code>.
113
   *
114
   * If an exception is thrown from this method, the stream is left in
115
   * an undefined state. This method can also throw Errors and
116
   * RuntimeExceptions if caused by existing readResolve() user code.
117
   *
118
   * @return The object read from the underlying stream.
119
   *
120
   * @exception ClassNotFoundException The class that an object being
121
   * read in belongs to cannot be found.
122
   *
123
   * @exception IOException Exception from underlying
124
   * <code>InputStream</code>.
125
   */
126
  public final Object readObject()
127
    throws ClassNotFoundException, IOException
128
  {
129
    if (this.useSubclassMethod)
130
      return readObjectOverride();
131
 
132
    Object ret_val;
133
    boolean old_mode = setBlockDataMode(false);
134
    byte marker = this.realInputStream.readByte();
135
 
136
    if (DEBUG)
137
      depth += 2;
138
 
139
    if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
140
 
141
    try
142
      {
143
        ret_val = parseContent(marker);
144
      }
145
    finally
146
      {
147
        setBlockDataMode(old_mode);
148
        if (DEBUG)
149
          depth -= 2;
150
      }
151
 
152
    return ret_val;
153
  }
154
 
155
   /**
156
    * Handles a content block within the stream, which begins with a marker
157
    * byte indicating its type.
158
    *
159
    * @param marker the byte marker.
160
    * @return an object which represents the parsed content.
161
    * @throws ClassNotFoundException if the class of an object being
162
    *                                read in cannot be found.
163
    * @throws IOException if invalid data occurs or one is thrown by the
164
    *                     underlying <code>InputStream</code>.
165
    */
166
   private Object parseContent(byte marker)
167
     throws ClassNotFoundException, IOException
168
   {
169
     Object ret_val;
170
     boolean is_consumed = false;
171
 
172
     switch (marker)
173
       {
174
       case TC_ENDBLOCKDATA:
175
        {
176
          ret_val = null;
177
          is_consumed = true;
178
          break;
179
        }
180
 
181
       case TC_BLOCKDATA:
182
       case TC_BLOCKDATALONG:
183
        {
184
          if (marker == TC_BLOCKDATALONG)
185
            { if(dump) dumpElementln("BLOCKDATALONG"); }
186
          else
187
            { if(dump) dumpElementln("BLOCKDATA"); }
188
          readNextBlock(marker);
189
        }
190
 
191
       case TC_NULL:
192
        {
193
          if(dump) dumpElementln("NULL");
194
          ret_val = null;
195
          break;
196
        }
197
 
198
       case TC_REFERENCE:
199
        {
200
          if(dump) dumpElement("REFERENCE ");
201
          Integer oid = new Integer(this.realInputStream.readInt());
202
          if(dump) dumpElementln(Integer.toHexString(oid.intValue()));
203
          ret_val = ((ObjectIdentityWrapper)
204
                     this.objectLookupTable.get(oid)).object;
205
          break;
206
        }
207
 
208
       case TC_CLASS:
209
        {
210
          if(dump) dumpElementln("CLASS");
211
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
212
          Class clazz = osc.forClass();
213
          assignNewHandle(clazz);
214
          ret_val = clazz;
215
          break;
216
        }
217
 
218
       case TC_PROXYCLASSDESC:
219
        {
220
          if(dump) dumpElementln("PROXYCLASS");
221
          int n_intf = this.realInputStream.readInt();
222
          String[] intfs = new String[n_intf];
223
          for (int i = 0; i < n_intf; i++)
224
            {
225
              intfs[i] = this.realInputStream.readUTF();
226
            }
227
 
228
          boolean oldmode = setBlockDataMode(true);
229
          Class cl = resolveProxyClass(intfs);
230
          setBlockDataMode(oldmode);
231
 
232
          ObjectStreamClass osc = lookupClass(cl);
233
          if (osc.firstNonSerializableParentConstructor == null)
234
            {
235
              osc.realClassIsSerializable = true;
236
              osc.fields = osc.fieldMapping = new ObjectStreamField[0];
237
              try
238
                {
239
                  osc.firstNonSerializableParentConstructor =
240
                    Object.class.getConstructor(new Class[0]);
241
                }
242
              catch (NoSuchMethodException x)
243
                {
244
                  throw (InternalError)
245
                    new InternalError("Object ctor missing").initCause(x);
246
                }
247
            }
248
          assignNewHandle(osc);
249
 
250
          if (!is_consumed)
251
            {
252
              byte b = this.realInputStream.readByte();
253
              if (b != TC_ENDBLOCKDATA)
254
                throw new IOException("Data annotated to class was not consumed." + b);
255
            }
256
          else
257
            is_consumed = false;
258
          ObjectStreamClass superosc = (ObjectStreamClass)readObject();
259
          osc.setSuperclass(superosc);
260
          ret_val = osc;
261
          break;
262
        }
263
 
264
       case TC_CLASSDESC:
265
        {
266
          ObjectStreamClass osc = readClassDescriptor();
267
 
268
          if (!is_consumed)
269
            {
270
              byte b = this.realInputStream.readByte();
271
              if (b != TC_ENDBLOCKDATA)
272
                throw new IOException("Data annotated to class was not consumed." + b);
273
            }
274
          else
275
            is_consumed = false;
276
 
277
          osc.setSuperclass ((ObjectStreamClass)readObject());
278
          ret_val = osc;
279
          break;
280
        }
281
 
282
       case TC_STRING:
283
       case TC_LONGSTRING:
284
        {
285
          if(dump) dumpElement("STRING=");
286
          String s = this.realInputStream.readUTF();
287
          if(dump) dumpElementln(s);
288
          ret_val = processResolution(null, s, assignNewHandle(s));
289
          break;
290
        }
291
 
292
       case TC_ARRAY:
293
        {
294
          if(dump) dumpElementln("ARRAY");
295
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
296
          Class componentType = osc.forClass().getComponentType();
297
          if(dump) dumpElement("ARRAY LENGTH=");
298
          int length = this.realInputStream.readInt();
299
          if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
300
          Object array = Array.newInstance(componentType, length);
301
          int handle = assignNewHandle(array);
302
          readArrayElements(array, componentType);
303
          if(dump)
304
            for (int i = 0, len = Array.getLength(array); i < len; i++)
305
              dumpElementln("  ELEMENT[" + i + "]=" + Array.get(array, i));
306
          ret_val = processResolution(null, array, handle);
307
          break;
308
        }
309
 
310
       case TC_OBJECT:
311
        {
312
          if(dump) dumpElementln("OBJECT");
313
          ObjectStreamClass osc = (ObjectStreamClass)readObject();
314
          Class clazz = osc.forClass();
315
 
316
          if (!osc.realClassIsSerializable)
317
            throw new NotSerializableException
318
              (clazz + " is not Serializable, and thus cannot be deserialized.");
319
 
320
          if (osc.realClassIsExternalizable)
321
            {
322
              Externalizable obj = osc.newInstance();
323
 
324
              int handle = assignNewHandle(obj);
325
 
326
              boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
327
 
328
              boolean oldmode = this.readDataFromBlock;
329
              if (read_from_blocks)
330
                setBlockDataMode(true);
331
 
332
              obj.readExternal(this);
333
 
334
              if (read_from_blocks)
335
                {
336
                  setBlockDataMode(oldmode);
337
                  if (!oldmode)
338
                    if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
339
                      throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
340
                }
341
 
342
              ret_val = processResolution(osc, obj, handle);
343
              break;
344
 
345
            } // end if (osc.realClassIsExternalizable)
346
 
347
          Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
348
 
349
          int handle = assignNewHandle(obj);
350
          Object prevObject = this.currentObject;
351
          ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
352
          TreeSet prevObjectValidators = this.currentObjectValidators;
353
 
354
          this.currentObject = obj;
355
          this.currentObjectValidators = null;
356
          ObjectStreamClass[] hierarchy =
357
            inputGetObjectStreamClasses(clazz);
358
 
359
          for (int i = 0; i < hierarchy.length; i++)
360
          {
361
              this.currentObjectStreamClass = hierarchy[i];
362
              if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
363
 
364
              // XXX: should initialize fields in classes in the hierarchy
365
              // that aren't in the stream
366
              // should skip over classes in the stream that aren't in the
367
              // real classes hierarchy
368
 
369
              Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
370
              if (readObjectMethod != null)
371
                {
372
                  fieldsAlreadyRead = false;
373
                  boolean oldmode = setBlockDataMode(true);
374
                  callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
375
                  setBlockDataMode(oldmode);
376
                }
377
              else
378
                {
379
                  readFields(obj, currentObjectStreamClass);
380
                }
381
 
382
              if (this.currentObjectStreamClass.hasWriteMethod())
383
                {
384
                  if(dump) dumpElement("ENDBLOCKDATA? ");
385
                  try
386
                    {
387
                      /* Read blocks until an end marker */
388
                      byte writeMarker = this.realInputStream.readByte();
389
                      while (writeMarker != TC_ENDBLOCKDATA)
390
                        {
391
                          parseContent(writeMarker);
392
                          writeMarker = this.realInputStream.readByte();
393
                        }
394
                      if(dump) dumpElementln("yes");
395
                    }
396
                  catch (EOFException e)
397
                    {
398
                      throw (IOException) new IOException
399
                        ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
400
                    }
401
                }
402
            }
403
 
404
          this.currentObject = prevObject;
405
          this.currentObjectStreamClass = prevObjectStreamClass;
406
          ret_val = processResolution(osc, obj, handle);
407
          if (currentObjectValidators != null)
408
            invokeValidators();
409
          this.currentObjectValidators = prevObjectValidators;
410
 
411
          break;
412
        }
413
 
414
       case TC_RESET:
415
        if(dump) dumpElementln("RESET");
416
        clearHandles();
417
        ret_val = readObject();
418
        break;
419
 
420
       case TC_EXCEPTION:
421
        {
422
          if(dump) dumpElement("EXCEPTION=");
423
          Exception e = (Exception)readObject();
424
          if(dump) dumpElementln(e.toString());
425
          clearHandles();
426
          throw new WriteAbortedException("Exception thrown during writing of stream", e);
427
        }
428
 
429
       default:
430
        throw new IOException("Unknown marker on stream: " + marker);
431
      }
432
    return ret_val;
433
  }
434
 
435
  /**
436
   * This method makes a partial check of types for the fields
437
   * contained given in arguments. It checks primitive types of
438
   * fields1 against non primitive types of fields2. This method
439
   * assumes the two lists has already been sorted according to
440
   * the Java specification.
441
   *
442
   * @param name Name of the class owning the given fields.
443
   * @param fields1 First list to check.
444
   * @param fields2 Second list to check.
445
   * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
446
   * in the non primitive part in fields2.
447
   */
448
  private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
449
    throws InvalidClassException
450
  {
451
    int nonPrimitive = 0;
452
 
453
    for (nonPrimitive = 0;
454
         nonPrimitive < fields1.length
455
           && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
456
      {
457
      }
458
 
459
    if (nonPrimitive == fields1.length)
460
      return;
461
 
462
    int i = 0;
463
    ObjectStreamField f1;
464
    ObjectStreamField f2;
465
 
466
    while (i < fields2.length
467
           && nonPrimitive < fields1.length)
468
      {
469
        f1 = fields1[nonPrimitive];
470
        f2 = fields2[i];
471
 
472
        if (!f2.isPrimitive())
473
          break;
474
 
475
        int compVal = f1.getName().compareTo (f2.getName());
476
 
477
        if (compVal < 0)
478
          {
479
            nonPrimitive++;
480
          }
481
        else if (compVal > 0)
482
          {
483
            i++;
484
          }
485
        else
486
          {
487
            throw new InvalidClassException
488
              ("invalid field type for " + f2.getName() +
489
               " in class " + name);
490
          }
491
      }
492
  }
493
 
494
  /**
495
   * This method reads a class descriptor from the real input stream
496
   * and use these data to create a new instance of ObjectStreamClass.
497
   * Fields are sorted and ordered for the real read which occurs for
498
   * each instance of the described class. Be aware that if you call that
499
   * method you must ensure that the stream is synchronized, in the other
500
   * case it may be completely desynchronized.
501
   *
502
   * @return A new instance of ObjectStreamClass containing the freshly
503
   * created descriptor.
504
   * @throws ClassNotFoundException if the required class to build the
505
   * descriptor has not been found in the system.
506
   * @throws IOException An input/output error occured.
507
   * @throws InvalidClassException If there was a compatibility problem
508
   * between the class present in the system and the serialized class.
509
   */
510
  protected ObjectStreamClass readClassDescriptor()
511
    throws ClassNotFoundException, IOException
512
  {
513
    if(dump) dumpElement("CLASSDESC NAME=");
514
    String name = this.realInputStream.readUTF();
515
    if(dump) dumpElement(name + "; UID=");
516
    long uid = this.realInputStream.readLong ();
517
    if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
518
    byte flags = this.realInputStream.readByte ();
519
    if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
520
    short field_count = this.realInputStream.readShort();
521
    if(dump) dumpElementln(Short.toString(field_count));
522
    ObjectStreamField[] fields = new ObjectStreamField[field_count];
523
    ObjectStreamClass osc = new ObjectStreamClass(name, uid,
524
                                                  flags, fields);
525
    assignNewHandle(osc);
526
 
527
    ClassLoader callersClassLoader = currentLoader();
528
 
529
    for (int i = 0; i < field_count; i++)
530
      {
531
        if(dump) dumpElement("  TYPE CODE=");
532
        char type_code = (char)this.realInputStream.readByte();
533
        if(dump) dumpElement(type_code + "; FIELD NAME=");
534
        String field_name = this.realInputStream.readUTF();
535
        if(dump) dumpElementln(field_name);
536
        String class_name;
537
 
538
        // If the type code is an array or an object we must
539
        // decode a String here. In the other case we convert
540
        // the type code and pass it to ObjectStreamField.
541
        // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
542
        if (type_code == 'L' || type_code == '[')
543
          class_name = (String)readObject();
544
        else
545
          class_name = String.valueOf(type_code);
546
 
547
        fields[i] =
548
          new ObjectStreamField(field_name, class_name, callersClassLoader);
549
      }
550
 
551
    /* Now that fields have been read we may resolve the class
552
     * (and read annotation if needed). */
553
    Class clazz = resolveClass(osc);
554
    boolean oldmode = setBlockDataMode(true);
555
    osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
556
    classLookupTable.put(clazz, osc);
557
    setBlockDataMode(oldmode);
558
 
559
    // find the first non-serializable, non-abstract
560
    // class in clazz's inheritance hierarchy
561
    Class first_nonserial = clazz.getSuperclass();
562
    // Maybe it is a primitive class, those don't have a super class,
563
    // or Object itself.  Otherwise we can keep getting the superclass
564
    // till we hit the Object class, or some other non-serializable class.
565
 
566
    if (first_nonserial == null)
567
      first_nonserial = clazz;
568
    else
569
      while (Serializable.class.isAssignableFrom(first_nonserial)
570
             || Modifier.isAbstract(first_nonserial.getModifiers()))
571
        first_nonserial = first_nonserial.getSuperclass();
572
 
573
    final Class local_constructor_class = first_nonserial;
574
 
575
    osc.firstNonSerializableParentConstructor =
576
        (Constructor)AccessController.doPrivileged(new PrivilegedAction()
577
          {
578
            public Object run()
579
            {
580
              try
581
                {
582
                  Constructor c = local_constructor_class.
583
                                    getDeclaredConstructor(new Class[0]);
584
                  if (Modifier.isPrivate(c.getModifiers()))
585
                    return null;
586
                  return c;
587
                }
588
              catch (NoSuchMethodException e)
589
                {
590
                  // error will be reported later, in newObject()
591
                  return null;
592
                }
593
            }
594
          });
595
 
596
    osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
597
    osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
598
 
599
    ObjectStreamField[] stream_fields = osc.fields;
600
    ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
601
    ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
602
 
603
    int stream_idx = 0;
604
    int real_idx = 0;
605
    int map_idx = 0;
606
 
607
    /*
608
     * Check that there is no type inconsistencies between the lists.
609
     * A special checking must be done for the two groups: primitive types and
610
     * not primitive types.
611
     */
612
    checkTypeConsistency(name, real_fields, stream_fields);
613
    checkTypeConsistency(name, stream_fields, real_fields);
614
 
615
 
616
    while (stream_idx < stream_fields.length
617
           || real_idx < real_fields.length)
618
      {
619
        ObjectStreamField stream_field = null;
620
        ObjectStreamField real_field = null;
621
 
622
        if (stream_idx == stream_fields.length)
623
          {
624
            real_field = real_fields[real_idx++];
625
          }
626
        else if (real_idx == real_fields.length)
627
          {
628
            stream_field = stream_fields[stream_idx++];
629
          }
630
        else
631
          {
632
            int comp_val =
633
              real_fields[real_idx].compareTo (stream_fields[stream_idx]);
634
 
635
            if (comp_val < 0)
636
              {
637
                real_field = real_fields[real_idx++];
638
              }
639
            else if (comp_val > 0)
640
              {
641
                stream_field = stream_fields[stream_idx++];
642
              }
643
            else
644
              {
645
                stream_field = stream_fields[stream_idx++];
646
                real_field = real_fields[real_idx++];
647
                if (stream_field.getType() != real_field.getType())
648
                  throw new InvalidClassException
649
                    ("invalid field type for " + real_field.getName() +
650
                     " in class " + name);
651
              }
652
          }
653
 
654
        /* If some of stream_fields does not correspond to any of real_fields,
655
         * or the opposite, then fieldmapping will go short.
656
         */
657
        if (map_idx == fieldmapping.length)
658
          {
659
            ObjectStreamField[] newfieldmapping =
660
              new ObjectStreamField[fieldmapping.length + 2];
661
            System.arraycopy(fieldmapping, 0,
662
                             newfieldmapping, 0, fieldmapping.length);
663
            fieldmapping = newfieldmapping;
664
          }
665
        fieldmapping[map_idx++] = stream_field;
666
        fieldmapping[map_idx++] = real_field;
667
      }
668
    osc.fieldMapping = fieldmapping;
669
 
670
    return osc;
671
  }
672
 
673
  /**
674
   * Reads the current objects non-transient, non-static fields from
675
   * the current class from the underlying output stream.
676
   *
677
   * This method is intended to be called from within a object's
678
   * <code>private void readObject (ObjectInputStream)</code>
679
   * method.
680
   *
681
   * @exception ClassNotFoundException The class that an object being
682
   * read in belongs to cannot be found.
683
   *
684
   * @exception NotActiveException This method was called from a
685
   * context other than from the current object's and current class's
686
   * <code>private void readObject (ObjectInputStream)</code>
687
   * method.
688
   *
689
   * @exception IOException Exception from underlying
690
   * <code>OutputStream</code>.
691
   */
692
  public void defaultReadObject()
693
    throws ClassNotFoundException, IOException, NotActiveException
694
  {
695
    if (this.currentObject == null || this.currentObjectStreamClass == null)
696
      throw new NotActiveException("defaultReadObject called by non-active"
697
                                   + " class and/or object");
698
 
699
    if (fieldsAlreadyRead)
700
      throw new NotActiveException("defaultReadObject called but fields "
701
                                   + "already read from stream (by "
702
                                   + "defaultReadObject or readFields)");
703
 
704
    boolean oldmode = setBlockDataMode(false);
705
    readFields(this.currentObject, this.currentObjectStreamClass);
706
    setBlockDataMode(oldmode);
707
 
708
    fieldsAlreadyRead = true;
709
  }
710
 
711
 
712
  /**
713
   * Registers a <code>ObjectInputValidation</code> to be carried out
714
   * on the object graph currently being deserialized before it is
715
   * returned to the original caller of <code>readObject ()</code>.
716
   * The order of validation for multiple
717
   * <code>ObjectInputValidation</code>s can be controled using
718
   * <code>priority</code>.  Validators with higher priorities are
719
   * called first.
720
   *
721
   * @see java.io.ObjectInputValidation
722
   *
723
   * @exception InvalidObjectException <code>validator</code> is
724
   * <code>null</code>
725
   *
726
   * @exception NotActiveException an attempt was made to add a
727
   * validator outside of the <code>readObject</code> method of the
728
   * object currently being deserialized
729
   */
730
  public void registerValidation(ObjectInputValidation validator,
731
                                 int priority)
732
    throws InvalidObjectException, NotActiveException
733
  {
734
    if (this.currentObject == null || this.currentObjectStreamClass == null)
735
      throw new NotActiveException("registerValidation called by non-active "
736
                                   + "class and/or object");
737
 
738
    if (validator == null)
739
      throw new InvalidObjectException("attempt to add a null "
740
                                       + "ObjectInputValidation object");
741
 
742
    if (currentObjectValidators == null)
743
      currentObjectValidators = new TreeSet();
744
 
745
    currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
746
  }
747
 
748
 
749
  /**
750
   * Called when a class is being deserialized.  This is a hook to
751
   * allow subclasses to read in information written by the
752
   * <code>annotateClass (Class)</code> method of an
753
   * <code>ObjectOutputStream</code>.
754
   *
755
   * This implementation looks up the active call stack for a
756
   * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
757
   * it is used to load the class associated with <code>osc</code>,
758
   * otherwise, the default system <code>ClassLoader</code> is used.
759
   *
760
   * @exception IOException Exception from underlying
761
   * <code>OutputStream</code>.
762
   *
763
   * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
764
   */
765
  protected Class resolveClass(ObjectStreamClass osc)
766
    throws ClassNotFoundException, IOException
767
  {
768
    String name = osc.getName();
769
    try
770
      {
771
        return Class.forName(name, true, currentLoader());
772
      }
773
    catch(ClassNotFoundException x)
774
      {
775
        if (name.equals("void"))
776
          return Void.TYPE;
777
        else if (name.equals("boolean"))
778
          return Boolean.TYPE;
779
        else if (name.equals("byte"))
780
          return Byte.TYPE;
781
        else if (name.equals("char"))
782
          return Character.TYPE;
783
        else if (name.equals("short"))
784
          return Short.TYPE;
785
        else if (name.equals("int"))
786
          return Integer.TYPE;
787
        else if (name.equals("long"))
788
          return Long.TYPE;
789
        else if (name.equals("float"))
790
          return Float.TYPE;
791
        else if (name.equals("double"))
792
          return Double.TYPE;
793
        else
794
          throw x;
795
      }
796
  }
797
 
798
  /**
799
   * Returns the most recent user defined ClassLoader on the execution stack
800
   * or null if none is found.
801
   */
802
  private ClassLoader currentLoader()
803
  {
804
    return VMObjectInputStream.currentClassLoader();
805
  }
806
 
807
  /**
808
   * Lookup a class stored in the local hashtable. If it is not
809
   * use the global lookup function in ObjectStreamClass to build
810
   * the ObjectStreamClass. This method is requested according to
811
   * the behaviour detected in the JDK by Kaffe's team.
812
   *
813
   * @param clazz Class to lookup in the hash table or for which
814
   * we must build a descriptor.
815
   * @return A valid instance of ObjectStreamClass corresponding
816
   * to the specified class.
817
   */
818
  private ObjectStreamClass lookupClass(Class clazz)
819
  {
820
    if (clazz == null)
821
      return null;
822
 
823
    ObjectStreamClass oclazz;
824
    oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
825
    if (oclazz == null)
826
      return ObjectStreamClass.lookup(clazz);
827
    else
828
      return oclazz;
829
  }
830
 
831
  /**
832
   * Reconstruct class hierarchy the same way
833
   * {@link java.io.ObjectStreamClass#getObjectStreamClasses(Class)} does
834
   * but using lookupClass instead of ObjectStreamClass.lookup. This
835
   * dup is necessary localize the lookup table. Hopefully some future
836
   * rewritings will be able to prevent this.
837
   *
838
   * @param clazz This is the class for which we want the hierarchy.
839
   *
840
   * @return An array of valid {@link java.io.ObjectStreamClass} instances which
841
   * represent the class hierarchy for clazz.
842
   */
843
  private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz)
844
  {
845
    ObjectStreamClass osc = lookupClass(clazz);
846
 
847
    if (osc == null)
848
      return new ObjectStreamClass[0];
849
    else
850
      {
851
        Vector oscs = new Vector();
852
 
853
        while (osc != null)
854
          {
855
            oscs.addElement(osc);
856
            osc = osc.getSuper();
857
          }
858
 
859
        int count = oscs.size();
860
        ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count];
861
 
862
        for (int i = count - 1; i >= 0; i--)
863
          sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i);
864
 
865
        return sorted_oscs;
866
      }
867
  }
868
 
869
  /**
870
   * Allows subclasses to resolve objects that are read from the
871
   * stream with other objects to be returned in their place.  This
872
   * method is called the first time each object is encountered.
873
   *
874
   * This method must be enabled before it will be called in the
875
   * serialization process.
876
   *
877
   * @exception IOException Exception from underlying
878
   * <code>OutputStream</code>.
879
   *
880
   * @see #enableResolveObject(boolean)
881
   */
882
  protected Object resolveObject(Object obj) throws IOException
883
  {
884
    return obj;
885
  }
886
 
887
 
888
  protected Class resolveProxyClass(String[] intfs)
889
    throws IOException, ClassNotFoundException
890
  {
891
    ClassLoader cl = currentLoader();
892
 
893
    Class[] clss = new Class[intfs.length];
894
    if(cl == null)
895
      {
896
        for (int i = 0; i < intfs.length; i++)
897
          clss[i] = Class.forName(intfs[i]);
898
        cl = ClassLoader.getSystemClassLoader();
899
      }
900
    else
901
      for (int i = 0; i < intfs.length; i++)
902
        clss[i] = Class.forName(intfs[i], false, cl);
903
    try
904
      {
905
        return Proxy.getProxyClass(cl, clss);
906
      }
907
    catch (IllegalArgumentException e)
908
      {
909
        throw new ClassNotFoundException(null, e);
910
      }
911
  }
912
 
913
  /**
914
   * If <code>enable</code> is <code>true</code> and this object is
915
   * trusted, then <code>resolveObject (Object)</code> will be called
916
   * in subsequent calls to <code>readObject (Object)</code>.
917
   * Otherwise, <code>resolveObject (Object)</code> will not be called.
918
   *
919
   * @exception SecurityException This class is not trusted.
920
   */
921
  protected boolean enableResolveObject (boolean enable)
922
    throws SecurityException
923
  {
924
    if (enable)
925
      {
926
        SecurityManager sm = System.getSecurityManager();
927
        if (sm != null)
928
          sm.checkPermission(new SerializablePermission("enableSubstitution"));
929
      }
930
 
931
    boolean old_val = this.resolveEnabled;
932
    this.resolveEnabled = enable;
933
    return old_val;
934
  }
935
 
936
  /**
937
   * Reads stream magic and stream version information from the
938
   * underlying stream.
939
   *
940
   * @exception IOException Exception from underlying stream.
941
   *
942
   * @exception StreamCorruptedException An invalid stream magic
943
   * number or stream version was read from the stream.
944
   */
945
  protected void readStreamHeader()
946
    throws IOException, StreamCorruptedException
947
  {
948
    if(dump) dumpElement("STREAM MAGIC ");
949
    if (this.realInputStream.readShort() != STREAM_MAGIC)
950
      throw new StreamCorruptedException("Invalid stream magic number");
951
 
952
    if(dump) dumpElementln("STREAM VERSION ");
953
    if (this.realInputStream.readShort() != STREAM_VERSION)
954
      throw new StreamCorruptedException("Invalid stream version number");
955
  }
956
 
957
  public int read() throws IOException
958
  {
959
    if (this.readDataFromBlock)
960
      {
961
        if (this.blockDataPosition >= this.blockDataBytes)
962
          readNextBlock();
963
        return (this.blockData[this.blockDataPosition++] & 0xff);
964
      }
965
    else
966
      return this.realInputStream.read();
967
  }
968
 
969
  public int read(byte[] data, int offset, int length) throws IOException
970
  {
971
    if (this.readDataFromBlock)
972
      {
973
        int remain = this.blockDataBytes - this.blockDataPosition;
974
        if (remain == 0)
975
          {
976
            readNextBlock();
977
            remain = this.blockDataBytes - this.blockDataPosition;
978
          }
979
        length = Math.min(length, remain);
980
        System.arraycopy(this.blockData, this.blockDataPosition,
981
                         data, offset, length);
982
        this.blockDataPosition += length;
983
 
984
        return length;
985
      }
986
    else
987
      return this.realInputStream.read(data, offset, length);
988
  }
989
 
990
  public int available() throws IOException
991
  {
992
    if (this.readDataFromBlock)
993
      {
994
        if (this.blockDataPosition >= this.blockDataBytes)
995
          readNextBlock ();
996
 
997
        return this.blockDataBytes - this.blockDataPosition;
998
      }
999
    else
1000
      return this.realInputStream.available();
1001
  }
1002
 
1003
  public void close() throws IOException
1004
  {
1005
    this.realInputStream.close();
1006
  }
1007
 
1008
  public boolean readBoolean() throws IOException
1009
  {
1010
    boolean switchmode = true;
1011
    boolean oldmode = this.readDataFromBlock;
1012
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1013
      switchmode = false;
1014
    if (switchmode)
1015
      oldmode = setBlockDataMode (true);
1016
    boolean value = this.dataInputStream.readBoolean ();
1017
    if (switchmode)
1018
      setBlockDataMode (oldmode);
1019
    return value;
1020
  }
1021
 
1022
  public byte readByte() throws IOException
1023
  {
1024
    boolean switchmode = true;
1025
    boolean oldmode = this.readDataFromBlock;
1026
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1027
      switchmode = false;
1028
    if (switchmode)
1029
      oldmode = setBlockDataMode(true);
1030
    byte value = this.dataInputStream.readByte();
1031
    if (switchmode)
1032
      setBlockDataMode(oldmode);
1033
    return value;
1034
  }
1035
 
1036
  public int readUnsignedByte() throws IOException
1037
  {
1038
    boolean switchmode = true;
1039
    boolean oldmode = this.readDataFromBlock;
1040
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
1041
      switchmode = false;
1042
    if (switchmode)
1043
      oldmode = setBlockDataMode(true);
1044
    int value = this.dataInputStream.readUnsignedByte();
1045
    if (switchmode)
1046
      setBlockDataMode(oldmode);
1047
    return value;
1048
  }
1049
 
1050
  public short readShort() throws IOException
1051
  {
1052
    boolean switchmode = true;
1053
    boolean oldmode = this.readDataFromBlock;
1054
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1055
      switchmode = false;
1056
    if (switchmode)
1057
      oldmode = setBlockDataMode(true);
1058
    short value = this.dataInputStream.readShort();
1059
    if (switchmode)
1060
      setBlockDataMode(oldmode);
1061
    return value;
1062
  }
1063
 
1064
  public int readUnsignedShort() throws IOException
1065
  {
1066
    boolean switchmode = true;
1067
    boolean oldmode = this.readDataFromBlock;
1068
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1069
      switchmode = false;
1070
    if (switchmode)
1071
      oldmode = setBlockDataMode(true);
1072
    int value = this.dataInputStream.readUnsignedShort();
1073
    if (switchmode)
1074
      setBlockDataMode(oldmode);
1075
    return value;
1076
  }
1077
 
1078
  public char readChar() throws IOException
1079
  {
1080
    boolean switchmode = true;
1081
    boolean oldmode = this.readDataFromBlock;
1082
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
1083
      switchmode = false;
1084
    if (switchmode)
1085
      oldmode = setBlockDataMode(true);
1086
    char value = this.dataInputStream.readChar();
1087
    if (switchmode)
1088
      setBlockDataMode(oldmode);
1089
    return value;
1090
  }
1091
 
1092
  public int readInt() throws IOException
1093
  {
1094
    boolean switchmode = true;
1095
    boolean oldmode = this.readDataFromBlock;
1096
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1097
      switchmode = false;
1098
    if (switchmode)
1099
      oldmode = setBlockDataMode(true);
1100
    int value = this.dataInputStream.readInt();
1101
    if (switchmode)
1102
      setBlockDataMode(oldmode);
1103
    return value;
1104
  }
1105
 
1106
  public long readLong() throws IOException
1107
  {
1108
    boolean switchmode = true;
1109
    boolean oldmode = this.readDataFromBlock;
1110
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1111
      switchmode = false;
1112
    if (switchmode)
1113
      oldmode = setBlockDataMode(true);
1114
    long value = this.dataInputStream.readLong();
1115
    if (switchmode)
1116
      setBlockDataMode(oldmode);
1117
    return value;
1118
  }
1119
 
1120
  public float readFloat() throws IOException
1121
  {
1122
    boolean switchmode = true;
1123
    boolean oldmode = this.readDataFromBlock;
1124
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
1125
      switchmode = false;
1126
    if (switchmode)
1127
      oldmode = setBlockDataMode(true);
1128
    float value = this.dataInputStream.readFloat();
1129
    if (switchmode)
1130
      setBlockDataMode(oldmode);
1131
    return value;
1132
  }
1133
 
1134
  public double readDouble() throws IOException
1135
  {
1136
    boolean switchmode = true;
1137
    boolean oldmode = this.readDataFromBlock;
1138
    if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
1139
      switchmode = false;
1140
    if (switchmode)
1141
      oldmode = setBlockDataMode(true);
1142
    double value = this.dataInputStream.readDouble();
1143
    if (switchmode)
1144
      setBlockDataMode(oldmode);
1145
    return value;
1146
  }
1147
 
1148
  public void readFully(byte data[]) throws IOException
1149
  {
1150
    this.dataInputStream.readFully(data);
1151
  }
1152
 
1153
  public void readFully(byte data[], int offset, int size)
1154
    throws IOException
1155
  {
1156
    this.dataInputStream.readFully(data, offset, size);
1157
  }
1158
 
1159
  public int skipBytes(int len) throws IOException
1160
  {
1161
    return this.dataInputStream.skipBytes(len);
1162
  }
1163
 
1164
  /**
1165
   * @deprecated
1166
   * @see java.io.DataInputStream#readLine ()
1167
   */
1168
  public String readLine() throws IOException
1169
  {
1170
    return this.dataInputStream.readLine();
1171
  }
1172
 
1173
  public String readUTF() throws IOException
1174
  {
1175
    return this.dataInputStream.readUTF();
1176
  }
1177
 
1178
  /**
1179
   * This class allows a class to specify exactly which fields should
1180
   * be read, and what values should be read for these fields.
1181
   *
1182
   * XXX: finish up comments
1183
   */
1184
  public abstract static class GetField
1185
  {
1186
    public abstract ObjectStreamClass getObjectStreamClass();
1187
 
1188
    public abstract boolean defaulted(String name)
1189
      throws IOException, IllegalArgumentException;
1190
 
1191
    public abstract boolean get(String name, boolean defvalue)
1192
      throws IOException, IllegalArgumentException;
1193
 
1194
    public abstract char get(String name, char defvalue)
1195
      throws IOException, IllegalArgumentException;
1196
 
1197
    public abstract byte get(String name, byte defvalue)
1198
      throws IOException, IllegalArgumentException;
1199
 
1200
    public abstract short get(String name, short defvalue)
1201
      throws IOException, IllegalArgumentException;
1202
 
1203
    public abstract int get(String name, int defvalue)
1204
      throws IOException, IllegalArgumentException;
1205
 
1206
    public abstract long get(String name, long defvalue)
1207
      throws IOException, IllegalArgumentException;
1208
 
1209
    public abstract float get(String name, float defvalue)
1210
      throws IOException, IllegalArgumentException;
1211
 
1212
    public abstract double get(String name, double defvalue)
1213
      throws IOException, IllegalArgumentException;
1214
 
1215
    public abstract Object get(String name, Object defvalue)
1216
      throws IOException, IllegalArgumentException;
1217
  }
1218
 
1219
  /**
1220
   * This method should be called by a method called 'readObject' in the
1221
   * deserializing class (if present). It cannot (and should not)be called
1222
   * outside of it. Its goal is to read all fields in the real input stream
1223
   * and keep them accessible through the {@link GetField} class. Calling
1224
   * this method will not alter the deserializing object.
1225
   *
1226
   * @return A valid freshly created 'GetField' instance to get access to
1227
   * the deserialized stream.
1228
   * @throws IOException An input/output exception occured.
1229
   * @throws ClassNotFoundException
1230
   * @throws NotActiveException
1231
   */
1232
  public GetField readFields()
1233
    throws IOException, ClassNotFoundException, NotActiveException
1234
  {
1235
    if (this.currentObject == null || this.currentObjectStreamClass == null)
1236
      throw new NotActiveException("readFields called by non-active class and/or object");
1237
 
1238
    if (prereadFields != null)
1239
      return prereadFields;
1240
 
1241
    if (fieldsAlreadyRead)
1242
      throw new NotActiveException("readFields called but fields already read from"
1243
                                   + " stream (by defaultReadObject or readFields)");
1244
 
1245
    final ObjectStreamClass clazz = this.currentObjectStreamClass;
1246
    final byte[] prim_field_data = new byte[clazz.primFieldSize];
1247
    final Object[] objs = new Object[clazz.objectFieldCount];
1248
 
1249
    // Apparently Block data is not used with GetField as per
1250
    // empirical evidence against JDK 1.2.  Also see Mauve test
1251
    // java.io.ObjectInputOutput.Test.GetPutField.
1252
    boolean oldmode = setBlockDataMode(false);
1253
    readFully(prim_field_data);
1254
    for (int i = 0; i < objs.length; ++ i)
1255
      objs[i] = readObject();
1256
    setBlockDataMode(oldmode);
1257
 
1258
    prereadFields = new GetField()
1259
      {
1260
        public ObjectStreamClass getObjectStreamClass()
1261
        {
1262
          return clazz;
1263
        }
1264
 
1265
        public boolean defaulted(String name)
1266
          throws IOException, IllegalArgumentException
1267
        {
1268
          ObjectStreamField f = clazz.getField(name);
1269
 
1270
          /* First if we have a serialized field use the descriptor */
1271
          if (f != null)
1272
            {
1273
              /* It is in serialPersistentFields but setClass tells us
1274
               * it should not be set. This value is defaulted.
1275
               */
1276
              if (f.isPersistent() && !f.isToSet())
1277
                return true;
1278
 
1279
              return false;
1280
            }
1281
 
1282
          /* This is not a serialized field. There should be
1283
           * a default value only if the field really exists.
1284
           */
1285
          try
1286
            {
1287
              return (clazz.forClass().getDeclaredField (name) != null);
1288
            }
1289
          catch (NoSuchFieldException e)
1290
            {
1291
              throw new IllegalArgumentException(e);
1292
            }
1293
        }
1294
 
1295
        public boolean get(String name, boolean defvalue)
1296
          throws IOException, IllegalArgumentException
1297
        {
1298
          ObjectStreamField field = getField(name, Boolean.TYPE);
1299
 
1300
          if (field == null)
1301
            return defvalue;
1302
 
1303
          return prim_field_data[field.getOffset()] == 0 ? false : true;
1304
        }
1305
 
1306
        public char get(String name, char defvalue)
1307
          throws IOException, IllegalArgumentException
1308
        {
1309
          ObjectStreamField field = getField(name, Character.TYPE);
1310
 
1311
          if (field == null)
1312
            return defvalue;
1313
 
1314
          int off = field.getOffset();
1315
 
1316
          return (char)(((prim_field_data[off++] & 0xFF) << 8)
1317
                        | (prim_field_data[off] & 0xFF));
1318
        }
1319
 
1320
        public byte get(String name, byte defvalue)
1321
          throws IOException, IllegalArgumentException
1322
        {
1323
          ObjectStreamField field = getField(name, Byte.TYPE);
1324
 
1325
          if (field == null)
1326
            return defvalue;
1327
 
1328
          return prim_field_data[field.getOffset()];
1329
        }
1330
 
1331
        public short get(String name, short defvalue)
1332
          throws IOException, IllegalArgumentException
1333
        {
1334
          ObjectStreamField field = getField(name, Short.TYPE);
1335
 
1336
          if (field == null)
1337
            return defvalue;
1338
 
1339
          int off = field.getOffset();
1340
 
1341
          return (short)(((prim_field_data[off++] & 0xFF) << 8)
1342
                         | (prim_field_data[off] & 0xFF));
1343
        }
1344
 
1345
        public int get(String name, int defvalue)
1346
          throws IOException, IllegalArgumentException
1347
        {
1348
          ObjectStreamField field = getField(name, Integer.TYPE);
1349
 
1350
          if (field == null)
1351
            return defvalue;
1352
 
1353
          int off = field.getOffset();
1354
 
1355
          return ((prim_field_data[off++] & 0xFF) << 24)
1356
            | ((prim_field_data[off++] & 0xFF) << 16)
1357
            | ((prim_field_data[off++] & 0xFF) << 8)
1358
            | (prim_field_data[off] & 0xFF);
1359
        }
1360
 
1361
        public long get(String name, long defvalue)
1362
          throws IOException, IllegalArgumentException
1363
        {
1364
          ObjectStreamField field = getField(name, Long.TYPE);
1365
 
1366
          if (field == null)
1367
            return defvalue;
1368
 
1369
          int off = field.getOffset();
1370
 
1371
          return (long)(((prim_field_data[off++] & 0xFFL) << 56)
1372
                        | ((prim_field_data[off++] & 0xFFL) << 48)
1373
                        | ((prim_field_data[off++] & 0xFFL) << 40)
1374
                        | ((prim_field_data[off++] & 0xFFL) << 32)
1375
                        | ((prim_field_data[off++] & 0xFF) << 24)
1376
                        | ((prim_field_data[off++] & 0xFF) << 16)
1377
                        | ((prim_field_data[off++] & 0xFF) << 8)
1378
                        | (prim_field_data[off] & 0xFF));
1379
        }
1380
 
1381
        public float get(String name, float defvalue)
1382
          throws IOException, IllegalArgumentException
1383
        {
1384
          ObjectStreamField field = getField(name, Float.TYPE);
1385
 
1386
          if (field == null)
1387
            return defvalue;
1388
 
1389
          int off = field.getOffset();
1390
 
1391
          return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
1392
                                      | ((prim_field_data[off++] & 0xFF) << 16)
1393
                                      | ((prim_field_data[off++] & 0xFF) << 8)
1394
                                      | (prim_field_data[off] & 0xFF));
1395
        }
1396
 
1397
        public double get(String name, double defvalue)
1398
          throws IOException, IllegalArgumentException
1399
        {
1400
          ObjectStreamField field = getField(name, Double.TYPE);
1401
 
1402
          if (field == null)
1403
            return defvalue;
1404
 
1405
          int off = field.getOffset();
1406
 
1407
          return Double.longBitsToDouble
1408
            ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
1409
                      | ((prim_field_data[off++] & 0xFFL) << 48)
1410
                      | ((prim_field_data[off++] & 0xFFL) << 40)
1411
                      | ((prim_field_data[off++] & 0xFFL) << 32)
1412
                      | ((prim_field_data[off++] & 0xFF) << 24)
1413
                      | ((prim_field_data[off++] & 0xFF) << 16)
1414
                      | ((prim_field_data[off++] & 0xFF) << 8)
1415
                      | (prim_field_data[off] & 0xFF)));
1416
        }
1417
 
1418
        public Object get(String name, Object defvalue)
1419
          throws IOException, IllegalArgumentException
1420
        {
1421
          ObjectStreamField field =
1422
            getField(name, defvalue == null ? null : defvalue.getClass ());
1423
 
1424
          if (field == null)
1425
            return defvalue;
1426
 
1427
          return objs[field.getOffset()];
1428
        }
1429
 
1430
        private ObjectStreamField getField(String name, Class type)
1431
          throws IllegalArgumentException
1432
        {
1433
          ObjectStreamField field = clazz.getField(name);
1434
          boolean illegal = false;
1435
 
1436
          // XXX This code is horrible and needs to be rewritten!
1437
          try
1438
            {
1439
              try
1440
                {
1441
                  Class field_type = field.getType();
1442
 
1443
                  if (type == field_type ||
1444
                      (type == null && !field_type.isPrimitive()))
1445
                    {
1446
                      /* See defaulted */
1447
                      return field;
1448
                    }
1449
 
1450
                  illegal = true;
1451
                  throw new IllegalArgumentException
1452
                    ("Field requested is of type "
1453
                     + field_type.getName()
1454
                     + ", but requested type was "
1455
                     + (type == null ?  "Object" : type.getName()));
1456
                }
1457
              catch (NullPointerException _)
1458
                {
1459
                  /* Here we catch NullPointerException, because it may
1460
                     only come from the call 'field.getType()'. If field
1461
                     is null, we have to return null and classpath ethic
1462
                     say we must try to avoid 'if (xxx == null)'.
1463
                  */
1464
                }
1465
              catch (IllegalArgumentException e)
1466
                {
1467
                  throw e;
1468
                }
1469
 
1470
              return null;
1471
            }
1472
          finally
1473
            {
1474
              /* If this is an unassigned field we should return
1475
               * the default value.
1476
               */
1477
              if (!illegal && field != null && !field.isToSet() && field.isPersistent())
1478
                return null;
1479
 
1480
              /* We do not want to modify transient fields. They should
1481
               * be left to 0.
1482
               */
1483
              try
1484
                {
1485
                  Field f = clazz.forClass().getDeclaredField(name);
1486
                  if (Modifier.isTransient(f.getModifiers()))
1487
                    throw new IllegalArgumentException
1488
                      ("no such field (non transient) " + name);
1489
                  if (field == null && f.getType() != type)
1490
                    throw new IllegalArgumentException
1491
                      ("Invalid requested type for field " + name);
1492
                }
1493
              catch (NoSuchFieldException e)
1494
                {
1495
                  if (field == null)
1496
                    throw new IllegalArgumentException(e);
1497
                }
1498
 
1499
            }
1500
        }
1501
      };
1502
 
1503
    fieldsAlreadyRead = true;
1504
    return prereadFields;
1505
  }
1506
 
1507
  /**
1508
   * Protected constructor that allows subclasses to override
1509
   * deserialization.  This constructor should be called by subclasses
1510
   * that wish to override <code>readObject (Object)</code>.  This
1511
   * method does a security check <i>NOTE: currently not
1512
   * implemented</i>, then sets a flag that informs
1513
   * <code>readObject (Object)</code> to call the subclasses
1514
   * <code>readObjectOverride (Object)</code> method.
1515
   *
1516
   * @see #readObjectOverride()
1517
   */
1518
  protected ObjectInputStream()
1519
    throws IOException, SecurityException
1520
  {
1521
    SecurityManager sec_man = System.getSecurityManager();
1522
    if (sec_man != null)
1523
      sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1524
    this.useSubclassMethod = true;
1525
  }
1526
 
1527
  /**
1528
   * This method allows subclasses to override the default
1529
   * de serialization mechanism provided by
1530
   * <code>ObjectInputStream</code>.  To make this method be used for
1531
   * writing objects, subclasses must invoke the 0-argument
1532
   * constructor on this class from their constructor.
1533
   *
1534
   * @see #ObjectInputStream()
1535
   */
1536
  protected Object readObjectOverride()
1537
    throws ClassNotFoundException, IOException, OptionalDataException
1538
  {
1539
    throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
1540
  }
1541
 
1542
  /**
1543
   * Assigns the next available handle to <code>obj</code>.
1544
   *
1545
   * @param obj The object for which we want a new handle.
1546
   * @return A valid handle for the specified object.
1547
   */
1548
  private int assignNewHandle(Object obj)
1549
  {
1550
    this.objectLookupTable.put(new Integer(this.nextOID),
1551
                               new ObjectIdentityWrapper(obj));
1552
    return this.nextOID++;
1553
  }
1554
 
1555
  private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
1556
    throws IOException
1557
  {
1558
    if (osc != null && obj instanceof Serializable)
1559
      {
1560
        try
1561
          {
1562
            Method m = osc.readResolveMethod;
1563
            if(m != null)
1564
            {
1565
                obj = m.invoke(obj, new Object[] {});
1566
            }
1567
          }
1568
        catch (IllegalAccessException ignore)
1569
          {
1570
          }
1571
        catch (InvocationTargetException exception)
1572
          {
1573
            Throwable cause = exception.getCause();
1574
            if (cause instanceof ObjectStreamException)
1575
              throw (ObjectStreamException) cause;
1576
            else if (cause instanceof RuntimeException)
1577
              throw (RuntimeException) cause;
1578
            else if (cause instanceof Error)
1579
              throw (Error) cause;
1580
          }
1581
      }
1582
 
1583
    if (this.resolveEnabled)
1584
      obj = resolveObject(obj);
1585
 
1586
    this.objectLookupTable.put(new Integer(handle),
1587
                               new ObjectIdentityWrapper(obj));
1588
 
1589
    return obj;
1590
  }
1591
 
1592
  private void clearHandles()
1593
  {
1594
    this.objectLookupTable.clear();
1595
    this.nextOID = baseWireHandle;
1596
  }
1597
 
1598
  private void readNextBlock() throws IOException
1599
  {
1600
    readNextBlock(this.realInputStream.readByte());
1601
  }
1602
 
1603
  private void readNextBlock(byte marker) throws IOException
1604
  {
1605
    if (marker == TC_BLOCKDATA)
1606
      {
1607
        if(dump) dumpElement("BLOCK DATA SIZE=");
1608
        this.blockDataBytes = this.realInputStream.readUnsignedByte();
1609
        if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1610
      }
1611
    else if (marker == TC_BLOCKDATALONG)
1612
      {
1613
        if(dump) dumpElement("BLOCK DATA LONG SIZE=");
1614
        this.blockDataBytes = this.realInputStream.readInt();
1615
        if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
1616
      }
1617
    else
1618
      {
1619
        throw new EOFException("Attempt to read primitive data, but no data block is active.");
1620
      }
1621
 
1622
    if (this.blockData.length < this.blockDataBytes)
1623
      this.blockData = new byte[this.blockDataBytes];
1624
 
1625
    this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
1626
    this.blockDataPosition = 0;
1627
  }
1628
 
1629
  private void readArrayElements (Object array, Class clazz)
1630
    throws ClassNotFoundException, IOException
1631
  {
1632
    if (clazz.isPrimitive())
1633
      {
1634
        if (clazz == Boolean.TYPE)
1635
          {
1636
            boolean[] cast_array = (boolean[])array;
1637
            for (int i=0; i < cast_array.length; i++)
1638
              cast_array[i] = this.realInputStream.readBoolean();
1639
            return;
1640
          }
1641
        if (clazz == Byte.TYPE)
1642
          {
1643
            byte[] cast_array = (byte[])array;
1644
            for (int i=0; i < cast_array.length; i++)
1645
              cast_array[i] = this.realInputStream.readByte();
1646
            return;
1647
          }
1648
        if (clazz == Character.TYPE)
1649
          {
1650
            char[] cast_array = (char[])array;
1651
            for (int i=0; i < cast_array.length; i++)
1652
              cast_array[i] = this.realInputStream.readChar();
1653
            return;
1654
          }
1655
        if (clazz == Double.TYPE)
1656
          {
1657
            double[] cast_array = (double[])array;
1658
            for (int i=0; i < cast_array.length; i++)
1659
              cast_array[i] = this.realInputStream.readDouble();
1660
            return;
1661
          }
1662
        if (clazz == Float.TYPE)
1663
          {
1664
            float[] cast_array = (float[])array;
1665
            for (int i=0; i < cast_array.length; i++)
1666
              cast_array[i] = this.realInputStream.readFloat();
1667
            return;
1668
          }
1669
        if (clazz == Integer.TYPE)
1670
          {
1671
            int[] cast_array = (int[])array;
1672
            for (int i=0; i < cast_array.length; i++)
1673
              cast_array[i] = this.realInputStream.readInt();
1674
            return;
1675
          }
1676
        if (clazz == Long.TYPE)
1677
          {
1678
            long[] cast_array = (long[])array;
1679
            for (int i=0; i < cast_array.length; i++)
1680
              cast_array[i] = this.realInputStream.readLong();
1681
            return;
1682
          }
1683
        if (clazz == Short.TYPE)
1684
          {
1685
            short[] cast_array = (short[])array;
1686
            for (int i=0; i < cast_array.length; i++)
1687
              cast_array[i] = this.realInputStream.readShort();
1688
            return;
1689
          }
1690
      }
1691
    else
1692
      {
1693
        Object[] cast_array = (Object[])array;
1694
        for (int i=0; i < cast_array.length; i++)
1695
          cast_array[i] = readObject();
1696
      }
1697
  }
1698
 
1699
  private void readFields (Object obj, ObjectStreamClass stream_osc)
1700
    throws ClassNotFoundException, IOException
1701
  {
1702
    ObjectStreamField[] fields = stream_osc.fieldMapping;
1703
 
1704
    for (int i = 0; i < fields.length; i += 2)
1705
      {
1706
        ObjectStreamField stream_field = fields[i];
1707
        ObjectStreamField real_field = fields[i + 1];
1708
        boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
1709
        boolean set_value = (real_field != null && real_field.isToSet());
1710
        String field_name;
1711
        char type;
1712
 
1713
        if (stream_field != null)
1714
          {
1715
            field_name = stream_field.getName();
1716
            type = stream_field.getTypeCode();
1717
          }
1718
        else
1719
          {
1720
            field_name = real_field.getName();
1721
            type = real_field.getTypeCode();
1722
          }
1723
 
1724
        switch(type)
1725
          {
1726
          case 'Z':
1727
            {
1728
              boolean value =
1729
                read_value ? this.realInputStream.readBoolean() : false;
1730
              if (dump && read_value && set_value)
1731
                dumpElementln("  " + field_name + ": " + value);
1732
              if (set_value)
1733
                real_field.setBooleanField(obj, value);
1734
              break;
1735
            }
1736
          case 'B':
1737
            {
1738
              byte value =
1739
                read_value ? this.realInputStream.readByte() : 0;
1740
              if (dump && read_value && set_value)
1741
                dumpElementln("  " + field_name + ": " + value);
1742
              if (set_value)
1743
                real_field.setByteField(obj, value);
1744
              break;
1745
            }
1746
          case 'C':
1747
            {
1748
              char value =
1749
                read_value ? this.realInputStream.readChar(): 0;
1750
              if (dump && read_value && set_value)
1751
                dumpElementln("  " + field_name + ": " + value);
1752
              if (set_value)
1753
                real_field.setCharField(obj, value);
1754
              break;
1755
            }
1756
          case 'D':
1757
            {
1758
              double value =
1759
                read_value ? this.realInputStream.readDouble() : 0;
1760
              if (dump && read_value && set_value)
1761
                dumpElementln("  " + field_name + ": " + value);
1762
              if (set_value)
1763
                real_field.setDoubleField(obj, value);
1764
              break;
1765
            }
1766
          case 'F':
1767
            {
1768
              float value =
1769
                read_value ? this.realInputStream.readFloat() : 0;
1770
              if (dump && read_value && set_value)
1771
                dumpElementln("  " + field_name + ": " + value);
1772
              if (set_value)
1773
                real_field.setFloatField(obj, value);
1774
              break;
1775
            }
1776
          case 'I':
1777
            {
1778
              int value =
1779
                read_value ? this.realInputStream.readInt() : 0;
1780
              if (dump && read_value && set_value)
1781
                dumpElementln("  " + field_name + ": " + value);
1782
              if (set_value)
1783
                real_field.setIntField(obj, value);
1784
              break;
1785
            }
1786
          case 'J':
1787
            {
1788
              long value =
1789
                read_value ? this.realInputStream.readLong() : 0;
1790
              if (dump && read_value && set_value)
1791
                dumpElementln("  " + field_name + ": " + value);
1792
              if (set_value)
1793
                real_field.setLongField(obj, value);
1794
              break;
1795
            }
1796
          case 'S':
1797
            {
1798
              short value =
1799
                read_value ? this.realInputStream.readShort() : 0;
1800
              if (dump && read_value && set_value)
1801
                dumpElementln("  " + field_name + ": " + value);
1802
              if (set_value)
1803
                real_field.setShortField(obj, value);
1804
              break;
1805
            }
1806
          case 'L':
1807
          case '[':
1808
            {
1809
              Object value =
1810
                read_value ? readObject() : null;
1811
              if (set_value)
1812
                real_field.setObjectField(obj, value);
1813
              break;
1814
            }
1815
          default:
1816
            throw new InternalError("Invalid type code: " + type);
1817
          }
1818
      }
1819
  }
1820
 
1821
  // Toggles writing primitive data to block-data buffer.
1822
  private boolean setBlockDataMode (boolean on)
1823
  {
1824
    boolean oldmode = this.readDataFromBlock;
1825
    this.readDataFromBlock = on;
1826
 
1827
    if (on)
1828
      this.dataInputStream = this.blockDataInput;
1829
    else
1830
      this.dataInputStream = this.realInputStream;
1831
    return oldmode;
1832
  }
1833
 
1834
  // returns a new instance of REAL_CLASS that has been constructed
1835
  // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
1836
  private Object newObject (Class real_class, Constructor constructor)
1837
    throws ClassNotFoundException, IOException
1838
  {
1839
    if (constructor == null)
1840
        throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
1841
    try
1842
      {
1843
        return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
1844
      }
1845
    catch (InstantiationException e)
1846
      {
1847
        throw (ClassNotFoundException) new ClassNotFoundException
1848
          ("Instance of " + real_class + " could not be created").initCause(e);
1849
      }
1850
  }
1851
 
1852
  // runs all registered ObjectInputValidations in prioritized order
1853
  // on OBJ
1854
  private void invokeValidators() throws InvalidObjectException
1855
  {
1856
    try
1857
      {
1858
        Iterator it = currentObjectValidators.iterator();
1859
        while(it.hasNext())
1860
          {
1861
            ValidatorAndPriority vap = (ValidatorAndPriority) it.next();
1862
            ObjectInputValidation validator = vap.validator;
1863
            validator.validateObject();
1864
          }
1865
      }
1866
    finally
1867
      {
1868
        currentObjectValidators = null;
1869
      }
1870
  }
1871
 
1872
  private void callReadMethod (Method readObject, Class klass, Object obj)
1873
    throws ClassNotFoundException, IOException
1874
  {
1875
    try
1876
      {
1877
        readObject.invoke(obj, new Object[] { this });
1878
      }
1879
    catch (InvocationTargetException x)
1880
      {
1881
        /* Rethrow if possible. */
1882
        Throwable exception = x.getTargetException();
1883
        if (exception instanceof RuntimeException)
1884
          throw (RuntimeException) exception;
1885
        if (exception instanceof IOException)
1886
          throw (IOException) exception;
1887
        if (exception instanceof ClassNotFoundException)
1888
          throw (ClassNotFoundException) exception;
1889
 
1890
        throw (IOException) new IOException(
1891
          "Exception thrown from readObject() on " + klass).initCause(x);
1892
      }
1893
    catch (Exception x)
1894
      {
1895
        throw (IOException) new IOException(
1896
          "Failure invoking readObject() on " + klass).initCause(x);
1897
      }
1898
 
1899
    // Invalidate fields which has been read through readFields.
1900
    prereadFields = null;
1901
  }
1902
 
1903
  private static final int BUFFER_SIZE = 1024;
1904
 
1905
  private DataInputStream realInputStream;
1906
  private DataInputStream dataInputStream;
1907
  private DataInputStream blockDataInput;
1908
  private int blockDataPosition;
1909
  private int blockDataBytes;
1910
  private byte[] blockData;
1911
  private boolean useSubclassMethod;
1912
  private int nextOID;
1913
  private boolean resolveEnabled;
1914
  private Hashtable objectLookupTable;
1915
  private Object currentObject;
1916
  private ObjectStreamClass currentObjectStreamClass;
1917
  private TreeSet currentObjectValidators;
1918
  private boolean readDataFromBlock;
1919
  private boolean fieldsAlreadyRead;
1920
  private Hashtable classLookupTable;
1921
  private GetField prereadFields;
1922
 
1923
  private static boolean dump;
1924
 
1925
  // The nesting depth for debugging output
1926
  private int depth = 0;
1927
 
1928
  private static final boolean DEBUG = false;
1929
 
1930
  private void dumpElement (String msg)
1931
  {
1932
    System.out.print(msg);
1933
  }
1934
 
1935
  private void dumpElementln (String msg)
1936
  {
1937
    System.out.println(msg);
1938
    for (int i = 0; i < depth; i++)
1939
      System.out.print (" ");
1940
    System.out.print (Thread.currentThread() + ": ");
1941
  }
1942
 
1943
  // used to keep a prioritized list of object validators
1944
  private static final class ValidatorAndPriority implements Comparable
1945
  {
1946
    int priority;
1947
    ObjectInputValidation validator;
1948
 
1949
    ValidatorAndPriority (ObjectInputValidation validator, int priority)
1950
    {
1951
      this.priority = priority;
1952
      this.validator = validator;
1953
    }
1954
 
1955
    public int compareTo (Object o)
1956
    {
1957
      ValidatorAndPriority vap = (ValidatorAndPriority)o;
1958
      return this.priority - vap.priority;
1959
    }
1960
  }
1961
}
1962
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.