//FileIO.cpp, Copyright (c) 2001-2008 R.Lackner
//read/write graphic objects
//
//    This file is part of RLPlot.
//
//    RLPlot is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    RLPlot 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 General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with RLPlot; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
#include "rlplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <ctype.h>
#include <fcntl.h>				//file open flags
#include <sys/stat.h>			//I/O flags

#ifdef _WINDOWS
	#include <io.h>					//for read/write
#else
	#define O_BINARY 0x0
	#include <unistd.h>
#endif

extern GraphObj *CurrGO;			//Selected Graphic Objects
extern Default defs;
extern int dlgtxtheight;
extern char TmpTxt[];
extern int cPlots;
GraphObj *LastOpenGO;

static notary *Notary = 0L;
static ReadCache *Cache = 0L;

unsigned long cObsW;				//count objects written

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// graphic input/output is driven by tables based on the descIO template
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct {
	char *label;
	unsigned short type;
	void *ptr;
	long *count;
	}descIO;

//the type member of descIO describes the following data types pointed to by ptr
enum {typNONE, typNZINT, typINT, typLFLOAT, typNZLFLOAT, 
	typDWORD, typFRECT, typNZLFPOINT, typLFPOINT, typPOINT3D,
	typAXDEF, typPTRAXDEF, typLINEDEF, typFILLDEF, typGOBJ,	typOBJLST,
	typFPLST, typFPLST3D, typIPLST, typTEXT, typTXTDEF, typPTRTXTDEF, 
	typLAST = 0x100};

static char *ptr =0L;
static int cbOut, sizeOut = 0, iFile = -1;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// output graph to file, elementary functions
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int OpenOutputFile(char *file)
{
	time_t ti;

	if(ptr) free(ptr);
	ptr = 0L;		cbOut = 0;		ti = time(0L);
	if(file && BackupFile(file)) {
#ifdef USE_WIN_SECURE
		if(_sopen_s(&iFile, file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 
			0x40, S_IWRITE) || iFile < 0){
			ErrorBox("Open failed for output file");
			return -1;
			}
#else
		if(-1 ==(iFile = open(file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
			S_IWRITE | S_IREAD))){
			ErrorBox("Open failed for output file");
			return -1;
			}
#endif
		ptr = (char *)malloc(sizeOut = 2000);
		if(!ptr) goto openerr;
		cbOut = rlp_strcpy(ptr, 20, ";RLP 1.0\n;File \"");
		add_to_buff(&ptr, &cbOut, &sizeOut, file, 0);
		add_to_buff(&ptr, &cbOut, &sizeOut, "\" created by RLPlot version "SZ_VERSION" for ", 0);
#ifdef _WINDOWS
		add_to_buff(&ptr, &cbOut, &sizeOut, "Windows", 7);
#else
		add_to_buff(&ptr, &cbOut, &sizeOut, "Qt", 2);
#endif
		add_to_buff(&ptr, &cbOut, &sizeOut, "\n;Date/Time: ", 13);
#ifdef USE_WIN_SECURE
		ctime_s(ptr+cbOut, 30, &ti);	cbOut += 25;
#else
		add_to_buff(&ptr, &cbOut, &sizeOut, ctime(&ti), 25);
#endif
		}
	return iFile;
openerr:
	ptr = 0L;	cbOut = sizeOut = 0;
#ifdef USE_WIN_SECURE
	if(iFile >=0) _close(iFile);
#else
	if(iFile >=0) close(iFile);
#endif
	return iFile = -1;
}

static void CloseOutputFile()
{
	if(iFile >= 0){
#ifdef USE_WIN_SECURE
		if(cbOut) _write(iFile, ptr, cbOut);
		_close(iFile);
#else
		if(cbOut) write(iFile, ptr, cbOut);
		close(iFile);
#endif
		}
	if(ptr) free(ptr);
	cbOut = sizeOut = 0;
	ptr = 0L;		iFile = -1;
}

static void WriteTypObjLst(GraphObj **obs, int c1)
{
	int i, j, no, n, *idx;
	
	if(!obs || !(idx=(int*)malloc(c1*sizeof(int)))) return;
	for(i = no = 0; i < c1; i++) {
		if(j = Notary->RegisterGO(obs[i])) idx[no++] = j;
		}
	add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
	add_int_to_buff(&ptr, &cbOut, &sizeOut, no, false, 0);
	add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
	for(i = 0; i < no; i += 16) {
		if(i) add_to_buff(&ptr, &cbOut, &sizeOut, "   ", 3);
		for(j = 0; (n=i+j) < no && j < 16; j++) {
			add_int_to_buff(&ptr, &cbOut, &sizeOut, idx[n], j != 0, 0);
			}
		if(n >= no) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
		}
}

static void WriteTypIpLst(POINT *ppt, int count)
{
	long i, j, c, n;

	if(!ppt) return;
	add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
	add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
	add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
	for(i = 0; i < count; i += 8) {
		for(j = c = 0; (n = i+j) <count && j < 8; j++) {
			add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].x, (j != 0), 0);
			add_int_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].y, true, 0);
			}
		if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
		}
}

static void WriteTypFpLst(lfPOINT *ppt, long count, bool bPar)
{
	int i, j, n;

	if (bPar){
		if(!ppt) return;
		add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
		add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
		add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
		}
	else {
		if(!ppt) count = 0;
		add_int_to_buff(&ptr, &cbOut, &sizeOut, count, true, 0);
		if(!count) {
			add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
			return;
			}
		add_to_buff(&ptr, &cbOut, &sizeOut, " {", 2);
		}
	for(i = 0; i < count; i += 8) {
		for(j = 0; (n = i+j) <count && j < 8; j++) {
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
			}
		if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
		}
}

static void WriteTypFpLst3D(fPOINT3D *ppt, int count)
{
	long i, j, c, n;

	if(!ppt) return;
	add_to_buff(&ptr, &cbOut, &sizeOut, "(", 1);
	add_int_to_buff(&ptr, &cbOut, &sizeOut, count, false, 0);
	add_to_buff(&ptr, &cbOut, &sizeOut, "){", 2);
	for(i = 0; i < count; i +=5) {
		for(j = c = 0; (n =i+j) <count && j < 5; j++) {
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fx, (j != 0));
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fy, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ppt[n].fz, true);
			}
		if(n >= count) add_to_buff(&ptr, &cbOut, &sizeOut, "}", 1);
		else add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
		}
}

static char * esc_str = 0L;
static int esc_str_size = 0;
static void WriteEscString(char *txt)
{
	int i, j, l, lim = 60;

	if(!txt || !txt[0]) return;
	l = (int)strlen(txt);
	if((l+10) > esc_str_size) if(!(esc_str = (char*)realloc(esc_str, esc_str_size = (l+100))))return;
	j = 0;	esc_str[j++] = '"';
	for(i = 0; txt[i]; i++) {
		switch(txt[i]) {
		case '\\':
			esc_str[j++] = '\\';	esc_str[j++] = '\\';
			break;
		case '\n':
			esc_str[j++] = '\\';	esc_str[j++] = 'n';
			break;
		default:	
			if(((unsigned char*)txt)[i] >= ' ') esc_str[j++] = txt[i];
			}
		if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
		if(j > lim && (l-i) > 3) {
			esc_str[j++] = '"';		esc_str[j++] = '\\';
			esc_str[j++] = '\n';	esc_str[j++] = ' ';
			esc_str[j++] = ' ';		esc_str[j++] = ' ';
			esc_str[j++] = '"';
			lim += 60;
			}
		}
	esc_str[j++] = '"';
	add_to_buff(&ptr, &cbOut, &sizeOut, esc_str, j);
}

bool ExecOutput(int id, char *Class, descIO *Desc)
{
	int i, last;
	fRECT *fr;
	AxisDEF *ax;
	LineDEF *ld;
	FillDEF *fd;
	TextDEF *tx;

	add_to_buff(&ptr, &cbOut, &sizeOut, "\n[", 2);
	add_int_to_buff(&ptr, &cbOut, &sizeOut, id, false, 0);
	add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
	add_to_buff(&ptr, &cbOut, &sizeOut, Class, 0);
	add_to_buff(&ptr, &cbOut, &sizeOut, "]\n", 2);
	cObsW++;
	for(i = 0; Desc[i].label; i++) {
		if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
		last = cbOut;
		add_to_buff(&ptr, &cbOut, &sizeOut, Desc[i].label, 0);
		add_to_buff(&ptr, &cbOut, &sizeOut, "=", 1);
		switch(Desc[i].type & 0xff){
		case typNZINT:
			if(!(*(int*)Desc[i].ptr)) {
				cbOut = last;			break;
				}
			//if not zero value continue as if int
		case typINT:
			add_int_to_buff(&ptr, &cbOut, &sizeOut, *(int*)Desc[i].ptr, true, 0);
			break;
		case typNZLFLOAT:
			if(*((double*)Desc[i].ptr) == 0.0) {
				cbOut = last;			break;
				}
			//if not zero or negative continue as if float
		case typLFLOAT:
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, *(double*)Desc[i].ptr, true);
			break;
		case typDWORD:
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, *(DWORD *)Desc[i].ptr, true);
			break;
		case typFRECT:
			fr = (fRECT*)Desc[i].ptr;
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmin, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymax, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Xmax, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fr->Ymin, true);
			break;
		case typNZLFPOINT:
			if(((lfPOINT *)Desc[i].ptr)->fx == ((lfPOINT *)Desc[i].ptr)->fy &&
				((lfPOINT *)Desc[i].ptr)->fx == 0.0f){
				cbOut = last;			break;
				}
			//if not zero continue as if fPOINT
		case typLFPOINT:
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fx, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((lfPOINT *)Desc[i].ptr)->fy, true);
			break;
		case typPOINT3D:
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fx, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fy, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ((fPOINT3D *)Desc[i].ptr)->fz, true);
			break;
		case typAXDEF:		case typPTRAXDEF:
			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
			//we do not set ownership: reconstruct after read
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, ax->flags, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->min, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->max, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fx, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fy, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[0].fz, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fx, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fy, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->loc[1].fz, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Start, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Step, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fx, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Center.fy, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ax->Radius, true);
			WriteTypFpLst(ax->breaks, ax->nBreaks, false);
			break;
		case typLINEDEF:
			ld = (LineDEF *)Desc[i].ptr;
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->width, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, ld->patlength, true);
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->color, true);
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, ld->pattern, true);
			break;
		case typFILLDEF:
			fd = (FillDEF *)Desc[i].ptr;
			//we set the 'hatch' member to zero: reconstruct after read
			add_int_to_buff(&ptr, &cbOut, &sizeOut, fd->type, true, 0);
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, fd->scale, true);
			add_to_buff(&ptr, &cbOut, &sizeOut, " 0x0", 4);
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, fd->color2, true);
			break;
		case typGOBJ:
			if(*(GraphObj **)(Desc[i].ptr)) add_int_to_buff(&ptr, &cbOut, &sizeOut, 
				Notary->RegisterGO(*(GraphObj **)(Desc[i].ptr)), true, 0);
			else cbOut = last;
			break;
		case typOBJLST:
			if(!(*(GraphObj ***)(Desc[i].ptr)) || !(*Desc[i].count)){
				cbOut = last;				break;
				}
			WriteTypObjLst(*(GraphObj ***)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
			break;
		case typIPLST:
			if(!(*(POINT**)(Desc[i].ptr)) || !(*Desc[i].count)){
				cbOut = last;				break;
				}
			WriteTypIpLst(*(POINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L);
			break;
		case typFPLST:
			if(!(*(lfPOINT**)(Desc[i].ptr)) || !(*Desc[i].count)){
				cbOut = last;				break;
				}
			WriteTypFpLst(*(lfPOINT**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0L, true);
			break;
		case typFPLST3D:
			if(!(*(fPOINT3D**)(Desc[i].ptr)) || !(*Desc[i].count)){
				cbOut = last;				break;
				}
			WriteTypFpLst3D(*(fPOINT3D**)Desc[i].ptr, Desc[i].count ? *Desc[i].count : 0);
			break;
		case typTEXT:
			if(!*(char**)(Desc[i].ptr)) cbOut = last;
			else WriteEscString(*((char**)Desc[i].ptr));
			break;
		case typTXTDEF:		case typPTRTXTDEF:
			tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
			if(!tx) {
				cbOut = last;				break;
				}
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColTxt, true);
			add_hex_to_buff(&ptr, &cbOut, &sizeOut, tx->ColBg, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->fSize, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotBL, true);
			add_dbl_to_buff(&ptr, &cbOut, &sizeOut, tx->RotCHAR, true);
			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Align, true, 0);
			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Mode, true, 0);
			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Style, true, 0);
			add_int_to_buff(&ptr, &cbOut, &sizeOut, tx->Font, true, 0);
			if(tx->text && tx->text[0]) {
				add_to_buff(&ptr, &cbOut, &sizeOut, " \"", 2);
				add_to_buff(&ptr, &cbOut, &sizeOut, tx->text, 0);
				add_to_buff(&ptr, &cbOut, &sizeOut, "\"\n", 2);
				}
			break;
			}
		if(Desc[i].type & typLAST) break;
		}
	if(ptr[cbOut-1] != '\n') add_to_buff(&ptr, &cbOut, &sizeOut, "\n", 1);
	return true;
}

void ReadTypIpLst(POINT *ptr, long count, unsigned char *first)
{
	int i, j, k, f[20];

	if(!ptr || !first) return;
#ifdef USE_WIN_SECURE
	k = sscanf_s((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d", 
		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
#else
	k = sscanf((char*)first, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d", 
		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
#endif
	for(i = 0,  j = 0; j < k && i < count; i++, j += 2) {
		ptr[i].x = f[j];	ptr[i].y = f[j+1];
		}
	while (i < count) {
		if(!Cache->GetInt(&ptr[i].x) || !Cache->GetInt(&ptr[i].y)) return;
		i++;
		}
}

void ReadTypFpLst(lfPOINT *ptr, long count, unsigned char *first)
{
	double f[20];
	int j, k;
	long i;

	if(!ptr || !first) return;
#ifdef USE_WIN_SECURE
	k = sscanf_s((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", 
		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
#else
	k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", 
		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19]);
#endif
	for(i = 0,  j = 0; j < k && i < count; i++, j += 2) {
		ptr[i].fx = f[j];	ptr[i].fy = f[j+1];
		}
	while (i < count) {
		if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy)) return;
		i++;
		}
}

void ReadTypFpLst3D(fPOINT3D *ptr, long count, unsigned char *first)
{
	double f[21];
	int j, k;
	long i;

	if(!ptr || !first) return;
#ifdef USE_WIN_SECURE
	k = sscanf_s((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19], &f[20]);
#else
	k = sscanf((char*)first, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
		&f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9],
		&f[10], &f[11], &f[12], &f[13], &f[14], &f[15], &f[16], &f[17], &f[18], &f[19], &f[20]);
#endif
	for(i = 0,  j = 0; j < k && i < count; i++, j += 3) {
		ptr[i].fx = f[j];	ptr[i].fy = f[j+1];		ptr[i].fz = f[j+2];
		}
	while (i < count) {
		if(!Cache->GetFloat(&ptr[i].fx) || !Cache->GetFloat(&ptr[i].fy) ||
			!Cache->GetFloat(&ptr[i].fz)) return;
		i++;
		}
}

void TranslateEscChar(char *txt)
{
	int i, j;

	if(txt && txt[0]) {
		for(i = j = 0; txt[i]; i++) {
			if(txt[i] == '\\') {
				switch(txt[i+1]) {
				case 'n':
					txt[j++] = 0x0a;	i++;	break;
				case 'r':
					txt[j++] = 0x0d;	i++;	break;
				case '"':	case 0x27:			case '\\':
					txt[j++] = txt[++i];		break;
				default:
					txt[j++] = txt[i];	break;
					}
				}
			else txt[j++] = txt[i];
			}
		txt[j] = 0;
		}
}

void AddLines(char **txt)
{
	char tmp[1000], *ntxt;
	bool mlines;
	int i, j, cb = (int)strlen(*txt);

	do {
		mlines = false;
		Cache->ReadLine(tmp, sizeof(tmp));
		for(i = (int)strlen(tmp); i > 0 &&(tmp[i-1] < 33 || (tmp[i-1] == 
			'"' && tmp[i-2] != '\\') ||	(tmp[i-1] == '\\' && 
			(mlines = true))); tmp[--i] = 0);
		for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
		TranslateEscChar(tmp);
		if(tmp[0] && (j = (int)strlen(tmp+i)) && (ntxt = (char*)realloc(*txt, cb + j + 1))) {
			rlp_strcpy(ntxt+cb, j+1, tmp+i);
			cb += j;	*(txt) = ntxt;
			}
		} while (mlines);
}

bool ExecInput(descIO *Desc)
{
	unsigned char c, tmp[1000], tmp2[20];
	int i, j, k, l;
	bool match, mlines;
	int il, jl;
	AxisDEF *ax;
	POINT *lp;
	lfPOINT *lfp;
	fPOINT3D *lfp3d;
	LineDEF *ld;
	FillDEF *fd;
	fRECT *fr;
	GraphObj **gobs;
	TextDEF *tx;

	if(!Desc || !Desc[0].label) return false;
	for(j = k = 0; ; ) {
		do{
			c = Cache->Getc();
			switch (c) {
			case '[':					//next object
			case 0:						//probably eof
				return true;
			case '}':					//a lists hang over
				c = Cache->Getc();
				break;
				}
		} while(c <33);
		for(i = 1, tmp[0] = c; i < sizeof(tmp) && '=' != (tmp[i] = Cache->Getc()); i++){
			if(tmp[i] < 32 && tmp[i]) i = -1;			//some error conditions
			else if(!tmp[i] && Cache->eof) return true;
			else if(tmp[i] == '[') return true;
			}
		tmp[i] = 0;
		match = mlines = false;
		do {
			if(0 == strcmp((char*)tmp, Desc[j].label)) {
				Cache->ReadLine((char*)tmp, sizeof(tmp));
				switch(Desc[j].type & 0xff){
				case typNZINT:
				case typINT:
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%d", (int*)Desc[j].ptr);
#else
					sscanf((char*)tmp, "%d", (int*)Desc[j].ptr);
#endif
					break;
				case typNZLFLOAT:		case typLFLOAT:
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%lf", (double*)Desc[j].ptr);
#else
					sscanf((char*)tmp, "%lf", (double*)Desc[j].ptr);
#endif
					break;
				case typDWORD:
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
#else
					sscanf((char*)tmp, "%x", (DWORD*)Desc[j].ptr);
#endif
					break;
				case typFRECT:
					fr = (fRECT*) Desc[j].ptr;
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
#else
					sscanf((char*)tmp, "%lf%lf%lf%lf", &fr->Xmin, &fr->Ymax, &fr->Xmax, &fr->Ymin);
#endif
					break;
				case typNZLFPOINT:		case typLFPOINT:
					lfp = (lfPOINT*) Desc[j].ptr;
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
#else
					sscanf((char*)tmp, "%lf%lf", &lfp->fx, &lfp->fy);
#endif
					break;
				case typPOINT3D:
					lfp3d = (fPOINT3D*) Desc[j].ptr;
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
#else
					sscanf((char*)tmp, "%lf%lf%lf", &lfp3d->fx, &lfp3d->fy, &lfp3d->fz);
#endif
					break;
				case typPTRAXDEF:
				case typAXDEF:
					ax = (Desc[j].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[j].ptr : *(AxisDEF **)Desc[j].ptr;
					//pointer for typPTRAXDEF and memory allocated by the Axis module!
					if(!ax) break;
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%x%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d", &ax->flags, &ax->min, &ax->max,
						&ax->loc[0].fx,	&ax->loc[0].fy, &ax->loc[0].fz, &ax->loc[1].fx,
						&ax->loc[1].fy, &ax->loc[1].fz, &ax->Start, &ax->Step, &ax->Center.fx, 
						&ax->Center.fy, &ax->Radius, &ax->nBreaks);
#else
					sscanf((char*)tmp, "%x%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d", &ax->flags, &ax->min, &ax->max,
						&ax->loc[0].fx,	&ax->loc[0].fy, &ax->loc[0].fz, &ax->loc[1].fx,
						&ax->loc[1].fy, &ax->loc[1].fz, &ax->Start, &ax->Step, &ax->Center.fx, 
						&ax->Center.fy, &ax->Radius, &ax->nBreaks);
#endif
					if(ax->nBreaks) {
						ax->breaks = (lfPOINT*)calloc(ax->nBreaks, sizeof(lfPOINT));
						for(i = 0; tmp[i] && tmp[i-1] != '{'; i++);
						if(tmp[i]) {
							ReadTypFpLst(ax->breaks, ax->nBreaks, (unsigned char*)tmp+i);
							SortAxisBreaks(ax);
							}
						}
					break;
				case typLINEDEF:
					ld = (LineDEF*) Desc[j].ptr;
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
#else
					sscanf((char*)tmp,"%lf%lf%x%x", &ld->width, &ld->patlength, &ld->color, &ld->pattern);
#endif
					break;
				case typFILLDEF:
					fd = (FillDEF*) Desc[j].ptr;
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
#else
					sscanf((char*)tmp, "%d%x%lf%x%x", &fd->type, &fd->color, &fd->scale, &fd->hatch, &fd->color2);
#endif
					fd->hatch = 0L;
					break;
				case typGOBJ:
					*(GraphObj**)(Desc[j].ptr) = Notary->PopGO(atol((char*)tmp));
					break;
				case typOBJLST:
					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
					if(!tmp[i]) break;
#ifdef USE_WIN_SECURE
					if(sscanf_s((char*)tmp+i+1, "%ld", &il) && il) {
#else
					if(sscanf((char*)tmp+i+1, "%ld", &il) && il) {
#endif
						*Desc[j].count = il;
						if(!*(GraphObj***)(Desc[j].ptr)){
							*(GraphObj***)(Desc[j].ptr) = (GraphObj**)calloc(il, sizeof(GraphObj*));
							}
						if((gobs = *(GraphObj***)(Desc[j].ptr))){
							i += 4;
							while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
#ifdef USE_WIN_SECURE
							strcat_s((char*)tmp, 1000, " ");
#else
							strcat((char*)tmp, " ");
#endif
							for( ;il >0; il--) {
								for(l = 0; l < sizeof(tmp2); ){
									if(tmp[i]) c = tmp[i++];
									else if(!(c = Cache->Getc())) break;
									if(c >='0' && c <='9') tmp2[l++] = c;
									else {
										tmp2[l] = 0;
										if(l)break;
										}
									}
#ifdef USE_WIN_SECURE
								sscanf_s((char*)tmp2, "%d", &jl);
#else
								sscanf((char*)tmp2, "%d", &jl);
#endif
								*gobs++ = Notary->PopGO(jl);
								if(c == '}') break;
								}
							}
						}	
					break;
				case typIPLST:
					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
					if(!tmp[i]) break;
#ifdef USE_WIN_SECURE
					if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
#else
					if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
#endif
						*Desc[j].count = il;
						if(!*(POINT**)(Desc[j].ptr)){
							*(POINT**)(Desc[j].ptr) = (POINT*)calloc(il, sizeof(POINT));
							}
						if(!(lp = *(POINT**)(Desc[j].ptr)))return false;
						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
						ReadTypIpLst(lp, il, (unsigned char*)tmp+i);
						}
					break;
				case typFPLST:
					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
					if(!tmp[i]) break;
#ifdef USE_WIN_SECURE
					if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
#else
					if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
#endif
						*Desc[j].count = il;
						if(!*(lfPOINT**)(Desc[j].ptr)){
							*(lfPOINT**)(Desc[j].ptr) = (lfPOINT*)calloc(il, sizeof(lfPOINT));
							}
						if(!(lfp = *(lfPOINT**)(Desc[j].ptr)))return false;
						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
						ReadTypFpLst(lfp, il, (unsigned char*)tmp+i);
						}
					break;
				case typFPLST3D:
					for(i = 0; i < 10 && tmp[i] != '(' && tmp[i]; i++);
					if(!tmp[i]) break;
#ifdef USE_WIN_SECURE
					if(sscanf_s((char*)tmp+i+1, "%d", &il) && il) {
#else
					if(sscanf((char*)tmp+i+1, "%d", &il) && il) {
#endif
						*Desc[j].count = il;
						if(!*(fPOINT3D**)(Desc[j].ptr)){
							*(fPOINT3D**)(Desc[j].ptr) = (fPOINT3D*)calloc(il, sizeof(fPOINT3D));
							}
						if(!Desc[j].ptr)return false;
						while(tmp[i-1] != '{') i++; while(tmp[i-1] < 33) i++;
						ReadTypFpLst3D(*(fPOINT3D**)(Desc[j].ptr), il, (unsigned char*)tmp+i);
						}
					break;
				case typTEXT:
					for(i = (int)strlen((char*)tmp); i > 0 &&(tmp[i-1] < 32 || (tmp[i-1] == 
						'"' && tmp[i-2] != '\\') ||	(tmp[i-1] == '\\' && 
						(mlines = true))); tmp[--i] = 0);
					for(i = 0; tmp[i] && (tmp[i] < 33 || tmp[i] == '"'); i++);
					TranslateEscChar((char*)tmp);
					if(tmp[0]){
						*(char**)(Desc[j].ptr) = (char*)memdup((char*)tmp+i, (int)strlen((char*)tmp+i)+1, 0);
						if(mlines) AddLines((char**)(Desc[j].ptr));
						}
					break;
				case typPTRTXTDEF:
				case typTXTDEF:
					tx = (Desc[j].type & 0xff) == typTXTDEF ? (TextDEF *)Desc[j].ptr : *(TextDEF **)Desc[j].ptr;
					if(!tx) {
						if((Desc[j].type & 0xff) == typTXTDEF) break;	//prabably wrong usage of typTXTDEF instad of
																//    typPTRTXTDEF
						tx = *(TextDEF **)(Desc[j].ptr) = (TextDEF*)calloc(1, sizeof(TextDEF));
						if(!tx) return false;					//memory allocation error
						}
#ifdef USE_WIN_SECURE
					sscanf_s((char*)tmp, "%x%x%lf%lf%lf%d%d%d%d", &tx->ColTxt, &tx->ColBg, 
						&tx->fSize, &tx->RotBL, &tx->RotCHAR,
						&tx->Align, &tx->Mode, &tx->Style, &tx->Font);
#else
					sscanf((char*)tmp, "%x%x%lf%lf%lf%d%d%d%d", &tx->ColTxt, &tx->ColBg, 
						&tx->fSize, &tx->RotBL, &tx->RotCHAR,
						&tx->Align, &tx->Mode, &tx->Style, &tx->Font);
#endif
					tx->iSize = 0;
					for(i = (int)strlen((char*)tmp); i >0 && tmp[i] != '"'; i--);
					if(i) {
						tmp[i] = 0;
						for(l = 0; l <i && tmp[l] != '"'; l++);
						if(i && tmp[l+1]) tx->text = (char*)memdup((char*)tmp+l+1, (int)strlen((char*)tmp+l+1)+1, 0);
						}
					break;
					}
				match = true;			j++;	k++;
				if(!Desc[j].label || (Desc[j-1].type & typLAST)) 
					j = k = 0;	//rewind: items in file not sorted
				}
			else {
				j++;
				k++;
				if(!Desc[j].label || (Desc[j-1].type & typLAST)) {				//Error:
					if(k > j){						//  item not defined in Desc
						match = true;				//  read parameters,
						Cache->ReadLine((char*)tmp, sizeof(tmp));	//   then continue
						}
					j= 0;
					}
				}
			}while(!match);
		}
}

bool SaveGraphAs(GraphObj *g)
{
	char *name = 0L;
	int i;
	bool bRet = true;

	if(Notary || !g) {
		ErrorBox("Output pending or\nno graph.");
		return false;
		}
	cObsW = 0;
	Notary = new notary();
	if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
		if(((Graph*)g)->filename) name = ((Graph*)g)->filename;
		}
	name = SaveGraphAsName(name);
	if (name && Notary) {
		iFile = OpenOutputFile(name);
		if(iFile >=0) {
			if(g && g->FileIO(FILE_WRITE)){
				if(g->Id == GO_GRAPH || g->Id == GO_PAGE) {
					g->Command(CMD_FILENAME, name, 0L);
					}
				for(i = (int)strlen(name); i >=0 && name[i] != '/' && name[i] != '\\'; i--);
				if(name[i]) i++;
				g->Command(CMD_SETNAME, name+i, 0L);
				g->Command(CMD_UPDHISTORY, 0L, 0L);
				}
			else ErrorBox("Could not write\ndata to file.");
			}
		else ErrorBox("Open failed for\noutput file.");
		CloseOutputFile();
		}
	else bRet = false;
	if(Notary) delete Notary;	Notary = 0L;
	return bRet;
}

char *GraphToMem(GraphObj *g, long *size)
{
	static char *ret;

	if(Notary || !g) {
		ErrorBox("Output pending or\nno graph.");
		return false;
		}
	cObsW = 0;				iFile = -1;
	cbOut = sizeOut = 0;	ptr = 0L;
	if (Notary = new notary()) {
		if(g && g->FileIO(FILE_WRITE)){
			//all done
			}
		delete Notary;					Notary = 0L;
		if(ptr) ptr[cbOut] = 0;
		ret = ptr;						if(size) *size = cbOut;
		iFile = -1;
		cbOut = sizeOut = 0;	ptr = 0L;
		return ret;
		}
	return 0L;
}

void UpdGOfromMem(GraphObj *go, unsigned char *buff)
{
	int i=0;

	if(!go || !buff) return;
	iFile = -1;							cbOut = sizeOut = 0;	ptr = 0L;
	for(i = 0; buff[i] && buff[i] != ']'; i++);
	if(!buff[i])return;
	for(; buff[i] && buff[i] <33; i++);
	if(!buff[i] || i < 4) return;
	if(!(Cache = new MemCache(buff+i-1))) return;
	if ((Notary = new notary()) && go->Id > GO_UNKNOWN && go->Id < GO_DEFRW) {
		//notary not needed but saver if tree exists
		go->Command(CMD_FLUSH, 0L, 0L);
		go->FileIO(INIT_VARS);			go->FileIO(FILE_READ);
		delete Notary;					Notary = 0L;
		}
	delete Cache;		Cache = 0L;
}

bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
{
	unsigned char c, tmp[80];
	char debug[80];
	int i, id, lid;
	unsigned int hv;
	GraphObj *go;
	scaleINFO sc_info;

	LastOpenGO = 0L;
	if(Notary || Cache) {
		ErrorBox("Output pending:\nRead Error.");
		return false;
		}
	if(!(Notary = new notary()))return false;
	if(mem) {
		if(!(Cache = new MemCache(mem))) return false;
		}
	else if(Cache = new ReadCache()){
		if(!Cache->Open(name)) {
			delete Notary;		delete Cache;
			Notary = 0L;		Cache = 0L;
			ErrorBox("Error open file");
			return false;
			}
		}
	else return false;
	//DEBUG: skipping header
	do {
		c = Cache->Getc();
		} while(c && c != '[');
	if(!c) goto ReadErr;
	do {
		for(i = 0; i < sizeof(tmp) && c != '=' && c; i++){
			tmp[i] = c = Cache->Getc();
			if(c == '[') i = -1;
			}
		if(!c) goto ReadErr;
		tmp[i] = tmp[i-1] = 0;			id=0;
#ifdef USE_WIN_SECURE
		sscanf_s((char*)tmp, "%d", &id);
#else
		sscanf((char*)tmp, "%d", &id);
#endif
		if(!id) goto ReadErr;
		//go to class name
		while((tmp[0] = Cache->Getc())<31 && tmp[0]);
		if(!tmp[0]) goto ReadErr;
		for(i = 1; i < sizeof(tmp) && c!= ']' && c; i++)
			tmp[i] = c = Cache->Getc();
		if(!c) goto ReadErr;
		tmp[i-1] = 0;
		go = 0L;
		hv = HashValue(tmp);
		switch(hv) {
		case 3895:	go = new Axis(FILE_READ);		break;
		case 886:	go = new Bar(FILE_READ);		break;
		case 81384:	go = new Symbol(FILE_READ);		break;
		case 62229:	go = new Bubble(FILE_READ);		break;
		case 948:	go = new Box(FILE_READ);		break;
		case 15411:	go = new Arrow(FILE_READ);		break;
		case 1052406:	go = new ErrorBar(FILE_READ);		break;
		case 324566:	go = new Whisker(FILE_READ);		break;
		case 1031437:	go = new DropLine(FILE_READ);		break;
		case 4839:	go = new Tick(FILE_READ);		break;
		case 16832:	go = new Label(FILE_READ);		break;
		case 1071373:	go = new GridLine(FILE_READ);		break;
		case 963085:	go = new DataLine(FILE_READ);		break;
		case 61662266:	go = new DataPolygon(FILE_READ);	break;
		case 435228:	go = new segment(FILE_READ);		break;
		case 1741325:	go = new polyline(FILE_READ);		break;
		case 435258:	go = new polygon(FILE_READ);		break;
		case 92534:	go = new Bezier(FILE_READ);		break;
		case 6888037:	go = new rectangle(FILE_READ);		break;
		case 1780087:	go = new roundrec(FILE_READ);		break;
		case 78813:	go = new Sphere(FILE_READ);		break;
		case 15463:	go = new Brick(FILE_READ);		break;
		case 69952:	go = new Line3D(FILE_READ);		break;
		case 386257:	go = new ellipse(FILE_READ);		break;
		case 95680:	go = new mLabel(FILE_READ);		break;
		case 4819316:	go = new PlotScatt(FILE_READ);		break;
		case 117848:	go = new xyStat(FILE_READ);		break;
		case 15935312:	go = new BubblePlot(FILE_READ);		break;
		case 247376:	go = new BoxPlot(FILE_READ);		break;
		case 317384:	go = new StackBar(FILE_READ);		break;
		case 1205932:	go = new PieChart(FILE_READ);		break;
		case 16664:	go = new Graph(FILE_READ);		break;
		case 25108:	go = new GoGroup(FILE_READ);		break;
		case 300976:	go = new Scatt3D(FILE_READ);		break;
		case 297280:	go = new Plane3D(FILE_READ);		break;
		case 19227098:	go = new Regression(FILE_READ);		break;
		case 297997:	go = new RegLine(FILE_READ);		break;
		case 4318417:	go = new SDellipse(FILE_READ);		break;
		case 4843600:	go = new PolarPlot(FILE_READ);		break;
		case 977452:	go = new DensDisp(FILE_READ);		break;
		case 4465:	go = new Page(FILE_READ);		break;
		case 75120:	go = new Plot3D(FILE_READ);		break;
		case 17142080:	go = new GridLine3D(FILE_READ);		break;
		case 246688:	go = new Arrow3D(FILE_READ);		break;
		case 75562:	go = new Ribbon(FILE_READ);		break;
		case 16503104:	go = new DropLine3D(FILE_READ);		break;
		case 28859579:	go = new svgOptions(FILE_READ);		break;
		case 70259:	go = new Limits(FILE_READ);		break;
		case 17145824:	go = new GridRadial(FILE_READ);		break;
		case 1074714:	go = new Function(FILE_READ);		break;
		case 256075:	go = new FitFunc(FILE_READ);		break;
		case 273377:	go = new LegItem(FILE_READ);		break;
		case 1053744:	go = new FreqDist(FILE_READ);		break;
		case 68748:	go = new Legend(FILE_READ);		break;
		case 66800:	go = new Grid3D(FILE_READ);		break;
		case 967843:	go = new DefsRW(FILE_READ);		break;
		case 66848:	go = new Func3D(FILE_READ);		break;
		case 5001225:	go = new TextFrame(FILE_READ);		break;
		case 4743132:	go = new NormQuant(FILE_READ);		break;
		case 64333904:	go = new ContourPlot(FILE_READ);	break;
		default:
#ifdef USE_WIN_SECURE
			sprintf_s(debug, 80, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
#else
			sprintf(debug, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
#endif
			InfoBox(debug);
			}
		if(go) {
			if(((int)id) < 0) DeleteGO(go);		//temporary objects have id < 0
			else if(!Notary->PushGO(lid = id, go)) DeleteGO(go);
			}
		if('[' != Cache->Lastc()) do {			//search next object
			c = Cache->Getc();
			} while(c && c != '[');
		tmp[0] = 0;
		}while (c);
	Cache->Close();
	if((LastOpenGO = go = Notary->PopGO(lid))) {
		go->Command(CMD_SET_DATAOBJ, 0L, 0L);
		if (name && name[0]) go->Command(CMD_FILENAME, name, 0L);
		delete Notary;		Notary = 0L;
		if(bPaste && go->Id == GO_GRAPH) {
			sc_info.sx.fx = -((Graph*)go)->GRect.Xmin;				sc_info.sy.fx = -((Graph*)go)->GRect.Ymin;
			sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0;	sc_info.sz.fx = 0.0;
			go->Command(CMD_SCALE, &sc_info, 0L);
			sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0/go->GetSize(SIZE_SCALE);
			sc_info.sx.fx = sc_info.sy.fx = sc_info.sz.fx = 0.0;
			go->Command(CMD_SCALE, &sc_info, 0L);
			}
		if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
			// object accepted
			}
		else if(go->Id < GO_GRAPH 
			&& !(root->Command(CMD_DROP_PLOT, (void *)go, 0L))){
			DeleteGO(go);	go = 0L;
			}
		else if(go->Id >= GO_GRAPH 
			&& !(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
			DeleteGO(go);	go = 0L;
			}
		//go may not be valid any more at this stage
		}
	if(Notary) delete Notary;		Notary = 0L;
	delete Cache;					Cache = 0L;
	return true;

ReadErr:
	Cache->Close();	
#ifdef USE_WIN_SECURE
	if(iFile >= 0) _close(iFile);
#else
	if(iFile >= 0) close(iFile);
#endif
	iFile = -1;
	delete Notary;		Notary = 0L;
	delete Cache;		Cache = 0L;
	if(!name || !defs.IniFile || strcmp(name, defs.IniFile))
		ErrorBox("An error occured during read.");
	return false;
}

bool InitVarsGO(descIO *Desc)
{
	int i;
	AxisDEF *ax;
	TextDEF *tx;

	for(i = 0; Desc[i].label; i++) {
		switch(Desc[i].type & 0xff) {
		case typNZINT:
		case typINT:
			*(int*)Desc[i].ptr = 0;			
			break;
		case typNZLFLOAT:
		case typLFLOAT:
			*(double*)Desc[i].ptr = 0.0;
			break;
		case typDWORD:
			*(DWORD*)Desc[i].ptr = 0x0L;
			break;
		case typFRECT:
			((fRECT*)Desc[i].ptr)->Xmin = ((fRECT*)Desc[i].ptr)->Xmax =
				((fRECT*)Desc[i].ptr)->Ymin = ((fRECT*)Desc[i].ptr)->Ymax = 0.0;
			break;
		case typNZLFPOINT:
		case typLFPOINT:
			((lfPOINT*)Desc[i].ptr)->fx = ((lfPOINT*)Desc[i].ptr)->fy = 0.0;
			break;
		case typPOINT3D:
			((fPOINT3D*)Desc[i].ptr)->fx = ((fPOINT3D*)Desc[i].ptr)->fy =
				((fPOINT3D*)Desc[i].ptr)->fz = 0.0;
			break;
		case typPTRAXDEF:
		case typAXDEF:
			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
			if(!ax) break;
			ax->owner = 0L;		ax->flags = 0L;		ax->breaks = 0L;	ax->nBreaks = 0;
			ax->min = ax->max = ax->Start = ax->Step = 0.0f;
			ax->loc[0].fx = ax->loc[0].fy = ax->loc[0].fz = 0.0f;
			ax->loc[1].fx = ax->loc[1].fy = ax->loc[1].fz = 0.0f;
			ax->Center.fx = ax->Center.fy = ax->Radius = 0.0f;
			break;
		case typLINEDEF:
			((LineDEF*)Desc[i].ptr)->width = defs.GetSize(SIZE_HAIRLINE);
			((LineDEF*)Desc[i].ptr)->patlength = defs.GetSize(SIZE_PATLENGTH);
			((LineDEF*)Desc[i].ptr)->color = ((LineDEF*)Desc[i].ptr)->pattern = 0x0L;
			break;
		case typFILLDEF:
			((FillDEF*)Desc[i].ptr)->type = FILL_NONE;
			((FillDEF*)Desc[i].ptr)->color = 0x00ffffffL;
			((FillDEF*)Desc[i].ptr)->scale = 1.0f;
			((FillDEF*)Desc[i].ptr)->hatch = (LineDEF*)0L;
			((FillDEF*)Desc[i].ptr)->color2 = 0x00ffffffL;
			break;
		case typGOBJ:
			*(GraphObj **)Desc[i].ptr = (GraphObj*)0L;
			break;
		case typOBJLST:
			*Desc[i].count = 0L;
			*(GraphObj ***)Desc[i].ptr = (GraphObj**)0L;
			break;
		case typIPLST:
			*Desc[i].count = 0L;
			*(POINT **)Desc[i].ptr = (POINT*)0L;
			break;
		case typFPLST:
			*Desc[i].count = 0L;
			*(lfPOINT **)Desc[i].ptr = (lfPOINT*)0L;
			break;
		case typFPLST3D:
			*Desc[i].count = 0L;
			*(fPOINT3D **)Desc[i].ptr = (fPOINT3D*)0L;
			break;
		case typTEXT:
			*(char **)Desc[i].ptr = (char*)0L;
			break;
		case typTXTDEF:
			tx = (TextDEF *)Desc[i].ptr;
			tx->ColTxt = 0x0L,			tx->ColBg = 0x00ffffffL;
			tx->fSize = defs.GetSize(SIZE_TEXT);
			tx->RotBL = tx->RotCHAR = 0.0;
			tx->Align = tx->Mode = tx->Style = tx->Font = 0L;
			tx->text = 0L;
			break;
		case typPTRTXTDEF:
			*(TextDEF**)Desc[i].ptr = (TextDEF*)0L;
			break;
			}
		if(Desc[i].type & typLAST) break;
		}
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Save object data to memory block
static unsigned char *SavVarBuf = 0L;
static long SavVarSize = 0,	SavVarPos = 0;
void SavVarInit(long len)
{
	if(SavVarBuf) free(SavVarBuf);
	SavVarBuf = (unsigned char *)malloc(SavVarSize = len+4096);
	SavVarPos = 0;
}

bool SavVarAdd(void *ptr, int size)
{
	int len;

	if(SavVarBuf && size>0) {
		len = sizeof(unsigned char *) + sizeof(int) + size;
		while (SavVarSize <= SavVarPos+len) {
			if(!(SavVarBuf = (unsigned char *)realloc(SavVarBuf, SavVarSize + 4096))) return false;
			SavVarSize += 4096;
			}
		memcpy(SavVarBuf+SavVarPos, &ptr, sizeof(unsigned char *));	SavVarPos += sizeof(unsigned char *);
		memcpy(SavVarBuf+SavVarPos, &size, sizeof(int));		SavVarPos += sizeof(int);
		if(ptr) {
			memcpy(SavVarBuf+SavVarPos, ptr, size);			SavVarPos += size;
			}
		return true;
		}
	return false;
}

void *SavVarFetch()
{
	void *tmp;

	SavVarAdd((void*)0L, sizeof(unsigned char*));				
	tmp = SavVarBuf;	SavVarSize = SavVarPos = 0;		SavVarBuf = 0L;
	return tmp;
}

bool SaveVarGO(descIO *Desc)
{
	int i;
	AxisDEF *ax;
	TextDEF *tx;

	for(i = 0; Desc[i].label; i++) {
		switch(Desc[i].type & 0xff){
		case typNZINT:
		case typINT:
			SavVarAdd(Desc[i].ptr, sizeof(int));
			break;
		case typNZLFLOAT:
		case typLFLOAT:
			SavVarAdd(Desc[i].ptr, sizeof(double));
			break;
		case typDWORD:
			SavVarAdd(Desc[i].ptr, sizeof(DWORD));
			break;
		case typFRECT:
			SavVarAdd(Desc[i].ptr, sizeof(fRECT));
			break;
		case typNZLFPOINT:
		case typLFPOINT:
			SavVarAdd(Desc[i].ptr, sizeof(lfPOINT));
			break;
		case typPOINT3D:
			SavVarAdd(Desc[i].ptr, sizeof(fPOINT3D));
			break;
		case typAXDEF:
		case typPTRAXDEF:
			ax = (Desc[i].type & 0xff) == typAXDEF ? (AxisDEF *)Desc[i].ptr : *(AxisDEF **)Desc[i].ptr;
			if(ax) {
				SavVarAdd(ax, sizeof(AxisDEF));
				if(ax->breaks && ax->nBreaks) {
					SavVarAdd(ax->breaks, ax->nBreaks * sizeof(lfPOINT));
					}
				}
			break;
		case typLINEDEF:
			SavVarAdd(Desc[i].ptr, sizeof(LineDEF));
			break;
		case typFILLDEF:
			SavVarAdd(Desc[i].ptr, sizeof(FillDEF));
			break;
		case typGOBJ:	case typOBJLST:		//not supported
			break;
		case typIPLST:						//probably in the future
			break;
		case typFPLST:
			SavVarAdd(Desc[i].count, sizeof(long));
			SavVarAdd(*((void **)Desc[i].ptr), sizeof(lfPOINT) * (*Desc[i].count));
			break;
		case typFPLST3D:
			SavVarAdd(Desc[i].count, sizeof(long));
			SavVarAdd(*((void **)Desc[i].ptr), sizeof(fPOINT3D) * (*Desc[i].count));
			break;
		case typTEXT:
			if(*(char**)(Desc[i].ptr)) SavVarAdd(Desc[i].ptr, (int)strlen(*(char**)(Desc[i].ptr))+1);
			break;
		case typTXTDEF:
		case typPTRTXTDEF:
			tx = (Desc[i].type &0xff) == typTXTDEF ? (TextDEF *)Desc[i].ptr : *(TextDEF **)Desc[i].ptr;
			if(tx) SavVarAdd(tx, sizeof(TextDEF) - sizeof(char*));
			break;
			}
		if(Desc[i].type & typLAST) break;
		}
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Graphic object member funtions for IO
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
svgOptions::FileIO(int rw)
{
	descIO Desc[] = {
		{"tagAttr", typTEXT, &svgattr, 0L},
		{"Script", typLAST | typTEXT, &script, 0L}};

	switch(rw) {
	case INIT_VARS:
		return InitVarsGO(Desc);
	case FILE_READ:
		return ExecInput(Desc);
		}
	return false;
}

bool
Symbol::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"Idx", typINT, &idx, 0L},
		{"Pos", typLFPOINT, &fPos, 0L},
		{"Size", typLFLOAT, &size, 0L},
		{"Line", typLINEDEF, &SymLine, 0L},
		{"FillCol", typDWORD, &SymFill.color, 0L},
		{"Text", typPTRTXTDEF, &SymTxt, 0L},
		{"Name", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		size = DefSize(SIZE_SYMBOL);
		SymLine.color = parent ? parent->GetColor(COL_SYM_LINE) : defs.Color(COL_SYM_LINE);
		SymLine.width = parent ? parent->GetSize(SIZE_SYM_LINE) : DefSize(SIZE_SYM_LINE);
		SymFill.type = FILL_NONE;
		SymFill.color = parent ? parent->GetColor(COL_SYM_FILL) : defs.Color(COL_SYM_FILL);
		SymFill.scale = 1.0f;
		SymFill.hatch = (LineDEF *) 0L;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		SymFill.hatch = (LineDEF *) 0L;
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Symbol", Desc);
		}
	return false;
}


bool
Bubble::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"Pos", typLFPOINT, &fPos, 0L},
		{"Size", typLFLOAT, &fs, 0L},
		{"Line", typLINEDEF, &BubbleLine, 0L},
		{"FillLine", typLINEDEF, &BubbleFillLine, 0L},
		{"Fill", typFILLDEF, &BubbleFill, 0L},
		{"Name", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		BubbleLine.width = DefSize(SIZE_BUBBLE_LINE);
		BubbleFillLine.width = DefSize(SIZE_BUBBLE_HATCH_LINE);
		BubbleLine.color = BubbleFillLine.color = defs.Color(COL_BUBBLE_LINE);
		BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
		ssRef = 0L;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		BubbleFill.hatch = &BubbleFillLine;
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Bubble", Desc);
		}
	return false;
}

bool
Bar::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"Pos", typLFPOINT, &fPos, 0L},
		{"Size", typLFLOAT, &size, 0L},
		{"Org", typLFPOINT, &BarBase, 0L},
		{"Line", typLINEDEF, &BarLine, 0L},
		{"Fill", typFILLDEF, &BarFill, 0L},
		{"FillLine", typLINEDEF, &HatchLine, 0L},
		{"Name", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		type = BAR_VERTB;
		memcpy(&BarFill, defs.GetFill(), sizeof(FillDEF));
		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
		BarFill.hatch = &HatchLine;
		memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
		size = DefSize(SIZE_BAR);
		mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		BarFill.hatch = &HatchLine;
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Bar", Desc);
		}
	return false;
}

void
DataLine::FileValues(char *name, int type, double start, double step)
{
	FILE *file;
	int i, c;
	double fx;
	lfPOINT *tfp;

#ifdef USE_WIN_SECURE
	if(fopen_s(&file, name, "r")) {
		sprintf_s(TmpTxt, TMP_TXT_SIZE, "DataLine: open failed for file \"%s\"", name);
#else
	if(!(file = fopen(name, "r"))) {
		sprintf(TmpTxt, "DataLine: open failed for file \"%s\"", name);
#endif
		ErrorBox(TmpTxt);
		return;
		}
	if(Values) free(Values);
	if(!(Values = (lfPOINT*)calloc( nPnt = 1000, sizeof(lfPOINT)))){
		fclose(file);
		return;
		}
	switch(type) {
	case 1:				//x and y values
		i = 0;
		do {
#ifdef USE_WIN_SECURE
			c = fscanf_s(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
#else
			c = fscanf(file, "%lf%lf", &Values[i].fx, &Values[i].fy);
#endif
			i++;
			if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
				Values = tfp;			nPnt += 1000;
				}
			else if(i >= nPnt) break;
			}while(c == 2);
		i--;
		break;
	case 2:				//only y values
		i = 0;	fx = start;
		do {
#ifdef USE_WIN_SECURE
			c = fscanf_s(file, "%lf", &Values[i].fy);
#else
			c = fscanf(file, "%lf", &Values[i].fy);
#endif
			Values[i].fx = fx;
			i++;	fx += step;
			if(i >= nPnt &&(tfp = (lfPOINT*)realloc(Values, (nPnt+1000)*sizeof(lfPOINT)))){
				Values = tfp;			nPnt += 1000;
				}
			}while(c == 1);
		i--;
		break;
		}
	nPntSet = i-1;
	fclose(file);
}

bool
DataLine::FileIO(int rw)
{
	char *file1 = 0L;
	char *file2 = 0L;
	double Start = 0.0f, Step = 0.0f;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssXref", typTEXT, &ssXref, 0L},
		{"ssYref", typTEXT, &ssYref, 0L},
		{"BgCol", typDWORD, &BgColor, 0L},
		{"Line", typLINEDEF, &LineDef, 0L},
		{"Data", typFPLST, &Values, &nPnt},
		{"file_xy", typTEXT, &file2, 0L},
		{"start_x", typNZLFLOAT, &Start, 0L},
		{"step_x", typNZLFLOAT, &Step, 0L},
		{"file_y", typTEXT, &file1, 0L},
		{"Desc", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		isPolygon = false;
		nPnt = nPntSet = cp = 0;
		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
		BgColor = defs.Color(COL_BG);
		pts = 0L;		dirty = true;	mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		min.fx = min.fy = max.fx = max.fy = 0.0;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		nPntSet = nPnt-1;
		if(file2)FileValues(file2, 1, 0.0, 1.0);
		else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
		if(file1) free(file1);
		if(file2) free(file2);
		if(nPnt && Values)return true;
		break;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "DataLine", Desc);
		}
	return false;
}

bool
DataPolygon::FileIO(int rw)
{
	char *file1 = 0L;
	char *file2 = 0L;
	double Start = 0.0f, Step = 0.0f;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssXref", typTEXT, &ssXref, 0L},
		{"ssYref", typTEXT, &ssYref, 0L},
		{"BgCol", typDWORD, &BgColor, 0L},
		{"Line", typLINEDEF, &LineDef, 0L},
		{"FillLine", typLINEDEF, &pgFillLine, 0L},
		{"Fill", typFILLDEF, &pgFill, 0L},
		{"Data", typFPLST, &Values, &nPnt},
		{"file_xy", typTEXT, &file2, 0L},
		{"start_x", typNZLFLOAT, &Start, 0L},
		{"step_x", typNZLFLOAT, &Step, 0L},
		{"file_y", typLAST | typTEXT, &file1, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		isPolygon = true;
		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
		LineDef.pattern = 0L;
		BgColor = defs.Color(COL_BG);
		memcpy(&pgFill, defs.GetFill(), sizeof(FillDEF));
		if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
		pgFill.hatch = &pgFillLine;		dirty = true;	mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		min.fx = min.fy = max.fx = max.fy = 0.0f;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		nPntSet = nPnt-1;
		if(file2)FileValues(file2, 1, 0.0f, 1.0f);
		else if(file1)FileValues(file1, 2, Start, fabs(Step) > defs.min4log ? Step : 1.0);
		if(file1) free(file1);
		if(file2) free(file2);
		pgFill.hatch = &pgFillLine;
		if(nPnt && Values)return true;
		break;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "DataPolygon", Desc);
		}
	return false;
}

bool
RegLine::FileIO(int rw)
{
	descIO Desc[] = {
		{"type", typNZINT, &type, 0L},
		{"nPoints", typINT, &nPoints, 0L},
		{"BgCol", typDWORD, &BgColor, 0L},
		{"Line", typLINEDEF, &LineDef, 0L},
		{"Range", typFRECT, &lim, 0L},
		{"uClip", typFRECT, &uclip, 0L},
		{"mx", typNZLFLOAT, &mx, 0L},
		{"my", typNZLFLOAT, &my, 0L},
		{"li1", typLFPOINT, &l1, 0L},
		{"li2", typLFPOINT, &l2, 0L},
		{"li3", typLFPOINT, &l3, 0L},
		{"li4", typLFPOINT, &l4, 0L},
		{"li5", typLAST | typLFPOINT, &l5, 0L}};

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		cp = 0;
		memcpy(&LineDef, defs.GetLine(), sizeof(LineDEF));
		BgColor = defs.Color(COL_BG);
		pts = 0L;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "RegLine", Desc);
		}
	return false;
}

void
SDellipse::RegGO(void *n)
{
	if(n) {
		if(rl)rl->RegGO(n);
		((notary*)n)->AddRegGO(this);
	}
}

bool
SDellipse::FileIO(int rw)
{
	descIO Desc[] = {
		{"type", typNZINT, &type, 0L},
		{"Line", typLINEDEF, &LineDef, 0L},
		{"Range", typFRECT, &lim, 0L},
		{"Regr", typGOBJ, &rl, 0L},
		{"Data", typLAST | typFPLST, &val, &nPoints}};

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		memcpy(&LineDef, defs.GetOutLine(), sizeof(LineDEF));
		pts = 0L;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(rl) rl->parent = this;
		return true;
	case FILE_WRITE:
		if(rl) rl->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "SDellipse", Desc);
		}
	return false;
}

bool
ErrorBar::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"Pos", typLFPOINT, &fPos, 0L},
		{"Err", typLFLOAT, &ferr, 0L},
		{"Size", typLFLOAT, &SizeBar, 0L},
		{"Line", typLINEDEF, &ErrLine, 0L},
		{"Desc", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		SizeBar = DefSize(SIZE_ERRBAR);
		ErrLine.width = DefSize(SIZE_ERRBAR_LINE);
		ErrLine.color = defs.Color(COL_SYM_LINE);
		mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "ErrorBar", Desc);
		}
	return false;
}

bool
Arrow::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"moveable", typNZINT, &moveable, 0L},
		{"p1", typLFPOINT, &pos1, 0L},
		{"p2", typLFPOINT, &pos2, 0L},
		{"CapW", typLFLOAT, &cw, 0L},
		{"CapL", typLFLOAT, &cl, 0L},
		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		cw = DefSize(SIZE_ARROW_CAPWIDTH);
		cl = DefSize(SIZE_ARROW_CAPLENGTH);
		LineDef.color = parent ? parent->GetColor(COL_DATA_LINE) : defs.Color(COL_DATA_LINE);
		LineDef.width = parent ? parent->GetSize(SIZE_ARROW_LINE) : DefSize(SIZE_ARROW_LINE);
		type = ARROW_LINE;		dh1 = dh2 = 0L;		mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Arrow", Desc);
		}
	return false;
}

bool
Box::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"High", typLFPOINT, &pos1, 0L},
		{"Low", typLFPOINT, &pos2, 0L},
		{"Size", typLFLOAT, &size, 0L},
		{"Line", typLINEDEF, &Outline, 0L},
		{"FillLine", typLINEDEF, &Hatchline, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"Name", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		memcpy(&Outline, defs.GetOutLine(), sizeof(LineDEF));
		memcpy(&Fill, defs.GetFill(), sizeof(FillDEF));
		if(Fill.hatch)memcpy(&Hatchline, Fill.hatch, sizeof(LineDEF));
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		Fill.hatch = &Hatchline;		size = DefSize(SIZE_BAR);
		ssRef = 0L;				mo = 0L;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		Fill.hatch = &Hatchline;
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Box", Desc);
		}
	return false;
}

bool
Whisker::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"High", typLFPOINT, &pos1, 0L},
		{"Low", typLFPOINT, &pos2, 0L},
		{"Size", typLFLOAT, &size, 0L},
		{"Line", typLINEDEF, &LineDef, 0L},
		{"Desc", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		size = DefSize(SIZE_WHISKER);
		LineDef.width = DefSize(SIZE_WHISKER_LINE);
		LineDef.color = defs.Color(COL_WHISKER);
		mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Whisker", Desc);
		}
	return false;
}

bool
DropLine::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typINT, &type, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"Pos", typLFPOINT, &fPos, 0L},
		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		LineDef.color = defs.Color(COL_SYM_LINE);
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "DropLine", Desc);
		}
	return false;
}

bool
Sphere::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"Pos", typPOINT3D, &fPos, 0L},
		{"Size", typLFLOAT, &size, 0L},
		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};
	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		size = DefSize(SIZE_SYMBOL);
		Line.color = defs.Color(COL_SYM_LINE);
		Line.width = DefSize(SIZE_SYM_LINE);
		Fill.color = defs.Color(COL_SYM_FILL);
		scl = 0L;		nscl = 0;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Sphere", Desc);
		}
	return false;
}

bool
Plane3D::FileIO(int rw)
{
	descIO Desc[] = {
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"values", typLAST | typFPLST3D, &dt, &ndt}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		ipl = 0L;	pts = 0L;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Plane3D", Desc);
		}
	return false;
}

bool
Brick::FileIO(int rw)
{
	descIO Desc[] = {
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"Pos", typPOINT3D, &fPos, 0L},
		{"depth", typLFLOAT, &depth, 0L},
		{"width", typLFLOAT, &width, 0L},
		{"height", typLFLOAT, &height, 0L},
		{"flags", typDWORD, &flags, 0L},
		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		Line.color = defs.Color(COL_SYM_LINE);
		Line.width = DefSize(SIZE_SYM_LINE);
		Fill.color = defs.Color(COL_SYM_FILL);
		faces = (plane**)calloc(6, sizeof(plane*));
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		mo = 0L;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Brick", Desc);
		}
	return false;
}

bool
DropLine3D::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typINT, &type, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Pos", typPOINT3D, &fPos, 0L},
		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		Line.color = defs.Color(COL_SYM_LINE);
		Line.width = DefSize(SIZE_HAIRLINE);	mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		ls[0] = ls[1] = ls[2] = ls[3] = ls[4] = ls[5] = 0L;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "DropLine3D", Desc);
		}
	return false;
}

bool
Arrow3D::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typINT, &type, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Org", typPOINT3D, &fPos1, 0L},
		{"Pos", typPOINT3D, &fPos2, 0L},
		{"CapW", typLFLOAT, &cw, 0L},
		{"CapL", typLFLOAT, &cl, 0L},
		{"ssRef", typLAST | typIPLST, &ssRef, &cssRef}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		cw = DefSize(SIZE_ARROW_CAPWIDTH);
		cl = DefSize(SIZE_ARROW_CAPLENGTH);
		Line.color = defs.Color(COL_ARROW);
		Line.width = DefSize(SIZE_ARROW_LINE);
		ls[0] = ls[1] = ls[2] = 0L;
		cap = 0L;
		type = ARROW_LINE;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Arrow3D", Desc);
		}
	return false;
}

bool
Line3D::FileIO(int rw)
{
	descIO Desc[] = {
		{"Line", typLINEDEF, &Line, 0L},
		{"ssRefX", typTEXT, &x_range, 0L},
		{"ssRefY", typTEXT, &y_range, 0L},
		{"ssRefZ", typTEXT, &z_range, 0L},
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"values", typLAST | typFPLST3D, &values, &nPts}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		Line.color = defs.Color(COL_DATA_LINE);
		Line.width = DefSize(SIZE_DATA_LINE);
		ls = 0L;	pts = 0L;	npts = 0L;	mo=0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		min.fx = min.fy = min.fz = max.fx = max.fy = max.fz = 0.0;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(nPts > 1) ls = (line_segment **)calloc(nPts-1, sizeof(line_segment*));
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Line3D", Desc);
		}
	return false;
}

bool
Label::FileIO(int rw)
{
	descIO Desc[] = {
		{"ssRef", typIPLST, &ssRef, &cssRef},
		{"moveable", typNZINT, &moveable, 0L},
		{"Pos", typNZLFPOINT, &fPos, 0L},
		{"Dist", typNZLFPOINT, &fDist, 0L},
		{"Flags", typDWORD, &flags, 0L},
		{"TxtDef", typLAST | typTXTDEF, &TextDef, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		TextDef.ColTxt = 0x0L;
		TextDef.ColBg = 0x00ffffffL;
		TextDef.fSize = DefSize(SIZE_TEXT);
		TextDef.RotBL = TextDef.RotCHAR = 0.0;
		TextDef.iSize = 0;
		TextDef.Align = TXA_VTOP | TXA_HLEFT;
		TextDef.Mode = TXM_TRANSPARENT;
		TextDef.Style = TXS_NORMAL;
		TextDef.Font = FONT_HELVETICA;
		TextDef.text = 0L;	bgcolor = 0x00ffffffL;
		bgLine.width = 0.0;		bgLine.patlength = 6.0;
		bgLine.color = bgcolor;	bgLine.pattern = 0L;
		CursorPos = 0;	defDisp = 0L;	bBGvalid = bModified = false;
		curr_z = 0.0;		is3D = false;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(parent && parent->Id != GO_MLABEL) {
			if(!TextDef.text || !TextDef.text[0]) return false;
			}
		return ExecOutput(Notary->RegisterGO(this), "Label", Desc);
		}
	return false;
}

void
mLabel::RegGO(void *n)
{
	int i;

	if(n) {
		if(Lines) for(i = 0; i < nLines; i++) if(Lines[i]) Lines[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
	}
}

bool
mLabel::FileIO(int rw)
{
	descIO Desc[] = {
		{"moveable", typNZINT, &moveable, 0L},
		{"Pos", typNZLFPOINT, &fPos, 0L},
		{"Dist", typNZLFPOINT, &fDist, 0L},
		{"lspc", typLFLOAT, &lspc, 0L},
		{"Flags", typDWORD, &flags, 0L},
		{"TxtDef", typTXTDEF, &TextDef, 0L},
		{"Lines", typLAST | typOBJLST, &Lines, &nLines}};
	int i;

	switch(rw) {
	case SAVE_VARS:
		//The lines inherit settings from this object.
		//We need not save them in this context
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		TextDef.ColTxt = 0x0L;
		TextDef.ColBg = 0x00ffffffL;
		TextDef.fSize = DefSize(SIZE_TEXT);
		TextDef.RotBL = TextDef.RotCHAR = 0.0;
		TextDef.iSize = 0;
		TextDef.Align = TXA_VTOP | TXA_HLEFT;
		TextDef.Mode = TXM_TRANSPARENT;
		TextDef.Style = TXS_NORMAL;
		TextDef.Font = FONT_HELVETICA;
		TextDef.text = 0L;
		undo_flags = 0L;	lspc = 1.0;
		curr_z = 0.0;		is3D = false;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(Lines) for ( i = 0; i < nLines; i++)
			if(Lines[i]) Lines[i]->parent = this;
		return true;
	case FILE_WRITE:
		if(Lines) for ( i = 0; i < nLines; i++)
			if(Lines[i]) Lines[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "mLabel", Desc);
		}
	return false;
}

bool
TextFrame::FileIO(int rw)
{
	descIO Desc[] = {
		{"moveable", typNZINT, &moveable, 0L},
		{"Pos1", typNZLFPOINT, &pos1, 0L},
		{"Pos2", typNZLFPOINT, &pos2, 0L},
		{"lspc", typLFLOAT, &lspc, 0L},
		{"Pad", typFRECT, &pad, 0L},
		{"TxtDef", typTXTDEF, &TextDef, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"FillLine", typLINEDEF, &FillLine, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"Text", typLAST | typTEXT, &text, 0L}};
	switch(rw) {
	case SAVE_VARS:
		return false;
	case INIT_VARS:
		InitVarsGO(Desc);
		TextDef.ColTxt = 0x0L;
		TextDef.ColBg = 0x00ffffffL;
		TextDef.fSize = DefSize(SIZE_TEXT);
		TextDef.RotBL = TextDef.RotCHAR = 0.0;
		TextDef.iSize = 0;
		TextDef.Align = TXA_VBOTTOM | TXA_HLEFT;
		TextDef.Mode = TXM_TRANSPARENT;
		TextDef.Style = TXS_NORMAL;
		TextDef.Font = FONT_HELVETICA;
		TextDef.text = 0L;
		lines = 0L;		nlines = 0;			drc = 0L;
		cur_pos.x = cur_pos.y = tm_c = 0;	tm_rec = 0L;
		bModified = bResize = has_m1 = has_m2 = false;
		if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
		Fill.hatch = &FillLine;			c_char = m1_char = m2_char = '?';
		pad.Xmin = pad.Xmax = pad.Ymin = pad.Ymax = DefSize(SIZE_SYMBOL)/2.0;
		Cursor.left = Cursor.right = Cursor.top = Cursor.bottom = 0;
		pad.Xmax *= 2.0;
		return true;
	case FILE_READ:
		ExecInput(Desc);				Fill.hatch = &FillLine;
		return true;
	case FILE_WRITE:
		if(lines)lines2text();
		if(!text || !text[0]) return false;
		return ExecOutput(Notary->RegisterGO(this), "TextFrame", Desc);
		}
	return false;
}

bool
segment::FileIO(int rw)
{
	descIO Desc[] = {
		{"moveable", typNZINT, &moveable, 0L},
		{"cent", typLFPOINT, &fCent, 0L},
		{"ri", typNZLFLOAT, &radius1, 0L},
		{"ra", typLFLOAT, &radius2, 0L},
		{"start", typLFLOAT, &angle1, 0L},
		{"end", typLFLOAT, &angle2, 0L},
		{"shout", typNZLFLOAT, &shift, 0L},
		{"Line", typLINEDEF, &segLine, 0L},
		{"FillLine", typLINEDEF, &segFillLine, 0L},
		{"Fill", typLAST | typFILLDEF, &segFill, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		segLine.width = DefSize(SIZE_SEGLINE);
		pts = 0L;	nPts = 0;	mo = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		segFill.hatch = &segFillLine;
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "segment", Desc);
		}
	return false;
}

bool
polyline::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"moveable", typNZINT, &moveable, 0L},
		{"Data", typFPLST, &Values, &nPoints},
		{"Line", typLINEDEF, &pgLine, 0L},
		{"FillLine", typLINEDEF, &pgFillLine, 0L},
		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
	
	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		memcpy(&pgLine, defs.plLineDEF(0L), sizeof(LineDEF));
		memcpy(&pgFill, defs.pgFillDEF(0L), sizeof(FillDEF));
		if(pgFill.hatch) memcpy(&pgFillLine, pgFill.hatch, sizeof(LineDEF));
		pgFill.hatch = &pgFillLine;
		pts = 0L;		nPts = 0;
		pHandles = 0L;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		pgFill.hatch = &pgFillLine;
		return true;
	case FILE_WRITE:
		if(type != 1) Desc[3].type |= typLAST;	//skip fill for polyline
		return ExecOutput(Notary->RegisterGO(this), 
			type == 1 ? (char*)"polygon" : (char*)"polyline", Desc);
		}
	return false;
}

bool
Bezier::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"moveable", typNZINT, &moveable, 0L},
		{"Data", typFPLST, &Values, &nPoints},
		{"Line", typLINEDEF, &pgLine, 0L},
		{"FillLine", typLINEDEF, &pgFillLine, 0L},
		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
	
	switch(rw) {
	case INIT_VARS:
		//assume that all initialization is done by polyline::FileIO(int rw)
		return true;
	case FILE_READ:
		ExecInput(Desc);
		pgFill.hatch = &pgFillLine;
		return true;
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "bezier", Desc);
		}
	return false;
}

bool
rectangle::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"moveable", typNZINT, &moveable, 0L},
		{"p1", typLFPOINT, &fp1, 0L},
		{"p2", typLFPOINT, &fp2, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"FillLine", typLINEDEF, &FillLine, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"Rad", typNZLFLOAT, &rad, 0L},
		{"Name", typLAST | typTEXT, &name, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		memcpy(&Line, defs.pgLineDEF(0L), sizeof(LineDEF));
		memcpy(&Fill, defs.pgFillDEF(0L), sizeof(FillDEF));
		if(Fill.hatch) memcpy(&FillLine, Fill.hatch, sizeof(LineDEF));
		Fill.hatch = &FillLine;
		pts = 0L;	nPts = 0L;
		rad = DefSize(SIZE_RRECT_RAD);
		drc = 0L;
		return true;
	case FILE_READ:
		ExecInput(Desc);
		Fill.hatch = &FillLine;
		return true;
	case FILE_WRITE:
		if(type != 2) rad = 0.0;
		ExecOutput(Notary->RegisterGO(this), 
			type == 1? (char*)"ellipse" : type == 2? (char*)"roundrec" :
			(char*)"rectangle", Desc);
		return true;
		}
	return false;
}

void
LegItem::RegGO(void *n)
{
	if(n) {
		if(Sym) Sym->RegGO(n);
		if(Desc) Desc->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
LegItem::FileIO(int rw)
{
	descIO Des[] = {
		{"D_Line", typLINEDEF, &DataLine, 0L},
		{"O_Line", typLINEDEF, &OutLine, 0L},
		{"H_Line", typLINEDEF, &HatchLine, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"Sym", typGOBJ, &Sym, 0L},
		{"Text", typGOBJ, &Desc, 0L},
		{"flags", typLAST | typDWORD, &flags, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Des);
	case INIT_VARS:
		InitVarsGO(Des);
		Fill.hatch = &HatchLine;
		return true;
	case FILE_READ:
		ExecInput(Des);
		Fill.hatch = &HatchLine;
		if(Sym) Sym->parent=this;
		if(Desc) Desc->parent=this;
		return true;
	case FILE_WRITE:
		if(Sym) Sym->FileIO(rw);
		if(Desc) Desc->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "LegItem", Des);
		}
	return false;
}

void
Legend::RegGO(void *n)
{
	int i;

	if(n) {
		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Legend::FileIO(int rw)
{
	descIO Desc[] = {
		{"pos", typLFPOINT, &pos, 0L},
		{"rec1", typFRECT, &B_Rect, 0L},
		{"rec2", typFRECT, &D_Rect, 0L},
		{"rec3", typFRECT, &F_Rect, 0L},
		{"Items", typLAST | typOBJLST, &Items, &nItems}};
	int i;
	double d;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		B_Rect.Ymin = DefSize(SIZE_DRECT_TOP);			B_Rect.Xmin = DefSize(SIZE_DRECT_LEFT);
		B_Rect.Xmax = B_Rect.Xmin + 1.5*(d = DefSize(SIZE_BAR));
		B_Rect.Ymin += d*0.2;
		B_Rect.Ymax = B_Rect.Ymin + d/2.0;
		D_Rect.Ymin = 0.0;			D_Rect.Xmin = d*0.7;
		D_Rect.Xmax = d*1.3;		D_Rect.Ymax = d*0.4;
		F_Rect.Ymin = 0.0;			F_Rect.Xmin = d*0.2;
		F_Rect.Xmax = d*1.3;		F_Rect.Ymax = d*0.4;
		to = 0L;					hasLine = false;
		trc.left = trc.right = trc.top = trc.bottom = 0;
		if(!name) {
			name = (char*)malloc(20 * sizeof(char));
			rlp_strcpy(name, 20, "Legend");
			}
		return true;
	case FILE_READ:
		nItems = 0L;
		ExecInput(Desc);
		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->parent=this;
		return true;
	case FILE_WRITE:
		if(Items) for(i = 0; i < nItems; i++) if(Items[i]) Items[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Legend", Desc);
		}
	return false;
}

void
PlotScatt::RegGO(void *n)
{
	int i;

	if(n) {
		if(TheLine) TheLine->RegGO(n);
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
		if(Errors) for(i = 0; i < nPoints; i++) if(Errors[i]) Errors[i]->RegGO(n);
		if(Arrows) for(i = 0; i < nPoints; i++) if(Arrows[i]) Arrows[i]->RegGO(n);
		if(DropLines) for(i = 0; i < nPoints; i++) if(DropLines[i]) DropLines[i]->RegGO(n);
		if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->RegGO(n);
		if(Bars) for(i = 0; i < nPoints; i++) if(Bars[i]) Bars[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
PlotScatt::FileIO(int rw)
{
	descIO Desc[] = {
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"DefSym", typNZINT, &DefSym, 0L},
		{"baDist", typLFPOINT, &BarDist, 0L},
		{"xRange", typTEXT, &xRange, 0L},
		{"yRange", typTEXT, &yRange, 0L},
		{"eRange", typTEXT, &ErrRange, 0L},
		{"lRange", typTEXT, &LbRange, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"Bars", typOBJLST, &Bars, &nPoints},
		{"Symbols", typOBJLST, &Symbols, &nPoints},
		{"PL", typGOBJ, &TheLine, 0L},
		{"ErrBars", typOBJLST, &Errors, &nPoints},
		{"Arrows", typOBJLST, &Arrows, &nPoints},
		{"dLines", typOBJLST, &DropLines, &nPoints},
		{"Labels", typOBJLST, &Labels, &nPoints},
		{"x_info", typTEXT, &x_info, 0L},
		{"y_info", typTEXT, &y_info, 0L},
		{"DataDesc", typLAST | typTEXT, &data_desc, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		x_info = y_info = z_info = 0L;
		InitVarsGO(Desc);
		DefSym = SYM_CIRCLE;
		DefSel = 0x01;
		dirty = true;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xy-plot (%s)", name);
#else
			i = sprintf(TmpTxt, "xy-plot (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		nPoints = 0L;
		ExecInput(Desc);
		ForEach(FE_PARENT, 0L, 0L);
		return true;
	case FILE_WRITE:
		if(TheLine) TheLine->FileIO(rw);
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
		if(Errors) for(i = 0; i < nPoints; i++) if(Errors[i]) Errors[i]->FileIO(rw);
		if(Arrows) for(i = 0; i < nPoints; i++) if(Arrows[i]) Arrows[i]->FileIO(rw);
		if(DropLines) for(i = 0; i < nPoints; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
		if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->FileIO(rw);
		if(Bars) for(i = 0; i < nPoints; i++) if(Bars[i]) Bars[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "PlotScatt", Desc);
		}
	return false;
}

bool
xyStat::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"DefSym", typNZINT, &DefSym, 0L},
		{"baDist", typLFPOINT, &BarDist, 0L},
		{"confi", typLFLOAT, &ci, 0L},
		{"xRange", typTEXT, &xRange, 0L},
		{"yRange", typTEXT, &yRange, 0L},
		{"prefix", typTEXT, &case_prefix, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"Bars", typOBJLST, &Bars, &nPoints},
		{"Symbols", typOBJLST, &Symbols, &nPoints},
		{"PL", typGOBJ, &TheLine, 0L},
		{"ErrBars", typOBJLST, &Errors, &nPoints},
		{"Labels", typOBJLST, &Labels, &nPoints},
		{"x_info", typTEXT, &x_info, 0L},
		{"y_info", typLAST | typTEXT, &y_info, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		//most initialistion is done by PlotScatt::FileIO
		curr_data = 0L;
		case_prefix = 0L;
		ci = 95.0;
		return true;
	case FILE_READ:
		nPoints = 0L;
		ExecInput(Desc);
		ForEach(FE_PARENT, 0L, 0L);
		return true;
	case FILE_WRITE:
		if(TheLine) TheLine->FileIO(rw);
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
		if(Errors) for(i = 0; i < nPoints; i++) if(Errors[i]) Errors[i]->FileIO(rw);
		if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->FileIO(rw);
		if(Bars) for(i = 0; i < nPoints; i++) if(Bars[i]) Bars[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "xyStat", Desc);
		}
	return false;
}

void
FreqDist::RegGO(void *n)
{
	int i;

	if(n) {
		if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
FreqDist::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"ssRef", typTEXT, &ssRef, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"cl_start", typNZLFLOAT, &start, 0L},
		{"cl_size", typLFLOAT, &step, 0L},
		{"BarLine", typLINEDEF, &BarLine, 0L},
		{"BarFill", typFILLDEF, &BarFill, 0L},
		{"BarFillLine", typLINEDEF, &HatchLine, 0L},
		{"plots", typLAST | typOBJLST, &plots, &nPlots}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		memcpy(&BarFill, defs.GetFill(), sizeof(FillDEF));
		BarFill.color = 0x00c0ffffL;
		if(BarFill.hatch) memcpy(&HatchLine, BarFill.hatch, sizeof(LineDEF));
		BarFill.hatch = &HatchLine;
		memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
		curr_data=0L;		dirty = true;
		dmin = HUGE_VAL, dmax = -HUGE_VAL;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "freq. dist. (%s)", name);
#else
			i = sprintf(TmpTxt, "freq. dist. (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->parent=this;
		return true;
	case FILE_WRITE:
		if(plots) for(i = 0; i < nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "FreqDist", Desc);
		}
	return false;
}

void
Regression::RegGO(void *n)
{
	int i;

	if(n) {
		if(rLine) rLine->RegGO(n);
		if(sde) sde->RegGO(n);
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Regression::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"xRange", typTEXT, &xRange, 0L},
		{"yRange", typTEXT, &yRange, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"Line", typGOBJ, &rLine, 0L},
		{"Ellipse", typGOBJ, &sde, 0L},
		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		dirty = true;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "regression (%s)", name);
#else
			i = sprintf(TmpTxt, "regression (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		nPoints = 0L;
		return ExecInput(Desc);
	case FILE_WRITE:
		if(rLine) rLine->FileIO(rw);
		if(sde) sde->FileIO(rw);
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Regression", Desc);
		}
	return false;
}

void
BubblePlot::RegGO(void *n)
{
	int i;

	if(n) {
		if(Bubbles) for(i = 0; i < nPoints; i++) if(Bubbles[i]) Bubbles[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
BubblePlot::FileIO(int rw)
{
	descIO Desc[] = {
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"Line", typLINEDEF, &BubbleLine, 0L},
		{"FillLine", typLINEDEF, &BubbleFillLine, 0L},
		{"Fill", typFILLDEF, &BubbleFill, 0L},
		{"Bubbles", typLAST | typOBJLST, &Bubbles, &nPoints}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		BubbleFill.color = defs.Color(COL_BUBBLE_FILL);
		BubbleLine.color = defs.Color(COL_BUBBLE_LINE);
		BubbleLine.width = DefSize(SIZE_BUBBLE_LINE);
		BubbleFillLine.color = defs.Color(COL_BUBBLE_FILLLINE);
		BubbleFillLine.width = DefSize(SIZE_BUBBLE_HATCH_LINE);
		BubbleFill.hatch = &BubbleFillLine;
		dirty = true;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Bubble Plot (%s)", name);
#else
			i = sprintf(TmpTxt, "Bubble Plot (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(Bubbles) for(i = 0; i < nPoints; i++) if(Bubbles[i]) Bubbles[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "BubblePlot", Desc);
		}
	return false;
}

void
PolarPlot::RegGO(void *n)
{
	int i;

	if(n) {
		if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->RegGO(n);
		if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
PolarPlot::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"ang_offs", typLFLOAT, &offs, 0L},
		{"Plots", typOBJLST, &Plots, (long*)&nPlots},
		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
		{"FillLine", typLINEDEF, &FillLine, 0L},
		{"Fill", typLAST | typFILLDEF, &Fill, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		CurrDisp = 0L;
		InitVarsGO(Desc);
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "polar root (%s)", name);
#else
			i = sprintf(TmpTxt, "polar root (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(Plots) for(i = 0; i < nPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
		if(Axes) for(i = 0; i < nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "PolarPlot", Desc);
		}
	return false;
}

void
BoxPlot::RegGO(void *n)
{
	int i;

	if(n) {
		if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->RegGO(n);
		if(Whiskers) for(i = 0; i < nPoints; i++) if(Whiskers[i]) Whiskers[i]->RegGO(n);
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
		if(Labels) for(i = 0; i < nPoints; i++) if(Labels[i]) Labels[i]->RegGO(n);
		if(TheLine) TheLine->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
BoxPlot::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"xRange", typTEXT, &xRange, 0L},
		{"yRange", typTEXT, &yRange, 0L},
		{"prefix", typTEXT, &case_prefix, 0L},
		{"boDist", typLFPOINT, &BoxDist, 0L},
		{"ci_box", typNZLFLOAT, &ci_box, 0L},
		{"ci_err", typNZLFLOAT, &ci_err, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"Boxes", typOBJLST, &Boxes, &nPoints},
		{"Whiskers", typOBJLST, &Whiskers, &nPoints},
		{"Symbols", typOBJLST, &Symbols, &nPoints},
		{"Labels", typOBJLST, &Labels, &nPoints},
		{"Line", typLAST | typGOBJ, &TheLine, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		dirty = true;		InitVarsGO(Desc);
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "boxes (%s)", name);
#else
			i = sprintf(TmpTxt, "boxes (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		curr_data = 0L;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(Boxes) for(i = 0; i < nPoints; i++) 
			if(Boxes[i]) Boxes[i]->FileIO(rw);
		if(Whiskers) for(i = 0; i < nPoints; i++) 
			if(Whiskers[i]) Whiskers[i]->FileIO(rw);
		if(Symbols) for(i = 0; i < nPoints; i++) 
			if(Symbols[i]) Symbols[i]->FileIO(rw);
		if(Labels) for(i = 0; i < nPoints; i++) 
			if(Labels[i]) Labels[i]->FileIO(rw);
		if(TheLine) TheLine->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "BoxPlot", Desc);
		}
	return false;
}

void
DensDisp::RegGO(void *n)
{
	int i;

	if(n) {
		if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
DensDisp::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"xRange", typTEXT, &xRange, 0L},
		{"yRange", typTEXT, &yRange, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"Line", typLINEDEF, &DefLine, 0L},
		{"FillLine", typLINEDEF, &DefFillLine, 0L},
		{"Fill", typFILLDEF, &DefFill, 0L},
		{"Boxes", typLAST | typOBJLST, &Boxes, &nPoints}};
	int i;

	switch(rw) {
	case INIT_VARS:
		return InitVarsGO(Desc);
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(Boxes) for(i = 0; i < nPoints; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "DensDisp", Desc);
		}
	return false;
}

void
StackBar::RegGO(void *n)
{
	int i;

	if(n) {
		if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) Boxes[i]->RegGO(n);
		if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) xyPlots[i]->RegGO(n);
		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->RegGO(n);
		if(Lines) for(i = 0; i < numPL; i++) if(Lines[i]) Lines[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
StackBar::FileIO(int rw)
{
	descIO Desc[] = {
		{"Bounds", typFRECT, &Bounds, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"cumData", typNZINT, &cum_data_mode, 0L},
		{"StartVal", typNZLFLOAT, &StartVal, 0L},
		{"Dspm", typNZLFPOINT, &dspm, 0L},
		{"ssXrange", typTEXT, &ssXrange, 0L},
		{"ssYrange", typTEXT, &ssYrange, 0L},
		{"BoxBars", typOBJLST, &Boxes, (long*)&numPlots},
		{"Plots", typOBJLST, &xyPlots, (long*)&numXY},
		{"Polygons", typOBJLST, &Polygons, (long*)&numPG},
		{"Lines", typLAST | typOBJLST, &Lines, (long*)&numPL}};
	int i;

	switch(rw) {
	case INIT_VARS:
		dirty = true;	CumData = 0L;
		InitVarsGO(Desc);
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "stack (%s)", name);
#else
			i = sprintf(TmpTxt, "stack (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		return true;
	case FILE_WRITE:
		if(Boxes) for(i = 0; i < numPlots; i++) if(Boxes[i]) Boxes[i]->FileIO(rw);
		if(xyPlots) for(i = 0; i < numXY; i++) if(xyPlots[i]) xyPlots[i]->FileIO(rw);
		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->FileIO(rw);
		if(Lines) for(i = 0; i < numPL; i++) if(Lines[i]) Lines[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Stacked", Desc);
		}
	return false;
}

void
PieChart::RegGO(void *n)
{
	int i;

	if(n) {
		if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
PieChart::FileIO(int rw)
{
	descIO Desc[] = {
		{"ssRefA", typTEXT, &ssRefA, 0L},
		{"ssRefR", typTEXT, &ssRefR, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"CtDef", typLFPOINT, &CtDef, 0L},
		{"FacRad", typLFLOAT, &FacRad, 0L},
		{"Segs", typLAST | typOBJLST, &Segments, (long*)&nPts}};
	int i;

	switch(rw) {
	case INIT_VARS:
		Bounds.Xmax = Bounds.Ymax = 100.0f;
		Bounds.Xmin = Bounds.Ymin = -100.0f;
		InitVarsGO(Desc);
		CtDef.fx = 90.0;	CtDef.fy = 360.0;
		FacRad = 1.0;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "pie chart (%s)", name);
#else
			i = sprintf(TmpTxt, "pie chart (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(Segments) for(i = 0; i < nPts; i++) if(Segments[i]) Segments[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "SegChart", Desc);
		}
	return false;
}

void
GoGroup::RegGO(void *n)
{
	int i;

	if(n) {
		if(Objects) for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
GoGroup::FileIO(int rw)
{
	descIO Desc[] = {
		{"Pos", typNZLFPOINT, &fPos, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Items", typLAST | typOBJLST, &Objects, (long*)&nObs}};
	int i;

	switch(rw) {
	case INIT_VARS:
		Bounds.Xmax = Bounds.Ymax = 100.0f;
		Bounds.Xmin = Bounds.Ymin = -100.0f;
		return InitVarsGO(Desc);
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		if(Objects) for(i = 0; i < nObs; i++) if(Objects[i]) Objects[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "group", Desc);
		}
	return false;
}

void
Scatt3D::RegGO(void *n)
{
	int i;

	if(n) {
		if(Line) Line->RegGO(n);
		if(rib) rib->RegGO(n);
		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->RegGO(n);
		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->RegGO(n);
		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->RegGO(n);
		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Scatt3D::FileIO(int rw)
{
	descIO Desc[] = {
		{"ssRefX", typTEXT, &ssRefX, 0L},
		{"ssRefY", typTEXT, &ssRefY, 0L},
		{"ssRefZ", typTEXT, &ssRefZ, 0L},
		{"DataDesc", typTEXT, &data_desc, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"z_axis", typNZINT, &use_zaxis, 0L},
		{"Line", typGOBJ, &Line, 0L},
		{"Balls", typOBJLST, &Balls, &nBalls},
		{"Columns", typOBJLST, &Columns, &nColumns},
		{"DropLines", typOBJLST, &DropLines, &nDropLines},
		{"ParaV", typGOBJ, &rib, 0L},
		{"Arrows", typLAST | typOBJLST, &Arrows, &nArrows}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		c_flags = 0L;
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
		dirty = true;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "xyz-plot (%s)", name);
#else
			i = sprintf(TmpTxt, "xyz-plot (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		//now set parent in all children
		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->parent = this;
		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->parent = this;
		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->parent = this;
		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->parent = this;
		if(Line) Line->parent = this;
		if(rib) rib->parent = this;
		return true;
	case FILE_WRITE:
		if(Line) Line->FileIO(rw);
		if(rib) rib->FileIO(rw);
		if(Balls) for(i = 0; i < nBalls; i++) if(Balls[i]) Balls[i]->FileIO(rw);
		if(Columns) for(i = 0; i < nColumns; i++) if(Columns[i]) Columns[i]->FileIO(rw);
		if(DropLines) for(i = 0; i < nDropLines; i++) if(DropLines[i]) DropLines[i]->FileIO(rw);
		if(Arrows) for(i = 0; i < nArrows; i++) if(Arrows[i]) Arrows[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Scatt3D", Desc);
		}
	return false;
}

void
Ribbon::RegGO(void *n)
{
	int i;

	if(n) {
		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Ribbon::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"z-pos", typNZLFLOAT, &z_value},
		{"z-width", typNZLFLOAT, &z_width},
		{"relwidth", typNZLFLOAT, &relwidth},
		{"ssRefX", typTEXT, &ssRefX, 0L},
		{"ssRefY", typTEXT, &ssRefY, 0L},
		{"ssRefZ", typTEXT, &ssRefZ, 0L},
		{"DataDesc", typTEXT, &data_desc, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"values", typFPLST3D, &values, &nVal},
		{"Planes", typLAST | typOBJLST, &planes, &nPlanes}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
		relwidth = 0.6;				dirty = true;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "ribbon (%s)", name);
#else
			i = sprintf(TmpTxt, "ribbon (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		//now set parent in all children
		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
		return true;
	case FILE_WRITE:
		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Ribbon", Desc);
		}
	return false;
}

void
Grid3D::RegGO(void *n)
{
	int i;

	if(n) {
		if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->RegGO(n);
		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Grid3D::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Start", typPOINT3D, &start, 0L},
		{"Step", typPOINT3D, &step, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"lines", typOBJLST, &lines, &nLines},
		{"planes", typLAST | typOBJLST, &planes, &nPlanes}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
		step.fx = step.fz = 1.0;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "grid (%s)", name);
#else
			i = sprintf(TmpTxt, "grid (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		//now set parent in all children
		if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->parent = this;
		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->parent = this;
		return true;
	case FILE_WRITE:
		if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->FileIO(rw);
		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Grid3D", Desc);
		}
	return false;
}

bool
Limits::FileIO(int rw)
{
	descIO Desc[] = {
		{"Bounds", typLAST | typFRECT, &Bounds, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "limits (%s)", name);
#else
			i = sprintf(TmpTxt, "limits (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), "Limits", Desc);
		}
	return false;
}

void
Function::RegGO(void *n)
{
	if(n) {
		if(dl)dl->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Function::FileIO(int rw)
{
	descIO Desc[] = {
		{"hide", typNZINT, &hidden, 0L},
		{"x1", typNZLFLOAT, &x1, 0L},
		{"x2", typNZLFLOAT, &x2, 0L},
		{"xstep", typNZLFLOAT, &xstep, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"f_xy", typTEXT, &cmdxy, 0L},
		{"param", typTEXT, &param, 0L},
		{"DataLine", typGOBJ, &dl, 0L},
		{"Desc", typLAST | typTEXT, &name, 0L}};
	int i;

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		cmdxy = param = 0L;
		memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "function (%s)", name);
#else
			i = sprintf(TmpTxt, "function (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(dl) dl->parent = this;
		return true;
	case FILE_WRITE:
		if(dl) dl->FileIO(rw);
		ExecOutput(Notary->RegisterGO(this), "Function", Desc);
		}
	return false;
}

void
FitFunc::RegGO(void *n)
{
	int i;

	if(n) {
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
FitFunc::FileIO(int rw)
{
	descIO Desc[] = {
		{"hide", typNZINT, &hidden, 0L},
		{"ssXref", typTEXT, &ssXref, 0L},
		{"ssYref", typTEXT, &ssYref, 0L},
		{"x1", typNZLFLOAT, &x1, 0L},
		{"x2", typNZLFLOAT, &x2, 0L},
		{"xstep", typNZLFLOAT, &xstep, 0L},
		{"conv", typNZLFLOAT, &conv, 0L},
		{"chi2", typNZLFLOAT, &chi2, 0L},
		{"maxiter", typNZINT, &maxiter, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"f_xy", typTEXT, &cmdxy, 0L},
		{"p_xy", typTEXT, &parxy, 0L},
		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
	int i;

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		cmdxy = parxy = 0L;
		memcpy(&Line, defs.GetLine(), sizeof(LineDEF));
		conv = 1.0e-15;	maxiter = 100;
		dl = 0L;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "fit function (%s)", name);
#else
			i = sprintf(TmpTxt, "fit function (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(Symbols) for(i = 0; i < nPoints; i++)
			if(Symbols[i]) Symbols[i]->parent = this;
		return true;
	case FILE_WRITE:
		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "FitFunc", Desc);
		}
	return false;
}

bool
NormQuant::FileIO(int rw)
{
	lfPOINT *dt;
	long cnt;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"nData", typINT, &nData, 0L},
		{"Data", typFPLST, &dt, &cnt},
		{"ssRef", typTEXT, &ssRef, 0L},
		{"x_info", typTEXT, &x_info, 0L},
		{"y_info", typLAST | typTEXT, &y_info, 0L}};
	int i, j, l;

	if(rw == FILE_WRITE) {
		if(nData < 4) return false;
		l = (nData >>1) +1;				cnt = l;
		if(!(dt = (lfPOINT *)calloc(l, sizeof(lfPOINT))))return false;
		for(i = j = 0; i < nData; i += 2, j++) {
			dt[j].fx = src_data[i];		dt[j].fy = src_data[i+1];
			}
		}
	else {
		dt = 0L;		cnt = 0;
		}
	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		sy = new Symbol(this, data, 0.0, 0.0, SYM_CIRCLE);
		x_vals = y_vals = src_data = 0L;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "normal quantiles (%s)", name);
#else
			i = sprintf(TmpTxt, "normal quantiles (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(dt && cnt > 1 && (src_data = (double*)malloc(nData*sizeof(double)))) {
			for(i = j = 0, l = nData-1; i < nData; i += 2, j++) {
				src_data[i] = dt[j].fx;		if(i < l) src_data[i+1] = dt[j].fy;
				}
			free(dt);
			}
		return true;
	case FILE_WRITE:
		ExecOutput(Notary->RegisterGO(this), "NormQuant", Desc);
		free(dt);
		return true;
		}
	return false;
}

bool
GridLine::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"Line", typLINEDEF, &LineDef, 0L},
		{"flags", typLAST | typDWORD, &flags, 0L}};

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		ncpts = 0;		cpts = 0L;	gl1 = gl2 = gl3 = 0L;	ls = 0L;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;	mo = 0L;
		return true;
	case FILE_READ:
		return ExecInput(Desc);
	case FILE_WRITE:
		return ExecOutput(Notary->RegisterGO(this), 
			Id == GO_GRIDLINE ?(char*)"GridLine" : 
			Id == GO_GRIDRADIAL? (char*)"GridRadial" : (char*)"GridLine3D", Desc);
		}
	return false;
}

void
Tick::RegGO(void *n)
{
	int i;

	if(n) {
		if(Grid && (flags & AXIS_GRIDLINE)) Grid->RegGO(n);
		if(label) label->RegGO(n);
		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Tick::FileIO(int rw)
{
	GraphObj *gl = Grid;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"Val", typLFLOAT, &value, 0L},
		{"Flags", typDWORD, &flags, 0L},
		{"Rot", typNZLFLOAT, &angle, 0L},
		{"GridType", typINT, &gl_type, 0L},
		{"Grid", typGOBJ, &gl, 0L},
		{"Label", typGOBJ, &label, 0L},
		{"Polygons", typOBJLST, &Polygons, &numPG},
		{"Size", typLAST | typLFLOAT, &size, 0L}};
	int i;

	switch(rw) {
	case SAVE_VARS:
		if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
		if(label) label->FileIO(rw);
//		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->FileIO(rw);
		return SaveVarGO(Desc);
	case INIT_VARS:
		InitVarsGO(Desc);
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		fix = fiy = 0.0f;	ls = 0L;	Grid = 0L;	mo = 0L;
		n_seg = s_seg = 0;	seg = 0L;	bValidTick = false;
		size = DefSize(SIZE_AXIS_TICKS);
		return true;
	case FILE_READ:
		ExecInput(Desc);
		Grid = (GridLine*) gl;
		if(Grid)Grid->parent = this;
		if(label)label->parent = this;
		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->parent = this;
		return true;
	case FILE_WRITE:
		if(Grid && (flags & AXIS_GRIDLINE)) Grid->FileIO(rw);
		else gl = 0L;
		if(label) label->FileIO(rw);
		if(Polygons) for(i = 0; i < numPG; i++) if(Polygons[i]) Polygons[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Tick", Desc);
		}
	return false;
}

void
Axis::TickFile(char *name)
{
	ReadCache *ca;
	int i, j, k, nt;
	char line[500], item[20];
	Tick **ttck;

	if(!name) return;
	if(!(ca = new ReadCache())) return;
	if(! ca->Open(name)) {
		delete ca;
#ifdef USE_WIN_SECURE
		sprintf_s(TmpTxt, TMP_TXT_SIZE, "Error open file \"%s\"\nfor axis ticks", name);
#else
		sprintf(TmpTxt, "Error open file \"%s\"\nfor axis ticks", name);
#endif
		ErrorBox(TmpTxt);
		return;
		}
	Command(CMD_FLUSH, 0L, 0L);
	if(!(Ticks = ((Tick**)calloc(nt = 100, sizeof(Tick*))))) return;
	for(i = 0; ; i++) {
		j = k = 0;
		ca->ReadLine(line, sizeof(line));
		if(!line[0]) break;
		while(line[j] && line[j] < 33) j++;
		do{ item[k] = line[j++]; }
			while(item[k] >32 && item[k++] != '=' && k <sizeof(item) && j <sizeof(line));
		item[k--] = 0;		if(!line[j-1])j--;
		while(k && !(isdigit(item[k])))item[k--]=0;
		while(line[j] && (line[j]<33 || line[j] == '"'))j++;
		k = (int)strlen(line);
		while(k >=j && (line[k] < 33 || line[k] == '"')) line[k--] = 0;
		//realloc table if necessary
		if(NumTicks >= nt) {
			if((ttck= (Tick**)realloc(Ticks, (nt += 1000)*sizeof(Tick*))))Ticks= ttck;
			else NumTicks--;
			}
		//now add tick to table
		if(!(Ticks[NumTicks] = new Tick(this, data, atof(item),
			line[j] ? axis->flags : axis->flags | AXIS_MINORTICK)))break;
		Ticks[NumTicks]->Command(CMD_SETTEXT, line+j, 0L);
		NumTicks++;
		}
	ca->Close();
	if(!NumTicks && Ticks) {
		free(Ticks);
		NumTicks = 0;
		}
	delete ca;
}

void
Axis::RegGO(void *n)
{
	int i;

	if(n) {
		for(i = 0; Ticks && i< NumTicks; i++) if(Ticks[i]) Ticks[i]->RegGO(n);
		if(axisLabel) axisLabel->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Axis::FileIO(int rw)
{
	char *tickfile = 0L;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"moveable", typNZINT, &moveable, 0L},
		{"sAxLine", typLFLOAT, &sizAxLine, 0L},
		{"sAxTick", typLFLOAT, &sizAxTick, 0L},
		{"BrkGap", typLFLOAT, &brkgap, 0L},
		{"BrkSymSize", typLFLOAT, &brksymsize, 0L},
		{"BrkSym", typINT, &brksym, 0L},
		{"sTickLabel", typLFLOAT, &sizAxTickLabel, 0L},
		{"tick_angle", typNZLFLOAT, &tick_angle, 0L},
		{"LbDist", typNZLFPOINT, &lbdist, 0L},
		{"TickLbDist", typNZLFPOINT, &tlbdist, 0L}, 
		{"tlbDef", typTXTDEF, &tlbdef, 0L},
		{"Color", typDWORD, &colAxis, 0L},
		{"AxisDef", typPTRAXDEF, &axis},
		{"GridLine", typLINEDEF, &GridLine, 0L},
		{"GridType", typINT, &gl_type, 0L},
		{"Ticks", typOBJLST, &Ticks, (long*)&NumTicks},
		{"Label", typGOBJ, &axisLabel, 0L},
		{"TickFile", typTEXT, &tickfile, 0L},
		{"ssRefTV", typTEXT, &ssMATval, 0L},
		{"ssRefTL", typTEXT, &ssMATlbl, 0L},
		{"ssRefMT", typTEXT, &ssMITval, 0L},
		{"g_type", typINT, &grad_type, 0L},
		{"g_col_0", typDWORD, &gCol_0, 0L},
		{"g_col_1", typDWORD, &gCol_1, 0L},
		{"g_col_2", typDWORD, &gCol_2, 0L},
		{"gTrans", typLAST | typDWORD, &gTrans, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		sizAxLine = DefSize(SIZE_AXIS_LINE);
		sizAxTick = DefSize(SIZE_AXIS_TICKS);
		sizAxTickLabel = DefSize(SIZE_TICK_LABELS);
		colAxis = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
		GridLine.color = 0x00808080L;
		GridLine.pattern = 0xf8f8f8f8L;
		brksymsize = DefSize(SIZE_TICK_LABELS);
		brkgap = DefSize(SIZE_AXIS_TICKS);
		brksym = 2;
		tlbdef.ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
		tlbdef.ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
		tlbdef.fSize = DefSize(SIZE_TICK_LABELS);	tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
		tlbdef.Style = TXS_NORMAL;					tlbdef.Mode = TXM_TRANSPARENT;
		tlbdef.Font = FONT_HELVETICA;				atv = 0L;
		tlbdef.text = 0L;		l_segs = 0L;		nl_segs = 0;
		drawOut = scaleOut = 0L;					bModified = false;
		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
		mo = 0L;		grad_type = 1;		gTrans = 0x00000000L;
		gCol_0 = 0x00ffffffL;	gCol_1 = 0x00ff0000L;	gCol_2 = 0x000000ffL;
		return true;
	case FILE_READ:
		if(axisLabel)DeleteGO(axisLabel);
		if(tickfile) free(tickfile);		if(ssMATval) free(ssMATval);
		if(ssMATlbl) free(ssMATlbl);		if(ssMITval) free(ssMITval);
		tickfile = 0L;
		if(ExecInput(Desc) && tickfile && tickfile[0]){
			TickFile(tickfile);
			free(tickfile);					tickfile = 0L;
			}
		if(axis) axis->owner = this;
		if(axisLabel)axisLabel->parent = this;
		if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->parent = this;
		return true;
	case FILE_WRITE:
		//do all ticks
		for(i = 0; Ticks && i< NumTicks; i++) if(Ticks[i]) Ticks[i]->FileIO(rw);
		if(axisLabel) axisLabel->FileIO(rw);
		if((type & 0x04)!=4) Desc[17].type |= typLAST;
		return ExecOutput(Notary->RegisterGO(this), "Axis", Desc);
		}
	return false;
}

void
ContourPlot::RegGO(void *n)
{
	int i;

	if(n) {
		if(Symbols) for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->RegGO(n);
		if(Labels) for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->RegGO(n);
		if(zAxis) zAxis->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
ContourPlot::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"xBounds", typLFPOINT, &xBounds, 0L},
		{"yBounds", typLFPOINT, &yBounds, 0L},
		{"zBounds", typLFPOINT, &zBounds, 0L},
		{"srz", typNZLFLOAT, &sr_zval, 0L},
		{"flags", typDWORD, &flags, 0L},
		{"zDef", typAXDEF, &z_axis, 0L},
		{"zAxis", typGOBJ, &zAxis, 0L},
		{"Values", typFPLST3D, &val, &nval},
		{"Symbols", typOBJLST, &Symbols, &nSym},
		{"Labels", typOBJLST, &Labels, &nLab},
		{"ssRefX", typTEXT, &ssRefX, 0L},
		{"ssRefY", typTEXT, &ssRefY, 0L},
		{"ssRefZ", typLAST | typTEXT, &ssRefZ, 0L}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
		sr_zval = 0.0;		flags = 0L;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "Contour Plot (%s)", name);
#else
			i = sprintf(TmpTxt, "Contour Plot (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		ExecInput(Desc);
		if(Symbols) for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->parent=this;
		if(Labels) for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->parent=this;
		if(zAxis) zAxis->parent = this;
		return true;
	case FILE_WRITE:
		if(Symbols) for(i = 0; i < nSym; i++) if(Symbols[i]) Symbols[i]->FileIO(rw);
		if(Labels) for(i = 0; i < nLab; i++) if(Labels[i]) Labels[i]->FileIO(rw);
		if(zAxis) zAxis->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "ContourPlot", Desc);
		}
	return false;
}

void
Plot3D::RegGO(void *n)
{
	int i;

	if(n) {
		if(plots) for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->RegGO(n);
		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Plot3D::FileIO(int rw)
{
	fPOINT3D rot_vec, rot_ang;
	descIO Desc[] = {
		{"hide", typNZINT, &hidden, 0L},
		{"xBounds", typLFPOINT, &xBounds, 0L},
		{"yBounds", typLFPOINT, &yBounds, 0L},
		{"zBounds", typLFPOINT, &zBounds, 0L},
		{"Corner1", typPOINT3D, &cub1, 0L},
		{"Corner2", typPOINT3D, &cub2, 0L},
		{"Center", typPOINT3D, &rotC, 0L},
		{"rot_vec", typPOINT3D, &rot_vec, 0L},
		{"rot_ang", typPOINT3D, &rot_ang, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"z_axis", typNZINT, &use_zaxis, 0L},
		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
		{"Plots", typLAST | typOBJLST, &plots, (long*)&nPlots}};
	int i;

	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);
		drag = 0L;		moveable = 1;
		//set up RotDef
		RotDef[0] = 0.919384;		RotDef[1] = 0.389104;		RotDef[2] = -0.057709;
		RotDef[3] = 0.327146;		RotDef[4] = 0.944974;		RotDef[5] = 1.0-RotDef[4];
		cub1.fx = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_LEFT);
		cub2.fx = DefSize(SIZE_GRECT_LEFT) + DefSize(SIZE_DRECT_RIGHT);
		cub1.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_BOTTOM);
		cub2.fy = DefSize(SIZE_GRECT_TOP) + DefSize(SIZE_DRECT_TOP);
		cub1.fy += DefSize(SIZE_DRECT_TOP);	cub2.fy += DefSize(SIZE_DRECT_TOP);
		cub1.fz = 0.0;
		cub2.fz = DefSize(SIZE_DRECT_BOTTOM) - DefSize(SIZE_DRECT_TOP);
		rotC.fx = (cub1.fx + cub2.fx)/2.0;		rotC.fy = (cub1.fy + cub2.fy)/2.0;
		rotC.fz = (cub1.fz + cub2.fz)/2.0;
		dispObs = 0L;		nmaxObs = 0;	crea_flags = 0L;		dirty = true;
		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
		Sc_Plots = 0L;		nscp = 0;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D-root (%s)", name);
#else
			i = sprintf(TmpTxt, "3D-root (%s)", name);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
		ExecInput(Desc);
		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
		return true;
	case FILE_WRITE:
		rot_vec.fx = RotDef[0];	rot_vec.fy = RotDef[1];	rot_vec.fz = RotDef[2];
		rot_ang.fx = RotDef[3];	rot_ang.fy = RotDef[4];	rot_ang.fz = RotDef[5];
		//do all plots
		for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
		//do all axes
		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Plot3D", Desc);
		}
	return false;
}

void
Func3D::RegGO(void *n)
{
}

bool
Func3D::FileIO(int rw)
{
	fPOINT3D rot_vec, rot_ang;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"xBounds", typLFPOINT, &xBounds, 0L},
		{"yBounds", typLFPOINT, &yBounds, 0L},
		{"zBounds", typLFPOINT, &zBounds, 0L},
		{"Corner1", typPOINT3D, &cub1, 0L},
		{"Corner2", typPOINT3D, &cub2, 0L},
		{"Center", typPOINT3D, &rotC, 0L},
		{"rot_vec", typPOINT3D, &rot_vec, 0L},
		{"rot_ang", typPOINT3D, &rot_ang, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"z_axis", typNZINT, &use_zaxis, 0L},
		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
		{"Plots", typOBJLST, &plots, (long*)&nPlots},
		{"x1", typNZLFLOAT, &x1, 0L},
		{"x2", typNZLFLOAT, &x2, 0L},
		{"xstep", typNZLFLOAT, &xstep, 0L},
		{"z1", typNZLFLOAT, &x1, 0L},
		{"z2", typNZLFLOAT, &x2, 0L},
		{"zstep", typNZLFLOAT, &xstep, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"f_xz", typTEXT, &cmdxy, 0L},
		{"param", typLAST | typTEXT, &param, 0L}};
	int i;

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		x1 = -20.0;		x2 = 20.0;	xstep = 2.0;
		z1 = -20.0;		z2 = 20.0;	zstep = 2.0;
		gda = 0L;		gob = 0L;
		param = cmdxy = 0L;
		Line.width = DefSize(SIZE_HAIRLINE);
		Line.patlength = DefSize(SIZE_PATLENGTH);
		Line.color = Line.pattern = 0x0L;
		Fill.color = 0x00c0c0c0;
		Fill.color2 = 0x00ffffff;
		Fill.hatch = 0L;
		Fill.type = FILL_LIGHT3D;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D function (Plot %d)", cPlots);
#else
			i = sprintf(TmpTxt, "3D function (Plot %d)", cPlots);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
		ExecInput(Desc);
		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
		return true;
	case FILE_WRITE:
		rot_vec.fx = RotDef[0];	rot_vec.fy = RotDef[1];	rot_vec.fz = RotDef[2];
		rot_ang.fx = RotDef[3];	rot_ang.fy = RotDef[4];	rot_ang.fz = RotDef[5];
		//do all plots
		for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
		//do all axes
		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
		ExecOutput(Notary->RegisterGO(this), "Func3D", Desc);
		}
	return false;
}

void
FitFunc3D::RegGO(void *n)
{
}

bool
FitFunc3D::FileIO(int rw)
{
	fPOINT3D rot_vec, rot_ang;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"hide", typNZINT, &hidden, 0L},
		{"ssXref", typTEXT, &ssXref, 0L},
		{"ssYref", typTEXT, &ssYref, 0L},
		{"ssZref", typTEXT, &ssZref, 0L},
		{"xBounds", typLFPOINT, &xBounds, 0L},
		{"yBounds", typLFPOINT, &yBounds, 0L},
		{"zBounds", typLFPOINT, &zBounds, 0L},
		{"Corner1", typPOINT3D, &cub1, 0L},
		{"Corner2", typPOINT3D, &cub2, 0L},
		{"Center", typPOINT3D, &rotC, 0L},
		{"rot_vec", typPOINT3D, &rot_vec, 0L},
		{"rot_ang", typPOINT3D, &rot_ang, 0L},
		{"x_axis", typNZINT, &use_xaxis, 0L},
		{"y_axis", typNZINT, &use_yaxis, 0L},
		{"z_axis", typNZINT, &use_zaxis, 0L},
		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
		{"Plots", typOBJLST, &plots, (long*)&nPlots},
		{"x1", typNZLFLOAT, &x1, 0L},
		{"x2", typNZLFLOAT, &x2, 0L},
		{"xstep", typNZLFLOAT, &xstep, 0L},
		{"z1", typNZLFLOAT, &x1, 0L},
		{"z2", typNZLFLOAT, &x2, 0L},
		{"zstep", typNZLFLOAT, &xstep, 0L},
		{"maxiter", typNZINT, &maxiter, 0L},
		{"Line", typLINEDEF, &Line, 0L},
		{"Fill", typFILLDEF, &Fill, 0L},
		{"f_xz", typTEXT, &cmdxy, 0L},
		{"param", typLAST | typTEXT, &param, 0L}};
	int i;

	switch(rw) {
	case SAVE_VARS:
		return SaveVarGO(Desc);
	case INIT_VARS:
		x1 = -20.0;		x2 = 20.0;	xstep = 2.0;
		z1 = -20.0;		z2 = 20.0;	zstep = 2.0;
		gda = 0L;		gob = 0L;
		conv = 1.0e-15;	maxiter = 100;
		param = cmdxy = ssXref = ssYref = ssZref = 0L;
		Line.width = DefSize(SIZE_HAIRLINE);
		Line.patlength = DefSize(SIZE_PATLENGTH);
		Line.color = Line.pattern = 0x0L;
		Fill.color = 0x00c0c0c0;
		Fill.color2 = 0x00ffffff;
		Fill.hatch = 0L;
		Fill.type = FILL_LIGHT3D;
		if(name) {
#ifdef USE_WIN_SECURE
			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "FitFunc3D (Plot %d)", cPlots);
#else
			i = sprintf(TmpTxt, "FitFunc3D (Plot %d)", cPlots);
#endif
			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
			}
		return true;
	case FILE_READ:
		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
		ExecInput(Desc);
		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
		return true;
	case FILE_WRITE:
		rot_vec.fx = RotDef[0];	rot_vec.fy = RotDef[1];	rot_vec.fz = RotDef[2];
		rot_ang.fx = RotDef[3];	rot_ang.fy = RotDef[4];	rot_ang.fz = RotDef[5];
		//do all plots
		for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
		//do all axes
		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
		ExecOutput(Notary->RegisterGO(this), "FitFunc3D", Desc);
		}
	return false;
}

void
Graph::RegGO(void *n)
{
	int i;

	if(n) {
		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->RegGO(n);
		if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Graph::FileIO(int rw)
{
	int ixax, iyax;
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"Units", typNZINT, &units, 0L},
		{"Scale", typNZLFLOAT, &scale, 0L},
		{"GRect", typFRECT, &GRect, 0L},
		{"DRect", typFRECT, &DRect, 0L},
		{"Bounds", typFRECT, &Bounds, 0L},
		{"ColFrame", typDWORD, &ColGR, 0L},
		{"ColFrameL", typDWORD, &ColGRL, 0L},
		{"ColRec", typDWORD, &ColDR, 0L},
		{"ColAxis", typDWORD, &ColAX, 0L},
		{"Xaxis", typAXDEF, &x_axis, 0L},
		{"Yaxis", typAXDEF, &y_axis, 0L},
		{"DefXAxis", typINT, &ixax, 0L},
		{"DefYAxis", typINT, &iyax, 0L},
		{"Axes", typOBJLST, &Axes, (long*)&NumAxes},
		{"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
	int i;
	bool bConvert = false;

	ixax = iyax = -1;
	switch(rw) {
	case INIT_VARS:
		InitVarsGO(Desc);						units = defs.cUnits = defs.dUnits;
		OwnDisp = bDialogOpen = false;			dirty = true;
		GRect.Ymin = defs.GetSize(SIZE_GRECT_TOP);		GRect.Ymax = defs.GetSize(SIZE_GRECT_BOTTOM);
		GRect.Xmin = defs.GetSize(SIZE_GRECT_LEFT);		GRect.Xmax = defs.GetSize(SIZE_GRECT_RIGHT);
		DRect.Ymin = defs.GetSize(SIZE_DRECT_TOP);		DRect.Ymax = defs.GetSize(SIZE_DRECT_BOTTOM);
		DRect.Xmin = defs.GetSize(SIZE_DRECT_LEFT);		DRect.Xmax = defs.GetSize(SIZE_DRECT_RIGHT);
		ColGR = defs.Color(COL_GRECT);					ColGRL = defs.Color(COL_GRECTLINE);
		ColDR = defs.Color(COL_DRECT);					ColBG = defs.Color(COL_BG);
		ColAX = defs.Color(COL_AXIS);
		x_axis.max = y_axis.max = 1.0;					x_axis.owner = y_axis.owner = (void *)this;
		rcDim.left = rcDim.right = rcDim.top = rcDim.bottom = 0;
		rcUpd.left = rcUpd.right = rcUpd.top = rcUpd.bottom = 0;
		CurrGO = 0L;		Disp = 0L;			Sc_Plots = 0L;
		AxisTempl = 0;		nscp = 0;			CurrDisp = 0L;
		ToolMode = TM_STANDARD;	bModified = false;		zoom_def = 0L;
		tl_pts = 0L;		tl_nPts = 0;		tickstyle = zoom_level = 0;
		frm_g = frm_d = 0L;	PasteObj = 0L;		filename = 0L;
		rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
		return true;
	case FILE_READ:
		units = 0;			//default to mm if statement mising in file
		if((bConvert =ExecInput(Desc)) && ixax>=0 && iyax >=0 && Axes && 
			NumAxes >= ixax+1 && NumAxes >= iyax) {
			if(Axes[ixax]) Axes[ixax]->Command(CMD_SET_AXDEF, &x_axis, 0L);
			if(Axes[iyax]) Axes[iyax]->Command(CMD_SET_AXDEF, &y_axis, 0L);
			return true;
			}
		return bConvert;
	case FILE_WRITE:
		bModified = false;		if(scale == 1.0) scale = 0.0;
		//find default axes
		if(Axes) for(i = 0; Axes && i < NumAxes; i++) {
			if(Axes[i] && Axes[i]->GetAxis() == &x_axis) ixax = i;
			else if(Axes[i] && Axes[i]->GetAxis() == &y_axis) iyax = i;
			}
		if(Id == GO_GRAPH)RegGO(Notary);
		//do all plots
		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
		//do all axes
		if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Graph", Desc);
		}
	return false;
}

void
Page::RegGO(void *n)
{
	int i;

	if(n) {
		if(Plots) for(i = 0; i< NumPlots; i++) 
			if(Plots[i] && Plots[i]->Id != GO_GRAPH) Plots[i]->RegGO(n);
		((notary*)n)->AddRegGO(this);
		}
}

bool
Page::FileIO(int rw)
{
	descIO Desc[] = {
		{"Type", typNZINT, &type, 0L},
		{"Units", typNZINT, &units, 0L},
		{"GRect", typFRECT, &GRect, 0L},
		{"Plots", typLAST | typOBJLST, &Plots, (long*)&NumPlots}};
	int i;

	switch(rw) {
	case INIT_VARS:
		//assume that Graph::FileIO(INIT_VARS) has been executed
		GRect.Xmin = GRect.Ymin = 0.0;
		GetPaper(&GRect.Xmax, &GRect.Ymax);
		ColBG = 0x00e8e8e8L;
		LineDef.width = 0.0;	LineDef.patlength = 1.0;
		LineDef.color = LineDef.pattern = 0x0L;
		FillDef.type = FILL_NONE;
		FillDef.color = 0x00ffffffL;	//use white paper
		FillDef.scale = 1.0;
		FillDef.hatch = 0L;		filename =0L;
		return true;
	case FILE_READ:
		Graph::FileIO(rw);
		return true;
	case FILE_WRITE:
		//do all plots
		bModified = false;
		if(Id == GO_PAGE)RegGO(Notary);
		if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) Plots[i]->FileIO(rw);
		return ExecOutput(Notary->RegisterGO(this), "Page", Desc);
		}
	return false;
}

bool
DefsRW::FileIO(int rw)
{
	descIO Desc[] = {
		{"dUnits", typINT, &defs.dUnits, 0L},
		{"cUnits", typINT, &defs.cUnits, 0L},
		{"dtHeight", typINT, &dlgtxtheight, 0L},
		{"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
		{"fmt_date", typTEXT, &defs.fmt_date, 0L},
		{"fmt_datetime", typTEXT, &defs.fmt_datetime, 0L},
		{"fmt_time", typTEXT, &defs.fmt_time, 0L},
		{"curr_path", typTEXT, &defs.currPath, 0L},
		{"menu_height", typINT, &defs.iMenuHeight, 0L},
		{"File1", typTEXT, &defs.File1, 0L},
		{"File2", typTEXT, &defs.File2, 0L},
		{"File3", typTEXT, &defs.File3, 0L},
		{"File4", typTEXT, &defs.File4, 0L},
		{"File5", typTEXT, &defs.File5, 0L},
		{"File6", typLAST | typTEXT, &defs.File6, 0L}};

	switch(rw) {
	case FILE_READ:
		ExecInput(Desc);
		//check for plausibility
		if(defs.ss_txt < 0.3 || defs.ss_txt > 3.0) defs.ss_txt = 0.9;
		if(defs.dUnits < 0 || defs.dUnits > 2) defs.dUnits = 0;
		defs.cUnits = defs.dUnits;
#ifdef _WINDOWS
		if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 16;
#else
		if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 10;
#endif
		return true;
	case FILE_WRITE:
		Notary = new notary();
#ifdef USE_WIN_SECURE
		_unlink(defs.IniFile);
#else
		unlink(defs.IniFile);
#endif
		iFile = OpenOutputFile(defs.IniFile);
		if(iFile >=0) {
			ExecOutput(-1, "Defaults", Desc);
			}
		CloseOutputFile();	if(Notary) delete Notary;	Notary = 0L;
		return true;
		}
	return false;
}
