/*
 * LWSDK Header File
 * Copyright 1999, NewTek, Inc.
 *
 * LWIO.H -- LightWave Save and Load State
 *
 * This header contains the definition of the structures needed to
 * perform I/O from a LightWave server.
 */
#ifndef LWSDK_IO_H
#define LWSDK_IO_H

#include <lwtypes.h>


/*
 * Data may be loaded and saved in binary or text files.  Text files
 * are often scene files, and binary files are often object files.
 *
 * In BINARY mode, the external form contains raw bytes having any
 * value from 0 to 255.  Reads and writes are entirely based on the
 * number of bytes requested.
 *
 * In ASCII mode, all data bytes must be in the extended ASCII range
 * of 32 to 255.  Values outside this range are ignored or undefined.
 */
#define LWIO_BINARY	 0
#define LWIO_ASCII	 1
#define LWIO_OBJECT	 LWIO_BINARY
#define LWIO_SCENE	 LWIO_ASCII


/*
 * Blocks of data can be marked with identifiers.  In BINARY mode the
 * four-byte ID code is used, and in ASCII mode the string token (which
 * should not contain spaces) is used.
 */
typedef struct st_LWBlockIdent {
	LWID		 id;
	const char	*token;
} LWBlockIdent;


/*
 * This structure is used when the server is writing its state to
 * the external store.  The 'writeData' is the first argument to all
 * the callback functions.
 *
 * write	execute a raw write to the store.  In BINARY mode, the
 *		number of bytes indicated by 'len' is written directly to 
 *		the output.  In ASCII mode the input buffer is treated as 
 *		a null-terminated string and the length is computed from 
 *		that.  The string is written with a newline at the end.
 *
 * writeI1	write an array of different sized and typed integers to
 * writeI2	the store.  In BINARY mode the 'n' numbers are written as
 * writeI4	1, 2 or 4 btype elements in "big-endian" (Motorola) 
 * writeU1	format.  In ASCII mode, all 'n' numbers are written to a 
 * writeU2	single line, the signed values in decimal and the unsigned 
 * writeU4	values in hexadecimal.  A newline is written after the 
 *		list of numbers unless the writing is done inside a leaf
 *		block.
 *
 * writeStr	write a null-terminated string to the store.  In ASCII
 *		mode the string may be contained in double quotes.
 *
 * writeID	write an identifier token to the store.  In BINARY mode
 *		this is the four-byte ID code, while in ASCII mode this
 *		is the string token.
 *
 * beginBlk	start a nested data block.  The block is identified by
 *		the ID codes defined in the LWBlockIdent, and the 'leaf'
 *		flag is true if this block will not contain other blocks.
 *
 * endBlk	end the current data block.
 *
 * depth	return the current block nesting level, where zero means
 *		we've entered no blocks.
 */
typedef struct st_LWSaveState {
	int		  ioMode;
	void		 *writeData;
	void		(*write)    (void *data, const char  *, int length);

	void		(*writeI1)  (void *data, const char  *, int n);
	void		(*writeI2)  (void *data, const short *, int n);
	void		(*writeI4)  (void *data, const int   *, int n);
	void		(*writeU1)  (void *data, const unsigned char  *, int n);
	void		(*writeU2)  (void *data, const unsigned short *, int n);
	void		(*writeU4)  (void *data, const unsigned int   *, int n);
	void		(*writeFP)  (void *data, const float *, int n);
	void		(*writeStr) (void *data, const char  *);
	void		(*writeID)  (void *data, const LWBlockIdent *);

	void		(*beginBlk) (void *data, const LWBlockIdent *, int leaf);
	void		(*endBlk)   (void *data);
	int		    (*depth)    (void *data);
	void		(*writeDP)  (void *data, const double *, int n);
} LWSaveState;


/*
 * This structure is used when the server is reading its state from
 * the external store.  The 'readData' is the first argument to all
 * the callback functions.
 *
 * read		execute a raw read of the store.  In binary mode, 'len'
 *		bytes are read directly from the store.  In ASCII mode,	up 
 *		to 'len' bytes of the current line are read from the 
 *		store, perhaps leaving more bytes to be read later.  The
 *		return value is the number of bytes read on the current
 *		line (which may be zero), or -1 for end of data.
 *
 * readI1	read an array of integers of various types and formats,
 * readI2	returning the number of integers successfully read.  In
 * readI4	BINARY mode a sequence of 'n' single, double or quad bytes
 * readU1	are read from the stream and interpreted as "big-endian"
 * readU2	(Motorola) format words.  In ASCII mode, the numbers are
 * readU4	read from the current line, in decimal for signed values 
 *		and in hexadecimal for unsigned values.
 *
 * readFP	read an array of floating point numbers from the store.
 *		The return value is the number of values read.
 *
 * readStr	read a string from the store.  In ASCII mode double quotes
 *		will be removed.
 *
 * readID	read an identifier token from the store.  In BINARY this is
 *		just a four-byte code value, but in ASCII this in the string
 *		token which will be matched with its longword code.
 *
 * findBlk	read ahead looking for the next block.  The array of block
 *		identifiers includes all the blocks that could be expected
 *		and is terminated with a null ID code.  If a reconginized
 *		block is found in the file, it's ID code is returned.  A
 *		zero return indicates no more valid blocks.
 *
 * endBlk	complete reading the current open block.
 *
 * depth	return the current block nesting level, where zero means
 *		we've entered no blocks.
 */
typedef struct st_LWLoadState {
	int	      ioMode;
	void	 *readData;
	int		(*read)    (void *data, char  *, int length);

	int		(*readI1)  (void *data, char  *, int n);
	int		(*readI2)  (void *data, short *, int n);
	int		(*readI4)  (void *data, int  *, int n);
	int		(*readU1)  (void *data, unsigned char  *, int n);
	int		(*readU2)  (void *data, unsigned short *, int n);
	int		(*readU4)  (void *data, unsigned int   *, int n);
	int		(*readFP)  (void *data, float *, int n);
	int		(*readStr) (void *data, char  *, int max);
	LWID	(*readID)  (void *data, const LWBlockIdent *);

	LWID	(*findBlk) (void *data, const LWBlockIdent *);
	void	(*endBlk)  (void *data);
	int		(*depth)   (void *data);
	int		(*readDP)  (void *data, double *, int n);
} LWLoadState;


/*
 * Macros make the call format easier to write.
 */
#define LWSAVE_I1(lwss,p,n)	(*(lwss)->writeI1)((lwss)->writeData,p,n)
#define LWSAVE_I2(lwss,p,n)	(*(lwss)->writeI2)((lwss)->writeData,p,n)
#define LWSAVE_I4(lwss,p,n)	(*(lwss)->writeI4)((lwss)->writeData,p,n)
#define LWSAVE_U1(lwss,p,n)	(*(lwss)->writeU1)((lwss)->writeData,p,n)
#define LWSAVE_U2(lwss,p,n)	(*(lwss)->writeU2)((lwss)->writeData,p,n)
#define LWSAVE_U4(lwss,p,n)	(*(lwss)->writeU4)((lwss)->writeData,p,n)
#define LWSAVE_FP(lwss,p,n)	(*(lwss)->writeFP)((lwss)->writeData,p,n)
#define LWSAVE_STR(lwss,p)	(*(lwss)->writeStr)((lwss)->writeData,p)
#define LWSAVE_ID(lwss,b)	(*(lwss)->writeID)((lwss)->writeData,b)
#define LWSAVE_BEGIN(lwss,b,l)	(*(lwss)->beginBlk)((lwss)->writeData,b,l)
#define LWSAVE_END(lwss)	(*(lwss)->endBlk)((lwss)->writeData)
#define LWSAVE_DEPTH(lwss)	(*(lwss)->depth)((lwss)->writeData)
#define LWSAVE_DP(lwss,p,n)	(*(lwss)->writeDP)((lwss)->writeData,p,n)

#define LWLOAD_I1(lwls,p,n)	(*(lwls)->readI1)((lwls)->readData,p,n)
#define LWLOAD_I2(lwls,p,n)	(*(lwls)->readI2)((lwls)->readData,p,n)
#define LWLOAD_I4(lwls,p,n)	(*(lwls)->readI4)((lwls)->readData,p,n)
#define LWLOAD_U1(lwls,p,n)	(*(lwls)->readU1)((lwls)->readData,p,n)
#define LWLOAD_U2(lwls,p,n)	(*(lwls)->readU2)((lwls)->readData,p,n)
#define LWLOAD_U4(lwls,p,n)	(*(lwls)->readU4)((lwls)->readData,p,n)
#define LWLOAD_FP(lwls,p,n)	(*(lwls)->readFP)((lwls)->readData,p,n)
#define LWLOAD_STR(lwls,p,n)	(*(lwls)->readStr)((lwls)->readData,p,n)
#define LWLOAD_ID(lwls,b)	(*(lwls)->readID)((lwls)->readData,b)
#define LWLOAD_FIND(lwls,b)	(*(lwls)->findBlk)((lwls)->readData,b)
#define LWLOAD_END(lwls)	(*(lwls)->endBlk)((lwls)->readData)
#define LWLOAD_DEPTH(lwls)	(*(lwls)->depth)((lwls)->readData)
#define LWLOAD_DP(lwls,p,n)	(*(lwls)->readDP)((lwls)->readData,p,n)


#define LWFILEIOFUNCS_GLOBAL	"File IO 2"
#define LWIO_BINARY_IFF		 0x8C0000

typedef struct st_LWFileIOFuncs {
	LWSaveState *		(*openSave) (const char *name, int ioMode);
	void		     	(*closeSave)(LWSaveState *save); 
	LWLoadState *		(*openLoad) (const char *name, int ioMode);
	void		    	(*closeLoad)(LWLoadState *load); 
} LWFileIOFuncs;

#endif

