From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/java/io/ObjectOutputStream.java | 1490 +++++++++++++++++++++ 1 file changed, 1490 insertions(+) create mode 100644 libjava/classpath/java/io/ObjectOutputStream.java (limited to 'libjava/classpath/java/io/ObjectOutputStream.java') diff --git a/libjava/classpath/java/io/ObjectOutputStream.java b/libjava/classpath/java/io/ObjectOutputStream.java new file mode 100644 index 000000000..71d2e0b34 --- /dev/null +++ b/libjava/classpath/java/io/ObjectOutputStream.java @@ -0,0 +1,1490 @@ +/* ObjectOutputStream.java -- Class used to write serialized objects + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import gnu.java.io.ObjectIdentityMap2Int; +import gnu.java.lang.reflect.TypeSignature; +import gnu.java.security.action.SetAccessibleAction; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +/** + * An ObjectOutputStream can be used to write objects + * as well as primitive data in a platform-independent manner to an + * OutputStream. + * + * The data produced by an ObjectOutputStream can be read + * and reconstituted by an ObjectInputStream. + * + * writeObject (Object) is used to write Objects, the + * write<type> methods are used to write primitive + * data (as in DataOutputStream). Strings can be written + * as objects or as primitive data. + * + * Not all objects can be written out using an + * ObjectOutputStream. Only those objects that are an + * instance of java.io.Serializable can be written. + * + * Using default serialization, information about the class of an + * object is written, all of the non-transient, non-static fields of + * the object are written, if any of these fields are objects, they are + * written out in the same manner. + * + * An object is only written out the first time it is encountered. If + * the object is encountered later, a reference to it is written to + * the underlying stream. Thus writing circular object graphs + * does not present a problem, nor are relationships between objects + * in a graph lost. + * + * Example usage: + *
+ * Hashtable map = new Hashtable ();
+ * map.put ("one", new Integer (1));
+ * map.put ("two", new Integer (2));
+ *
+ * ObjectOutputStream oos =
+ * new ObjectOutputStream (new FileOutputStream ("numbers"));
+ * oos.writeObject (map);
+ * oos.close ();
+ *
+ * ObjectInputStream ois =
+ * new ObjectInputStream (new FileInputStream ("numbers"));
+ * Hashtable newmap = (Hashtable)ois.readObject ();
+ *
+ * System.out.println (newmap);
+ * 
+ * + * The default serialization can be overriden in two ways. + * + * By defining a method private void + * writeObject (ObjectOutputStream), a class can dictate exactly + * how information about itself is written. + * defaultWriteObject () may be called from this method to + * carry out default serialization. This method is not + * responsible for dealing with fields of super-classes or subclasses. + * + * By implementing java.io.Externalizable. This gives + * the class complete control over the way it is written to the + * stream. If this approach is used the burden of writing superclass + * and subclass data is transfered to the class implementing + * java.io.Externalizable. + * + * @see java.io.DataOutputStream + * @see java.io.Externalizable + * @see java.io.ObjectInputStream + * @see java.io.Serializable + * @author Tom Tromey (tromey@redhat.com) + * @author Jeroen Frijters (jeroen@frijters.net) + * @author Guilhem Lavaux (guilhem@kaffe.org) + * @author Michael Koch (konqueror@gmx.de) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class ObjectOutputStream extends OutputStream + implements ObjectOutput, ObjectStreamConstants +{ + /** + * Creates a new ObjectOutputStream that will do all of + * its writing onto out. This method also initializes + * the stream by writing the header information (stream magic number + * and stream version). + * + * @exception IOException Writing stream header to underlying + * stream cannot be completed. + * + * @see #writeStreamHeader() + */ + public ObjectOutputStream (OutputStream out) throws IOException + { + realOutput = new DataOutputStream(out); + blockData = new byte[ BUFFER_SIZE ]; + blockDataCount = 0; + blockDataOutput = new DataOutputStream(this); + setBlockDataMode(true); + replacementEnabled = false; + isSerializing = false; + nextOID = baseWireHandle; + OIDLookupTable = new ObjectIdentityMap2Int(); + protocolVersion = defaultProtocolVersion; + useSubclassMethod = false; + writeStreamHeader(); + + if (DEBUG) + { + String val = System.getProperty("gcj.dumpobjects"); + if (val != null && !val.equals("")) + dump = true; + } + } + + /** + * Writes a representation of obj to the underlying + * output stream by writing out information about its class, then + * writing out each of the objects non-transient, non-static + * fields. If any of these fields are other objects, + * they are written out in the same manner. + * + * This method can be overriden by a class by implementing + * private void writeObject (ObjectOutputStream). + * + * If an exception is thrown from this method, the stream is left in + * an undefined state. + * + * @param obj the object to serialize. + * @exception NotSerializableException An attempt was made to + * serialize an Object that is not serializable. + * + * @exception InvalidClassException Somebody tried to serialize + * an object which is wrongly formatted. + * + * @exception IOException Exception from underlying + * OutputStream. + * @see #writeUnshared(Object) + */ + public final void writeObject(Object obj) throws IOException + { + writeObject(obj, true); + } + + /** + * Writes an object to the stream in the same manner as + * {@link #writeObject(Object)}, but without the use of + * references. As a result, the object is always written + * to the stream in full. Likewise, if an object is written + * by this method and is then later written again by + * {@link #writeObject(Object)}, both calls will write out + * the object in full, as the later call to + * {@link #writeObject(Object)} will know nothing of the + * earlier use of {@link #writeUnshared(Object)}. + * + * @param obj the object to serialize. + * @throws NotSerializableException if the object being + * serialized does not implement + * {@link Serializable}. + * @throws InvalidClassException if a problem occurs with + * the class of the object being + * serialized. + * @throws IOException if an I/O error occurs on the underlying + * OutputStream. + * @since 1.4 + * @see #writeObject(Object) + */ + public void writeUnshared(Object obj) + throws IOException + { + writeObject(obj, false); + } + + /** + * Writes a representation of obj to the underlying + * output stream by writing out information about its class, then + * writing out each of the objects non-transient, non-static + * fields. If any of these fields are other objects, + * they are written out in the same manner. + * + * This method can be overriden by a class by implementing + * private void writeObject (ObjectOutputStream). + * + * If an exception is thrown from this method, the stream is left in + * an undefined state. + * + * @param obj the object to serialize. + * @param shared true if the serialized object should be + * shared with later calls. + * @exception NotSerializableException An attempt was made to + * serialize an Object that is not serializable. + * + * @exception InvalidClassException Somebody tried to serialize + * an object which is wrongly formatted. + * + * @exception IOException Exception from underlying + * OutputStream. + * @see #writeUnshared(Object) + */ + private final void writeObject(Object obj, boolean shared) + throws IOException + { + if (useSubclassMethod) + { + if (dump) + dumpElementln ("WRITE OVERRIDE: " + obj); + + writeObjectOverride(obj); + return; + } + + if (dump) + dumpElementln ("WRITE: ", obj); + + depth += 2; + + boolean was_serializing = isSerializing; + boolean old_mode = setBlockDataMode(false); + try + { + isSerializing = true; + boolean replaceDone = false; + Object replacedObject = null; + + while (true) + { + if (obj == null) + { + realOutput.writeByte(TC_NULL); + break; + } + + int handle = findHandle(obj); + if (handle >= 0 && shared) + { + realOutput.writeByte(TC_REFERENCE); + realOutput.writeInt(handle); + break; + } + + if (obj instanceof Class) + { + Class cl = (Class)obj; + ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl); + realOutput.writeByte(TC_CLASS); + if (!osc.isProxyClass) + { + writeObject (osc); + } + else + {System.err.println("1"); + realOutput.writeByte(TC_PROXYCLASSDESC); + Class[] intfs = cl.getInterfaces(); + realOutput.writeInt(intfs.length); + for (int i = 0; i < intfs.length; i++) + realOutput.writeUTF(intfs[i].getName()); + + boolean oldmode = setBlockDataMode(true); + annotateProxyClass(cl); + setBlockDataMode(oldmode); + realOutput.writeByte(TC_ENDBLOCKDATA); + + writeObject(osc.getSuper()); + } + if (shared) + assignNewHandle(obj); + break; + } + + if (obj instanceof ObjectStreamClass) + { + writeClassDescriptor((ObjectStreamClass) obj); + break; + } + + Class clazz = obj.getClass(); + ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz); + if (osc == null) + throw new NotSerializableException(clazz.getName()); + + if (osc.isEnum()) + { + /* TC_ENUM classDesc newHandle enumConstantName */ + realOutput.writeByte(TC_ENUM); + writeObject(osc); + if (shared) + assignNewHandle(obj); + writeObject(((Enum) obj).name()); + break; + } + + if ((replacementEnabled || obj instanceof Serializable) + && ! replaceDone) + { + replacedObject = obj; + + if (obj instanceof Serializable) + { + try + { + Method m = osc.writeReplaceMethod; + if (m != null) + obj = m.invoke(obj, new Object[0]); + } + catch (IllegalAccessException ignore) + { + } + catch (InvocationTargetException ignore) + { + } + } + + if (replacementEnabled) + obj = replaceObject(obj); + + replaceDone = true; + continue; + } + + if (obj instanceof String) + { + String s = (String)obj; + long l = realOutput.getUTFlength(s, 0, 0); + if (l <= 65535) + { + realOutput.writeByte(TC_STRING); + if (shared) + assignNewHandle(obj); + realOutput.writeUTFShort(s, (int)l); + } + else + { + realOutput.writeByte(TC_LONGSTRING); + if (shared) + assignNewHandle(obj); + realOutput.writeUTFLong(s, l); + } + break; + } + + if (clazz.isArray ()) + { + realOutput.writeByte(TC_ARRAY); + writeObject(osc); + if (shared) + assignNewHandle(obj); + writeArraySizeAndElements(obj, clazz.getComponentType()); + break; + } + + realOutput.writeByte(TC_OBJECT); + writeObject(osc); + + if (shared) + if (replaceDone) + assignNewHandle(replacedObject); + else + assignNewHandle(obj); + + if (obj instanceof Externalizable) + { + if (protocolVersion == PROTOCOL_VERSION_2) + setBlockDataMode(true); + + ((Externalizable)obj).writeExternal(this); + + if (protocolVersion == PROTOCOL_VERSION_2) + { + setBlockDataMode(false); + realOutput.writeByte(TC_ENDBLOCKDATA); + } + + break; + } + + if (obj instanceof Serializable) + { + Object prevObject = this.currentObject; + ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; + currentObject = obj; + ObjectStreamClass[] hierarchy = osc.hierarchy(); + + for (int i = 0; i < hierarchy.length; i++) + { + currentObjectStreamClass = hierarchy[i]; + + fieldsAlreadyWritten = false; + if (currentObjectStreamClass.hasWriteMethod()) + { + if (dump) + dumpElementln ("WRITE METHOD CALLED FOR: ", obj); + setBlockDataMode(true); + callWriteMethod(obj, currentObjectStreamClass); + setBlockDataMode(false); + realOutput.writeByte(TC_ENDBLOCKDATA); + if (dump) + dumpElementln ("WRITE ENDBLOCKDATA FOR: ", obj); + } + else + { + if (dump) + dumpElementln ("WRITE FIELDS CALLED FOR: ", obj); + writeFields(obj, currentObjectStreamClass); + } + } + + this.currentObject = prevObject; + this.currentObjectStreamClass = prevObjectStreamClass; + currentPutField = null; + break; + } + + throw new NotSerializableException(clazz.getName() + + " in " + + obj.getClass()); + } // end pseudo-loop + } + catch (ObjectStreamException ose) + { + // Rethrow these are fatal. + throw ose; + } + catch (IOException e) + { + realOutput.writeByte(TC_EXCEPTION); + reset(true); + + setBlockDataMode(false); + try + { + if (DEBUG) + { + e.printStackTrace(System.out); + } + writeObject(e); + } + catch (IOException ioe) + { + StreamCorruptedException ex = + new StreamCorruptedException + (ioe + " thrown while exception was being written to stream."); + if (DEBUG) + { + ex.printStackTrace(System.out); + } + throw ex; + } + + reset (true); + + } + finally + { + isSerializing = was_serializing; + setBlockDataMode(old_mode); + depth -= 2; + + if (dump) + dumpElementln ("END: ", obj); + } + } + + protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException + { + if (osc.isProxyClass) + { + realOutput.writeByte(TC_PROXYCLASSDESC); + Class[] intfs = osc.forClass().getInterfaces(); + realOutput.writeInt(intfs.length); + for (int i = 0; i < intfs.length; i++) + realOutput.writeUTF(intfs[i].getName()); + + assignNewHandle(osc); + + boolean oldmode = setBlockDataMode(true); + annotateProxyClass(osc.forClass()); + setBlockDataMode(oldmode); + realOutput.writeByte(TC_ENDBLOCKDATA); + } + else + { + realOutput.writeByte(TC_CLASSDESC); + realOutput.writeUTF(osc.getName()); + if (osc.isEnum()) + realOutput.writeLong(0L); + else + realOutput.writeLong(osc.getSerialVersionUID()); + assignNewHandle(osc); + + int flags = osc.getFlags(); + + if (protocolVersion == PROTOCOL_VERSION_2 + && osc.isExternalizable()) + flags |= SC_BLOCK_DATA; + + realOutput.writeByte(flags); + + ObjectStreamField[] fields = osc.fields; + + if (fields == ObjectStreamClass.INVALID_FIELDS) + throw new InvalidClassException + (osc.getName(), "serialPersistentFields is invalid"); + + realOutput.writeShort(fields.length); + + ObjectStreamField field; + for (int i = 0; i < fields.length; i++) + { + field = fields[i]; + realOutput.writeByte(field.getTypeCode ()); + realOutput.writeUTF(field.getName ()); + + if (! field.isPrimitive()) + writeObject(field.getTypeString()); + } + + boolean oldmode = setBlockDataMode(true); + annotateClass(osc.forClass()); + setBlockDataMode(oldmode); + realOutput.writeByte(TC_ENDBLOCKDATA); + } + + if (osc.isSerializable() || osc.isExternalizable()) + writeObject(osc.getSuper()); + else + writeObject(null); + } + + /** + * Writes the current objects non-transient, non-static fields from + * the current class to the underlying output stream. + * + * This method is intended to be called from within a object's + * private void writeObject (ObjectOutputStream) + * method. + * + * @exception NotActiveException This method was called from a + * context other than from the current object's and current class's + * private void writeObject (ObjectOutputStream) + * method. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + public void defaultWriteObject() + throws IOException, NotActiveException + { + markFieldsWritten(); + writeFields(currentObject, currentObjectStreamClass); + } + + + private void markFieldsWritten() throws IOException + { + if (currentObject == null || currentObjectStreamClass == null) + throw new NotActiveException + ("defaultWriteObject called by non-active class and/or object"); + + if (fieldsAlreadyWritten) + throw new IOException + ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once"); + + fieldsAlreadyWritten = true; + } + + /** + * Resets stream to state equivalent to the state just after it was + * constructed. + * + * Causes all objects previously written to the stream to be + * forgotten. A notification of this reset is also written to the + * underlying stream. + * + * @exception IOException Exception from underlying + * OutputStream or reset called while serialization is + * in progress. + */ + public void reset() throws IOException + { + reset(false); + } + + + private void reset(boolean internal) throws IOException + { + if (!internal) + { + if (isSerializing) + throw new IOException("Reset called while serialization in progress"); + + realOutput.writeByte(TC_RESET); + } + + clearHandles(); + } + + + /** + * Informs this ObjectOutputStream to write data + * according to the specified protocol. There are currently two + * different protocols, specified by PROTOCOL_VERSION_1 + * and PROTOCOL_VERSION_2. This implementation writes + * data using PROTOCOL_VERSION_2 by default, as is done + * since the JDK 1.2. + *

+ * For an explanation of the differences between the two protocols + * see the Java Object Serialization Specification. + *

+ * + * @param version the version to use. + * + * @throws IllegalArgumentException if version is not a valid + * protocol. + * @throws IllegalStateException if called after the first the first object + * was serialized. + * @throws IOException if an I/O error occurs. + * + * @see ObjectStreamConstants#PROTOCOL_VERSION_1 + * @see ObjectStreamConstants#PROTOCOL_VERSION_2 + * + * @since 1.2 + */ + public void useProtocolVersion(int version) throws IOException + { + if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2) + throw new IllegalArgumentException("Invalid protocol version requested."); + + if (nextOID != baseWireHandle) + throw new IllegalStateException("Protocol version cannot be changed " + + "after serialization started."); + + protocolVersion = version; + } + + /** + * An empty hook that allows subclasses to write extra information + * about classes to the stream. This method is called the first + * time each class is seen, and after all of the standard + * information about the class has been written. + * + * @exception IOException Exception from underlying + * OutputStream. + * + * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass) + */ + protected void annotateClass(Class cl) throws IOException + { + } + + protected void annotateProxyClass(Class cl) throws IOException + { + } + + /** + * Allows subclasses to replace objects that are written to the + * stream with other objects to be written in their place. This + * method is called the first time each object is encountered + * (modulo reseting of the stream). + * + * This method must be enabled before it will be called in the + * serialization process. + * + * @exception IOException Exception from underlying + * OutputStream. + * + * @see #enableReplaceObject(boolean) + */ + protected Object replaceObject(Object obj) throws IOException + { + return obj; + } + + + /** + * If enable is true and this object is + * trusted, then replaceObject (Object) will be called + * in subsequent calls to writeObject (Object). + * Otherwise, replaceObject (Object) will not be called. + * + * @exception SecurityException This class is not trusted. + */ + protected boolean enableReplaceObject(boolean enable) + throws SecurityException + { + if (enable) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new SerializablePermission("enableSubstitution")); + } + + boolean old_val = replacementEnabled; + replacementEnabled = enable; + return old_val; + } + + + /** + * Writes stream magic and stream version information to the + * underlying stream. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + protected void writeStreamHeader() throws IOException + { + realOutput.writeShort(STREAM_MAGIC); + realOutput.writeShort(STREAM_VERSION); + } + + /** + * Protected constructor that allows subclasses to override + * serialization. This constructor should be called by subclasses + * that wish to override writeObject (Object). This + * method does a security check NOTE: currently not + * implemented, then sets a flag that informs + * writeObject (Object) to call the subclasses + * writeObjectOverride (Object) method. + * + * @see #writeObjectOverride(Object) + */ + protected ObjectOutputStream() throws IOException, SecurityException + { + SecurityManager sec_man = System.getSecurityManager (); + if (sec_man != null) + sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + useSubclassMethod = true; + } + + + /** + * This method allows subclasses to override the default + * serialization mechanism provided by + * ObjectOutputStream. To make this method be used for + * writing objects, subclasses must invoke the 0-argument + * constructor on this class from there constructor. + * + * @see #ObjectOutputStream() + * + * @exception NotActiveException Subclass has arranged for this + * method to be called, but did not implement this method. + */ + protected void writeObjectOverride(Object obj) throws NotActiveException, + IOException + { + throw new NotActiveException + ("Subclass of ObjectOutputStream must implement writeObjectOverride"); + } + + + /** + * @see DataOutputStream#write(int) + */ + public void write (int data) throws IOException + { + if (writeDataAsBlocks) + { + if (blockDataCount == BUFFER_SIZE) + drain(); + + blockData[ blockDataCount++ ] = (byte)data; + } + else + realOutput.write(data); + } + + + /** + * @see DataOutputStream#write(byte[]) + */ + public void write(byte[] b) throws IOException + { + write(b, 0, b.length); + } + + + /** + * @see DataOutputStream#write(byte[],int,int) + */ + public void write(byte[] b, int off, int len) throws IOException + { + if (writeDataAsBlocks) + { + if (len < 0) + throw new IndexOutOfBoundsException(); + + if (blockDataCount + len < BUFFER_SIZE) + { + System.arraycopy(b, off, blockData, blockDataCount, len); + blockDataCount += len; + } + else + { + drain(); + writeBlockDataHeader(len); + realOutput.write(b, off, len); + } + } + else + realOutput.write(b, off, len); + } + + + /** + * @see DataOutputStream#flush() + */ + public void flush () throws IOException + { + drain(); + realOutput.flush(); + } + + + /** + * Causes the block-data buffer to be written to the underlying + * stream, but does not flush underlying stream. + * + * @exception IOException Exception from underlying + * OutputStream. + */ + protected void drain() throws IOException + { + if (blockDataCount == 0) + return; + + if (writeDataAsBlocks) + writeBlockDataHeader(blockDataCount); + realOutput.write(blockData, 0, blockDataCount); + blockDataCount = 0; + } + + + /** + * @see java.io.DataOutputStream#close () + */ + public void close() throws IOException + { + flush(); + realOutput.close(); + } + + + /** + * @see java.io.DataOutputStream#writeBoolean (boolean) + */ + public void writeBoolean(boolean data) throws IOException + { + blockDataOutput.writeBoolean(data); + } + + + /** + * @see java.io.DataOutputStream#writeByte (int) + */ + public void writeByte(int data) throws IOException + { + blockDataOutput.writeByte(data); + } + + + /** + * @see java.io.DataOutputStream#writeShort (int) + */ + public void writeShort (int data) throws IOException + { + blockDataOutput.writeShort(data); + } + + + /** + * @see java.io.DataOutputStream#writeChar (int) + */ + public void writeChar(int data) throws IOException + { + blockDataOutput.writeChar(data); + } + + + /** + * @see java.io.DataOutputStream#writeInt (int) + */ + public void writeInt(int data) throws IOException + { + blockDataOutput.writeInt(data); + } + + + /** + * @see java.io.DataOutputStream#writeLong (long) + */ + public void writeLong(long data) throws IOException + { + blockDataOutput.writeLong(data); + } + + + /** + * @see java.io.DataOutputStream#writeFloat (float) + */ + public void writeFloat(float data) throws IOException + { + blockDataOutput.writeFloat(data); + } + + + /** + * @see java.io.DataOutputStream#writeDouble (double) + */ + public void writeDouble(double data) throws IOException + { + blockDataOutput.writeDouble(data); + } + + + /** + * @see java.io.DataOutputStream#writeBytes (java.lang.String) + */ + public void writeBytes(String data) throws IOException + { + blockDataOutput.writeBytes(data); + } + + + /** + * @see java.io.DataOutputStream#writeChars (java.lang.String) + */ + public void writeChars(String data) throws IOException + { + dataOutput.writeChars(data); + } + + + /** + * @see java.io.DataOutputStream#writeUTF (java.lang.String) + */ + public void writeUTF(String data) throws IOException + { + dataOutput.writeUTF(data); + } + + + /** + * This class allows a class to specify exactly which fields should + * be written, and what values should be written for these fields. + * + * XXX: finish up comments + */ + public abstract static class PutField + { + public abstract void put (String name, boolean value); + public abstract void put (String name, byte value); + public abstract void put (String name, char value); + public abstract void put (String name, double value); + public abstract void put (String name, float value); + public abstract void put (String name, int value); + public abstract void put (String name, long value); + public abstract void put (String name, short value); + public abstract void put (String name, Object value); + + /** + * @deprecated + */ + public abstract void write (ObjectOutput out) throws IOException; + } + + public PutField putFields() throws IOException + { + if (currentPutField != null) + return currentPutField; + + currentPutField = new PutField() + { + private byte[] prim_field_data + = new byte[currentObjectStreamClass.primFieldSize]; + private Object[] objs + = new Object[currentObjectStreamClass.objectFieldCount]; + + private ObjectStreamField getField (String name) + { + ObjectStreamField field + = currentObjectStreamClass.getField(name); + + if (field == null) + throw new IllegalArgumentException("no such serializable field " + name); + + return field; + } + + public void put(String name, boolean value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'Z'); + prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0); + } + + public void put(String name, byte value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'B'); + prim_field_data[field.getOffset()] = value; + } + + public void put(String name, char value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'C'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, double value) + { + ObjectStreamField field = getField (name); + + checkType(field, 'D'); + int off = field.getOffset(); + long l_value = Double.doubleToLongBits (value); + prim_field_data[off++] = (byte)(l_value >>> 52); + prim_field_data[off++] = (byte)(l_value >>> 48); + prim_field_data[off++] = (byte)(l_value >>> 40); + prim_field_data[off++] = (byte)(l_value >>> 32); + prim_field_data[off++] = (byte)(l_value >>> 24); + prim_field_data[off++] = (byte)(l_value >>> 16); + prim_field_data[off++] = (byte)(l_value >>> 8); + prim_field_data[off] = (byte)l_value; + } + + public void put(String name, float value) + { + ObjectStreamField field = getField(name); + + checkType(field, 'F'); + int off = field.getOffset(); + int i_value = Float.floatToIntBits(value); + prim_field_data[off++] = (byte)(i_value >>> 24); + prim_field_data[off++] = (byte)(i_value >>> 16); + prim_field_data[off++] = (byte)(i_value >>> 8); + prim_field_data[off] = (byte)i_value; + } + + public void put(String name, int value) + { + ObjectStreamField field = getField(name); + checkType(field, 'I'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 24); + prim_field_data[off++] = (byte)(value >>> 16); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, long value) + { + ObjectStreamField field = getField(name); + checkType(field, 'J'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 52); + prim_field_data[off++] = (byte)(value >>> 48); + prim_field_data[off++] = (byte)(value >>> 40); + prim_field_data[off++] = (byte)(value >>> 32); + prim_field_data[off++] = (byte)(value >>> 24); + prim_field_data[off++] = (byte)(value >>> 16); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, short value) + { + ObjectStreamField field = getField(name); + checkType(field, 'S'); + int off = field.getOffset(); + prim_field_data[off++] = (byte)(value >>> 8); + prim_field_data[off] = (byte)value; + } + + public void put(String name, Object value) + { + ObjectStreamField field = getField(name); + + if (value != null && + ! field.getType().isAssignableFrom(value.getClass ())) + throw new IllegalArgumentException("Class " + value.getClass() + + " cannot be cast to " + field.getType()); + objs[field.getOffset()] = value; + } + + public void write(ObjectOutput out) throws IOException + { + // Apparently Block data is not used with PutField as per + // empirical evidence against JDK 1.2. Also see Mauve test + // java.io.ObjectInputOutput.Test.GetPutField. + boolean oldmode = setBlockDataMode(false); + out.write(prim_field_data); + for (int i = 0; i < objs.length; ++ i) + out.writeObject(objs[i]); + setBlockDataMode(oldmode); + } + + private void checkType(ObjectStreamField field, char type) + throws IllegalArgumentException + { + if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0) + != type) + throw new IllegalArgumentException(); + } + }; + // end PutFieldImpl + + return currentPutField; + } + + + public void writeFields() throws IOException + { + if (currentPutField == null) + throw new NotActiveException("writeFields can only be called after putFields has been called"); + + markFieldsWritten(); + currentPutField.write(this); + } + + + // write out the block-data buffer, picking the correct header + // depending on the size of the buffer + private void writeBlockDataHeader(int size) throws IOException + { + if (size < 256) + { + realOutput.writeByte(TC_BLOCKDATA); + realOutput.write(size); + } + else + { + realOutput.writeByte(TC_BLOCKDATALONG); + realOutput.writeInt(size); + } + } + + + // lookup the handle for OBJ, return null if OBJ doesn't have a + // handle yet + private int findHandle(Object obj) + { + return OIDLookupTable.get(obj); + } + + + // assigns the next availible handle to OBJ + private int assignNewHandle(Object obj) + { + OIDLookupTable.put(obj, nextOID); + return nextOID++; + } + + + // resets mapping from objects to handles + private void clearHandles() + { + nextOID = baseWireHandle; + OIDLookupTable.clear(); + } + + + // write out array size followed by each element of the array + private void writeArraySizeAndElements(Object array, Class clazz) + throws IOException + { + int length = Array.getLength(array); + + if (clazz.isPrimitive()) + { + if (clazz == Boolean.TYPE) + { + boolean[] cast_array = (boolean[])array; + realOutput.writeInt (length); + for (int i = 0; i < length; i++) + realOutput.writeBoolean(cast_array[i]); + return; + } + if (clazz == Byte.TYPE) + { + byte[] cast_array = (byte[])array; + realOutput.writeInt(length); + realOutput.write(cast_array, 0, length); + return; + } + if (clazz == Character.TYPE) + { + char[] cast_array = (char[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeChar(cast_array[i]); + return; + } + if (clazz == Double.TYPE) + { + double[] cast_array = (double[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeDouble(cast_array[i]); + return; + } + if (clazz == Float.TYPE) + { + float[] cast_array = (float[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeFloat(cast_array[i]); + return; + } + if (clazz == Integer.TYPE) + { + int[] cast_array = (int[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + realOutput.writeInt(cast_array[i]); + return; + } + if (clazz == Long.TYPE) + { + long[] cast_array = (long[])array; + realOutput.writeInt (length); + for (int i = 0; i < length; i++) + realOutput.writeLong(cast_array[i]); + return; + } + if (clazz == Short.TYPE) + { + short[] cast_array = (short[])array; + realOutput.writeInt (length); + for (int i = 0; i < length; i++) + realOutput.writeShort(cast_array[i]); + return; + } + } + else + { + Object[] cast_array = (Object[])array; + realOutput.writeInt(length); + for (int i = 0; i < length; i++) + writeObject(cast_array[i]); + } + } + + +/* GCJ LOCAL */ + // writes out FIELDS of OBJECT for the specified ObjectStreamClass. + // FIELDS are already supposed already to be in canonical order, but + // under some circumstances (to do with Proxies) this isn't the + // case, so we call ensureFieldsSet(). + private void writeFields(Object obj, ObjectStreamClass osc) + throws IOException + { + osc.ensureFieldsSet(osc.forClass()); +/* END GCJ LOCAL */ + + ObjectStreamField[] fields = osc.fields; + boolean oldmode = setBlockDataMode(false); + + try + { + writeFields(obj,fields); + } + catch (IllegalArgumentException _) + { + InvalidClassException e = new InvalidClassException + ("writing fields of class " + osc.forClass().getName()); + e.initCause(_); + throw e; + } + catch (IOException e) + { + throw e; + } + catch (Exception _) + { + IOException e = new IOException("Unexpected exception " + _); + e.initCause(_); + throw(e); + } + + setBlockDataMode(oldmode); + } + + + /** + * Helper function for writeFields(Object,ObjectStreamClass): write + * fields from given fields array. Pass exception on. + * + * @param obj the object to be written + * + * @param fields the fields of obj to be written. + */ + private void writeFields(Object obj, ObjectStreamField[] fields) + throws + IllegalArgumentException, IllegalAccessException, IOException + { + for (int i = 0; i < fields.length; i++) + { + ObjectStreamField osf = fields[i]; + Field field = osf.field; + + if (DEBUG && dump) + dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType()); + + switch (osf.getTypeCode()) + { + case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break; + case 'B': realOutput.writeByte (field.getByte (obj)); break; + case 'S': realOutput.writeShort (field.getShort (obj)); break; + case 'C': realOutput.writeChar (field.getChar (obj)); break; + case 'I': realOutput.writeInt (field.getInt (obj)); break; + case 'F': realOutput.writeFloat (field.getFloat (obj)); break; + case 'J': realOutput.writeLong (field.getLong (obj)); break; + case 'D': realOutput.writeDouble (field.getDouble (obj)); break; + case 'L': + case '[': writeObject (field.get (obj)); break; + default: + throw new IOException("Unexpected type code " + osf.getTypeCode()); + } + } + } + + + // Toggles writing primitive data to block-data buffer. + // Package-private to avoid a trampoline constructor. + boolean setBlockDataMode(boolean on) throws IOException + { + if (on == writeDataAsBlocks) + return on; + + drain(); + boolean oldmode = writeDataAsBlocks; + writeDataAsBlocks = on; + + if (on) + dataOutput = blockDataOutput; + else + dataOutput = realOutput; + + return oldmode; + } + + + private void callWriteMethod(Object obj, ObjectStreamClass osc) + throws IOException + { + currentPutField = null; + try + { + Object args[] = {this}; + osc.writeObjectMethod.invoke(obj, args); + } + catch (InvocationTargetException x) + { + /* Rethrow if possible. */ + Throwable exception = x.getTargetException(); + if (exception instanceof RuntimeException) + throw (RuntimeException) exception; + if (exception instanceof IOException) + throw (IOException) exception; + + IOException ioe + = new IOException("Exception thrown from writeObject() on " + + osc.forClass().getName() + ": " + + exception.getClass().getName()); + ioe.initCause(exception); + throw ioe; + } + catch (Exception x) + { + IOException ioe + = new IOException("Failure invoking writeObject() on " + + osc.forClass().getName() + ": " + + x.getClass().getName()); + ioe.initCause(x); + throw ioe; + } + } + + private void dumpElementln (String msg, Object obj) + { + try + { + for (int i = 0; i < depth; i++) + System.out.print (" "); + System.out.print (Thread.currentThread() + ": "); + System.out.print (msg); + if (java.lang.reflect.Proxy.isProxyClass(obj.getClass())) + System.out.print (obj.getClass()); + else + System.out.print (obj); + } + catch (Exception _) + { + } + finally + { + System.out.println (); + } + } + + private void dumpElementln (String msg) + { + for (int i = 0; i < depth; i++) + System.out.print (" "); + System.out.print (Thread.currentThread() + ": "); + System.out.println(msg); + } + + // this value comes from 1.2 spec, but is used in 1.1 as well + private static final int BUFFER_SIZE = 1024; + + private static int defaultProtocolVersion = PROTOCOL_VERSION_2; + + private DataOutputStream dataOutput; + private boolean writeDataAsBlocks; + private DataOutputStream realOutput; + private DataOutputStream blockDataOutput; + private byte[] blockData; + private int blockDataCount; + private Object currentObject; + // Package-private to avoid a trampoline. + ObjectStreamClass currentObjectStreamClass; + private PutField currentPutField; + private boolean fieldsAlreadyWritten; + private boolean replacementEnabled; + private boolean isSerializing; + private int nextOID; + private ObjectIdentityMap2Int OIDLookupTable; + private int protocolVersion; + private boolean useSubclassMethod; + private SetAccessibleAction setAccessible = new SetAccessibleAction(); + + // The nesting depth for debugging output + private int depth = 0; + + // Set if we're generating debugging dumps + private boolean dump = false; + + private static final boolean DEBUG = false; +} -- cgit v1.2.3