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

Subversion Repositories scarts

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

powered by: WebSVN 2.1.0

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