//
// $Id: InStream.h,v 1.11 2005/07/12 19:15:37 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * 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

#import <ObjectiveLib/Memory.h>
#import <Foundation/NSCoder.h>

@class NSData;

extern NSString* const OLInputOutputException;
extern NSString* const OLEndOfStreamException;

/**
 * @class OLInStream InStream.h ObjectiveLib/InStream.h
 *
 * Base class for reading data. OLInStream provides the basic stream services
 * which include reading primitive data types, strings encoded with UTF-8 and
 * 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.
 *
 * @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
 */
@interface OLInStream : NSCoder
{
@protected
    /**
     * The memory allocator used by the stream
     */
    OLAllocator* allocator;
}

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the stream. The stream is initialized for reading with the default
 * memory allocator.
 *
 * @return a reference to this stream
 */
- (id) init;

/**
 * Initialize the stream. The stream is initialized for reading with the given
 * memory allocator, @a alloc.
 *
 * @pre The memory allocator @a alloc must support autorelease.
 *
 * @exception NSInvalidArgumentException if @a alloc does not support autorelease
 * @return a reference to this stream
 */
- (id) initWithAllocator: (OLAllocator*)alloc;

/**
 * Finalize the stream and deallocate any allocated memory.
 */
- (void) dealloc;
/* @} */

/**
 * 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 string. The value is read as if it had been written by OLOutStream#writeStringAsUTF8:.
 * Specifically, a field of bytes is read and assumed to be encoded with the UTF-8
 * encoding. A NSString object is created and returned. The returned string will be
 * autoreleased before being returned.
 *
 * @exception OLInputOutputException if the value could not be read
 * @exception OLEndOfStreamException if the end of the stream has been reached
 * @return the string read
 */
- (NSString*) readStringAsUTF8;

/**
 * @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 using the memory allocator in use by this stream.
 *
 * @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;
/* @} */

@end

#endif
