/*****************************************************************************
* Generic parser for the "Irit" solid modeller, in binary mode.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.1, Nov. 1993   *
*****************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <setjmp.h>
#include "irit_sm.h"
#include "prsr_loc.h"
#include "allocate.h"
#include "attribut.h"
#include "irit_soc.h"

#define BIN_FILE_SYNC_STAMP	0x30106000

typedef enum {
    IP_OBJ_REG_TYPES = 199,	 /* Seperator between regular and aux types. */
    IP_OBJ_AUX_ATTR = 200,	 /* These are the auxiliary objects/structs. */
    IP_OBJ_AUX_VERTEX,
    IP_OBJ_AUX_POLY,
    IP_OBJ_AUX_CURVE,
    IP_OBJ_AUX_SURFACE,
    IP_OBJ_AUX_TRIMSRF,
    IP_OBJ_AUX_TRIMCRV,
    IP_OBJ_AUX_TRIMCRVSEG,
    IP_OBJ_AUX_TRIVAR,
    IP_OBJ_AUX_MATRIX,
    IP_OBJ_AUX_STRING,
    IP_OBJ_AUX_OLST,
    IP_OBJ_AUX_END
} IPObjAuxStructType;

static int
    GlblLastSync = -1;

static void InputUnGetBinSync(int Sync);
static int InputGetBinSync(int Handler, int Abort);
static VoidPtr InputGetBinBlock(int Handler, VoidPtr Block, int Size);
static void OutputPutBinSync(int Handler, int Type);
static void OutputPutBinBlock(int Handler, VoidPtr Block, int Size);
static void IritPrsrGetBinObjectAux(int Handler,
				    IPObjectStruct *PObjParent,
				    int Sync);
static IPPolygonStruct *InputGetBinPolys(int Handler, int IsPolygon);
static CagdCrvStruct *InputGetBinCurves(int Handler);
static CagdSrfStruct *InputGetBinSurfaces(int Handler);
static TrimSrfStruct *InputGetBinTrimSrfs(int Handler);
static TrivTVStruct *InputGetBinTrivars(int Handler);
static MatrixType *InputGetBinMatrix(int Handler);
static char *InputGetBinString(int Handler);
static IPObjectStruct **InputGetBinOList(int Handler, int Len);
static IPAttributeStruct *InputGetBinAttributes(int Handler);
static void OutputPutBinPolys(int Handler, IPPolygonStruct *Pl);
static void OutputPutBinCurves(int Handler, CagdCrvStruct *Crv);
static void OutputPutBinSurfaces(int Handler, CagdSrfStruct *Srf);
static void OutputPutBinTrimSrfs(int Handler, TrimSrfStruct *TrimSrf);
static void OutputPutBinTrivars(int Handler, TrivTVStruct *Trivar);
static void OutputPutBinAttributes(int Handler, IPAttributeStruct *Attrs);

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to unget a sync stamp from input stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Sync:     To unget.                                                      *
*                                                                            *
* RETURN VALUE:                                                              *
*   None								     *
*****************************************************************************/
static void InputUnGetBinSync(int Sync)
{
    GlblLastSync = Sync;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a sync stamp from input stream.			     *
*   Returns zero if no input is available.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Abort:    Should we abort with fatal error if no sync!?		     *
*                                                                            *
* RETURN VALUE:                                                              *
*   int:      Type of object stamp or 0 of no sync.                          *
*****************************************************************************/
static int InputGetBinSync(int Handler, int Abort)
{
    unsigned long l;

    if (GlblLastSync >= 0) {
	l = GlblLastSync;
	GlblLastSync = -1;
	return l;
    }

    InputGetBinBlock(Handler, (VoidPtr) &l, sizeof(long));

    if ((l & 0xffffff00) == BIN_FILE_SYNC_STAMP) {
	return l & 0xff;
    }
    else {
	if (Abort)
	    _IPParserAbort(IP_ERR_BIN_UNDEF_OBJ,
			   "Fail to sync on binary stream.");

	return -1;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a block of character from input stream.		     *
*    If input returns EOF blocks until new inputs arrive (can happen if      *
* reading from a non io blocked socket).				     *
*    If Block is NULL a new block with the right Size is allocated.	     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Block:     Where read block should go to.                                *
*   Size:      Size of block to read.                                        *
*                                                                            *
* RETURN VALUE:                                                              *
*   VoidPtr    Read data. Same as Block if given Block was not NULL.         *
*****************************************************************************/
static VoidPtr InputGetBinBlock(int Handler, VoidPtr Block, int Size)
{
    int c;
    char
	*p = (char *) Block;

    if (Block == NULL)
        Block = IritMalloc(Size);

    while (Size-- > 0) {
	if (_IPStream[Handler].f == NULL) {
	    while ((c = SocReadCharNonBlock(Handler)) == EOF) {
		IritSleep(10);
	    }
	}
	else
	    c = getc(_IPStream[Handler].f);

	*p++ = c;
    }

    return Block;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a sync stamp to output stream.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Type:      Type of stamp.                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinSync(int Handler, int Type)
{
    unsigned long l = (Type | BIN_FILE_SYNC_STAMP);

    OutputPutBinBlock(Handler, (VoidPtr) &l, sizeof(long));
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a block of character to output stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:  A handler to the open stream.				     *
*   Block:    Block to write.                                                *
*   Size:     Size of Block.                                                 *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinBlock(int Handler, VoidPtr Block, int Size)
{
    if (_IPStream[Handler].f == NULL) {
	SocWriteLine(Handler, Block, Size);
    }
    else
        fwrite(Block, Size, 1, _IPStream[Handler].f);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to read one object from a given binary file, directly.	     M
*   Objects may be recursively defined (as lists), in which case all are     M
* read in this single call.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Handler:  A handler to the open stream.				     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    Read object.                                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   IritPrsrGetBinObject, files, parser                                      M
*****************************************************************************/
IPObjectStruct *IritPrsrGetBinObject(int Handler)
{
    IPObjectStruct
	*PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);
    int Sync,
	Flatten = IritPrsrSetFlattenObjects(FALSE),
	ObjCount = 0;

    /* If the following gain control and is non zero - its from error! */
    if (setjmp(_IritPrsrLongJumpBuffer) != 0) {
	/* Error had occured (and will be reported). Return something... */
	PObjList -> ObjType = IP_OBJ_NUMERIC;
	PObjList -> U.R = 0.0;
	return PObjList;
    }

    do {
	/* If Sync is for a new object - get the object: */
	if ((Sync = InputGetBinSync(Handler, FALSE)) < IP_OBJ_REG_TYPES &&
	    Sync >= 0) {
	    IPObjectStruct
		*PObjParent = IPAllocObject("", IP_OBJ_UNDEF, NULL);

	    IritPrsrGetBinObjectAux(Handler, PObjParent, Sync);
	    ListObjectInsert(PObjList, ObjCount++, PObjParent);
	}
    }
    while (!_IritPrsrReadOneObject && Sync < IP_OBJ_REG_TYPES && Sync > -1);

    ListObjectInsert(PObjList, ObjCount++, NULL);

    /* If it is not a sync for an object structure, unget it. */
    if (Sync >= IP_OBJ_REG_TYPES)
	InputUnGetBinSync(Sync);

    PObjList = IritPrsrProcessReadObject(PObjList);

    IritPrsrSetFlattenObjects(Flatten);

    return(PObjList);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to read one object from a given binary file, directly.	     *
*   Objects may be recursively defined (as lists), in which case all are     *
* read in this single call.						     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   PObjParent:  One list object, this read object should be hooked as an    *
*                element.						     *
*   Sync:	 Binary stream sync value.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void IritPrsrGetBinObjectAux(int Handler,
				    IPObjectStruct *PObjParent,
				    int Sync)
{
    InputGetBinBlock(Handler, (VoidPtr) PObjParent, sizeof(IPObjectStruct));
    PObjParent -> Pnext = NULL;
    PObjParent -> Count = 1;

    if (PObjParent -> Attrs)
	PObjParent -> Attrs = InputGetBinAttributes(Handler);

    switch (Sync) {
	case IP_OBJ_POLY:
	    PObjParent -> U.Pl =
		InputGetBinPolys(Handler, IP_IS_POLYGON_OBJ(PObjParent));
	    break;
	case IP_OBJ_NUMERIC:
	    break;
	case IP_OBJ_POINT:
	    break;
	case IP_OBJ_VECTOR:
	    break;
	case IP_OBJ_PLANE:
	    break;
	case IP_OBJ_MATRIX:
	    PObjParent -> U.Mat = InputGetBinMatrix(Handler);

	    if (stricmp(PObjParent -> Name, "VIEW_MAT") == 0) {
		IritPrsrWasViewMat = TRUE;
		MAT_COPY(IritPrsrViewMat, PObjParent -> U.Mat);
	    }
	    else if (stricmp(PObjParent -> Name, "PRSP_MAT") == 0) {
		IritPrsrWasPrspMat = TRUE;
		MAT_COPY(IritPrsrPrspMat, PObjParent -> U.Mat);
	    }
	    break;
	case IP_OBJ_CURVE:
	    PObjParent -> U.Crvs = InputGetBinCurves(Handler);
	    break;
	case IP_OBJ_SURFACE:
	    PObjParent -> U.Srfs = InputGetBinSurfaces(Handler);
	    break;
	case IP_OBJ_TRIMSRF:
	    PObjParent -> U.TrimSrfs = InputGetBinTrimSrfs(Handler);
	    break;
	case IP_OBJ_TRIVAR:
	    PObjParent -> U.Trivars = InputGetBinTrivars(Handler);
	    break;
	case IP_OBJ_STRING:
	    PObjParent -> U.Str = InputGetBinString(Handler);
	    break;
	case IP_OBJ_LIST_OBJ:
	    PObjParent -> U.Lst.PObjList =
		InputGetBinOList(Handler, PObjParent -> U.Lst.ListMaxLen);
	    break;
	case IP_OBJ_CTLPT:
	    break;
	default:
	    _IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");
    }

    if (Sync != IP_OBJ_LIST_OBJ &&
	AttrGetObjectColor(PObjParent) == IP_ATTR_NO_COLOR)
    	AttrSetObjectColor(PObjParent, IP_LOAD_COLOR);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of polys from bin input stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   IsPolygon: Should we treat them as polygons?                             *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPPolygonStruct *:  Read list of polygons.                               *
*****************************************************************************/
static IPPolygonStruct *InputGetBinPolys(int Handler, int IsPolygon)
{
    int PSync;
    IPPolygonStruct
	*PHead = NULL,
	*PTail = NULL;

    while ((PSync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_POLY) {
	int VSync;
	IPPolygonStruct
	    *Poly = IPAllocPolygon(0, 0, NULL, NULL);
	IPVertexStruct *Vrtx,
	    *VTail = NULL;

	InputGetBinBlock(Handler, (VoidPtr) Poly, sizeof(IPPolygonStruct));
	if (Poly -> Attrs)
	    Poly -> Attrs = InputGetBinAttributes(Handler);

	Poly -> PVertex = NULL;
	while ((VSync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_VERTEX) {
	    Vrtx = IPAllocVertex(0, 0, NULL, NULL);
	    InputGetBinBlock(Handler, (VoidPtr) Vrtx, sizeof(IPVertexStruct));
	    if (Vrtx -> Attrs)
		Vrtx -> Attrs = InputGetBinAttributes(Handler);

	    if (Poly -> PVertex) {
	        VTail -> Pnext = Vrtx;
		VTail = Vrtx;
	    }
	    else {
		VTail = Poly -> PVertex = Vrtx;
	    }
	}
	if (_IritPrsrPolyListCirc)
	    VTail -> Pnext = Poly -> PVertex;
	else
	    VTail -> Pnext = NULL;
	if (VSync != IP_OBJ_AUX_END)
	    _IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

	if (IsPolygon) {
	    if (!IP_HAS_PLANE_POLY(Poly))
		IritPrsrUpdatePolyPlane(Poly);

	    IritPrsrUpdateVrtxNrml(Poly, Poly -> Plane);
	}

	if (PHead) {
	    PTail -> Pnext = Poly;
	    PTail = Poly;
	}
	else {
	    PHead = PTail = Poly;
	}
    }
    if (PSync != IP_OBJ_AUX_END)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    if (PTail)
	PTail -> Pnext = NULL;

    if (PHead == NULL)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    return PHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of curves from bin input stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   CagdCrvStruct *:   Read list of curves.                                  *
*****************************************************************************/
static CagdCrvStruct *InputGetBinCurves(int Handler)
{
    int i, Sync, Size;
    CagdCrvStruct *Crv,
	*CHead = NULL,
	*CTail = NULL;

    while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_CURVE) {
	Crv = (CagdCrvStruct *) IritMalloc(sizeof(CagdCrvStruct));
	InputGetBinBlock(Handler, (VoidPtr) Crv, sizeof(CagdCrvStruct));
	Crv -> Attr = NULL;
	Crv -> Pnext = NULL;
	Size = sizeof(CagdRType) * Crv -> Length;

	for (i = !CAGD_IS_RATIONAL_PT(Crv -> PType);
	     i <= CAGD_NUM_OF_PT_COORD(Crv -> PType);
	     i++) {
	    Crv -> Points[i] = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (Crv -> Points[i]), Size);
	}

	for (i = CAGD_NUM_OF_PT_COORD(Crv -> PType) + 1;
	     i <= CAGD_MAX_PT_COORD;
	     i++)
	    Crv -> Points[i] = NULL;

	if (Crv -> GType == CAGD_CBSPLINE_TYPE) {
	    Size = sizeof(CagdRType) *
			      (Crv -> Length + Crv -> Order +
			       (Crv -> Periodic ? Crv -> Order - 1 : 0));
	    Crv -> KnotVector = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (Crv -> KnotVector), Size);
	}

	if (CHead == NULL) {
	    CHead = CTail = Crv;
	}
	else {
	    CTail -> Pnext = Crv;
	    CTail = Crv;
	}
    }
    if (Sync != IP_OBJ_AUX_END)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    if (CHead == NULL)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    return CHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of surfaces from bin input stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   CagdSrfStruct *:    Read list of surfaces.                               *
*****************************************************************************/
static CagdSrfStruct *InputGetBinSurfaces(int Handler)
{
    int i, Sync, Size;
    CagdSrfStruct *Srf,
	*SHead = NULL,
	*STail = NULL;

    while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_SURFACE) {
	Srf = (CagdSrfStruct *) IritMalloc(sizeof(CagdSrfStruct));
	InputGetBinBlock(Handler, (VoidPtr) Srf, sizeof(CagdSrfStruct));
	Srf -> Attr = NULL;
	Srf -> Pnext = NULL;
	Size = sizeof(CagdRType) * Srf -> ULength * Srf -> VLength;

	for (i = !CAGD_IS_RATIONAL_PT(Srf -> PType);
	     i <= CAGD_NUM_OF_PT_COORD(Srf -> PType);
	     i++) {
	    Srf -> Points[i] = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (Srf -> Points[i]), Size);
	}

	for (i = CAGD_NUM_OF_PT_COORD(Srf -> PType) + 1;
	     i <= CAGD_MAX_PT_COORD;
	     i++)
	    Srf -> Points[i] = NULL;

	if (Srf -> GType == CAGD_SBSPLINE_TYPE) {
	    Size = sizeof(CagdRType) *
			(Srf -> ULength + Srf -> UOrder +
			 (Srf -> UPeriodic ? Srf -> UOrder - 1 : 0));
	    Srf -> UKnotVector = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (Srf -> UKnotVector), Size);
	    Size = sizeof(CagdRType) *
			(Srf -> VLength + Srf -> VOrder +
			 (Srf -> VPeriodic ? Srf -> VOrder - 1 : 0));
	    Srf -> VKnotVector = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (Srf -> VKnotVector), Size);
	}

	if (SHead == NULL) {
	    SHead = STail = Srf;
	}
	else {
	    STail -> Pnext = Srf;
	    STail = Srf;
	}
    }
    if (Sync != IP_OBJ_AUX_END || SHead == NULL)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    return SHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of trimmed surfaces from bin input stream.	     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   TrimSrfStruct *:    Read list of trimm surfaces.                         *
*****************************************************************************/
static TrimSrfStruct *InputGetBinTrimSrfs(int Handler)
{
    int Sync;
    TrimSrfStruct *TrimSrf,
	*SHead = NULL,
	*STail = NULL;

    while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_TRIMSRF) {
	TrimCrvStruct *TrimCrv,
	    *CHead = NULL,
	    *CTail = NULL;

	TrimSrf = (TrimSrfStruct *) IritMalloc(sizeof(TrimSrfStruct));
	InputGetBinBlock(Handler, (VoidPtr) TrimSrf, sizeof(TrimSrfStruct));
	TrimSrf -> Attr = NULL;
	TrimSrf -> Pnext = NULL;
	TrimSrf -> Srf = InputGetBinSurfaces(Handler);

	while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_TRIMCRV) {
	    TrimCrvSegStruct *TrimCrvSeg,
	        *CSHead = NULL,
		*CSTail = NULL;

	    TrimCrv = (TrimCrvStruct *) IritMalloc(sizeof(TrimCrvStruct));
	    InputGetBinBlock(Handler, (VoidPtr) TrimCrv, sizeof(TrimCrvStruct));
	    TrimCrv -> Attr = NULL;
	    TrimCrv -> Pnext = NULL;

	    while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_TRIMCRVSEG) {
		TrimCrvSeg = (TrimCrvSegStruct *)
					IritMalloc(sizeof(TrimCrvSegStruct));
		InputGetBinBlock(Handler, (VoidPtr) TrimCrvSeg,
						    sizeof(TrimCrvSegStruct));
		TrimCrvSeg -> Attr = NULL;
		TrimCrvSeg -> Pnext = NULL;
		TrimCrvSeg -> EucCrv = NULL;
		TrimCrvSeg -> UVCrv = InputGetBinCurves(Handler);

		if (CSHead == NULL) {
		    CSHead = CSTail = TrimCrvSeg;
		}
		else {
		    CSTail -> Pnext = TrimCrvSeg;
		    CSTail = TrimCrvSeg;
		}
 	    }
	    if (Sync != IP_OBJ_AUX_END || CSHead == NULL)
		_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

	    TrimCrv -> TrimCrvSegList = CSHead;

	    if (CHead == NULL) {
		CHead = CTail = TrimCrv;
	    }
	    else {
		CTail -> Pnext = TrimCrv;
		CTail = TrimCrv;
	    }
	}
	if (Sync != IP_OBJ_AUX_END || CHead == NULL)
	    _IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

	TrimSrf -> TrimCrvList = CHead;

	if (SHead == NULL) {
	    SHead = STail = TrimSrf;
	}
	else {
	    STail -> Pnext = TrimSrf;
	    STail = TrimSrf;
	}
    }
    if (Sync != IP_OBJ_AUX_END || SHead == NULL)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    return SHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of surfaces from bin input stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   CagdSrfStruct *:    Read list of surfcaes.                               *
*****************************************************************************/
static TrivTVStruct *InputGetBinTrivars(int Handler)
{
    int i, Sync, Size;
    TrivTVStruct *TV,
	*SHead = NULL,
	*STail = NULL;

    while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_TRIVAR) {
	TV = (TrivTVStruct *) IritMalloc(sizeof(TrivTVStruct));
	InputGetBinBlock(Handler, (VoidPtr) TV, sizeof(TrivTVStruct));
	TV -> Attr = NULL;
	TV -> Pnext = NULL;
	Size = sizeof(CagdRType) *
				TV -> ULength * TV -> VLength * TV -> WLength;

	for (i = !CAGD_IS_RATIONAL_PT(TV -> PType);
	     i <= CAGD_NUM_OF_PT_COORD(TV -> PType);
	     i++) {
	    TV -> Points[i] = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (TV -> Points[i]), Size);
	}

	for (i = CAGD_NUM_OF_PT_COORD(TV -> PType) + 1;
	     i <= CAGD_MAX_PT_COORD;
	     i++)
	    TV -> Points[i] = NULL;

	if (TV -> GType == TRIV_TVBSPLINE_TYPE) {
	    Size = sizeof(CagdRType) *
			(TV -> ULength + TV -> UOrder +
			 (TV -> UPeriodic ? TV -> UOrder - 1 : 0));
	    TV -> UKnotVector = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (TV -> UKnotVector), Size);
	    Size = sizeof(CagdRType) *
			(TV -> VLength + TV -> VOrder +
			 (TV -> VPeriodic ? TV -> VOrder - 1 : 0));
	    TV -> VKnotVector = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (TV -> VKnotVector), Size);
	    Size = sizeof(CagdRType) *
			(TV -> WLength + TV -> WOrder +
			 (TV -> WPeriodic ? TV -> WOrder - 1 : 0));
	    TV -> WKnotVector = (CagdRType *) IritMalloc(Size);
	    InputGetBinBlock(Handler, (VoidPtr) (TV -> WKnotVector), Size);
	}

	if (SHead == NULL) {
	    SHead = STail = TV;
	}
	else {
	    STail -> Pnext = TV;
	    STail = TV;
	}
    }
    if (Sync != IP_OBJ_AUX_END || SHead == NULL)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    return SHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a matrix from bin input stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   MatrixType *:   Read matrix.                                             *
*****************************************************************************/
static MatrixType *InputGetBinMatrix(int Handler)
{
    MatrixType *Mat;

    if (InputGetBinSync(Handler, TRUE) != IP_OBJ_AUX_MATRIX)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");
    Mat = (MatrixType *) IritMalloc(sizeof(MatrixType));
    InputGetBinBlock(Handler, (VoidPtr) Mat, sizeof(MatrixType));

    return Mat;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a string from bin input stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   char *:   Read string.  	                                             *
*****************************************************************************/
static char *InputGetBinString(int Handler)
{
    long Len;
    char *Str;

    if (InputGetBinSync(Handler, TRUE) != IP_OBJ_AUX_STRING)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");
    InputGetBinBlock(Handler, (VoidPtr) &Len, sizeof(long));
    Str = (char *) IritMalloc(Len);
    InputGetBinBlock(Handler, (VoidPtr) Str, Len);
    return Str;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of objects from bin input stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Len:       Number of objects in list.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPObjectStruct **:   Read list of objects.                               *
*****************************************************************************/
static IPObjectStruct **InputGetBinOList(int Handler, int Len)
{
    int i;
    struct IPObjectStruct *PTmp,
	**PObjList = (IPObjectStruct **)
	    IritMalloc(Len * sizeof(IPObjectStruct *));

    if (InputGetBinSync(Handler, TRUE) != IP_OBJ_AUX_OLST)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");
    InputGetBinBlock(Handler, (VoidPtr) PObjList, Len * sizeof(IPObjectStruct *));

    for (i = 0; i < Len && PObjList[i] != NULL; i++) {
	int Sync = InputGetBinSync(Handler, TRUE);

	PTmp = IPAllocObject("", IP_OBJ_UNDEF, NULL);
	IritPrsrGetBinObjectAux(Handler, PTmp, Sync);
	PObjList[i] = PTmp;
    }
    if (i < Len - 1)
	PObjList[i] = NULL;

    return PObjList;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to get a list of attributes from bin input stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPAttributeStruct *:   Read list of attributes.                          *
*****************************************************************************/
static IPAttributeStruct *InputGetBinAttributes(int Handler)
{
    int Sync;
    IPAttributeStruct *Attr,
	*ATail = NULL,
	*AHead = NULL;

    while ((Sync = InputGetBinSync(Handler, TRUE)) == IP_OBJ_AUX_ATTR) {
	long Len;

	Attr = (IPAttributeStruct *) IritMalloc(sizeof(IPAttributeStruct));
	InputGetBinBlock(Handler, (VoidPtr) Attr, sizeof(IPAttributeStruct));
	InputGetBinBlock(Handler, (VoidPtr) &Len, sizeof(long));
	Attr -> Name = IritMalloc(Len);
	InputGetBinBlock(Handler, (VoidPtr) (Attr -> Name), Len);
	if (Attr -> Type == IP_ATTR_STR) {
	    if (InputGetBinSync(Handler, TRUE) != IP_OBJ_AUX_STRING)
		_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");
	    InputGetBinBlock(Handler, (VoidPtr) &Len, sizeof(long));
	    Attr -> U.Str = IritMalloc(Len);
	    InputGetBinBlock(Handler, (VoidPtr) (Attr -> U.Str), Len);
	}
	else if (Attr -> Type == IP_ATTR_OBJ)
	    Attr -> U.PObj = IritPrsrGetBinObject(Handler);

	if (AHead) {
	    ATail -> Pnext = Attr;
	    ATail = Attr;
	}
	else {
	    ATail = AHead = Attr;
	}
    }
    if (Sync != IP_OBJ_AUX_END)
	_IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");

    return AHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to write one object to a given binary file, directly.		     M
*    Objects may be recursively defined, as lists of objects.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Handler:   A handler to the open stream.				     *
*   PObj:      Object to write.                                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IritPrsrPutBinObject, files, parser                                      M
*****************************************************************************/
void IritPrsrPutBinObject(int Handler, IPObjectStruct *PObj)
{
    int i;
    long Len;
    IPObjectStruct *PTmp;

    /* If the following gain control and is non zero - its from error! */
    if (setjmp(_IritPrsrLongJumpBuffer) != 0) {
	/* Error had occured (and will be reported). */
	return;
    }

    OutputPutBinSync(Handler, PObj -> ObjType);
    OutputPutBinBlock(Handler, (VoidPtr) PObj, sizeof(IPObjectStruct));
    if (PObj -> Attrs != NULL)
	OutputPutBinAttributes(Handler, PObj -> Attrs);

    switch (PObj -> ObjType) {
	case IP_OBJ_POLY:
	    OutputPutBinPolys(Handler, PObj -> U.Pl);
	    break;
	case IP_OBJ_NUMERIC:
	    break;
	case IP_OBJ_POINT:
	    break;
	case IP_OBJ_VECTOR:
	    break;
	case IP_OBJ_PLANE:
	    break;
	case IP_OBJ_MATRIX:
	    OutputPutBinSync(Handler, IP_OBJ_AUX_MATRIX);
	    OutputPutBinBlock(Handler, (VoidPtr) (*PObj -> U.Mat),
			      sizeof(MatrixType));
	    break;
	case IP_OBJ_CURVE:
	    OutputPutBinCurves(Handler, PObj -> U.Crvs);
	    break;
	case IP_OBJ_SURFACE:
	    OutputPutBinSurfaces(Handler, PObj -> U.Srfs);
	    break;
	case IP_OBJ_TRIMSRF:
	    OutputPutBinTrimSrfs(Handler, PObj -> U.TrimSrfs);
	    break;
	case IP_OBJ_TRIVAR:
	    OutputPutBinTrivars(Handler, PObj -> U.Trivars);
	    break;
	case IP_OBJ_STRING:
	    OutputPutBinSync(Handler, IP_OBJ_AUX_STRING);
	    Len = strlen(PObj -> U.Str) + 1;
	    OutputPutBinBlock(Handler, (VoidPtr) &Len, sizeof(long));
	    OutputPutBinBlock(Handler, (VoidPtr) (PObj -> U.Str), Len);
	    break;
	case IP_OBJ_LIST_OBJ:
	    OutputPutBinSync(Handler, IP_OBJ_AUX_OLST);
	    OutputPutBinBlock(Handler, (VoidPtr) PObj -> U.Lst.PObjList,
			sizeof(IPObjectStruct *) * PObj -> U.Lst.ListMaxLen);
	    for (i = 0;
		 i < PObj -> U.Lst.ListMaxLen &&
		 (PTmp = ListObjectGet(PObj, i)) != NULL;
		 i++) {
		IritPrsrPutBinObject(Handler, PTmp);
	    }
	    break;
	case IP_OBJ_CTLPT:
	    break;
	default:
	    _IPParserAbort(IP_ERR_BIN_UNDEF_OBJ, "");
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a list of polys to bin output stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Pl:        Polys to write.                                               *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinPolys(int Handler, IPPolygonStruct *Pl)
{
    for (; Pl != NULL; Pl = Pl -> Pnext) {
	IPVertexStruct
	    *V = Pl -> PVertex;

	OutputPutBinSync(Handler, IP_OBJ_AUX_POLY);
	OutputPutBinBlock(Handler, (VoidPtr) Pl, sizeof(IPPolygonStruct));
	if (Pl -> Attrs != NULL)
	    OutputPutBinAttributes(Handler, Pl -> Attrs);

	do {
	    OutputPutBinSync(Handler, IP_OBJ_AUX_VERTEX);
	    OutputPutBinBlock(Handler, (VoidPtr) V, sizeof(IPVertexStruct));
	    if (V -> Attrs != NULL)
		OutputPutBinAttributes(Handler, V -> Attrs);
	    V = V -> Pnext;
	}
	while (V != NULL && V != Pl -> PVertex);
	OutputPutBinSync(Handler, IP_OBJ_AUX_END);
    }
    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a list of curves to bin output stream.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Crv:       Curves to write.                                              *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinCurves(int Handler, CagdCrvStruct *Crv)
{
    for ( ; Crv != NULL; Crv = Crv -> Pnext) {
	int i,
	    Size = sizeof(CagdRType) * Crv -> Length;

	OutputPutBinSync(Handler, IP_OBJ_AUX_CURVE);
	OutputPutBinBlock(Handler, (VoidPtr) Crv, sizeof(CagdCrvStruct));

	for (i = !CAGD_IS_RATIONAL_PT(Crv -> PType);
	     i <= CAGD_NUM_OF_PT_COORD(Crv -> PType);
	     i++) {
	    OutputPutBinBlock(Handler, (VoidPtr) (Crv -> Points[i]), Size);
	}

	if (Crv -> GType == CAGD_CBSPLINE_TYPE) {
	    Size = sizeof(CagdRType) *
			(Crv -> Length + Crv -> Order +
			 (Crv -> Periodic ? Crv -> Order - 1 : 0));
	    OutputPutBinBlock(Handler, (VoidPtr) (Crv -> KnotVector), Size);
	}
    }
    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a list of surface to bin output stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Srf:       Surfaces to write.                                            *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinSurfaces(int Handler, CagdSrfStruct *Srf)
{
    for ( ; Srf != NULL; Srf = Srf -> Pnext) {
	int i,
	    Size = sizeof(CagdRType) * Srf -> ULength * Srf -> VLength;

	OutputPutBinSync(Handler, IP_OBJ_AUX_SURFACE);
	OutputPutBinBlock(Handler, (VoidPtr) Srf, sizeof(CagdSrfStruct));

	for (i = !CAGD_IS_RATIONAL_PT(Srf -> PType);
	     i <= CAGD_NUM_OF_PT_COORD(Srf -> PType);
	     i++) {
	    OutputPutBinBlock(Handler, (VoidPtr) (Srf -> Points[i]), Size);
	}

	if (Srf -> GType == CAGD_SBSPLINE_TYPE) {
	    Size = sizeof(CagdRType) *
			(Srf -> ULength + Srf -> UOrder +
			 (Srf -> UPeriodic ? Srf -> UOrder - 1 : 0));
	    OutputPutBinBlock(Handler, (VoidPtr) (Srf -> UKnotVector), Size);
	    Size = sizeof(CagdRType) *
			(Srf -> VLength + Srf -> VOrder +
			 (Srf -> VPeriodic ? Srf -> VOrder - 1 : 0));
	    OutputPutBinBlock(Handler, (VoidPtr) (Srf -> VKnotVector), Size);
	}
    }
    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a list of trimmed surfaces to bin output stream.	     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   TrimSrf:   Trimmed surfaces to write.                                    *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinTrimSrfs(int Handler, TrimSrfStruct *TrimSrf)
{
    for ( ; TrimSrf != NULL; TrimSrf = TrimSrf -> Pnext) {
	TrimCrvStruct
	    *TrimCrv = TrimSrf -> TrimCrvList;

	OutputPutBinSync(Handler, IP_OBJ_AUX_TRIMSRF);
	OutputPutBinBlock(Handler, (VoidPtr) (TrimSrf), sizeof(TrimSrfStruct));
	OutputPutBinSurfaces(Handler, TrimSrf -> Srf);
	for ( ; TrimCrv != NULL; TrimCrv = TrimCrv -> Pnext) {
	    TrimCrvSegStruct
		*TrimCrvSeg = TrimCrv -> TrimCrvSegList;

	    OutputPutBinSync(Handler, IP_OBJ_AUX_TRIMCRV);
	    OutputPutBinBlock(Handler, (VoidPtr) (TrimCrv), sizeof(TrimCrvStruct));

	    for ( ; TrimCrvSeg != NULL; TrimCrvSeg = TrimCrvSeg -> Pnext) {
		OutputPutBinSync(Handler, IP_OBJ_AUX_TRIMCRVSEG);
		OutputPutBinBlock(Handler, (VoidPtr) (TrimCrvSeg),
				  sizeof(TrimCrvSegStruct));

		OutputPutBinCurves(Handler, TrimCrvSeg -> UVCrv);
	    }
	    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
	}
	OutputPutBinSync(Handler, IP_OBJ_AUX_END);
    }
    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a list of trivairates to bin output stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   TV:        Trivariates to write.                                         *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinTrivars(int Handler, TrivTVStruct *TV)
{
    for ( ; TV != NULL; TV = TV -> Pnext) {
	int i,
	    Size = sizeof(CagdRType) *
			       TV -> ULength * TV -> VLength  * TV -> WLength;

	OutputPutBinSync(Handler, IP_OBJ_AUX_TRIVAR);
	OutputPutBinBlock(Handler, (VoidPtr) TV, sizeof(TrivTVStruct));

	for (i = !CAGD_IS_RATIONAL_PT(TV -> PType);
	     i <= CAGD_NUM_OF_PT_COORD(TV -> PType);
	     i++) {
	    OutputPutBinBlock(Handler, (VoidPtr) (TV -> Points[i]), Size);
	}

	if (TV -> GType == TRIV_TVBSPLINE_TYPE) {
	    Size = sizeof(CagdRType) *
			(TV -> ULength + TV -> UOrder +
			 (TV -> UPeriodic ? TV -> UOrder - 1 : 0));
	    OutputPutBinBlock(Handler, (VoidPtr) (TV -> UKnotVector), Size);
	    Size = sizeof(CagdRType) *
			(TV -> VLength + TV -> VOrder +
			 (TV -> VPeriodic ? TV -> VOrder - 1 : 0));
	    OutputPutBinBlock(Handler, (VoidPtr) (TV -> VKnotVector), Size);
	    Size = sizeof(CagdRType) *
			(TV -> WLength + TV -> WOrder +
			 (TV -> WPeriodic ? TV -> WOrder - 1 : 0));
	    OutputPutBinBlock(Handler, (VoidPtr) (TV -> WKnotVector), Size);
	}
    }
    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to put a list of attributes to bin output stream.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Handler:   A handler to the open stream.				     *
*   Attrs:     Attributes to write.                                          *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void OutputPutBinAttributes(int Handler, IPAttributeStruct *Attrs)
{
    Attrs = AttrTraceAttributes(Attrs, Attrs);

    while (Attrs) {
	if (Attrs -> Name[0] != '_' &&
	    (Attrs -> Type == IP_ATTR_INT ||
	     Attrs -> Type == IP_ATTR_REAL ||
	     Attrs -> Type == IP_ATTR_STR ||
	     Attrs -> Type == IP_ATTR_OBJ)) {
	    long
		Len = strlen(Attrs -> Name) + 1;

	    OutputPutBinSync(Handler, IP_OBJ_AUX_ATTR);
	    OutputPutBinBlock(Handler, (VoidPtr) Attrs,
			      sizeof(IPAttributeStruct));
	    OutputPutBinBlock(Handler, (VoidPtr) &Len, sizeof(long));
	    OutputPutBinBlock(Handler, (VoidPtr) (Attrs -> Name), Len);

	    if (Attrs -> Type == IP_ATTR_STR) {
		Len = strlen(Attrs -> U.Str) + 1;

		OutputPutBinSync(Handler, IP_OBJ_AUX_STRING);
		OutputPutBinBlock(Handler, (VoidPtr) &Len, sizeof(long));
		OutputPutBinBlock(Handler, (VoidPtr) (Attrs -> U.Str), Len);
	    }
	    else if (Attrs -> Type == IP_ATTR_OBJ)
		IritPrsrPutBinObject(Handler, Attrs -> U.PObj);
	}

	Attrs = AttrTraceAttributes(Attrs, NULL);
    }
    OutputPutBinSync(Handler, IP_OBJ_AUX_END);
}
