/* * Copyright (C) 2004, 2005 Joe Walnes. * Copyright (C) 2006, 2007 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * * Created on 23. August 2004 by Joe Walnes */ package com.thoughtworks.xstream.core.util; import java.io.IOException; import java.io.InvalidObjectException; import java.io.NotActiveException; import java.io.ObjectInputStream; import java.io.ObjectInputValidation; import java.io.ObjectStreamClass; import java.io.StreamCorruptedException; import java.util.Map; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.DataHolder; public class CustomObjectInputStream extends ObjectInputStream { private FastStack callbacks = new FastStack(1); private static final String DATA_HOLDER_KEY = CustomObjectInputStream.class.getName(); public static interface StreamCallback { Object readFromStream() throws IOException; Map readFieldsFromStream() throws IOException; void defaultReadObject() throws IOException; void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException, InvalidObjectException; void close() throws IOException; } public static synchronized CustomObjectInputStream getInstance(DataHolder whereFrom, CustomObjectInputStream.StreamCallback callback) { try { CustomObjectInputStream result = (CustomObjectInputStream) whereFrom.get(DATA_HOLDER_KEY); if (result == null) { result = new CustomObjectInputStream(callback); whereFrom.put(DATA_HOLDER_KEY, result); } else { result.pushCallback(callback); } return result; } catch (IOException e) { throw new ConversionException("Cannot create CustomObjectStream", e); } } /** * Warning, this object is expensive to create (due to functionality inherited from superclass). * Use the static fetch() method instead, wherever possible. * * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectInputStream.StreamCallback) */ public CustomObjectInputStream(StreamCallback callback) throws IOException, SecurityException { super(); this.callbacks.push(callback); } /** * Allows the CustomObjectInputStream (which is expensive to create) to be reused. */ public void pushCallback(StreamCallback callback) { this.callbacks.push(callback); } public StreamCallback popCallback(){ return (StreamCallback) this.callbacks.pop(); } public StreamCallback peekCallback(){ return (StreamCallback) this.callbacks.peek(); } public void defaultReadObject() throws IOException { peekCallback().defaultReadObject(); } protected Object readObjectOverride() throws IOException { return peekCallback().readFromStream(); } public Object readUnshared() throws IOException, ClassNotFoundException { return readObject(); } public boolean readBoolean() throws IOException { return ((Boolean)peekCallback().readFromStream()).booleanValue(); } public byte readByte() throws IOException { return ((Byte)peekCallback().readFromStream()).byteValue(); } public int readUnsignedByte() throws IOException { int b = ((Byte)peekCallback().readFromStream()).byteValue(); if (b < 0) { b += Byte.MAX_VALUE; } return b; } public int readInt() throws IOException { return ((Integer)peekCallback().readFromStream()).intValue(); } public char readChar() throws IOException { return ((Character)peekCallback().readFromStream()).charValue(); } public float readFloat() throws IOException { return ((Float)peekCallback().readFromStream()).floatValue(); } public double readDouble() throws IOException { return ((Double)peekCallback().readFromStream()).doubleValue(); } public long readLong() throws IOException { return ((Long)peekCallback().readFromStream()).longValue(); } public short readShort() throws IOException { return ((Short)peekCallback().readFromStream()).shortValue(); } public int readUnsignedShort() throws IOException { int b = ((Short)peekCallback().readFromStream()).shortValue(); if (b < 0) { b += Short.MAX_VALUE; } return b; } public String readUTF() throws IOException { return (String)peekCallback().readFromStream(); } public void readFully(byte[] buf) throws IOException { readFully(buf, 0, buf.length); } public void readFully(byte[] buf, int off, int len) throws IOException { byte[] b = (byte[])peekCallback().readFromStream(); System.arraycopy(b, 0, buf, off, len); } public int read() throws IOException { return readUnsignedByte(); } public int read(byte[] buf, int off, int len) throws IOException { byte[] b = (byte[])peekCallback().readFromStream(); if (b.length != len) { throw new StreamCorruptedException("Expected " + len + " bytes from stream, got " + b.length); } System.arraycopy(b, 0, buf, off, len); return len; } public int read(byte b[]) throws IOException { return read(b, 0, b.length); } public GetField readFields() throws IOException { return new CustomGetField(peekCallback().readFieldsFromStream()); } private class CustomGetField extends GetField { private Map fields; public CustomGetField(Map fields) { this.fields = fields; } public ObjectStreamClass getObjectStreamClass() { throw new UnsupportedOperationException(); } private Object get(String name) { return fields.get(name); } public boolean defaulted(String name) { return !fields.containsKey(name); } public byte get(String name, byte val) { return defaulted(name) ? val : ((Byte)get(name)).byteValue(); } public char get(String name, char val) { return defaulted(name) ? val : ((Character)get(name)).charValue(); } public double get(String name, double val) { return defaulted(name) ? val : ((Double)get(name)).doubleValue(); } public float get(String name, float val) { return defaulted(name) ? val : ((Float)get(name)).floatValue(); } public int get(String name, int val) { return defaulted(name) ? val : ((Integer)get(name)).intValue(); } public long get(String name, long val) { return defaulted(name) ? val : ((Long)get(name)).longValue(); } public short get(String name, short val) { return defaulted(name) ? val : ((Short)get(name)).shortValue(); } public boolean get(String name, boolean val) { return defaulted(name) ? val : ((Boolean)get(name)).booleanValue(); } public Object get(String name, Object val) { return defaulted(name) ? val : get(name); } } public void registerValidation(ObjectInputValidation validation, int priority) throws NotActiveException, InvalidObjectException { peekCallback().registerValidation(validation, priority); } public void close() throws IOException { peekCallback().close(); } /****** Unsupported methods ******/ public int available() { throw new UnsupportedOperationException(); } public String readLine() { throw new UnsupportedOperationException(); } public int skipBytes(int len) { throw new UnsupportedOperationException(); } public long skip(long n) { throw new UnsupportedOperationException(); } public void mark(int readlimit) { throw new UnsupportedOperationException(); } public void reset() { throw new UnsupportedOperationException(); } public boolean markSupported() { return false; } }