public void defaultReadObject() {
            if (_value._currentCoder == null || _value._currentObject == null) {
                throw new ConversionException("not in call to readObject");
            }
            _value._currentCoder.renderDefaultFields(_value, _value._currentObject);
        }

    }

    public OldValueInputStream oldValueInputStream(ObjectStreamClass classDescriptor) throws IOException {
        return new OldValueInputStream(this, classDescriptor);
    }

    public OldValueOutputStream oldValueOutputStream(ObjectStreamClass classDescriptor) throws IOException {
        return new OldValueOutputStream(this, classDescriptor);
    }

    /**
     * An ObjectOutputStream that reads bytes from this Value using standard
     * Java serialization. If constructed with a non-null ObjectStreamClass,
     * then readStreamHeader and readClassDescriptor are overridden to read
     * nothing because the SerialValueCoder will already have access to the
     * necessary information.
     */
    public static class OldValueInputStream extends ObjectInputStream {
        Value _value;
        boolean _innerClassDescriptor;
        int _mark = -1;
        ObjectStreamClass _classDescriptor;

        private OldValueInputStream(final Value value, ObjectStreamClass classDescriptor) throws IOException {
            this(value);
            if (classDescriptor == null) {
                throw new ConversionException("Null class descriptor");
            }
            _value = value;
            _classDescriptor = classDescriptor;
        }

        private OldValueInputStream(final Value value) throws IOException {
            super(new InputStream() {
                public int read() {
                    if (value._next < value._end) {
                        return value._bytes[value._next++] & 0xFF;
                    } else {
                        return -1;
                    }
                }

                public int read(byte[] bytes) {
                    return read(bytes, 0, bytes.length);
                }

                public int read(byte[] bytes, int offset, int size) {
                    if (value._next + size > value._end) {
                        size = value._end - value._next;
                    }
                    if (size <= 0) {
                        size = -1;
                    } else {
                        System.arraycopy(value._bytes, value._next, bytes, offset, size);

                        value._next += size;
                    }
                    return size;
                }

                public long skip(long lsize) {
                    int size = lsize > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) lsize;
                    if (size < 0)
                        return 0;
                    if (value._next + size > value._end) {
                        size = value._end - value._next;
                    }
                    if (size < 0)
                        return 0;
                    value._next += size;
                    return size;
                }

                public int available() {
                    int available = value._end - value._next;
                    return available > 0 ? available : 0;
                }

            });
            _value = value;
        }

        protected final ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
            if (_classDescriptor == null) {
                return super.readClassDescriptor();
            } else if (_innerClassDescriptor) {
                int handle = readInt();
                ClassInfo classInfo = _value.classInfoForHandle(handle);
                ObjectStreamClass classDescriptor = null;
                if (classInfo != null) {
                    classDescriptor = classInfo.getClassDescriptor();
                }
                if (classDescriptor == null) {
                    throw new ConversionException("Unknown class handle " + handle);
                }
                return classDescriptor;
            } else {
                _innerClassDescriptor = true;
                return _classDescriptor;
            }
        }

        protected final void readStreamHeader() throws IOException {
            if (_classDescriptor == null)
                super.readStreamHeader();
        }

        public void mark(int readLimit) {
            _mark = _value._next;
        }

        public void reset() throws IOException {
            if (_mark < 0) {
                throw new IOException("No mark");
            } else {
                _value._next = _mark;
            }
        }

        public boolean markSupported() {
            return true;
        }

        /**
         * Override the default implementation because we want to use the
         * application's ClassLoader, not necessarily the bootstrap loader.
         */
        protected Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
            String name = desc.getName();
            return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
        }
    }

    /**
     * An ObjectOutputStream that writes bytes into this Value using standard
     * Java serialization. If constructed with a non-null ObjectStreamClass,
     * then writeStreamHeader and writeClassDescriptor are overridden to write
     * nothing because the SerialValueCoder will already have access to the
     * necessary information.
     */
    static class OldValueOutputStream extends ObjectOutputStream {
        Value _value;
        ObjectStreamClass _classDescriptor;
        boolean _innerClassDescriptor;

        OldValueOutputStream(final Value value, ObjectStreamClass classDescriptor) throws IOException {
            this(value);
            if (classDescriptor == null) {
                throw new ConversionException("Null class descriptor");
            }
            _classDescriptor = classDescriptor;
        }

        private OldValueOutputStream(final Value value) throws IOException {
            super(new OutputStream() {
                public void write(int b) {
                    value.ensureFit(1);
                    value._bytes[value._size++] = (byte) b;
                }

                public void write(byte[] bytes) {
                    write(bytes, 0, bytes.length);
                }

                public void write(byte[] bytes, int offset, int size) {
                    value.ensureFit(size);
                    System.arraycopy(bytes, offset, value._bytes, value._size, size);
                    value._size += size;
                }
            });
            _value = value;
        }

        protected final void writeClassDescriptor(ObjectStreamClass classDescriptor) throws IOException {
            if (_classDescriptor == null) {
                super.writeClassDescriptor(classDescriptor);
            } else if (_innerClassDescriptor) {
                Class<?> clazz = classDescriptor.forClass();
                int handle = _value.handleForIndexedClass(clazz);
                writeInt(handle);
            } else {
                _innerClassDescriptor = true;
            }
        }

        protected final void writeStreamHeader() throws IOException {
            if (_classDescriptor == null)
                super.writeStreamHeader();
        }
    }

    DefaultValueCoder getCurrentCoder() {
        return _currentCoder;
    }

    Object getCurrentObject() {
        return _currentObject;
    }

    void setCurrentCoder(DefaultValueCoder coder) {
        _currentCoder = coder;
    }

    void setCurrentObject(Object object) {
        _currentObject = object;
    }

    private ValueCache getValueCache() {
        if (_valueCache == null && _valueCacheWeakRef != null) {
            _valueCache = _valueCacheWeakRef.get();
        }
        if (_valueCache == null) {
            _valueCache = new ValueCache();
            _valueCacheWeakRef = new WeakReference<ValueCache>(_valueCache);
        }
        return _valueCache;
    }

    private void releaseValueCache() {
        _serializedItemCount = 0;
        if (_valueCache != null) {
            _valueCache.clear();
            // Clear the hard reference.
            _valueCache = null;
        }
    }

    /**
     * Holds a collection of Object values associated with their position within
     * the serialized Value. Used only during get and put operations so that
     * reference graphs with cycles can be encoded and decoded properly. A
     * Persistit instance has a collection of ValueCache objects that get() and
     * put() operations allocate and relinquish when done.
     */
    static class ValueCache {
        private final static int INITIAL_SIZE = 256;

        /**
         * handle -> Object
         */
        Object[] _array = new Object[INITIAL_SIZE];

        int _handleCount = 0;

        ValueCache() {
            clear();
        }

        /**
         * Look up the handle for an Object that has already been stored in this
         * Value.
         * 
         * @param object
         * @return The handle, or -1 if the object has not been stored yet.
         */
        int lookup(Object object) {
            for (int index = _handleCount; --index >= 0;) {
                if (_array[index] == object) {
                    return index;
                }
            }
            return -1;
        }

        /**
         * Get the object stored with the supplied handle value.
         * 
         * @param handle
         * @return The object
         */
        Object get(int handle) {
            return _array[handle];
        }

        /**
         * Record the association between the supplied handle and object values.
         * Subsequent lookup and get operations will then be able to find this
         * object or fetch it by handle.
         * 
         * @param handle
         * @param object
         * @return previous handle, or -1 if none
         */
        void store(int handle, Object object) {
            if (handle >= _array.length)
                grow(1 + handle * 2);
            if (handle >= _handleCount) {
                _handleCount = handle + +1;
            }
            _array[handle] = object;
        }

        int put(int handle, Object object) {
            int previous = lookup(object);
            if (previous != -1) {
                return previous;
            }
            store(handle, object);
            return -1;
        }

        /**
         * Enlarges the backing arrays to support more objects
         */
        void grow(int newSize) {
            Object[] temp = _array;
            _array = new Object[newSize];
            System.arraycopy(temp, 0, _array, 0, temp.length);
        }

        /**
         * Clears all object/handle associations.
         */
        void clear() {
            for (int index = _handleCount; --index >= 0;) {
                _array[index] = null;
            }
            _handleCount = 0;
        }
    }

    private static class DisplayMarker {
        int _start;

        DisplayMarker(int start) {
            _start = start;
        }

        public String toString() {
            return "@" + Integer.toString(_start);
        }
    }

    static class Version {
        private final long _versionHandle;
        private final long _commitTimestamp;
        private final Value _value;

        private Version(long versionHandle, long commitTimestamp, Value value) {
            _versionHandle = versionHandle;
            _commitTimestamp = commitTimestamp;
            _value = value;
        }

        /**
         * @return the versionHandle
         */
        public long getVersionHandle() {
            return _versionHandle;
        }

        /**
         * @return the commitTimestamp
         */
        public long getCommitTimestamp() {
            return _commitTimestamp;
        }

        /**
         * @return the value
         */
        public Value getValue() {
            return _value;
        }

        public long getStartTimestamp() {
            return TransactionIndex.vh2ts(_versionHandle);
        }

        public int getStep() {
            return TransactionIndex.vh2step(_versionHandle);
        }

        public String toString() {
            try {
                StringBuilder sb = new StringBuilder();
                sb.append(String.format("%,d", getStartTimestamp()));
                if (getStep() > 0) {
                    sb.append(String.format("#%02d", getStep()));
                }
                sb.append("<" + TransactionStatus.tcString(_commitTimestamp) + ">");
                sb.append(":");
                sb.append(_value);
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
                return e.toString();
            }
        }
    }

    /**
     * Construct a list of <code>Version</code> objects, each denoting one of
     * the multi-value versions currently held in this Value object.
     * 
     * @return the list of <code>Version<code>s
     * @throws PersistitException
     */
    List<Version> unpackMvvVersions() throws PersistitException {
        final List<Version> versions = new ArrayList<Version>();
        MVV.VersionVisitor visitor = new MVV.VersionVisitor() {

            @Override
            public void sawVersion(long version, int valueOffset, int valueLength) {
                long tc = -1;

                try {
                    tc = _persistit.getTransactionIndex().commitStatus(version, TransactionStatus.UNCOMMITTED, 0);
                } catch (Exception e) {
                    tc = -1;
                }
                Value value = new Value(_persistit);
                value.ensureFit(valueLength);
                System.arraycopy(_bytes, valueOffset, value.getEncodedBytes(), 0, valueLength);
                value.setEncodedSize(valueLength);
                value.trim();
                versions.add(new Version(version, tc, value));
            }

            @Override
            public void init() throws PersistitException {

            }
        };
        MVV.visitAllVersions(visitor, getEncodedBytes(), 0, getEncodedSize());
        return versions;
    }

    private void putCharSequenceInternal(CharSequence string) {
        int length = string.length();
        ensureFit(length + 1);
        final int saveSize = _size;
        int index = _size;
        _bytes[index++] = (byte) CLASS_STRING;

        int maxLength = _bytes.length;

        for (int i = 0; i < length; i++) {
            char c = string.charAt(i);

            if (c <= 0x007F) {
                if (index + 1 > maxLength) {
                    _size = index;
                    ensureFit(index + 1 + (length - i) * 2);
                    maxLength = _bytes.length;
                }
                _bytes[index++] = (byte) c;
            } else if (c > 0x07FF) {
                if (index + 3 > maxLength) {
                    _size = index;
                    ensureFit(index + 3 + (length - i) * 2);
                    maxLength = _bytes.length;
                }
                _bytes[index++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                _bytes[index++] = (byte) (0x80 | ((c >> 6) & 0x3F));
                _bytes[index++] = (byte) (0x80 | ((c >> 0) & 0x3F));
            } else {
                if (index + 2 > maxLength) {
                    _size = index;
                    ensureFit(index + 2 + (length - i) * 2);
                    maxLength = _bytes.length;
                }
                _bytes[index++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
                _bytes[index++] = (byte) (0x80 | ((c >> 0) & 0x3F));
            }
        }