| 1 | /* ObjectInputStream.java -- Class used to read serialized objects
|
|---|
| 2 | Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This file is part of GNU Classpath.
|
|---|
| 5 |
|
|---|
| 6 | GNU Classpath is free software; you can redistribute it and/or modify
|
|---|
| 7 | it under the terms of the GNU General Public License as published by
|
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 9 | any later version.
|
|---|
| 10 |
|
|---|
| 11 | GNU Classpath is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 14 | General Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License
|
|---|
| 17 | along with GNU Classpath; see the file COPYING. If not, write to the
|
|---|
| 18 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 19 | 02111-1307 USA.
|
|---|
| 20 |
|
|---|
| 21 | Linking this library statically or dynamically with other modules is
|
|---|
| 22 | making a combined work based on this library. Thus, the terms and
|
|---|
| 23 | conditions of the GNU General Public License cover the whole
|
|---|
| 24 | combination.
|
|---|
| 25 |
|
|---|
| 26 | As a special exception, the copyright holders of this library give you
|
|---|
| 27 | permission to link this library with independent modules to produce an
|
|---|
| 28 | executable, regardless of the license terms of these independent
|
|---|
| 29 | modules, and to copy and distribute the resulting executable under
|
|---|
| 30 | terms of your choice, provided that you also meet, for each linked
|
|---|
| 31 | independent module, the terms and conditions of the license of that
|
|---|
| 32 | module. An independent module is a module which is not derived from
|
|---|
| 33 | or based on this library. If you modify this library, you may extend
|
|---|
| 34 | this exception to your version of the library, but you are not
|
|---|
| 35 | obligated to do so. If you do not wish to do so, delete this
|
|---|
| 36 | exception statement from your version. */
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 | package java.io;
|
|---|
| 40 |
|
|---|
| 41 | import java.lang.reflect.Array;
|
|---|
| 42 | import java.lang.reflect.Modifier;
|
|---|
| 43 | import java.lang.reflect.Proxy;
|
|---|
| 44 | import java.util.Arrays;
|
|---|
| 45 | import java.util.Hashtable;
|
|---|
| 46 | import java.util.Vector;
|
|---|
| 47 |
|
|---|
| 48 | import gnu.java.io.ObjectIdentityWrapper;
|
|---|
| 49 | import gnu.java.lang.reflect.TypeSignature;
|
|---|
| 50 | import java.lang.reflect.Field;
|
|---|
| 51 | import java.lang.reflect.Method;
|
|---|
| 52 | import java.lang.reflect.InvocationTargetException;
|
|---|
| 53 |
|
|---|
| 54 | import gnu.classpath.Configuration;
|
|---|
| 55 |
|
|---|
| 56 | public class ObjectInputStream extends InputStream
|
|---|
| 57 | implements ObjectInput, ObjectStreamConstants
|
|---|
| 58 | {
|
|---|
| 59 | /**
|
|---|
| 60 | Creates a new <code>ObjectInputStream</code> that will do all of
|
|---|
| 61 | its reading from <code>in</code>. This method also checks
|
|---|
| 62 | the stream by reading the header information (stream magic number
|
|---|
| 63 | and stream version).
|
|---|
| 64 |
|
|---|
| 65 | @exception IOException Reading stream header from underlying
|
|---|
| 66 | stream cannot be completed.
|
|---|
| 67 |
|
|---|
| 68 | @exception StreamCorruptedException An invalid stream magic
|
|---|
| 69 | number or stream version was read from the stream.
|
|---|
| 70 |
|
|---|
| 71 | @see readStreamHeader ()
|
|---|
| 72 | */
|
|---|
| 73 | public ObjectInputStream (InputStream in)
|
|---|
| 74 | throws IOException, StreamCorruptedException
|
|---|
| 75 | {
|
|---|
| 76 | if (Configuration.DEBUG)
|
|---|
| 77 | {
|
|---|
| 78 | String val = System.getProperty("gcj.dumpobjects");
|
|---|
| 79 | if (dump == false && val != null && !val.equals(""))
|
|---|
| 80 | {
|
|---|
| 81 | dump = true;
|
|---|
| 82 | System.out.println ("Serialization debugging enabled");
|
|---|
| 83 | }
|
|---|
| 84 | else if (dump == true && (val == null || val.equals("")))
|
|---|
| 85 | {
|
|---|
| 86 | dump = false;
|
|---|
| 87 | System.out.println ("Serialization debugging disabled");
|
|---|
| 88 | }
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | this.resolveEnabled = false;
|
|---|
| 92 | this.isDeserializing = false;
|
|---|
| 93 | this.blockDataPosition = 0;
|
|---|
| 94 | this.blockDataBytes = 0;
|
|---|
| 95 | this.blockData = new byte[BUFFER_SIZE];
|
|---|
| 96 | this.blockDataInput = new DataInputStream (this);
|
|---|
| 97 | this.realInputStream = new DataInputStream (in);
|
|---|
| 98 | this.nextOID = baseWireHandle;
|
|---|
| 99 | this.objectLookupTable = new Hashtable ();
|
|---|
| 100 | this.validators = new Vector ();
|
|---|
| 101 | setBlockDataMode (true);
|
|---|
| 102 | readStreamHeader ();
|
|---|
| 103 | }
|
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 | /**
|
|---|
| 107 | Returns the next deserialized object read from the underlying stream.
|
|---|
| 108 |
|
|---|
| 109 | This method can be overriden by a class by implementing
|
|---|
| 110 | <code>private void readObject (ObjectInputStream)</code>.
|
|---|
| 111 |
|
|---|
| 112 | If an exception is thrown from this method, the stream is left in
|
|---|
| 113 | an undefined state.
|
|---|
| 114 |
|
|---|
| 115 | @exception ClassNotFoundException The class that an object being
|
|---|
| 116 | read in belongs to cannot be found.
|
|---|
| 117 |
|
|---|
| 118 | @exception IOException Exception from underlying
|
|---|
| 119 | <code>InputStream</code>.
|
|---|
| 120 | */
|
|---|
| 121 | public final Object readObject () throws ClassNotFoundException, IOException
|
|---|
| 122 | {
|
|---|
| 123 | if (this.useSubclassMethod)
|
|---|
| 124 | return readObjectOverride ();
|
|---|
| 125 |
|
|---|
| 126 | boolean was_deserializing;
|
|---|
| 127 |
|
|---|
| 128 | Object ret_val;
|
|---|
| 129 | was_deserializing = this.isDeserializing;
|
|---|
| 130 |
|
|---|
| 131 | boolean is_consumed = false;
|
|---|
| 132 | boolean old_mode = setBlockDataMode (false);
|
|---|
| 133 |
|
|---|
| 134 | this.isDeserializing = true;
|
|---|
| 135 |
|
|---|
| 136 | byte marker = this.realInputStream.readByte ();
|
|---|
| 137 | dumpElement ("MARKER: 0x" + Integer.toHexString(marker) + " ");
|
|---|
| 138 |
|
|---|
| 139 | try
|
|---|
| 140 | {
|
|---|
| 141 | switch (marker)
|
|---|
| 142 | {
|
|---|
| 143 | case TC_ENDBLOCKDATA:
|
|---|
| 144 | {
|
|---|
| 145 | ret_val = null;
|
|---|
| 146 | is_consumed = true;
|
|---|
| 147 | break;
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | case TC_BLOCKDATA:
|
|---|
| 151 | case TC_BLOCKDATALONG:
|
|---|
| 152 | {
|
|---|
| 153 | if (marker == TC_BLOCKDATALONG)
|
|---|
| 154 | dumpElementln ("BLOCKDATALONG");
|
|---|
| 155 | else
|
|---|
| 156 | dumpElementln ("BLOCKDATA");
|
|---|
| 157 | readNextBlock (marker);
|
|---|
| 158 | throw new StreamCorruptedException ("Unexpected blockData");
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | case TC_NULL:
|
|---|
| 162 | {
|
|---|
| 163 | dumpElementln ("NULL");
|
|---|
| 164 | ret_val = null;
|
|---|
| 165 | break;
|
|---|
| 166 | }
|
|---|
| 167 |
|
|---|
| 168 | case TC_REFERENCE:
|
|---|
| 169 | {
|
|---|
| 170 | dumpElement ("REFERENCE ");
|
|---|
| 171 | Integer oid = new Integer (this.realInputStream.readInt ());
|
|---|
| 172 | dumpElementln (Integer.toHexString(oid.intValue()));
|
|---|
| 173 | ret_val = ((ObjectIdentityWrapper)
|
|---|
| 174 | this.objectLookupTable.get (oid)).object;
|
|---|
| 175 | break;
|
|---|
| 176 | }
|
|---|
| 177 |
|
|---|
| 178 | case TC_CLASS:
|
|---|
| 179 | {
|
|---|
| 180 | dumpElementln ("CLASS");
|
|---|
| 181 | ObjectStreamClass osc = (ObjectStreamClass)readObject ();
|
|---|
| 182 | Class clazz = osc.forClass ();
|
|---|
| 183 | assignNewHandle (clazz);
|
|---|
| 184 | ret_val = clazz;
|
|---|
| 185 | break;
|
|---|
| 186 | }
|
|---|
| 187 |
|
|---|
| 188 | case TC_PROXYCLASSDESC:
|
|---|
| 189 | {
|
|---|
| 190 | dumpElementln ("PROXYCLASS");
|
|---|
| 191 | int n_intf = this.realInputStream.readInt();
|
|---|
| 192 | String[] intfs = new String[n_intf];
|
|---|
| 193 | for (int i = 0; i < n_intf; i++)
|
|---|
| 194 | {
|
|---|
| 195 | intfs[i] = this.realInputStream.readUTF();
|
|---|
| 196 | System.out.println(intfs[i]);
|
|---|
| 197 | }
|
|---|
| 198 |
|
|---|
| 199 | boolean oldmode = setBlockDataMode (true);
|
|---|
| 200 | Class cl = resolveProxyClass(intfs);
|
|---|
| 201 | setBlockDataMode(oldmode);
|
|---|
| 202 |
|
|---|
| 203 | ObjectStreamClass osc = ObjectStreamClass.lookup(cl);
|
|---|
| 204 | assignNewHandle (osc);
|
|---|
| 205 |
|
|---|
| 206 | if (!is_consumed)
|
|---|
| 207 | {
|
|---|
| 208 | byte b = this.realInputStream.readByte ();
|
|---|
| 209 | if (b != TC_ENDBLOCKDATA)
|
|---|
| 210 | throw new IOException ("Data annotated to class was not consumed." + b);
|
|---|
| 211 | }
|
|---|
| 212 | else
|
|---|
| 213 | is_consumed = false;
|
|---|
| 214 | ObjectStreamClass superosc = (ObjectStreamClass)readObject ();
|
|---|
| 215 | osc.setSuperclass (superosc);
|
|---|
| 216 | ret_val = osc;
|
|---|
| 217 | break;
|
|---|
| 218 | }
|
|---|
| 219 |
|
|---|
| 220 | case TC_CLASSDESC:
|
|---|
| 221 | {
|
|---|
| 222 | dumpElement ("CLASSDESC NAME=");
|
|---|
| 223 | String name = this.realInputStream.readUTF ();
|
|---|
| 224 | dumpElement (name + "; UID=");
|
|---|
| 225 | long uid = this.realInputStream.readLong ();
|
|---|
| 226 | dumpElement (Long.toHexString(uid) + "; FLAGS=");
|
|---|
| 227 | byte flags = this.realInputStream.readByte ();
|
|---|
| 228 | dumpElement (Integer.toHexString(flags) + "; FIELD COUNT=");
|
|---|
| 229 | short field_count = this.realInputStream.readShort ();
|
|---|
| 230 | dumpElementln (Short.toString(field_count));
|
|---|
| 231 | ObjectStreamField[] fields = new ObjectStreamField[field_count];
|
|---|
| 232 | ObjectStreamClass osc = new ObjectStreamClass (name, uid,
|
|---|
| 233 | flags, fields);
|
|---|
| 234 | assignNewHandle (osc);
|
|---|
| 235 |
|
|---|
| 236 | for (int i=0; i < field_count; i++)
|
|---|
| 237 | {
|
|---|
| 238 | dumpElement (" TYPE CODE=");
|
|---|
| 239 | char type_code = (char)this.realInputStream.readByte ();
|
|---|
| 240 | dumpElement (type_code + "; FIELD NAME=");
|
|---|
| 241 | String field_name = this.realInputStream.readUTF ();
|
|---|
| 242 | dumpElementln (field_name);
|
|---|
| 243 | String class_name;
|
|---|
| 244 |
|
|---|
| 245 | if (type_code == 'L' || type_code == '[')
|
|---|
| 246 | class_name = (String)readObject ();
|
|---|
| 247 | else
|
|---|
| 248 | class_name = String.valueOf (type_code);
|
|---|
| 249 |
|
|---|
| 250 | // There're many cases you can't get java.lang.Class from
|
|---|
| 251 | // typename if your context class loader can't load it,
|
|---|
| 252 | // then use typename to construct the field
|
|---|
| 253 | fields[i] =
|
|---|
| 254 | new ObjectStreamField (field_name, class_name);
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | boolean oldmode = setBlockDataMode (true);
|
|---|
| 258 | osc.setClass (resolveClass (osc));
|
|---|
| 259 | setBlockDataMode (oldmode);
|
|---|
| 260 |
|
|---|
| 261 | if (!is_consumed)
|
|---|
| 262 | {
|
|---|
| 263 | byte b = this.realInputStream.readByte ();
|
|---|
| 264 | if (b != TC_ENDBLOCKDATA)
|
|---|
| 265 | throw new IOException ("Data annotated to class was not consumed." + b);
|
|---|
| 266 | }
|
|---|
| 267 | else
|
|---|
| 268 | is_consumed = false;
|
|---|
| 269 |
|
|---|
| 270 | osc.setSuperclass ((ObjectStreamClass)readObject ());
|
|---|
| 271 | ret_val = osc;
|
|---|
| 272 | break;
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | case TC_STRING:
|
|---|
| 276 | case TC_LONGSTRING:
|
|---|
| 277 | {
|
|---|
| 278 | dumpElement ("STRING=");
|
|---|
| 279 | String s = this.realInputStream.readUTF ();
|
|---|
| 280 | dumpElementln (s);
|
|---|
| 281 | ret_val = processResolution (s, assignNewHandle (s));
|
|---|
| 282 | break;
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | case TC_ARRAY:
|
|---|
| 286 | {
|
|---|
| 287 | dumpElementln ("ARRAY");
|
|---|
| 288 | ObjectStreamClass osc = (ObjectStreamClass)readObject ();
|
|---|
| 289 | Class componentType = osc.forClass ().getComponentType ();
|
|---|
| 290 | dumpElement ("ARRAY LENGTH=");
|
|---|
| 291 | int length = this.realInputStream.readInt ();
|
|---|
| 292 | dumpElementln (length + "; COMPONENT TYPE=" + componentType);
|
|---|
| 293 | Object array = Array.newInstance (componentType, length);
|
|---|
| 294 | int handle = assignNewHandle (array);
|
|---|
| 295 | readArrayElements (array, componentType);
|
|---|
| 296 | for (int i=0, len=Array.getLength(array); i < len; i++)
|
|---|
| 297 | dumpElementln (" ELEMENT[" + i + "]=" + Array.get(array, i));
|
|---|
| 298 | ret_val = processResolution (array, handle);
|
|---|
| 299 | break;
|
|---|
| 300 | }
|
|---|
| 301 |
|
|---|
| 302 | case TC_OBJECT:
|
|---|
| 303 | {
|
|---|
| 304 | dumpElementln ("OBJECT");
|
|---|
| 305 | ObjectStreamClass osc = (ObjectStreamClass)readObject ();
|
|---|
| 306 | Class clazz = osc.forClass ();
|
|---|
| 307 |
|
|---|
| 308 | if (!Serializable.class.isAssignableFrom (clazz))
|
|---|
| 309 | throw new NotSerializableException (clazz + " is not Serializable, and thus cannot be deserialized.");
|
|---|
| 310 |
|
|---|
| 311 | if (Externalizable.class.isAssignableFrom (clazz))
|
|---|
| 312 | {
|
|---|
| 313 | Externalizable obj = null;
|
|---|
| 314 |
|
|---|
| 315 | try
|
|---|
| 316 | {
|
|---|
| 317 | obj = (Externalizable)clazz.newInstance ();
|
|---|
| 318 | }
|
|---|
| 319 | catch (InstantiationException e)
|
|---|
| 320 | {
|
|---|
| 321 | throw new ClassNotFoundException ("Instance of " + clazz
|
|---|
| 322 | + " could not be created");
|
|---|
| 323 | }
|
|---|
| 324 | catch (IllegalAccessException e)
|
|---|
| 325 | {
|
|---|
| 326 | throw new ClassNotFoundException ("Instance of " + clazz
|
|---|
| 327 | + " could not be created because class or zero-argument constructor is not accessible");
|
|---|
| 328 | }
|
|---|
| 329 | catch (NoSuchMethodError e)
|
|---|
| 330 | {
|
|---|
| 331 | throw new ClassNotFoundException ("Instance of " + clazz
|
|---|
| 332 | + " could not be created because zero-argument constructor is not defined");
|
|---|
| 333 | }
|
|---|
| 334 |
|
|---|
| 335 | int handle = assignNewHandle (obj);
|
|---|
| 336 |
|
|---|
| 337 | boolean read_from_blocks = ((osc.getFlags () & SC_BLOCK_DATA) != 0);
|
|---|
| 338 |
|
|---|
| 339 | boolean oldmode = this.readDataFromBlock;
|
|---|
| 340 | if (read_from_blocks)
|
|---|
| 341 | setBlockDataMode (true);
|
|---|
| 342 |
|
|---|
| 343 | obj.readExternal (this);
|
|---|
| 344 |
|
|---|
| 345 | if (read_from_blocks)
|
|---|
| 346 | setBlockDataMode (oldmode);
|
|---|
| 347 |
|
|---|
| 348 | ret_val = processResolution (obj, handle);
|
|---|
| 349 | break;
|
|---|
| 350 | } // end if (Externalizable.class.isAssignableFrom (clazz))
|
|---|
| 351 |
|
|---|
| 352 | // find the first non-serializable, non-abstract
|
|---|
| 353 | // class in clazz's inheritance hierarchy
|
|---|
| 354 | Class first_nonserial = clazz.getSuperclass ();
|
|---|
| 355 | while (Serializable.class.isAssignableFrom (first_nonserial)
|
|---|
| 356 | || Modifier.isAbstract (first_nonserial.getModifiers ()))
|
|---|
| 357 | first_nonserial = first_nonserial.getSuperclass ();
|
|---|
| 358 |
|
|---|
| 359 | Object obj = null;
|
|---|
| 360 | obj = newObject (clazz, first_nonserial);
|
|---|
| 361 |
|
|---|
| 362 | if (obj == null)
|
|---|
| 363 | throw new ClassNotFoundException ("Instance of " + clazz +
|
|---|
| 364 | " could not be created");
|
|---|
| 365 |
|
|---|
| 366 | int handle = assignNewHandle (obj);
|
|---|
| 367 | this.currentObject = obj;
|
|---|
| 368 | ObjectStreamClass[] hierarchy =
|
|---|
| 369 | ObjectStreamClass.getObjectStreamClasses (clazz);
|
|---|
| 370 |
|
|---|
| 371 | for (int i=0; i < hierarchy.length; i++)
|
|---|
| 372 | {
|
|---|
| 373 | this.currentObjectStreamClass = hierarchy[i];
|
|---|
| 374 |
|
|---|
| 375 | dumpElementln ("Reading fields of "
|
|---|
| 376 | + this.currentObjectStreamClass.getName ());
|
|---|
| 377 |
|
|---|
| 378 | // XXX: should initialize fields in classes in the hierarchy
|
|---|
| 379 | // that aren't in the stream
|
|---|
| 380 | // should skip over classes in the stream that aren't in the
|
|---|
| 381 | // real classes hierarchy
|
|---|
| 382 |
|
|---|
| 383 | if (this.currentObjectStreamClass.hasReadMethod())
|
|---|
| 384 | {
|
|---|
| 385 | fieldsAlreadyRead = false;
|
|---|
| 386 | boolean oldmode = setBlockDataMode (true);
|
|---|
| 387 | callReadMethod (obj, this.currentObjectStreamClass);
|
|---|
| 388 | setBlockDataMode (oldmode);
|
|---|
| 389 | dumpElement ("ENDBLOCKDATA? ");
|
|---|
| 390 | try
|
|---|
| 391 | {
|
|---|
| 392 | // FIXME: XXX: This try block is to catch EOF which is
|
|---|
| 393 | // thrown for some objects. That indicates a bug in the logic.
|
|---|
| 394 | if (this.realInputStream.readByte () != TC_ENDBLOCKDATA)
|
|---|
| 395 | throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method.");
|
|---|
| 396 | dumpElementln ("yes");
|
|---|
| 397 | }
|
|---|
| 398 | catch (EOFException e)
|
|---|
| 399 | {
|
|---|
| 400 | dumpElementln ("no, got EOFException");
|
|---|
| 401 | }
|
|---|
| 402 | catch (IOException e)
|
|---|
| 403 | {
|
|---|
| 404 | dumpElementln ("no, got IOException");
|
|---|
| 405 | }
|
|---|
| 406 | }
|
|---|
| 407 | else
|
|---|
| 408 | {
|
|---|
| 409 | readFields (obj, currentObjectStreamClass);
|
|---|
| 410 | }
|
|---|
| 411 | }
|
|---|
| 412 |
|
|---|
| 413 | this.currentObject = null;
|
|---|
| 414 | this.currentObjectStreamClass = null;
|
|---|
| 415 | ret_val = processResolution (obj, handle);
|
|---|
| 416 | break;
|
|---|
| 417 | }
|
|---|
| 418 |
|
|---|
| 419 | case TC_RESET:
|
|---|
| 420 | dumpElementln ("RESET");
|
|---|
| 421 | clearHandles ();
|
|---|
| 422 | ret_val = readObject ();
|
|---|
| 423 | break;
|
|---|
| 424 |
|
|---|
| 425 | case TC_EXCEPTION:
|
|---|
| 426 | {
|
|---|
| 427 | dumpElement ("EXCEPTION=");
|
|---|
| 428 | Exception e = (Exception)readObject ();
|
|---|
| 429 | dumpElementln (e.toString());
|
|---|
| 430 | clearHandles ();
|
|---|
| 431 | throw new WriteAbortedException ("Exception thrown during writing of stream", e);
|
|---|
| 432 | }
|
|---|
| 433 |
|
|---|
| 434 | default:
|
|---|
| 435 | throw new IOException ("Unknown marker on stream: " + marker);
|
|---|
| 436 | }
|
|---|
| 437 | }
|
|---|
| 438 | finally
|
|---|
| 439 | {
|
|---|
| 440 | setBlockDataMode (old_mode);
|
|---|
| 441 |
|
|---|
| 442 | this.isDeserializing = was_deserializing;
|
|---|
| 443 |
|
|---|
| 444 | if (! was_deserializing)
|
|---|
| 445 | {
|
|---|
| 446 | if (validators.size () > 0)
|
|---|
| 447 | invokeValidators ();
|
|---|
| 448 | }
|
|---|
| 449 | }
|
|---|
| 450 |
|
|---|
| 451 | return ret_val;
|
|---|
| 452 | }
|
|---|
| 453 |
|
|---|
| 454 | /**
|
|---|
| 455 | Reads the current objects non-transient, non-static fields from
|
|---|
| 456 | the current class from the underlying output stream.
|
|---|
| 457 |
|
|---|
| 458 | This method is intended to be called from within a object's
|
|---|
| 459 | <code>private void readObject (ObjectInputStream)</code>
|
|---|
| 460 | method.
|
|---|
| 461 |
|
|---|
| 462 | @exception ClassNotFoundException The class that an object being
|
|---|
| 463 | read in belongs to cannot be found.
|
|---|
| 464 |
|
|---|
| 465 | @exception NotActiveException This method was called from a
|
|---|
| 466 | context other than from the current object's and current class's
|
|---|
| 467 | <code>private void readObject (ObjectInputStream)</code>
|
|---|
| 468 | method.
|
|---|
| 469 |
|
|---|
| 470 | @exception IOException Exception from underlying
|
|---|
| 471 | <code>OutputStream</code>.
|
|---|
| 472 | */
|
|---|
| 473 | public void defaultReadObject ()
|
|---|
| 474 | throws ClassNotFoundException, IOException, NotActiveException
|
|---|
| 475 | {
|
|---|
| 476 | if (this.currentObject == null || this.currentObjectStreamClass == null)
|
|---|
| 477 | throw new NotActiveException ("defaultReadObject called by non-active class and/or object");
|
|---|
| 478 |
|
|---|
| 479 | if (fieldsAlreadyRead)
|
|---|
| 480 | throw new NotActiveException ("defaultReadObject called but fields already read from stream (by defaultReadObject or readFields)");
|
|---|
| 481 |
|
|---|
| 482 | boolean oldmode = setBlockDataMode(false);
|
|---|
| 483 | readFields (this.currentObject, this.currentObjectStreamClass);
|
|---|
| 484 | setBlockDataMode(oldmode);
|
|---|
| 485 |
|
|---|
| 486 | fieldsAlreadyRead = true;
|
|---|
| 487 | }
|
|---|
| 488 |
|
|---|
| 489 |
|
|---|
| 490 | /**
|
|---|
| 491 | Registers a <code>ObjectInputValidation</code> to be carried out
|
|---|
| 492 | on the object graph currently being deserialized before it is
|
|---|
| 493 | returned to the original caller of <code>readObject ()</code>.
|
|---|
| 494 | The order of validation for multiple
|
|---|
| 495 | <code>ObjectInputValidation</code>s can be controled using
|
|---|
| 496 | <code>priority</code>. Validators with higher priorities are
|
|---|
| 497 | called first.
|
|---|
| 498 |
|
|---|
| 499 | @see java.io.ObjectInputValidation
|
|---|
| 500 |
|
|---|
| 501 | @exception InvalidObjectException <code>validator</code> is
|
|---|
| 502 | <code>null</code>
|
|---|
| 503 |
|
|---|
| 504 | @exception NotActiveException an attempt was made to add a
|
|---|
| 505 | validator outside of the <code>readObject</code> method of the
|
|---|
| 506 | object currently being deserialized
|
|---|
| 507 | */
|
|---|
| 508 | public void registerValidation (ObjectInputValidation validator,
|
|---|
| 509 | int priority)
|
|---|
| 510 | throws InvalidObjectException, NotActiveException
|
|---|
| 511 | {
|
|---|
| 512 | if (this.currentObject == null || this.currentObjectStreamClass == null)
|
|---|
| 513 | throw new NotActiveException ("registerValidation called by non-active class and/or object");
|
|---|
| 514 |
|
|---|
| 515 | if (validator == null)
|
|---|
| 516 | throw new InvalidObjectException ("attempt to add a null ObjectInputValidation object");
|
|---|
| 517 |
|
|---|
| 518 | this.validators.addElement (new ValidatorAndPriority (validator,
|
|---|
| 519 | priority));
|
|---|
| 520 | }
|
|---|
| 521 |
|
|---|
| 522 |
|
|---|
| 523 | /**
|
|---|
| 524 | Called when a class is being deserialized. This is a hook to
|
|---|
| 525 | allow subclasses to read in information written by the
|
|---|
| 526 | <code>annotateClass (Class)</code> method of an
|
|---|
| 527 | <code>ObjectOutputStream</code>.
|
|---|
| 528 |
|
|---|
| 529 | This implementation looks up the active call stack for a
|
|---|
| 530 | <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
|
|---|
| 531 | it is used to load the class associated with <code>osc</code>,
|
|---|
| 532 | otherwise, the default system <code>ClassLoader</code> is used.
|
|---|
| 533 |
|
|---|
| 534 | @exception IOException Exception from underlying
|
|---|
| 535 | <code>OutputStream</code>.
|
|---|
| 536 |
|
|---|
| 537 | @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
|
|---|
| 538 | */
|
|---|
| 539 | protected Class resolveClass (ObjectStreamClass osc)
|
|---|
| 540 | throws ClassNotFoundException, IOException
|
|---|
| 541 | {
|
|---|
| 542 | SecurityManager sm = System.getSecurityManager ();
|
|---|
| 543 | if (sm == null)
|
|---|
| 544 | sm = new SecurityManager () {};
|
|---|
| 545 |
|
|---|
| 546 | // FIXME: currentClassLoader doesn't yet do anything useful. We need
|
|---|
| 547 | // to call forName() with the classloader of the class which called
|
|---|
| 548 | // readObject(). See SecurityManager.getClassContext().
|
|---|
| 549 | ClassLoader cl = currentClassLoader (sm);
|
|---|
| 550 |
|
|---|
| 551 | if (cl == null)
|
|---|
| 552 | return Class.forName (osc.getName ());
|
|---|
| 553 | else
|
|---|
| 554 | return cl.loadClass (osc.getName ());
|
|---|
| 555 | }
|
|---|
| 556 |
|
|---|
| 557 | /**
|
|---|
| 558 | Allows subclasses to resolve objects that are read from the
|
|---|
| 559 | stream with other objects to be returned in their place. This
|
|---|
| 560 | method is called the first time each object is encountered.
|
|---|
| 561 |
|
|---|
| 562 | This method must be enabled before it will be called in the
|
|---|
| 563 | serialization process.
|
|---|
| 564 |
|
|---|
| 565 | @exception IOException Exception from underlying
|
|---|
| 566 | <code>OutputStream</code>.
|
|---|
| 567 |
|
|---|
| 568 | @see enableResolveObject (boolean)
|
|---|
| 569 | */
|
|---|
| 570 | protected Object resolveObject (Object obj) throws IOException
|
|---|
| 571 | {
|
|---|
| 572 | return obj;
|
|---|
| 573 | }
|
|---|
| 574 |
|
|---|
| 575 |
|
|---|
| 576 | protected Class resolveProxyClass (String[] intfs)
|
|---|
| 577 | throws IOException, ClassNotFoundException
|
|---|
| 578 | {
|
|---|
| 579 | SecurityManager sm = System.getSecurityManager ();
|
|---|
| 580 |
|
|---|
| 581 | if (sm == null)
|
|---|
| 582 | sm = new SecurityManager () {};
|
|---|
| 583 |
|
|---|
| 584 | ClassLoader cl = currentClassLoader (sm);
|
|---|
| 585 |
|
|---|
| 586 | Class[] clss = new Class[intfs.length];
|
|---|
| 587 | if(cl == null){
|
|---|
| 588 | for (int i = 0; i < intfs.length; i++)
|
|---|
| 589 | clss[i] = Class.forName(intfs[i]);
|
|---|
| 590 | cl = ClassLoader.getSystemClassLoader();
|
|---|
| 591 | }
|
|---|
| 592 | else
|
|---|
| 593 | for (int i = 0; i < intfs.length; i++)
|
|---|
| 594 | clss[i] = cl.loadClass(intfs[i]);
|
|---|
| 595 | try {
|
|---|
| 596 | return Proxy.getProxyClass(cl, clss);
|
|---|
| 597 | } catch (IllegalArgumentException e) {
|
|---|
| 598 | throw new ClassNotFoundException(null, e);
|
|---|
| 599 | }
|
|---|
| 600 | }
|
|---|
| 601 |
|
|---|
| 602 | /**
|
|---|
| 603 | If <code>enable</code> is <code>true</code> and this object is
|
|---|
| 604 | trusted, then <code>resolveObject (Object)</code> will be called
|
|---|
| 605 | in subsequent calls to <code>readObject (Object)</code>.
|
|---|
| 606 | Otherwise, <code>resolveObject (Object)</code> will not be called.
|
|---|
| 607 |
|
|---|
| 608 | @exception SecurityException This class is not trusted.
|
|---|
| 609 | */
|
|---|
| 610 | protected boolean enableResolveObject (boolean enable)
|
|---|
| 611 | throws SecurityException
|
|---|
| 612 | {
|
|---|
| 613 | if (enable)
|
|---|
| 614 | {
|
|---|
| 615 | SecurityManager sm = System.getSecurityManager ();
|
|---|
| 616 | if (sm != null)
|
|---|
| 617 | sm.checkPermission (new SerializablePermission ("enableSubstitution"));
|
|---|
| 618 | }
|
|---|
| 619 |
|
|---|
| 620 | boolean old_val = this.resolveEnabled;
|
|---|
| 621 | this.resolveEnabled = enable;
|
|---|
| 622 | return old_val;
|
|---|
| 623 | }
|
|---|
| 624 |
|
|---|
| 625 |
|
|---|
| 626 | /**
|
|---|
| 627 | Reads stream magic and stream version information from the
|
|---|
| 628 | underlying stream.
|
|---|
| 629 |
|
|---|
| 630 | @exception IOException Exception from underlying stream.
|
|---|
| 631 |
|
|---|
| 632 | @exception StreamCorruptedException An invalid stream magic
|
|---|
| 633 | number or stream version was read from the stream.
|
|---|
| 634 | */
|
|---|
| 635 | protected void readStreamHeader ()
|
|---|
| 636 | throws IOException, StreamCorruptedException
|
|---|
| 637 | {
|
|---|
| 638 | dumpElement ("STREAM MAGIC ");
|
|---|
| 639 | if (this.realInputStream.readShort () != STREAM_MAGIC)
|
|---|
| 640 | throw new StreamCorruptedException ("Invalid stream magic number");
|
|---|
| 641 |
|
|---|
| 642 | dumpElementln ("STREAM VERSION ");
|
|---|
| 643 | if (this.realInputStream.readShort () != STREAM_VERSION)
|
|---|
| 644 | throw new StreamCorruptedException ("Invalid stream version number");
|
|---|
| 645 | }
|
|---|
| 646 |
|
|---|
| 647 |
|
|---|
| 648 | public int read () throws IOException
|
|---|
| 649 | {
|
|---|
| 650 | if (this.readDataFromBlock)
|
|---|
| 651 | {
|
|---|
| 652 | if (this.blockDataPosition >= this.blockDataBytes)
|
|---|
| 653 | readNextBlock ();
|
|---|
| 654 | return (this.blockData[this.blockDataPosition++] & 0xff);
|
|---|
| 655 | }
|
|---|
| 656 | else
|
|---|
| 657 | return this.realInputStream.read ();
|
|---|
| 658 | }
|
|---|
| 659 |
|
|---|
| 660 | public int read (byte[] data, int offset, int length) throws IOException
|
|---|
| 661 | {
|
|---|
| 662 | if (this.readDataFromBlock)
|
|---|
| 663 | {
|
|---|
| 664 | if (this.blockDataPosition + length > this.blockDataBytes)
|
|---|
| 665 | {
|
|---|
| 666 | int remain = this.blockDataBytes - this.blockDataPosition;
|
|---|
| 667 | if (remain != 0)
|
|---|
| 668 | {
|
|---|
| 669 | System.arraycopy (this.blockData, this.blockDataPosition,
|
|---|
| 670 | data, offset, remain);
|
|---|
| 671 | offset += remain;
|
|---|
| 672 | length -= remain;
|
|---|
| 673 | }
|
|---|
| 674 | readNextBlock ();
|
|---|
| 675 | }
|
|---|
| 676 |
|
|---|
| 677 | System.arraycopy (this.blockData, this.blockDataPosition,
|
|---|
| 678 | data, offset, length);
|
|---|
| 679 | this.blockDataPosition += length;
|
|---|
| 680 |
|
|---|
| 681 | return length;
|
|---|
| 682 | }
|
|---|
| 683 | else
|
|---|
| 684 | return this.realInputStream.read (data, offset, length);
|
|---|
| 685 | }
|
|---|
| 686 |
|
|---|
| 687 | public int available () throws IOException
|
|---|
| 688 | {
|
|---|
| 689 | if (this.readDataFromBlock)
|
|---|
| 690 | {
|
|---|
| 691 | if (this.blockDataPosition >= this.blockDataBytes)
|
|---|
| 692 | readNextBlock ();
|
|---|
| 693 |
|
|---|
| 694 | return this.blockDataBytes - this.blockDataPosition;
|
|---|
| 695 | }
|
|---|
| 696 | else
|
|---|
| 697 | return this.realInputStream.available ();
|
|---|
| 698 | }
|
|---|
| 699 |
|
|---|
| 700 | public void close () throws IOException
|
|---|
| 701 | {
|
|---|
| 702 | this.realInputStream.close ();
|
|---|
| 703 | }
|
|---|
| 704 |
|
|---|
| 705 | public boolean readBoolean () throws IOException
|
|---|
| 706 | {
|
|---|
| 707 | return this.dataInputStream.readBoolean ();
|
|---|
| 708 | }
|
|---|
| 709 |
|
|---|
| 710 | public byte readByte () throws IOException
|
|---|
| 711 | {
|
|---|
| 712 | return this.dataInputStream.readByte ();
|
|---|
| 713 | }
|
|---|
| 714 |
|
|---|
| 715 | public int readUnsignedByte () throws IOException
|
|---|
| 716 | {
|
|---|
| 717 | return this.dataInputStream.readUnsignedByte ();
|
|---|
| 718 | }
|
|---|
| 719 |
|
|---|
| 720 | public short readShort () throws IOException
|
|---|
| 721 | {
|
|---|
| 722 | return this.dataInputStream.readShort ();
|
|---|
| 723 | }
|
|---|
| 724 |
|
|---|
| 725 | public int readUnsignedShort () throws IOException
|
|---|
| 726 | {
|
|---|
| 727 | return this.dataInputStream.readUnsignedShort ();
|
|---|
| 728 | }
|
|---|
| 729 |
|
|---|
| 730 | public char readChar () throws IOException
|
|---|
| 731 | {
|
|---|
| 732 | return this.dataInputStream.readChar ();
|
|---|
| 733 | }
|
|---|
| 734 |
|
|---|
| 735 | public int readInt () throws IOException
|
|---|
| 736 | {
|
|---|
| 737 | return this.dataInputStream.readInt ();
|
|---|
| 738 | }
|
|---|
| 739 |
|
|---|
| 740 | public long readLong () throws IOException
|
|---|
| 741 | {
|
|---|
| 742 | return this.dataInputStream.readLong ();
|
|---|
| 743 | }
|
|---|
| 744 |
|
|---|
| 745 | public float readFloat () throws IOException
|
|---|
| 746 | {
|
|---|
| 747 | return this.dataInputStream.readFloat ();
|
|---|
| 748 | }
|
|---|
| 749 |
|
|---|
| 750 | public double readDouble () throws IOException
|
|---|
| 751 | {
|
|---|
| 752 | return this.dataInputStream.readDouble ();
|
|---|
| 753 | }
|
|---|
| 754 |
|
|---|
| 755 | public void readFully (byte data[]) throws IOException
|
|---|
| 756 | {
|
|---|
| 757 | this.dataInputStream.readFully (data);
|
|---|
| 758 | }
|
|---|
| 759 |
|
|---|
| 760 | public void readFully (byte data[], int offset, int size)
|
|---|
| 761 | throws IOException
|
|---|
| 762 | {
|
|---|
| 763 | this.dataInputStream.readFully (data, offset, size);
|
|---|
| 764 | }
|
|---|
| 765 |
|
|---|
| 766 | public int skipBytes (int len) throws IOException
|
|---|
| 767 | {
|
|---|
| 768 | return this.dataInputStream.skipBytes (len);
|
|---|
| 769 | }
|
|---|
| 770 |
|
|---|
| 771 | /**
|
|---|
| 772 | @deprecated
|
|---|
| 773 | @see java.io.DataInputStream#readLine ()
|
|---|
| 774 | */
|
|---|
| 775 | public String readLine () throws IOException
|
|---|
| 776 | {
|
|---|
| 777 | return this.dataInputStream.readLine ();
|
|---|
| 778 | }
|
|---|
| 779 |
|
|---|
| 780 | public String readUTF () throws IOException
|
|---|
| 781 | {
|
|---|
| 782 | return this.dataInputStream.readUTF ();
|
|---|
| 783 | }
|
|---|
| 784 |
|
|---|
| 785 |
|
|---|
| 786 | /**
|
|---|
| 787 | This class allows a class to specify exactly which fields should
|
|---|
| 788 | be read, and what values should be read for these fields.
|
|---|
| 789 |
|
|---|
| 790 | XXX: finish up comments
|
|---|
| 791 | */
|
|---|
| 792 | public static abstract class GetField
|
|---|
| 793 | {
|
|---|
| 794 | public abstract ObjectStreamClass getObjectStreamClass ();
|
|---|
| 795 |
|
|---|
| 796 | public abstract boolean defaulted (String name)
|
|---|
| 797 | throws IOException, IllegalArgumentException;
|
|---|
| 798 |
|
|---|
| 799 | public abstract boolean get (String name, boolean defvalue)
|
|---|
| 800 | throws IOException, IllegalArgumentException;
|
|---|
| 801 |
|
|---|
| 802 | public abstract char get (String name, char defvalue)
|
|---|
| 803 | throws IOException, IllegalArgumentException;
|
|---|
| 804 |
|
|---|
| 805 | public abstract byte get (String name, byte defvalue)
|
|---|
| 806 | throws IOException, IllegalArgumentException;
|
|---|
| 807 |
|
|---|
| 808 | public abstract short get (String name, short defvalue)
|
|---|
| 809 | throws IOException, IllegalArgumentException;
|
|---|
| 810 |
|
|---|
| 811 | public abstract int get (String name, int defvalue)
|
|---|
| 812 | throws IOException, IllegalArgumentException;
|
|---|
| 813 |
|
|---|
| 814 | public abstract long get (String name, long defvalue)
|
|---|
| 815 | throws IOException, IllegalArgumentException;
|
|---|
| 816 |
|
|---|
| 817 | public abstract float get (String name, float defvalue)
|
|---|
| 818 | throws IOException, IllegalArgumentException;
|
|---|
| 819 |
|
|---|
| 820 | public abstract double get (String name, double defvalue)
|
|---|
| 821 | throws IOException, IllegalArgumentException;
|
|---|
| 822 |
|
|---|
| 823 | public abstract Object get (String name, Object defvalue)
|
|---|
| 824 | throws IOException, IllegalArgumentException;
|
|---|
| 825 | }
|
|---|
| 826 |
|
|---|
| 827 | public GetField readFields ()
|
|---|
| 828 | throws IOException, ClassNotFoundException, NotActiveException
|
|---|
| 829 | {
|
|---|
| 830 | if (this.currentObject == null || this.currentObjectStreamClass == null)
|
|---|
| 831 | throw new NotActiveException ("readFields called by non-active class and/or object");
|
|---|
| 832 |
|
|---|
| 833 | if (fieldsAlreadyRead)
|
|---|
| 834 | throw new NotActiveException ("readFields called but fields already read from stream (by defaultReadObject or readFields)");
|
|---|
| 835 |
|
|---|
| 836 | final ObjectStreamClass clazz = this.currentObjectStreamClass;
|
|---|
| 837 | final byte[] prim_field_data = new byte[clazz.primFieldSize];
|
|---|
| 838 | final Object[] objs = new Object[clazz.objectFieldCount];
|
|---|
| 839 |
|
|---|
| 840 | // Apparently Block data is not used with GetField as per
|
|---|
| 841 | // empirical evidence against JDK 1.2. Also see Mauve test
|
|---|
| 842 | // java.io.ObjectInputOutput.Test.GetPutField.
|
|---|
| 843 | boolean oldmode = setBlockDataMode (false);
|
|---|
| 844 | readFully (prim_field_data);
|
|---|
| 845 | for (int i = 0; i < objs.length; ++ i)
|
|---|
| 846 | objs[i] = readObject ();
|
|---|
| 847 | setBlockDataMode (oldmode);
|
|---|
| 848 |
|
|---|
| 849 | return new GetField ()
|
|---|
| 850 | {
|
|---|
| 851 | public ObjectStreamClass getObjectStreamClass ()
|
|---|
| 852 | {
|
|---|
| 853 | return clazz;
|
|---|
| 854 | }
|
|---|
| 855 |
|
|---|
| 856 | public boolean defaulted (String name)
|
|---|
| 857 | throws IOException, IllegalArgumentException
|
|---|
| 858 | {
|
|---|
| 859 | return clazz.getField (name) == null;
|
|---|
| 860 | }
|
|---|
| 861 |
|
|---|
| 862 | public boolean get (String name, boolean defvalue)
|
|---|
| 863 | throws IOException, IllegalArgumentException
|
|---|
| 864 | {
|
|---|
| 865 | ObjectStreamField field = getField (name, Boolean.TYPE);
|
|---|
| 866 |
|
|---|
| 867 | if (field == null)
|
|---|
| 868 | return defvalue;
|
|---|
| 869 |
|
|---|
| 870 | return prim_field_data[field.getOffset ()] == 0 ? false : true;
|
|---|
| 871 | }
|
|---|
| 872 |
|
|---|
| 873 | public char get (String name, char defvalue)
|
|---|
| 874 | throws IOException, IllegalArgumentException
|
|---|
| 875 | {
|
|---|
| 876 | ObjectStreamField field = getField (name, Character.TYPE);
|
|---|
| 877 |
|
|---|
| 878 | if (field == null)
|
|---|
| 879 | return defvalue;
|
|---|
| 880 |
|
|---|
| 881 | int off = field.getOffset ();
|
|---|
| 882 |
|
|---|
| 883 | return (char)(((prim_field_data[off++] & 0xFF) << 8)
|
|---|
| 884 | | (prim_field_data[off] & 0xFF));
|
|---|
| 885 | }
|
|---|
| 886 |
|
|---|
| 887 | public byte get (String name, byte defvalue)
|
|---|
| 888 | throws IOException, IllegalArgumentException
|
|---|
| 889 | {
|
|---|
| 890 | ObjectStreamField field = getField (name, Byte.TYPE);
|
|---|
| 891 |
|
|---|
| 892 | if (field == null)
|
|---|
| 893 | return defvalue;
|
|---|
| 894 |
|
|---|
| 895 | return prim_field_data[field.getOffset ()];
|
|---|
| 896 | }
|
|---|
| 897 |
|
|---|
| 898 | public short get (String name, short defvalue)
|
|---|
| 899 | throws IOException, IllegalArgumentException
|
|---|
| 900 | {
|
|---|
| 901 | ObjectStreamField field = getField (name, Short.TYPE);
|
|---|
| 902 |
|
|---|
| 903 | if (field == null)
|
|---|
| 904 | return defvalue;
|
|---|
| 905 |
|
|---|
| 906 | int off = field.getOffset ();
|
|---|
| 907 |
|
|---|
| 908 | return (short)(((prim_field_data[off++] & 0xFF) << 8)
|
|---|
| 909 | | (prim_field_data[off] & 0xFF));
|
|---|
| 910 | }
|
|---|
| 911 |
|
|---|
| 912 | public int get (String name, int defvalue)
|
|---|
| 913 | throws IOException, IllegalArgumentException
|
|---|
| 914 | {
|
|---|
| 915 | ObjectStreamField field = getField (name, Integer.TYPE);
|
|---|
| 916 |
|
|---|
| 917 | if (field == null)
|
|---|
| 918 | return defvalue;
|
|---|
| 919 |
|
|---|
| 920 | int off = field.getOffset ();
|
|---|
| 921 |
|
|---|
| 922 | return ((prim_field_data[off++] & 0xFF) << 24)
|
|---|
| 923 | | ((prim_field_data[off++] & 0xFF) << 16)
|
|---|
| 924 | | ((prim_field_data[off++] & 0xFF) << 8)
|
|---|
| 925 | | (prim_field_data[off] & 0xFF);
|
|---|
| 926 | }
|
|---|
| 927 |
|
|---|
| 928 | public long get (String name, long defvalue)
|
|---|
| 929 | throws IOException, IllegalArgumentException
|
|---|
| 930 | {
|
|---|
| 931 | ObjectStreamField field = getField (name, Long.TYPE);
|
|---|
| 932 |
|
|---|
| 933 | if (field == null)
|
|---|
| 934 | return defvalue;
|
|---|
| 935 |
|
|---|
| 936 | int off = field.getOffset ();
|
|---|
| 937 |
|
|---|
| 938 | return (long)(((prim_field_data[off++] & 0xFF) << 56)
|
|---|
| 939 | | ((prim_field_data[off++] & 0xFF) << 48)
|
|---|
| 940 | | ((prim_field_data[off++] & 0xFF) << 40)
|
|---|
| 941 | | ((prim_field_data[off++] & 0xFF) << 32)
|
|---|
| 942 | | ((prim_field_data[off++] & 0xFF) << 24)
|
|---|
| 943 | | ((prim_field_data[off++] & 0xFF) << 16)
|
|---|
| 944 | | ((prim_field_data[off++] & 0xFF) << 8)
|
|---|
| 945 | | (prim_field_data[off] & 0xFF));
|
|---|
| 946 | }
|
|---|
| 947 |
|
|---|
| 948 | public float get (String name, float defvalue)
|
|---|
| 949 | throws IOException, IllegalArgumentException
|
|---|
| 950 | {
|
|---|
| 951 | ObjectStreamField field = getField (name, Float.TYPE);
|
|---|
| 952 |
|
|---|
| 953 | if (field == null)
|
|---|
| 954 | return defvalue;
|
|---|
| 955 |
|
|---|
| 956 | int off = field.getOffset ();
|
|---|
| 957 |
|
|---|
| 958 | return Float.intBitsToFloat (((prim_field_data[off++] & 0xFF) << 24)
|
|---|
| 959 | | ((prim_field_data[off++] & 0xFF) << 16)
|
|---|
| 960 | | ((prim_field_data[off++] & 0xFF) << 8)
|
|---|
| 961 | | (prim_field_data[off] & 0xFF));
|
|---|
| 962 | }
|
|---|
| 963 |
|
|---|
| 964 | public double get (String name, double defvalue)
|
|---|
| 965 | throws IOException, IllegalArgumentException
|
|---|
| 966 | {
|
|---|
| 967 | ObjectStreamField field = getField (name, Double.TYPE);
|
|---|
| 968 |
|
|---|
| 969 | if (field == null)
|
|---|
| 970 | return defvalue;
|
|---|
| 971 |
|
|---|
| 972 | int off = field.getOffset ();
|
|---|
| 973 |
|
|---|
| 974 | return Double.longBitsToDouble
|
|---|
| 975 | ( (long) (((prim_field_data[off++] & 0xFF) << 56)
|
|---|
| 976 | | ((prim_field_data[off++] & 0xFF) << 48)
|
|---|
| 977 | | ((prim_field_data[off++] & 0xFF) << 40)
|
|---|
| 978 | | ((prim_field_data[off++] & 0xFF) << 32)
|
|---|
| 979 | | ((prim_field_data[off++] & 0xFF) << 24)
|
|---|
| 980 | | ((prim_field_data[off++] & 0xFF) << 16)
|
|---|
| 981 | | ((prim_field_data[off++] & 0xFF) << 8)
|
|---|
| 982 | | (prim_field_data[off] & 0xFF)));
|
|---|
| 983 | }
|
|---|
| 984 |
|
|---|
| 985 | public Object get (String name, Object defvalue)
|
|---|
| 986 | throws IOException, IllegalArgumentException
|
|---|
| 987 | {
|
|---|
| 988 | ObjectStreamField field =
|
|---|
| 989 | getField (name, defvalue == null ? null : defvalue.getClass ());
|
|---|
| 990 |
|
|---|
| 991 | if (field == null)
|
|---|
| 992 | return defvalue;
|
|---|
| 993 |
|
|---|
| 994 | return objs[field.getOffset ()];
|
|---|
| 995 | }
|
|---|
| 996 |
|
|---|
| 997 | private ObjectStreamField getField (String name, Class type)
|
|---|
| 998 | throws IllegalArgumentException
|
|---|
| 999 | {
|
|---|
| 1000 | ObjectStreamField field = clazz.getField (name);
|
|---|
| 1001 |
|
|---|
| 1002 | if (field == null)
|
|---|
| 1003 | return null;
|
|---|
| 1004 |
|
|---|
| 1005 | Class field_type = field.getType ();
|
|---|
| 1006 |
|
|---|
| 1007 | if (type == field_type ||
|
|---|
| 1008 | (type == null && ! field_type.isPrimitive ()))
|
|---|
| 1009 | return field;
|
|---|
| 1010 |
|
|---|
| 1011 | throw new IllegalArgumentException ("Field requested is of type "
|
|---|
| 1012 | + field_type.getName ()
|
|---|
| 1013 | + ", but requested type was "
|
|---|
| 1014 | + (type == null ?
|
|---|
| 1015 | "Object" : type.getName ()));
|
|---|
| 1016 | }
|
|---|
| 1017 | };
|
|---|
| 1018 |
|
|---|
| 1019 | }
|
|---|
| 1020 |
|
|---|
| 1021 |
|
|---|
| 1022 | /**
|
|---|
| 1023 | Protected constructor that allows subclasses to override
|
|---|
| 1024 | deserialization. This constructor should be called by subclasses
|
|---|
| 1025 | that wish to override <code>readObject (Object)</code>. This
|
|---|
| 1026 | method does a security check <i>NOTE: currently not
|
|---|
| 1027 | implemented</i>, then sets a flag that informs
|
|---|
| 1028 | <code>readObject (Object)</code> to call the subclasses
|
|---|
| 1029 | <code>readObjectOverride (Object)</code> method.
|
|---|
| 1030 |
|
|---|
| 1031 | @see readObjectOverride (Object)
|
|---|
| 1032 | */
|
|---|
| 1033 | protected ObjectInputStream ()
|
|---|
| 1034 | throws IOException, SecurityException
|
|---|
| 1035 | {
|
|---|
| 1036 | SecurityManager sec_man = System.getSecurityManager ();
|
|---|
| 1037 | if (sec_man != null)
|
|---|
| 1038 | sec_man.checkPermission (SUBCLASS_IMPLEMENTATION_PERMISSION);
|
|---|
| 1039 | this.useSubclassMethod = true;
|
|---|
| 1040 | }
|
|---|
| 1041 |
|
|---|
| 1042 |
|
|---|
| 1043 | /**
|
|---|
| 1044 | This method allows subclasses to override the default
|
|---|
| 1045 | de serialization mechanism provided by
|
|---|
| 1046 | <code>ObjectInputStream</code>. To make this method be used for
|
|---|
| 1047 | writing objects, subclasses must invoke the 0-argument
|
|---|
| 1048 | constructor on this class from their constructor.
|
|---|
| 1049 |
|
|---|
| 1050 | @see ObjectInputStream ()
|
|---|
| 1051 | */
|
|---|
| 1052 | protected Object readObjectOverride ()
|
|---|
| 1053 | throws ClassNotFoundException, IOException, OptionalDataException
|
|---|
| 1054 | {
|
|---|
| 1055 | throw new IOException ("Subclass of ObjectInputStream must implement readObjectOverride");
|
|---|
| 1056 | }
|
|---|
| 1057 |
|
|---|
| 1058 |
|
|---|
| 1059 | // assigns the next availible handle to OBJ
|
|---|
| 1060 | private int assignNewHandle (Object obj)
|
|---|
| 1061 | {
|
|---|
| 1062 | this.objectLookupTable.put (new Integer (this.nextOID),
|
|---|
| 1063 | new ObjectIdentityWrapper (obj));
|
|---|
| 1064 | return this.nextOID++;
|
|---|
| 1065 | }
|
|---|
| 1066 |
|
|---|
| 1067 |
|
|---|
| 1068 | private Object processResolution (Object obj, int handle)
|
|---|
| 1069 | throws IOException
|
|---|
| 1070 | {
|
|---|
| 1071 | if (obj instanceof Serializable)
|
|---|
| 1072 | {
|
|---|
| 1073 | Method m = null;
|
|---|
| 1074 | try
|
|---|
| 1075 | {
|
|---|
| 1076 | Class classArgs[] = {};
|
|---|
| 1077 | m = obj.getClass ().getDeclaredMethod ("readResolve", classArgs);
|
|---|
| 1078 | // m can't be null by definition since an exception would
|
|---|
| 1079 | // have been thrown so a check for null is not needed.
|
|---|
| 1080 | obj = m.invoke (obj, new Object[] {});
|
|---|
| 1081 | }
|
|---|
| 1082 | catch (NoSuchMethodException ignore)
|
|---|
| 1083 | {
|
|---|
| 1084 | }
|
|---|
| 1085 | catch (IllegalAccessException ignore)
|
|---|
| 1086 | {
|
|---|
| 1087 | }
|
|---|
| 1088 | catch (InvocationTargetException ignore)
|
|---|
| 1089 | {
|
|---|
| 1090 | }
|
|---|
| 1091 | }
|
|---|
| 1092 |
|
|---|
| 1093 | if (this.resolveEnabled)
|
|---|
| 1094 | obj = resolveObject (obj);
|
|---|
| 1095 |
|
|---|
| 1096 | this.objectLookupTable.put (new Integer (handle),
|
|---|
| 1097 | new ObjectIdentityWrapper (obj));
|
|---|
| 1098 |
|
|---|
| 1099 | return obj;
|
|---|
| 1100 | }
|
|---|
| 1101 |
|
|---|
| 1102 |
|
|---|
| 1103 | private void clearHandles ()
|
|---|
| 1104 | {
|
|---|
| 1105 | this.objectLookupTable.clear ();
|
|---|
| 1106 | this.nextOID = baseWireHandle;
|
|---|
| 1107 | }
|
|---|
| 1108 |
|
|---|
| 1109 |
|
|---|
| 1110 | private void readNextBlock () throws IOException
|
|---|
| 1111 | {
|
|---|
| 1112 | readNextBlock (this.realInputStream.readByte ());
|
|---|
| 1113 | }
|
|---|
| 1114 |
|
|---|
| 1115 |
|
|---|
| 1116 | private void readNextBlock (byte marker) throws IOException
|
|---|
| 1117 | {
|
|---|
| 1118 | if (marker == TC_BLOCKDATA)
|
|---|
| 1119 | {
|
|---|
| 1120 | dumpElement ("BLOCK DATA SIZE=");
|
|---|
| 1121 | this.blockDataBytes = this.realInputStream.readUnsignedByte ();
|
|---|
| 1122 | dumpElementln (Integer.toString(this.blockDataBytes));
|
|---|
| 1123 | }
|
|---|
| 1124 | else if (marker == TC_BLOCKDATALONG)
|
|---|
| 1125 | {
|
|---|
| 1126 | dumpElement ("BLOCK DATA LONG SIZE=");
|
|---|
| 1127 | this.blockDataBytes = this.realInputStream.readInt ();
|
|---|
| 1128 | dumpElementln (Integer.toString(this.blockDataBytes));
|
|---|
| 1129 | }
|
|---|
| 1130 | else
|
|---|
| 1131 | {
|
|---|
| 1132 | throw new EOFException ("Attempt to read primitive data, but no data block is active.");
|
|---|
| 1133 | }
|
|---|
| 1134 |
|
|---|
| 1135 | if (this.blockData.length < this.blockDataBytes)
|
|---|
| 1136 | this.blockData = new byte[this.blockDataBytes];
|
|---|
| 1137 |
|
|---|
| 1138 | this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
|
|---|
| 1139 | this.blockDataPosition = 0;
|
|---|
| 1140 | }
|
|---|
| 1141 |
|
|---|
| 1142 |
|
|---|
| 1143 | private void readArrayElements (Object array, Class clazz)
|
|---|
| 1144 | throws ClassNotFoundException, IOException
|
|---|
| 1145 | {
|
|---|
| 1146 | if (clazz.isPrimitive ())
|
|---|
| 1147 | {
|
|---|
| 1148 | if (clazz == Boolean.TYPE)
|
|---|
| 1149 | {
|
|---|
| 1150 | boolean[] cast_array = (boolean[])array;
|
|---|
| 1151 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1152 | cast_array[i] = this.realInputStream.readBoolean ();
|
|---|
| 1153 | return;
|
|---|
| 1154 | }
|
|---|
| 1155 | if (clazz == Byte.TYPE)
|
|---|
| 1156 | {
|
|---|
| 1157 | byte[] cast_array = (byte[])array;
|
|---|
| 1158 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1159 | cast_array[i] = this.realInputStream.readByte ();
|
|---|
| 1160 | return;
|
|---|
| 1161 | }
|
|---|
| 1162 | if (clazz == Character.TYPE)
|
|---|
| 1163 | {
|
|---|
| 1164 | char[] cast_array = (char[])array;
|
|---|
| 1165 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1166 | cast_array[i] = this.realInputStream.readChar ();
|
|---|
| 1167 | return;
|
|---|
| 1168 | }
|
|---|
| 1169 | if (clazz == Double.TYPE)
|
|---|
| 1170 | {
|
|---|
| 1171 | double[] cast_array = (double[])array;
|
|---|
| 1172 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1173 | cast_array[i] = this.realInputStream.readDouble ();
|
|---|
| 1174 | return;
|
|---|
| 1175 | }
|
|---|
| 1176 | if (clazz == Float.TYPE)
|
|---|
| 1177 | {
|
|---|
| 1178 | float[] cast_array = (float[])array;
|
|---|
| 1179 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1180 | cast_array[i] = this.realInputStream.readFloat ();
|
|---|
| 1181 | return;
|
|---|
| 1182 | }
|
|---|
| 1183 | if (clazz == Integer.TYPE)
|
|---|
| 1184 | {
|
|---|
| 1185 | int[] cast_array = (int[])array;
|
|---|
| 1186 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1187 | cast_array[i] = this.realInputStream.readInt ();
|
|---|
| 1188 | return;
|
|---|
| 1189 | }
|
|---|
| 1190 | if (clazz == Long.TYPE)
|
|---|
| 1191 | {
|
|---|
| 1192 | long[] cast_array = (long[])array;
|
|---|
| 1193 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1194 | cast_array[i] = this.realInputStream.readLong ();
|
|---|
| 1195 | return;
|
|---|
| 1196 | }
|
|---|
| 1197 | if (clazz == Short.TYPE)
|
|---|
| 1198 | {
|
|---|
| 1199 | short[] cast_array = (short[])array;
|
|---|
| 1200 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1201 | cast_array[i] = this.realInputStream.readShort ();
|
|---|
| 1202 | return;
|
|---|
| 1203 | }
|
|---|
| 1204 | }
|
|---|
| 1205 | else
|
|---|
| 1206 | {
|
|---|
| 1207 | Object[] cast_array = (Object[])array;
|
|---|
| 1208 | for (int i=0; i < cast_array.length; i++)
|
|---|
| 1209 | cast_array[i] = readObject ();
|
|---|
| 1210 | }
|
|---|
| 1211 | }
|
|---|
| 1212 |
|
|---|
| 1213 |
|
|---|
| 1214 | private void readFields (Object obj, ObjectStreamClass stream_osc)
|
|---|
| 1215 | throws ClassNotFoundException, IOException
|
|---|
| 1216 | {
|
|---|
| 1217 | ObjectStreamField[] stream_fields = stream_osc.fields;
|
|---|
| 1218 | ObjectStreamField[] real_fields =
|
|---|
| 1219 | ObjectStreamClass.lookup (stream_osc.forClass ()).fields;
|
|---|
| 1220 |
|
|---|
| 1221 | boolean default_initialize, set_value;
|
|---|
| 1222 | String field_name = null;
|
|---|
| 1223 | Class type = null;
|
|---|
| 1224 | ObjectStreamField stream_field = null;
|
|---|
| 1225 | ObjectStreamField real_field = null;
|
|---|
| 1226 | int stream_idx = 0;
|
|---|
| 1227 | int real_idx = 0;
|
|---|
| 1228 |
|
|---|
| 1229 | while (stream_idx < stream_fields.length
|
|---|
| 1230 | && real_idx < real_fields.length)
|
|---|
| 1231 | {
|
|---|
| 1232 | default_initialize = false;
|
|---|
| 1233 | set_value = true;
|
|---|
| 1234 |
|
|---|
| 1235 | if (stream_idx == stream_fields.length)
|
|---|
| 1236 | default_initialize = true;
|
|---|
| 1237 | else
|
|---|
| 1238 | {
|
|---|
| 1239 | stream_field = stream_fields[stream_idx];
|
|---|
| 1240 | type = stream_field.getType ();
|
|---|
| 1241 | }
|
|---|
| 1242 |
|
|---|
| 1243 | if (real_idx == real_fields.length)
|
|---|
| 1244 | set_value = false;
|
|---|
| 1245 | else
|
|---|
| 1246 | {
|
|---|
| 1247 | real_field = real_fields[real_idx];
|
|---|
| 1248 | type = real_field.getType ();
|
|---|
| 1249 | field_name = real_field.getName ();
|
|---|
| 1250 | }
|
|---|
| 1251 |
|
|---|
| 1252 | if (set_value && !default_initialize)
|
|---|
| 1253 | {
|
|---|
| 1254 | int comp_val =
|
|---|
| 1255 | real_field.compareTo (stream_field);
|
|---|
| 1256 |
|
|---|
| 1257 | if (comp_val < 0)
|
|---|
| 1258 | {
|
|---|
| 1259 | default_initialize = true;
|
|---|
| 1260 | real_idx++;
|
|---|
| 1261 | }
|
|---|
| 1262 | else if (comp_val > 0)
|
|---|
| 1263 | {
|
|---|
| 1264 | set_value = false;
|
|---|
| 1265 | stream_idx++;
|
|---|
| 1266 | }
|
|---|
| 1267 | else
|
|---|
| 1268 | {
|
|---|
| 1269 | real_idx++;
|
|---|
| 1270 | stream_idx++;
|
|---|
| 1271 | }
|
|---|
| 1272 | }
|
|---|
| 1273 |
|
|---|
| 1274 | try
|
|---|
| 1275 | {
|
|---|
| 1276 | if (type == Boolean.TYPE)
|
|---|
| 1277 | {
|
|---|
| 1278 | boolean value =
|
|---|
| 1279 | default_initialize ? false : this.realInputStream.readBoolean ();
|
|---|
| 1280 | if (!default_initialize && set_value)
|
|---|
| 1281 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1282 | if (set_value)
|
|---|
| 1283 | setBooleanField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1284 | }
|
|---|
| 1285 | else if (type == Byte.TYPE)
|
|---|
| 1286 | {
|
|---|
| 1287 | byte value =
|
|---|
| 1288 | default_initialize ? 0 : this.realInputStream.readByte ();
|
|---|
| 1289 | if (!default_initialize && set_value)
|
|---|
| 1290 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1291 | if (set_value)
|
|---|
| 1292 | setByteField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1293 | }
|
|---|
| 1294 | else if (type == Character.TYPE)
|
|---|
| 1295 | {
|
|---|
| 1296 | char value =
|
|---|
| 1297 | default_initialize ? (char)0 : this.realInputStream.readChar ();
|
|---|
| 1298 | if (!default_initialize && set_value)
|
|---|
| 1299 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1300 | if (set_value)
|
|---|
| 1301 | setCharField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1302 | }
|
|---|
| 1303 | else if (type == Double.TYPE)
|
|---|
| 1304 | {
|
|---|
| 1305 | double value =
|
|---|
| 1306 | default_initialize ? 0 : this.realInputStream.readDouble ();
|
|---|
| 1307 | if (!default_initialize && set_value)
|
|---|
| 1308 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1309 | if (set_value)
|
|---|
| 1310 | setDoubleField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1311 | }
|
|---|
| 1312 | else if (type == Float.TYPE)
|
|---|
| 1313 | {
|
|---|
| 1314 | float value =
|
|---|
| 1315 | default_initialize ? 0 : this.realInputStream.readFloat ();
|
|---|
| 1316 | if (!default_initialize && set_value)
|
|---|
| 1317 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1318 | if (set_value)
|
|---|
| 1319 | setFloatField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1320 | }
|
|---|
| 1321 | else if (type == Integer.TYPE)
|
|---|
| 1322 | {
|
|---|
| 1323 | int value =
|
|---|
| 1324 | default_initialize ? 0 : this.realInputStream.readInt ();
|
|---|
| 1325 | if (!default_initialize && set_value)
|
|---|
| 1326 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1327 | if (set_value)
|
|---|
| 1328 | setIntField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1329 | }
|
|---|
| 1330 | else if (type == Long.TYPE)
|
|---|
| 1331 | {
|
|---|
| 1332 | long value =
|
|---|
| 1333 | default_initialize ? 0 : this.realInputStream.readLong ();
|
|---|
| 1334 | if (!default_initialize && set_value)
|
|---|
| 1335 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1336 | if (set_value)
|
|---|
| 1337 | setLongField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1338 | }
|
|---|
| 1339 | else if (type == Short.TYPE)
|
|---|
| 1340 | {
|
|---|
| 1341 | short value =
|
|---|
| 1342 | default_initialize ? (short)0 : this.realInputStream.readShort ();
|
|---|
| 1343 | if (!default_initialize && set_value)
|
|---|
| 1344 | dumpElementln (" " + field_name + ": " + value);
|
|---|
| 1345 | if (set_value)
|
|---|
| 1346 | setShortField (obj, stream_osc.forClass (), field_name, value);
|
|---|
| 1347 | }
|
|---|
| 1348 | else
|
|---|
| 1349 | {
|
|---|
| 1350 | Object value =
|
|---|
| 1351 | default_initialize ? null : readObject ();
|
|---|
| 1352 | if (set_value)
|
|---|
| 1353 | setObjectField (obj, stream_osc.forClass (), field_name,
|
|---|
| 1354 | real_field.getTypeString (), value);
|
|---|
| 1355 | }
|
|---|
| 1356 | }
|
|---|
| 1357 | catch (NoSuchFieldError e)
|
|---|
| 1358 | {
|
|---|
| 1359 | dumpElementln("XXXX " + field_name + " does not exist.");
|
|---|
| 1360 | }
|
|---|
| 1361 | }
|
|---|
| 1362 | }
|
|---|
| 1363 |
|
|---|
| 1364 | // Toggles writing primitive data to block-data buffer.
|
|---|
| 1365 | private boolean setBlockDataMode (boolean on)
|
|---|
| 1366 | {
|
|---|
| 1367 | boolean oldmode = this.readDataFromBlock;
|
|---|
| 1368 | this.readDataFromBlock = on;
|
|---|
| 1369 |
|
|---|
| 1370 | if (on)
|
|---|
| 1371 | this.dataInputStream = this.blockDataInput;
|
|---|
| 1372 | else
|
|---|
| 1373 | this.dataInputStream = this.realInputStream;
|
|---|
| 1374 | return oldmode;
|
|---|
| 1375 | }
|
|---|
| 1376 |
|
|---|
| 1377 |
|
|---|
| 1378 | // returns a new instance of REAL_CLASS that has been constructed
|
|---|
| 1379 | // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
|
|---|
| 1380 | private Object newObject (Class real_class, Class constructor_class)
|
|---|
| 1381 | {
|
|---|
| 1382 | try
|
|---|
| 1383 | {
|
|---|
| 1384 | Object obj = allocateObject (real_class);
|
|---|
| 1385 | callConstructor (constructor_class, obj);
|
|---|
| 1386 | return obj;
|
|---|
| 1387 | }
|
|---|
| 1388 | catch (InstantiationException e)
|
|---|
| 1389 | {
|
|---|
| 1390 | return null;
|
|---|
| 1391 | }
|
|---|
| 1392 | }
|
|---|
| 1393 |
|
|---|
| 1394 |
|
|---|
| 1395 | // runs all registered ObjectInputValidations in prioritized order
|
|---|
| 1396 | // on OBJ
|
|---|
| 1397 | private void invokeValidators () throws InvalidObjectException
|
|---|
| 1398 | {
|
|---|
| 1399 | Object[] validators = new Object[this.validators.size ()];
|
|---|
| 1400 | this.validators.copyInto (validators);
|
|---|
| 1401 | Arrays.sort (validators);
|
|---|
| 1402 |
|
|---|
| 1403 | try
|
|---|
| 1404 | {
|
|---|
| 1405 | for (int i=0; i < validators.length; i++)
|
|---|
| 1406 | ((ObjectInputValidation)validators[i]).validateObject ();
|
|---|
| 1407 | }
|
|---|
| 1408 | finally
|
|---|
| 1409 | {
|
|---|
| 1410 | this.validators.removeAllElements ();
|
|---|
| 1411 | }
|
|---|
| 1412 | }
|
|---|
| 1413 |
|
|---|
| 1414 |
|
|---|
| 1415 | // this native method is used to get access to the protected method
|
|---|
| 1416 | // of the same name in SecurityManger
|
|---|
| 1417 | private static ClassLoader currentClassLoader (SecurityManager sm)
|
|---|
| 1418 | {
|
|---|
| 1419 | // FIXME: This is too simple.
|
|---|
| 1420 | return ClassLoader.getSystemClassLoader ();
|
|---|
| 1421 | }
|
|---|
| 1422 |
|
|---|
| 1423 | private static Field getField (Class klass, String name)
|
|---|
| 1424 | throws java.lang.NoSuchFieldException
|
|---|
| 1425 | {
|
|---|
| 1426 | return klass.getDeclaredField(name);
|
|---|
| 1427 | }
|
|---|
| 1428 |
|
|---|
| 1429 | private static Method getMethod (Class klass, String name, Class args[])
|
|---|
| 1430 | throws java.lang.NoSuchMethodException
|
|---|
| 1431 | {
|
|---|
| 1432 | return klass.getDeclaredMethod(name, args);
|
|---|
| 1433 | }
|
|---|
| 1434 |
|
|---|
| 1435 | private void callReadMethod (Object obj, ObjectStreamClass osc) throws IOException
|
|---|
| 1436 | {
|
|---|
| 1437 | Class klass = osc.forClass();
|
|---|
| 1438 | try
|
|---|
| 1439 | {
|
|---|
| 1440 | Class classArgs[] = {ObjectInputStream.class};
|
|---|
| 1441 | Method m = getMethod (klass, "readObject", classArgs);
|
|---|
| 1442 | if (m == null)
|
|---|
| 1443 | return;
|
|---|
| 1444 | Object args[] = {this};
|
|---|
| 1445 | m.invoke (obj, args);
|
|---|
| 1446 | }
|
|---|
| 1447 | catch (InvocationTargetException x)
|
|---|
| 1448 | {
|
|---|
| 1449 | /* Rethrow if possible. */
|
|---|
| 1450 | Throwable exception = x.getTargetException();
|
|---|
| 1451 | if (exception instanceof RuntimeException)
|
|---|
| 1452 | throw (RuntimeException) exception;
|
|---|
| 1453 | if (exception instanceof IOException)
|
|---|
| 1454 | throw (IOException) exception;
|
|---|
| 1455 |
|
|---|
| 1456 | throw new IOException ("Exception thrown from readObject() on " +
|
|---|
| 1457 | klass + ": " + exception.getClass().getName());
|
|---|
| 1458 | }
|
|---|
| 1459 | catch (Exception x)
|
|---|
| 1460 | {
|
|---|
| 1461 | throw new IOException ("Failure invoking readObject() on " +
|
|---|
| 1462 | klass + ": " + x.getClass().getName());
|
|---|
| 1463 | }
|
|---|
| 1464 | }
|
|---|
| 1465 |
|
|---|
| 1466 | private native Object allocateObject (Class clazz)
|
|---|
| 1467 | throws InstantiationException;
|
|---|
| 1468 |
|
|---|
| 1469 | private native void callConstructor (Class clazz, Object obj);
|
|---|
| 1470 |
|
|---|
| 1471 | private void setBooleanField (Object obj, Class klass, String field_name,
|
|---|
| 1472 | boolean val)
|
|---|
| 1473 | {
|
|---|
| 1474 | try
|
|---|
| 1475 | {
|
|---|
| 1476 | Field f = getField (klass, field_name);
|
|---|
| 1477 | f.setAccessible(true);
|
|---|
| 1478 | f.setBoolean (obj, val);
|
|---|
| 1479 | }
|
|---|
| 1480 | catch (Exception _)
|
|---|
| 1481 | {
|
|---|
| 1482 | }
|
|---|
| 1483 | }
|
|---|
| 1484 |
|
|---|
| 1485 | private void setByteField (Object obj, Class klass, String field_name,
|
|---|
| 1486 | byte val)
|
|---|
| 1487 | {
|
|---|
| 1488 | try
|
|---|
| 1489 | {
|
|---|
| 1490 | Field f = getField (klass, field_name);
|
|---|
| 1491 | f.setAccessible(true);
|
|---|
| 1492 | f.setByte (obj, val);
|
|---|
| 1493 | }
|
|---|
| 1494 | catch (Exception _)
|
|---|
| 1495 | {
|
|---|
| 1496 | }
|
|---|
| 1497 | }
|
|---|
| 1498 |
|
|---|
| 1499 | private void setCharField (Object obj, Class klass, String field_name,
|
|---|
| 1500 | char val)
|
|---|
| 1501 | {
|
|---|
| 1502 | try
|
|---|
| 1503 | {
|
|---|
| 1504 | Field f = getField (klass, field_name);
|
|---|
| 1505 | f.setAccessible(true);
|
|---|
| 1506 | f.setChar (obj, val);
|
|---|
| 1507 | }
|
|---|
| 1508 | catch (Exception _)
|
|---|
| 1509 | {
|
|---|
| 1510 | }
|
|---|
| 1511 | }
|
|---|
| 1512 |
|
|---|
| 1513 | private void setDoubleField (Object obj, Class klass, String field_name,
|
|---|
| 1514 | double val)
|
|---|
| 1515 | {
|
|---|
| 1516 | try
|
|---|
| 1517 | {
|
|---|
| 1518 | Field f = getField (klass, field_name);
|
|---|
| 1519 | f.setAccessible(true);
|
|---|
| 1520 | f.setDouble (obj, val);
|
|---|
| 1521 | }
|
|---|
| 1522 | catch (Exception _)
|
|---|
| 1523 | {
|
|---|
| 1524 | }
|
|---|
| 1525 | }
|
|---|
| 1526 |
|
|---|
| 1527 | private void setFloatField (Object obj, Class klass, String field_name,
|
|---|
| 1528 | float val)
|
|---|
| 1529 | {
|
|---|
| 1530 | try
|
|---|
| 1531 | {
|
|---|
| 1532 | Field f = getField (klass, field_name);
|
|---|
| 1533 | f.setAccessible(true);
|
|---|
| 1534 | f.setFloat (obj, val);
|
|---|
| 1535 | }
|
|---|
| 1536 | catch (Exception _)
|
|---|
| 1537 | {
|
|---|
| 1538 | }
|
|---|
| 1539 | }
|
|---|
| 1540 |
|
|---|
| 1541 | private void setIntField (Object obj, Class klass, String field_name,
|
|---|
| 1542 | int val)
|
|---|
| 1543 | {
|
|---|
| 1544 | try
|
|---|
| 1545 | {
|
|---|
| 1546 | Field f = getField (klass, field_name);
|
|---|
| 1547 | f.setAccessible(true);
|
|---|
| 1548 | f.setInt (obj, val);
|
|---|
| 1549 | }
|
|---|
| 1550 | catch (Exception _)
|
|---|
| 1551 | {
|
|---|
| 1552 | }
|
|---|
| 1553 | }
|
|---|
| 1554 |
|
|---|
| 1555 |
|
|---|
| 1556 | private void setLongField (Object obj, Class klass, String field_name,
|
|---|
| 1557 | long val)
|
|---|
| 1558 | {
|
|---|
| 1559 | try
|
|---|
| 1560 | {
|
|---|
| 1561 | Field f = getField (klass, field_name);
|
|---|
| 1562 | f.setAccessible(true);
|
|---|
| 1563 | f.setLong (obj, val);
|
|---|
| 1564 | }
|
|---|
| 1565 | catch (Exception _)
|
|---|
| 1566 | {
|
|---|
| 1567 | }
|
|---|
| 1568 | }
|
|---|
| 1569 |
|
|---|
| 1570 |
|
|---|
| 1571 | private void setShortField (Object obj, Class klass, String field_name,
|
|---|
| 1572 | short val)
|
|---|
| 1573 | {
|
|---|
| 1574 | try
|
|---|
| 1575 | {
|
|---|
| 1576 | Field f = getField (klass, field_name);
|
|---|
| 1577 | f.setAccessible(true);
|
|---|
| 1578 | f.setShort (obj, val);
|
|---|
| 1579 | }
|
|---|
| 1580 | catch (Exception _)
|
|---|
| 1581 | {
|
|---|
| 1582 | }
|
|---|
| 1583 | }
|
|---|
| 1584 |
|
|---|
| 1585 |
|
|---|
| 1586 | private void setObjectField (Object obj, Class klass, String field_name, String type_code,
|
|---|
| 1587 | Object val)
|
|---|
| 1588 | {
|
|---|
| 1589 | try
|
|---|
| 1590 | {
|
|---|
| 1591 | Field f = getField (klass, field_name);
|
|---|
| 1592 | f.setAccessible(true);
|
|---|
| 1593 | // FIXME: We should check the type_code here
|
|---|
| 1594 | f.set (obj, val);
|
|---|
| 1595 | }
|
|---|
| 1596 | catch (Exception _)
|
|---|
| 1597 | {
|
|---|
| 1598 | }
|
|---|
| 1599 | }
|
|---|
| 1600 |
|
|---|
| 1601 | private static final int BUFFER_SIZE = 1024;
|
|---|
| 1602 | private static final Class[] readObjectParams = { ObjectInputStream.class };
|
|---|
| 1603 |
|
|---|
| 1604 | private DataInputStream realInputStream;
|
|---|
| 1605 | private DataInputStream dataInputStream;
|
|---|
| 1606 | private DataInputStream blockDataInput;
|
|---|
| 1607 | private int blockDataPosition;
|
|---|
| 1608 | private int blockDataBytes;
|
|---|
| 1609 | private byte[] blockData;
|
|---|
| 1610 | private boolean useSubclassMethod;
|
|---|
| 1611 | private int nextOID;
|
|---|
| 1612 | private boolean resolveEnabled;
|
|---|
| 1613 | private Hashtable objectLookupTable;
|
|---|
| 1614 | private Object currentObject;
|
|---|
| 1615 | private ObjectStreamClass currentObjectStreamClass;
|
|---|
| 1616 | private boolean readDataFromBlock;
|
|---|
| 1617 | private boolean isDeserializing;
|
|---|
| 1618 | private boolean fieldsAlreadyRead;
|
|---|
| 1619 | private Vector validators;
|
|---|
| 1620 |
|
|---|
| 1621 | private static boolean dump;
|
|---|
| 1622 |
|
|---|
| 1623 | private void dumpElement (String msg)
|
|---|
| 1624 | {
|
|---|
| 1625 | if (Configuration.DEBUG && dump)
|
|---|
| 1626 | System.out.print(msg);
|
|---|
| 1627 | }
|
|---|
| 1628 |
|
|---|
| 1629 | private void dumpElementln (String msg)
|
|---|
| 1630 | {
|
|---|
| 1631 | if (Configuration.DEBUG && dump)
|
|---|
| 1632 | System.out.println(msg);
|
|---|
| 1633 | }
|
|---|
| 1634 |
|
|---|
| 1635 | static
|
|---|
| 1636 | {
|
|---|
| 1637 | if (Configuration.INIT_LOAD_LIBRARY)
|
|---|
| 1638 | {
|
|---|
| 1639 | System.loadLibrary ("javaio");
|
|---|
| 1640 | }
|
|---|
| 1641 | }
|
|---|
| 1642 | }
|
|---|
| 1643 |
|
|---|
| 1644 |
|
|---|
| 1645 | // used to keep a prioritized list of object validators
|
|---|
| 1646 | class ValidatorAndPriority implements Comparable
|
|---|
| 1647 | {
|
|---|
| 1648 | int priority;
|
|---|
| 1649 | ObjectInputValidation validator;
|
|---|
| 1650 |
|
|---|
| 1651 | ValidatorAndPriority (ObjectInputValidation validator, int priority)
|
|---|
| 1652 | {
|
|---|
| 1653 | this.priority = priority;
|
|---|
| 1654 | this.validator = validator;
|
|---|
| 1655 | }
|
|---|
| 1656 |
|
|---|
| 1657 | public int compareTo (Object o)
|
|---|
| 1658 | {
|
|---|
| 1659 | ValidatorAndPriority vap = (ValidatorAndPriority)o;
|
|---|
| 1660 | return this.priority - vap.priority;
|
|---|
| 1661 | }
|
|---|
| 1662 | }
|
|---|