//
// $Id: ObjectInStream.h,v 1.16 2007/03/06 20:42:19 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004-2007
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#if !defined(OBJECTINSTREAM_OL_GUARD)
#define OBJECTINSTREAM_OL_GUARD

#include <ObjectiveLib/LayeredInStream.h>

@class OLHashMap;
@class OLSharedPointerTable;

/**
 * @class OLObjectInStream ObjectInStream.h ObjectiveLib/ObjectInStream.h
 *
 * A stream that can read objects and classes. In addition to reading objects
 * and classes OLObjectInStream reads a tag of every type that OLObjectOutStream
 * has written to the stream. If a certain type is expected but another type
 * is found, then an exception is thrown indicating the inconsistency.
 *
 * @sa OLObjectOutStream
 *
 * @ingroup Streams
 */
@interface OLObjectInStream : OLLayeredInStream
{
@protected
    /**
     * The classes read by the stream
     */
    OLHashMap*              classes;

    /**
     * The shared pointers read by the stream
     */
    OLSharedPointerTable*   sharedPointers;

    /**
     * The system version read by the stream
     */
    uint32_t                systemVersion;
}

/**
 * Create and return a new object in stream. The stream is created with @a underStream
 * as the next stream below the new one in the stack of streams.
 *
 * @param underStream the stream from which to read
 * @return a reference to the newly created stream
 */
+ (id) streamWithInStream: (OLInStream*)underStream;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the stream. The stream is created with @a underStream
 * as the next stream below the new one in the stack of streams.
 *
 * @param underStream the stream from which to read
 * @return a reference to this stream
 */
- (id) initWithInStream: (OLInStream*)underStream;
#if !defined(OL_NO_OPENSTEP)
- (void) dealloc;
#endif
/* @} */

/**
 * Return the version of the given class name. If the class has been read
 * with the #readClass method, then the version of the class will be returned.
 *
 * @note The method #readClass is called whenever an object is read for which
 * the class of the object has not yet been read. Thus, reading an instance
 * of OLText will also cause #readClass for OLText to be called.
 *
 * @param className the name of the class that should be queried
 * @return the version of the class if the class has been read or UINT_MAX
 * otherwise
 */
- (unsigned) classVersion: (const char*)className;
#if defined(OL_NO_OPENSTEP)
- (void) freeStreamResources;
#endif
- (BOOL) readBool;

/**
 * Read a class. A class previously written by #OLObjectOutStream.writeClass: is read.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLClassNotFoundException if the class stored in the stream is not available
 * in the current runtime
 * @return the class
 */
- (Class) readClass;
- (double) readDouble;
- (float) readFloat;

/**
 * Read the object stream header. This method can be overridden to read a custom header
 * from the object stream. The message will be called in due course, so it is
 * @b never necessary to call this method.
 *
 * @note Subclasses that override this method should call the superclass' method
 * before reading any additional data.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 */
- (void) readHeader;
- (unsigned) readInt;
- (uint16_t) readInt16;
- (uint32_t) readInt32;
- (uint64_t) readInt64;

/**
 * Read an object. An object previously written by #OLObjectOutStream.writeObject: is read.
 *
 * @pre The object being read must implement either the OLStreamable protocol or the
 * NSCoding protocol. If both protocols are found, then the methods from OLStreamable
 * are given preference.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLClassNotFoundException if a class on which instantiating the object depends
 * cannot be found in the current runtime
 * @return the object
 */
- (id) readObject;

/**
 * Return the version of the system stored in the stream. The version of the @b ObjectiveLib
 * streaming system that is stored in the stream is returned.
 *
 * @return the stored system version
 */
- (unsigned) systemVersion;

#if !defined(OL_NO_OPENSTEP)
/**
 * @name NSCoder Support
 *
 * Support the streaming of objects that adopt the NSCoding protocol
 */
/* @{ */
- (void*) decodeBytesWithReturnedLength: (unsigned*)numBytes;
- (NSData*) decodeDataObject;

/**
 * Decode an object. This method mere forwards the message to #readObject, so there is
 * nothing to be gained by using this message over that one.
 *
 * @return the object read
 */
- (id) decodeObject;

/**
 * Decode a value of a specified Objective-C type. Read a value of an arbitrary type from
 * the stream. Note that in order to preserve platform-independence in the resulting
 * stream, constraints are placed on how the data are read. Types that otherwise have
 * indeterminate sizes will always be normalized to sizes chosen by @b ObjectiveLib. The
 * sizes read are as follows:
 * <table border=0>
 * <tr><td><b>Type</b></td><td><b>Size</b></td></tr>
 * <tr><td>char</td><td>1</td></tr>
 * <tr><td>short</td><td>2</td></tr>
 * <tr><td>int</td><td>4</td></tr>
 * <tr><td>long</td><td>4</td></tr>
 * <tr><td>long long</td><td>8</td></tr>
 * </table>
 *
 * Additionally, the behavior of returned pointers is different if the system is running
 * under GNUstep or under Cocoa. Under GNUstep freshly allocated pointers returned from
 * this method will be autoreleased, while under Cocoa the caller owns the pointer and
 * must release it. This is not my fault.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @exception OLClassNotFoundException if a class required by the request cannot be found
 * in the current runtime
 * @param valueType the type of the value at @a address
 * @param address the location of the value to read
 */
- (void) decodeValueOfObjCType: (const char*)valueType at: (void*)address;

/**
 * Return the version of a class stored in the stream. For the class named @a className
 * the version that was written to the stream is returned. This method is typically used
 * when a class is decoding an instance of itself to determine how the decoding
 * should be performed.
 *
 * @note If no class by the given name can be found in the runtime, then the value
 * NSNotFound is returned.
 *
 * @param className the name of the class
 * @return the version of the class
 */
- (unsigned) versionForClassName: (NSString*)className;
/* @} */
#endif

@end

#endif
