//
// $Id: InStream.h,v 1.19 2007/03/08 19:59:21 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(INSTREAM_OL_GUARD)
#define INSTREAM_OL_GUARD

#include <ObjectiveLib/Config.h>
#if defined(OL_NO_OPENSTEP)
#include <ObjectiveLib/ReferenceCountedStream.h>
#if defined(OL_HAVE_INTTYPES_H)
#include <inttypes.h>
#else
#include <stdint.h>
#endif
#else
#include <ObjectiveLib/ObjectBase.h>
#if defined(OL_GENERATING_DOCUMENTATION)
#include <Foundation/NSCoder.h>
#else
#import <Foundation/NSCoder.h>
#endif

@class NSData;
#endif

@class OLText;

/**
 * @class OLInStream InStream.h ObjectiveLib/InStream.h
 *
 * Base class for reading data. OLInStream provides the basic stream services
 * which include reading primitive data types and the
 * services of NSCoder. The NSCoder services are provided in order to allow
 * objects which already support the NSCoding protocol to read themselves
 * through an instance of OLObjectInStream. The lower-level methods provided
 * by OLInStream are preferred for new code. Obviously, the NSCoder support is
 * only available if @b ObjectiveLib was built with OpenStep support.
 *
 * @note Object instances and classes cannot be read using OLInStream. An instance
 * of OLObjectInStream must be used instead. The NSCoder support provided in
 * OLInStream is merely a byproduct of the class hierarchy imposed by NSCoder.
 *
 * @ingroup Streams
 */
#if defined(OL_NO_OPENSTEP)
@interface OLInStream : OLReferenceCountedStream
#else
@interface OLInStream : NSCoder
#endif
{
}

/**
 * Close the stream. After receiving this message the stream will no long
 * be available for reading.
 *
 * @exception OLInputOutputException if there is an error closing the stream
 */
- (void) close;

/**
 * Read a boolean value from the stream. The value is read as if it had been written
 * by OLOutStream#writeBool:. Specifically, one byte of data is read and YES is returned
 * if that byte is non-zero, otherwise NO is returned.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (BOOL) readBool;

/**
 * Read a byte from the stream. The default implementation of this method is to
 * call #readBytes:count:, so subclasses that can optimize reading one byte
 * should do so.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the byte read
 */
- (uint8_t) readByte;

/**
 * Read a sequence of bytes from the stream. This is the fundamental method for reading
 * from a stream, and subclasses must override this method. The number of bytes read
 * is returned except in the case where the end of the stream has been reached. Rather
 * than raising an exception in this case, this method returns UINT_MAX.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @param buffer the address to which the bytes should be read
 * @param max the maximum number bytes that should be read
 * @return the number of bytes read or UINT_MAX if no bytes could be read
 */
- (unsigned) readBytes: (uint8_t*)buffer count: (unsigned)max;

/**
 * Read a double value from the stream. The value is read as if it had been written
 * by OLOutStream#writeDouble:. Specifically, an 8-byte field of data is read and
 * converted from network byte order to host byte order.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (double) readDouble;

/**
 * Read a float value from the stream. The value is read as if it had been written
 * by OLOutStream#writeFloat:. Specifically, an 4-byte field of data is read and
 * converted from network byte order to host byte order.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (float) readFloat;

/**
 * Read an integer value from the stream. The value is read as if it had been written
 * by OLOutStream#writeInt:. Specifically, an 4-byte field of data is read and
 * converted from network byte order to host byte order.
 *
 * @note Regardless of the size of the type @c int on the platform being used, the value
 * read will always be exactly four bytes long and returned as an @c unsigned value.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (unsigned) readInt;

/**
 * Read a 16-bit integer value from the stream. The value is read as if it had been written
 * by OLOutStream#writeInt16:. Specifically, an 2-byte field of data is read and
 * converted from network byte order to host byte order.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (uint16_t) readInt16;

/**
 * Read a 32-bit integer value from the stream. The value is read as if it had been written
 * by OLOutStream#writeInt32:. Specifically, an 4-byte field of data is read and
 * converted from network byte order to host byte order.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (uint32_t) readInt32;

/**
 * Read a 64-bit integer value from the stream. The value is read as if it had been written
 * by OLOutStream#writeInt64:. Specifically, an 8-byte field of data is read and
 * converted from network byte order to host byte order.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the value read
 */
- (uint64_t) readInt64;

/**
 * Read a selector from the stream. The value is read as if it had been written by
 * OLOutStream#writeSelector:.
 *
 * @exception OLInputOutputException if the selector could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the selector read
 */
- (SEL) readSelector;

#if !defined(OL_NO_OPENSTEP)
/**
 * @name NSCoder Support
 *
 * Support the streaming of objects that adopt the NSCoding protocol
 */
/* @{ */
/**
 * Returns whether the stream supports keyed coding. No stream classes in @b ObjectiveLib
 * support keyed coding, so this method will always return NO.
 *
 * @return NO, always
 */
- (BOOL) allowsKeyedCoding;

/**
 * Decode a buffer of data. This method is included solely to support objects that already
 * support the NSCoding protocol, and relies on the lower-level message #readBytes:count:.
 * This message can be used to read data written by OLOutStream#encodeBytes:length:,
 * however there is nothing to be gained by using this pair of messages over the preferred
 * pair OLOutStream#writeBytes:count: and #readBytes:count:.
 *
 * The returned pointer will be autoreleased before being returned and the value at the
 * address @a numBytes will contain the number of bytes actually read.
 * 
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @param numBytes the number of bytes read
 * @return a pointer to the bytes read
 */
- (void*) decodeBytesWithReturnedLength: (unsigned*)numBytes;

/**
 * Decode a data object. This method is included solely to support objects that already
 * support the NSCoding protocol, and relies on the lower-level message #readBytes:count:.
 * This message can be used to read data written by OLOutStream#encodeDataObject:,
 * however there is nothing to be gained by using this pair of messages over the preferred
 * pair OLOutStream#writeBytes:count: and #readBytes:count:.
 *
 * The returned data object will be autoreleased before being returned.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the read data object
 */
- (NSData*) decodeDataObject;

/**
 * Decode an object. This method is not implemented in OLInStream. In order to read object
 * instances from a stream one must use the layered stream class OLObjectInStream.
 *
 * @return the object instance that this class failed to 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.
 *
 * @note Object instances and classes cannot be read using OLInStream's implementation
 * of this method. OLObjectInStream must be used.
 *
 * @exception OLInputOutputException if there is an error reading from the stream
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @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;
/* @} */
#endif

@end

#endif
