public Object ReadObject(ObjectDecoder decoder)
        {
            if (_firstObject)
            {
                int magic = ReadInt();
                if (magic != BinaryObjectEncoder.OBJECT_MAGIC)
                {
                    throw new ConnectorException("Bad magic number: " + magic);
                }
                int version = ReadInt();
                if (version != BinaryObjectEncoder.ENCODING_VERSION)
                {
                    throw new ConnectorException("Unexpected version: " + version);
                }
                _firstObject = false;
            }

            //if it's a top-level object, it's proceeded by a constant pool
            if (_readStateStack.Count == 0)
            {
                int size = ReadInt();
                for (int i = 0; i < size; i++)
                {
                    String constant = ReadString(false);
                    int code = ReadInt();
                    _constantPool[code] = constant;
                }
            }

            Type clazz = ReadClass();

            ReadState state = new ReadState();
            while (true)
            {
                byte type = ReadByte();
                if (type == BinaryObjectEncoder.FIELD_TYPE_END_OBJECT)
                {
                    break;
                }
                else if (type == BinaryObjectEncoder.FIELD_TYPE_ANONYMOUS_FIELD)
                {
                    byte[] bytes = ReadByteArray();
                    state.anonymousFields.Add(bytes);
                }
                else if (type == BinaryObjectEncoder.FIELD_TYPE_NAMED_FIELD)
                {
                    String fieldName = ReadString(true);
                    byte[] bytes = ReadByteArray();
                    state.objectFields[fieldName] = bytes;
                }
                else
                {
                    throw new ConnectorException("Unknown type: " + type);
                }
            }
            _readStateStack.Add(state);

            Object rv;
            if (clazz == null)
            {
                rv = null;
            }
            else
            {
                ObjectSerializationHandler handler =
                    ObjectSerializerRegistry.GetHandlerByObjectType(clazz);
                if (handler == null)
                {
                    //we may have special handlers for certain types of arrays
                    //if handler is null, treat like any other array
                    if (clazz.IsArray)
                    {
                        int length = GetNumAnonymousFields();
                        Array array = Array.CreateInstance(clazz.GetElementType(),
                                length);
                        for (int i = 0; i < length; i++)
                        {
                            StartAnonymousField(i);
                            Object element = ReadObject(decoder);
                            array.SetValue(element, i);
                        }
                        rv = array;
                    }
                    else
                    {
                        throw new ConnectorException("No deserializer for type: " + clazz);
                    }
                }
                else
                {
                    rv = handler.Deserialize(decoder);
                }
            }
            _readStateStack.RemoveAt(_readStateStack.Count - 1);
            return rv;
        }
        public bool StartField(String name)
        {
            ReadState readState = _readStateStack[_readStateStack.Count - 1];

            return(readState.StartField(name));
        }
        public int GetNumAnonymousFields()
        {
            ReadState readState = _readStateStack[_readStateStack.Count - 1];

            return(readState.anonymousFields.Count);
        }
        public void StartAnonymousField(int index)
        {
            ReadState readState = _readStateStack[_readStateStack.Count - 1];

            readState.StartAnonymousField(index);
        }
        public Object ReadObject(ObjectDecoder decoder)
        {
            if (_firstObject)
            {
                int magic = ReadInt();
                if (magic != BinaryObjectEncoder.OBJECT_MAGIC)
                {
                    throw new ConnectorException("Bad magic number: " + magic);
                }
                int version = ReadInt();
                if (version != BinaryObjectEncoder.ENCODING_VERSION)
                {
                    throw new ConnectorException("Unexpected version: " + version);
                }
                _firstObject = false;
            }

            //if it's a top-level object, it's proceeded by a constant pool
            if (_readStateStack.Count == 0)
            {
                int size = ReadInt();
                for (int i = 0; i < size; i++)
                {
                    String constant = ReadString(false);
                    int    code     = ReadInt();
                    _constantPool[code] = constant;
                }
            }

            Type clazz = ReadClass();

            ReadState state = new ReadState();

            while (true)
            {
                byte type = ReadByte();
                if (type == BinaryObjectEncoder.FIELD_TYPE_END_OBJECT)
                {
                    break;
                }
                else if (type == BinaryObjectEncoder.FIELD_TYPE_ANONYMOUS_FIELD)
                {
                    byte[] bytes = ReadByteArray();
                    state.anonymousFields.Add(bytes);
                }
                else if (type == BinaryObjectEncoder.FIELD_TYPE_NAMED_FIELD)
                {
                    String fieldName = ReadString(true);
                    byte[] bytes     = ReadByteArray();
                    state.objectFields[fieldName] = bytes;
                }
                else
                {
                    throw new ConnectorException("Unknown type: " + type);
                }
            }
            _readStateStack.Add(state);

            Object rv;

            if (clazz == null)
            {
                rv = null;
            }
            else
            {
                ObjectSerializationHandler handler =
                    ObjectSerializerRegistry.GetHandlerByObjectType(clazz);
                if (handler == null)
                {
                    //we may have special handlers for certain types of arrays
                    //if handler is null, treat like any other array
                    if (clazz.IsArray)
                    {
                        int   length = GetNumAnonymousFields();
                        Array array  = Array.CreateInstance(clazz.GetElementType(),
                                                            length);
                        for (int i = 0; i < length; i++)
                        {
                            StartAnonymousField(i);
                            Object element = ReadObject(decoder);
                            array.SetValue(element, i);
                        }
                        rv = array;
                    }
                    else
                    {
                        throw new ConnectorException("No deserializer for type: " + clazz);
                    }
                }
                else
                {
                    rv = handler.Deserialize(decoder);
                }
            }
            _readStateStack.RemoveAt(_readStateStack.Count - 1);
            return(rv);
        }