/*------------------------------------------------------------------------------
	FILE	:	Parser.c
	CREATED	:	98/05/17
	AUTHOR	:	Mircea Petrescu
	CONTENTS:	parsing structures, variables & functions
------------------------------------------------------------------------------*/




#include "StdInc.h"
#include "File.h"
#include "DynArray.h"
#include "Parser.h"
#include "Register.h"
#include "Link.h"
#include "Error.h"

#ifdef LDT_SCR
#include "SCR.h"
#endif

#ifdef LDT_MULTITHREADED
CRITICAL_SECTION GReadExclusion;
#endif


#define FALSE 0
#define TRUE 1


extern int g_isFileNameValid;

/*  Valid characters in a word */

char tbl[256];

/* variables used for in place break into words */

char g_lastChar=0;  
int g_lastIndex=-1;
int parseLen[256], parseCount;
unsigned char* parsePos[256];

/* for in-place word break */
unsigned char* g_ulPos=0;


unsigned long g_ulBeginLineMark; /* last begin of line found */

/* variables for building a complete section name  (in case of subsections) */

char g_szType[512]="";
char g_szName[512]="";
char g_szParent[512]="";
char g_szId[512]="";

LDT_tdst_FileDesc TheFileDesc, *g_FileDesc=NULL;

LDT_tdst_Link *g_CrtSection=NULL;

int g_EOF=0;

/*------------------------------------------------------------------------------
	DESC.	:	initializes character classes for parsing
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

void InitParser( void )
{
	char sztmp[]=".:^!%&*+-<=>?_|~\\QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890";
	int i;

	for( i=0; i<128; i++ )
		tbl[i]= (char)(( strchr( sztmp, (char)i )!=NULL )?1:0 );
	for( i=128; i<255; i++ )
		tbl[i]= 1;
	tbl[255]=0;

	
	tbl[(unsigned char )'\"']=2;
	tbl[(unsigned char )'[']=3;
	tbl[(unsigned char )']']=4;
	tbl[(unsigned char )'$']=5;
	tbl[(unsigned char )'{']=6;
	tbl[(unsigned char )'}']=7;
	tbl[(unsigned char )';']=8;
	tbl[(unsigned char )'\n']=9;
	tbl[(unsigned char )',']=10; /* Catalin Cocos - support for NULL parameters - ex: "(,,,,,)" !!! */
	tbl[(unsigned char )')']=10; /* Catalin Cocos - support for NULL parameters - ex: "(,,,,,)" !!! */
	tbl[(unsigned char )'(']=10; /* Catalin Cocos - support for NULL parameters - ex: "(,,,,,)" !!! */
}

/*------------------------------------------------------------------------------
	DESC.	:	access function for word #i in current line
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
	MODIFIED:	Catalin Cocos
------------------------------------------------------------------------------*/
char *LDT_szGetParam( int i )
{
	if( (i<0) || (i>=parseCount) )
		return NULL;

	if( g_FileDesc->iLastIndex!=-1 )
		*g_ulPos=g_FileDesc->chLastChar;

	g_ulPos = parsePos[i]+parseLen[i];
	g_FileDesc->chLastChar = *g_ulPos;
	*g_ulPos = 0;

	g_FileDesc->iLastIndex = i;

	return (char *) parsePos[i];
}

/*------------------------------------------------------------------------------
	DESC.	:	actualize section name and level in file @ begin section
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/
char LowerCase[500];

void BeginSection( void )
{
	char *szName = LDT_szGetParam( 0 );
	char *szId;
//	strcpy(szName = LowerCase, LDT_szGetParam( 0 ));
//	for( ; *szName; szName++ )
//		if( ( *szName>='A') && ( *szName<='Z' ) )
//			*szName+='a'-'A';
//	szName = LowerCase;

	if( g_szParent[0]!=0 )
		strcat( g_szParent, "^" );
	strcat( g_szParent, g_szName );
	
	strcpy( g_szName, szName );

	szId=strchr( g_szName, ':' );
	if( szId )
	{
		strcpy( g_szId, szId+1 );
		*szId=0;
		strcpy( g_szType, g_szName );
		if(*(szId+1))
			*szId=':';
	}
	else
	{
		g_szId[0]=0;
		strcpy( g_szType, szName );
	}


	if( !(g_FileDesc->uwLoadType) ) 
	/* construct file contents in case not loading all file */
	{
		LDT_DSAr_Add(	&g_FileDesc->arContents,
					(void *) LDT_Create_Position(	g_szId, g_szParent, GetType( g_szType, LDT_REG_SECTION ),
													g_FileDesc->uwFlags, g_ulBeginLineMark, g_FileDesc->iLineNumber,
													g_FileDesc->iLevel )
				);
	}

	g_FileDesc->iLevel++;
}

/*------------------------------------------------------------------------------
	DESC.	:	actualize section name and level in file @ end section
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

void EndSection( void )
{
	char *szTmp, *szTmp1;
	int erase=0;
	g_FileDesc->iLevel--;
	szTmp=strrchr( g_szParent, '^' ); /* get last child in parent  xxx:xx^xxx:xx^XXX:XX */
	if( szTmp )  /* if we have a child ( parent is not xxx:xx )*/
	{
		*szTmp=0;    /* cut it from parent */
		szTmp++;
	}
	else {
		szTmp=g_szParent;   /* only one section name */
		erase=1;			/* so erase it after we extract child */
	}
	strcpy( g_szName, szTmp );  /* CC - moved this line here !!! the copy is always needed ///  paste it to current section name */

	szTmp1=strchr( szTmp, ':' );  /* current name in szTmp */
	if( szTmp1 )
	{
		strcpy( g_szId, szTmp1+1 );   /* split it in Type:Id */
		*szTmp1=0;
	}
	else g_szId[0]=0;

	strcpy( g_szType, szTmp );

	if( erase )
		g_szParent[0]=0;
	
	if( g_FileDesc->iLevel==0 )  /* adjust for file level */
	{
		g_szName[0]=0;
		g_szParent[0]=0;
		g_CrtSection=NULL;
	}
}


/*------------------------------------------------------------------------------
	DESC.	:	split a line in the component words
	CREATED	:	98/06/29        
	AUTHOR	:	Catalin Cocos
------------------------------------------------------------------------------*/

void GetWords( LDT_tdst_MemFile* pMemFile, unsigned char* buffer, int bSeek )
{
	int i = 0;
	int NULL_Parameter = 0;

	parseCount=0; /* MP - reset at each line!!! */

	if( bSeek ) 
	{
		while( buffer[i] != '\n' ) i++;
		pMemFile->Pos = buffer +i +1 - (unsigned char *)pMemFile->pBuffer;
		return;
	}

	for(;;)
	{
		while( tbl[buffer[i]] == 0 ) i++;

		switch( tbl[buffer[i]] )
		{
		case 2: /* a string */
			i++;
			parsePos[parseCount]= buffer + i;
			while( buffer[i] != '\"') i++;
			parseLen[parseCount] = buffer +i -parsePos[parseCount];
			parseCount++;
			i++;
			NULL_Parameter = 0;
			break;
		case 3: /* a format specifier -- ignore */
			while( buffer[i] != ']' && buffer[i] != '\n' ) i++;
			if(buffer[i] == ']') i++;
			break;
		case 8: /* comment  - skip the rest of the line */
			while( buffer[i] != '\n') i++;
		case 9:	/* end of line */
			pMemFile->Pos = buffer +i +1 - (unsigned char *)pMemFile->pBuffer;
			return;
		case 10:
			if(NULL_Parameter)
			{
				parsePos[parseCount]= buffer + i;
				parseLen[parseCount] = 0;
				parseCount++;
			}
			else NULL_Parameter = 1;
			i++;
			break;
		default: /* an usual word */
			parsePos[parseCount]= buffer + i;
			while( tbl[buffer[i]] == 1 ) i++;
			parseLen[parseCount] = buffer +i -parsePos[parseCount];
			parseCount++;
			NULL_Parameter = 0;
			break;
		}
	}
}


LDT_tdeParseResult fn_e_ParseLine( int bSeek )
{
	LDT_tdst_MemFile* pMemFile = g_FileDesc->_pInfoMemFile;
	unsigned char *buffer;
	char *sz;

	parseCount=0;				/* no words */
	g_EOF=0;  /* not at end of file */

	if( g_FileDesc->iLastIndex!=-1 )
	{	/* sentinel - restores the previously requested word */
		*g_ulPos = g_FileDesc->chLastChar;
		g_FileDesc->iLastIndex=-1;
	}
	
	for( ;; )
	{
		int i = 0;
	
		if(pMemFile->Pos >= pMemFile->Size)							/* the end of file was reached*/
		{
			g_EOF=1;
			return 	(g_FileDesc->iLevel--? ParseResult_EOF: ParseResult_EndSection);	
		}

		buffer=(unsigned char *)pMemFile->pBuffer+pMemFile->Pos;	/* the line buffer */
		g_FileDesc->iLineNumber++;									/* incrementing the line number */
		while( tbl[buffer[i]] == 0 ) i++;							/* skipping the blank spaces */
		g_ulBeginLineMark=pMemFile->Pos + i;						/* the beginning of the line */


		switch( tbl[buffer[i]] )
		{
			case 1: /* an entry */
				GetWords(pMemFile, buffer +i, bSeek);				
				return ParseResult_Entry;
			case 5: /* directive */
				GetWords(pMemFile, buffer +i +1, 0);    /* MP - force processing */
				
				strcpy(sz = LowerCase, LDT_szGetParam( 0 ));
				for( ; *sz; sz++ )
					if( ( *sz>='A') && ( *sz<='Z' ) )
					*sz+='a'-'A';

				if(!parseCount) break;
				switch(*((long*)LowerCase))
				{
				case 'crof': g_FileDesc->uwFlags|=LDT_uw_Anl_ForceAnalyse; break;	/* "ForceAnalyse" */
				case 'fdne': g_FileDesc->uwFlags&=~LDT_uw_Anl_ForceAnalyse; break;	/* "EndForceAnalyse" */
				case 'ston': g_FileDesc->uwFlags|=LDT_uw_Anl_NotSaveSection; break;	/* "NotSaveSection" */
				case 'ndne': g_FileDesc->uwFlags&=~LDT_uw_Anl_NotSaveSection; break;/* "EndNotSaveSection"*/
				case 'ctes':	/* "SetCurrentFileLong" || "SetCurrentFileDouble" */
					if( parseCount != 3 )
					{
#if defined(LDT_ERROR_TREATMENT)
						ERRoR(0, NULL, 0, "Invalid 'SetCurrentFile-Double/Long' directive");
#endif
						break; 
					}
					i = atoi( LDT_szGetParam( 1 ) );
					if( i<0 || i>7 )
					{
#if defined(LDT_ERROR_TREATMENT)
						ERRoR(0, NULL, 0, "'SetCurrentFile-Double/Long' index is out of range.");
#endif
						break;
					}
					if( strcmp( LowerCase, "setcurrentfiledouble" ) )
						g_FileDesc->ulValues[i]=(unsigned long)atol( LDT_szGetParam( 2 ) );
					else
						g_FileDesc->dValues[i]=(double)atof( LDT_szGetParam( 2 ) );
					break;
				case 'mmoc':	/* "Comments" */
					for(g_FileDesc->uwFlags|=LDT_uw_Anl_Comments;;)		/* parse the file until the "EndComments" directive is found or EOF is reached */
					{
						i = 0;
						if(pMemFile->Pos >= pMemFile->Size)							/* the end of file was reached*/
							return 	(g_FileDesc->iLevel? ParseResult_EOF: ParseResult_EndSection);	

						buffer=(unsigned char *)pMemFile->pBuffer+pMemFile->Pos;	/* the line buffer */
						g_FileDesc->iLineNumber++;									/* incrementing the line number */
						while( tbl[buffer[i]] == 0 ) i++;							/* skipping the blank spaces */
						g_ulBeginLineMark=pMemFile->Pos + i;						/* the beginning of the line */

						if(tbl[buffer[i]] == 5)
						{
							GetWords(pMemFile, buffer +i +1, bSeek);
							strcpy(sz = LowerCase, LDT_szGetParam( 0 ));
							for( ; *sz; sz++ )
								if( ( *sz>='A') && ( *sz<='Z' ) )
									*sz+='a'-'A';

							if(parseCount && (!strcmp( LowerCase, "endcomments" ))) 
								g_FileDesc->uwFlags&=~LDT_uw_Anl_Comments;
							break;
						}
						else
						{
							while( tbl[buffer[i]] != 9 ) i++;						/* skip the line */
							pMemFile->Pos = buffer +i +1 - (unsigned char*)pMemFile->pBuffer;
						}
					}
				}
				break;
			case 6: /* begin of section */
				GetWords(pMemFile, buffer +i +1, 0);				
				BeginSection();
				return ParseResult_BeginSection;
			case 7: /* end of section */ 
				GetWords( pMemFile, buffer +i +1, bSeek);			
				EndSection();
				return ParseResult_EndSection;
			case 8: /* a comment */
				while( tbl[buffer[i]] != 9 ) i++;					/* skip the line */
			case 9: /* an empty line */
				pMemFile->Pos = buffer +i +1 - (unsigned char*)pMemFile->pBuffer;
				break;
		}
	}
}

/*------------------------------------------------------------------------------
	DESC.	:	get next entry in section ( or begin/end section )
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/


LDT_tdeParseResult LDT_GetNextEntry( void )
{
	return fn_e_ParseLine(0);
}

/*------------------------------------------------------------------------------
	DESC.	:	various access functions for callbacks
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

char *LDT_szGetSectionName()
{
	return g_szId;
}

char *LDT_szGetSectionType()
{
	return g_szType;
}

char *LDT_szGetEntryName()
{
	return LDT_szGetParam(0);
}

int LDT_iGetNbParams()
{
	return parseCount;
}

/*------------------------------------------------------------------------------
	DESC.	:	various access functions for file values
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/
#pragma warning( disable:4127 )

unsigned long LDT_GetFileLong( int i )
{
	if( !g_FileDesc )
	{
#ifdef LDT_SCR
	  long ret;
	  SCR_M_RdL0_GetFileLong(0, i, long, ret);
	  return ret;
#else
#if defined(LDT_ERROR_TREATMENT)
	  ERRoR( 0, NULL, 0, "LDT_GetFileLong failed. No open file available.");
#endif
	  return 0;
#endif
	}
	return g_FileDesc->ulValues[i];
}

double LDT_GetFileDouble( int i )
{
	if( !g_FileDesc )
	/*	return (double)0.0;   patch MP - TEMP !!!*/
	{
#ifdef LDT_SCR
	  double ret;
	  SCR_M_RdL0_GetFileDouble(0, i, ret);
	  return ret;
#else
#if defined(LDT_ERROR_TREATMENT)
	  ERRoR( 0, NULL, 0, "LDT_GetFileDouble failed. No open file available.");
#endif
	  return 0.f;
#endif
	}
	return g_FileDesc->dValues[i];
}

#pragma warning( default:4127 )

void LDT_SetFileLong( int i, unsigned long ul )
{
	if( !g_FileDesc )
		return;
	g_FileDesc->ulValues[i]=ul;
}

void LDT_SetFileDouble( int i, double d )
{
	if( !g_FileDesc )
		return;
	g_FileDesc->dValues[i]=d;
}

unsigned long g_ulValues[8];

void LDT_SetTempLong( int i, unsigned long ul )
{
	g_ulValues[i]=ul;
}

unsigned long LDT_GetTempLong( int i )
{
	return g_ulValues[i];
}


/*------------------------------------------------------------------------------
	DESC.	:	opens a file and fills in the FileDesc
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
	MODIFIED:	Catalin Cocos
------------------------------------------------------------------------------*/

void OpenFileDesc( char* szFile, LDT_tdst_MemFile* pFile )
{
	int i;
	TheFileDesc.szFile=szFile;
	TheFileDesc._pInfoMemFile = pFile;

	TheFileDesc.iLevel=0;
	TheFileDesc.iLineNumber=0;	

	TheFileDesc.iLastIndex=-1;
	TheFileDesc.chLastChar=0; 

	TheFileDesc.uwFlags=0;
	TheFileDesc.uwLoadType=0; 	/* CC : Loading Type */
	
	for( i=0; i<64; i++ )
		TheFileDesc.ulValues[i]=0; 
	for( i=0; i<8; i++ )
		TheFileDesc.dValues[i]=0.0;

	g_FileDesc=&TheFileDesc;

	g_szName[0]=0;
	g_szParent[0]=0;
}

/*------------------------------------------------------------------------------
	DESC.	:	closes a file and fills in the FileDesc
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

void CloseFileDesc( void )
{
	int idx;
	f_CloseMem( TheFileDesc._pInfoMemFile );
	/* CC : contents clean-up -> start */
	for(idx = LDT_DSAr_GetUpperBound( &TheFileDesc.arContents); idx>=0; idx--)
		LDT_Delete_Position(TheFileDesc.arContents.pData[idx]);
	TheFileDesc.arContents.nSize = 0;
	/* CC : contents clean-up -> end */

	g_FileDesc=NULL;
}

/*------------------------------------------------------------------------------
	DESC.	:	positions a file and fills in the FileDesc
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

void PositionFile( LDT_tdst_Position *pos )
{
	f_SeekMem( TheFileDesc._pInfoMemFile, pos->dwPos, SEEK_SET );
	g_ulBeginLineMark=pos->dwPos;

	TheFileDesc.iLineNumber=pos->nLine;
	TheFileDesc.iLevel=pos->iLevel;
	TheFileDesc.uwFlags=pos->uwFlags;

	TheFileDesc.iLastIndex=-1;
	TheFileDesc.chLastChar=0;
	
	fn_e_ParseLine( 0 );  /* read the begin section line */	
}

LDT_tdst_Link *pParent[100];

/*------------------------------------------------------------------------------
	DESC.	:	default create - does nothing
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

int LDT_Default_NULL_Create(LDT_tdst_Link *link)
{
	link->pObject = NULL;
	return 0;
}

/*------------------------------------------------------------------------------
	DESC.	:	skipping a section
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

void LDT_SkipSection( )
{
	LDT_tdeParseResult result;
	int iLevel=g_FileDesc->iLevel;

	do{
		result=fn_e_ParseLine( 0 );
	}while ((g_FileDesc->iLevel>=iLevel)&&(result !=ParseResult_EOF) );

}


/*------------------------------------------------------------------------------
	DESC.	:	default loading
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

int LDT_Default_Load( LDT_tdst_Link *_Link )
{
	LDT_tdeParseResult result;
	_Link=_Link;

	do{
		result=LDT_GetNextEntry();
		if( result== ParseResult_BeginSection )
				LDT_LoadSection( NULL );
	}while ( result!=ParseResult_EndSection );

	return 0;
}

/*------------------------------------------------------------------------------
	DESC.	:	load the whole file
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

int LoadAllFile( LDT_tdst_Link *link )
{
	int ERR = 0;
	TheFileDesc.uwLoadType=1; /* CC : load-all-file flag */
	g_CrtSection=pParent[0]= link;
	if(( link->dwFlags&LDT_LF_LOADED ) == 0)
	{
		/* CC ...allowing file closure ->start*/
		if(( link->dwFlags&LDT_LF_ALLOCATED ) == 0)
		{
			ERR=link->Type->Create( link ); /* the Type is always !NULL */
			if(ERR)
			{
#if defined(LDT_ERROR_TREATMENT)
				ERRoR(0, link, ERR, "Unable to create associated object.");
#endif
			}
			else
				link->dwFlags |= LDT_LF_ALLOCATED; /* the link was allocated */
		}
		if(!ERR)
		{
			ERR = link->Type->Load( link );
#if defined(LDT_ERROR_TREATMENT)
			if(ERR)
				ERRoR(0, link, ERR, "Unable to load file. User error triggered in callback.");
			else if(TheFileDesc.iLevel>=0)
				ERRoR(0, link, 0, "Erroneous file load callback. Failure to reach the section end mark! (premature return or subsections not treated)");
#endif
			link->dwFlags |= LDT_LF_LOADED; /* the link was loaded */
		}
		/* CC ...allowing file closure ->end*/
	}
	return ERR;
}

/*------------------------------------------------------------------------------
	DESC.	:	loads a list of delayed references ( corresponding to a file )
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
	MODIFIED:	Catalin Cocos
------------------------------------------------------------------------------*/

int Solve( LDT_tdst_Refs *refs )
{
	
	LDT_tdst_MemFile* pFile;
	char bAllFile=0;
	LDT_tdst_Link *link = NULL, *link1, TmpLink;
	LDT_tdeParseResult result;
	LDT_tdst_CallbackEntry *Type;
	int ERR = 0, level;

	unsigned int uiPos=0;
	static char buffer[256];
	int ok=1;

	link=(LDT_tdst_Link*)LDT_DSAr_GetAt( &refs->Links, 0 );

	if( LDT_DSAr_GetSize( &refs->Links )==1 )
	{
		if( link->dwFlags& LDT_LF_FILE )
			bAllFile=1;
	}
	pParent[0]=NULL;

#ifdef LDT_MULTITHREADED
	pFile = refs->pFile;
#else		
	pFile = AccessFile(refs->szFile);
#endif

	if(pFile == INVALID_HANDLE_VALUE)
	{
		if(bAllFile)
		{
#if defined(LDT_ERROR_TREATMENT) && ( LDT_WARNING_LEVEL >= 1 || LDT_ERROR_LEVEL >= 1)
			ERRoR(1, link, 0, "Unable to open the file.");
#endif
			return 0;
		}
		else
		{
#if defined(LDT_ERROR_TREATMENT) && ( LDT_WARNING_LEVEL >= 1 || LDT_ERROR_LEVEL >= 1)
			ERRoR(1, link, 0, "Unable to load section. Containing file not found.");
#endif
			return -1;
		}
	}
	
	OpenFileDesc( refs->szFile, pFile );		/* initialize file parsing */

	if( bAllFile ) ERR = LoadAllFile( link ); /* load all file */
	else /* load a list of sections */
	{
		do{
			result=fn_e_ParseLine( 1 );
			switch( result )
			{
			case ParseResult_BeginSection:
				{
					int index;
					
					/* Type = GetType( g_szType, LDT_REG_SECTION ); */
					Type = ((LDT_tdst_Position*)g_FileDesc->arContents.pData[g_FileDesc->arContents.nSize-1])->Type;
					
					TmpLink.szFile = refs->szFile;
					TmpLink.szParent = g_szParent;
					TmpLink.szName = g_szId;
					TmpLink.Type = Type;
					
					index=LDT_DSAr_Index( &refs->Links, &TmpLink, NULL ); 

					if( index!=-1 )
					{	/* the section is to be loaded */
						link1=(LDT_tdst_Link *)LDT_DSAr_GetAt( &refs->Links, index );
						LDT_DSAr_RemoveAt( &refs->Links, index );
						pParent[ g_FileDesc->iLevel ]=link1;
						g_CrtSection=link1;
						level = g_FileDesc->iLevel - 1;
						ERR=Type->Load( link1 );
						if(ERR)
						{
#if defined(LDT_ERROR_TREATMENT)
							ERRoR(0, link1, ERR, "Unable to load section. User error triggered in callback.");
#endif
							CloseFileDesc(); /* close the file */
							return -1;
						}
						if(level != g_FileDesc->iLevel)
						{
#if defined(LDT_ERROR_TREATMENT)
							ERRoR(0, link1, 0, "Erroneous load callback. Failure to reach the section end mark! (premature return or subsections not treated)");
#endif
							CloseFileDesc(); /* close the file */
							return -1;
						}

						link1->dwFlags |= LDT_LF_LOADED; /* the link was loaded */
					}	
				}
			default:
				break;
			}
		}while ( (!g_EOF)&&(LDT_DSAr_GetSize(&refs->Links)>0) );

		if(LDT_DSAr_GetSize(&refs->Links)>0)
			LDT_DSAr_QSort( &g_FileDesc->arContents );

		while( LDT_DSAr_GetSize(&refs->Links)>0 )
		{
			LDT_tdst_Position pos, *p;
			int index=LDT_DSAr_GetUpperBound( &refs->Links );
			link1=(LDT_tdst_Link *)LDT_DSAr_GetAt( &refs->Links, index );
			if( link1->dwFlags&LDT_LF_FILE ) /* all file requested */
			{
				int i;
				/* reset the file */
				if( g_FileDesc->iLastIndex!=-1 )
				{	/* sentinel - restores the previously requested word */
					*g_ulPos = g_FileDesc->chLastChar;
					g_FileDesc->iLastIndex=-1;
				}
			
				f_SeekMem( TheFileDesc._pInfoMemFile, 0, SEEK_SET );
				
				TheFileDesc.iLevel=0;
				TheFileDesc.iLineNumber=0;	

				TheFileDesc.iLastIndex=-1;
				TheFileDesc.chLastChar=0; 

				TheFileDesc.uwFlags=0;
	
				for( i=0; i<8; i++ )
				{
					TheFileDesc.ulValues[i]=0; 
					TheFileDesc.dValues[i]=0.0;
				}

				ERR = LoadAllFile( link1 ); /* load all file */

				CloseFileDesc(); /* close the file */
				return ERR;
			}
			LDT_DSAr_RemoveAt( &refs->Links, index );
			pos.szName=link1->szName;
			pos.szParent=link1->szParent;
			pos.Type=link1->Type;
			index=LDT_DSAr_Index( &g_FileDesc->arContents, (void *)&pos, NULL );
			if( index<0 )
			{
#if defined(LDT_ERROR_TREATMENT) && ( LDT_WARNING_LEVEL >= 1 || LDT_ERROR_LEVEL >= 1)
				ERRoR(1, link1, 0, "Unable to load section. Section not found.");
#endif
				continue;	/* the link was not found */
			}
			p=(LDT_tdst_Position *)LDT_DSAr_GetAt(  &g_FileDesc->arContents, index );
			PositionFile( p );
			g_CrtSection=link1;
			pParent[g_FileDesc->iLevel]=link1;
			level = g_FileDesc->iLevel - 1;
			if( (index=link1->Type->Load( link1 )) != 0 )
			{
#if defined(LDT_ERROR_TREATMENT)
				ERRoR(0, link1, ERR, "Unable to load section. User error triggered in callback.");
#endif
				break;
			}
			if(level != g_FileDesc->iLevel)
			{
#if defined(LDT_ERROR_TREATMENT) 
				ERRoR(0, link1, 0, "Erroneous load callback. Failure to reach the section end mark! (premature return or subsections not treated)");
#endif
				break;
			}
			link1->dwFlags |= LDT_LF_LOADED; /* the link was loaded */
		}
	}

	CloseFileDesc(); /* close the file */
	return ERR;
}

/*------------------------------------------------------------------------------
	DESC.	:	breaks a reference name in file, parent, type, id
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/

void LDT_SplitSectionName( char *szSection, char *szFile, char *szParent, char *szType, char *szId ) 
{
	char *szP, *szI, *szT;

	strcpy( szFile, szSection );

	szT=strrchr( szFile, '^' );
	if( szT )
	{
		*szT=0;
		szT++;
	}
		
	szI=szT?strrchr( szT, ':' ):NULL;
	if( szI )
	{
		*szI=0;
		szI++;
		strcpy( szId, szI );
	}
	else szId[0]=0;

	if( szT )
		strcpy( szType, szT );
	else szType[0]=0;

	szP=strchr( szFile, '^' );
	if( szP )
	{
		*szP=0;
		szP++;
		strcpy( szParent, szP );
	}
	else szParent[0]=0;
}

/*------------------------------------------------------------------------------
	DESC.	:	computes name of current section and returns length of file name
	CREATED	:	98/05/17        
	AUTHOR	:	Mircea Petrescu
------------------------------------------------------------------------------*/
int LDT_ComputeSectionName( LDT_tdst_Link *link, char *buffer )
{
	if( g_FileDesc && g_isFileNameValid )
		strcpy( buffer, g_FileDesc->_pInfoMemFile->pName );
	else
		strcpy( buffer, link->szFile );
	if(!(link->dwFlags & LDT_LF_FILE))
	{
		if( link->szParent[0] )
		{
			strcat( buffer, "^" );
			strcat( buffer, link->szParent );
		}
		strcat( buffer, "^" );
		strcat( buffer, link->Type->szType );
		if( link->szName[0] )
		{
			strcat( buffer, ":" );
			strcat( buffer, link->szName );
		}
	}
	return ((g_FileDesc && g_isFileNameValid) ? g_FileDesc->_pInfoMemFile->sPathLength: 0);
}

#ifdef LDT_LOG_STATISTICS
extern TimerStruct Totalreadtime; 
extern unsigned TotalFileCount;
extern double TotalFileSize;
#endif


/*------------------------------------------------------------------------------
	DESC.	:	accesses a disk file
	INPUT	:	filename
	OUTPUT	:	the file
	CREATED	:	24/08/98        
	AUTHOR	:	Catalin Cocos
------------------------------------------------------------------------------*/
LDT_tdst_MemFile* AccessFile( char* szFile )
{
	char Buffer[_MAX_PATH * 2] = "";
	LDT_tdst_MemFile* pFile = NULL;
	LDT_tdst_TypePaths* pPaths = NULL;
	char* sz, *ext = strrchr( szFile, '.');

#ifdef LDT_LOG_STATISTICS
	StartTimer(&Totalreadtime);
#endif

	if(ext)
	{	/* try to get the default path(s) for the file type*/
		int idx;
		ext++;
//		sz=ext;
//		for( ; *sz; sz++ )
//			if( ( *sz>='A') && ( *sz<='Z' ) )
//			*sz+='a'-'A';
		idx = LDT_DSAr_Index( &g_ArPaths, (LDT_tdst_TypePaths*) &ext, NULL);
		if(idx>=0)
			pPaths = (LDT_tdst_TypePaths*) g_ArPaths.pData[idx]; /* search succeeded */
	}

	if( pPaths )
	{
		int NumDirs, idx, i, max;
		char** pDirDatas, *szBaseDir, *dummy = "" ;
		NumDirs = LDT_DSAr_GetSize( &g_ArBaseDirectories );
		pDirDatas = NumDirs? (char**)g_ArBaseDirectories.pData: (NumDirs++,&dummy);
		for(idx = 0; idx<NumDirs; idx++ )
		{
			szBaseDir = pDirDatas[idx];
		
			for( i = 0, max = pPaths->arPaths.nSize; i< max; i++ )
			{
				sz = pPaths->arPaths.pData[i];
				strcpy(Buffer, szBaseDir);
				if(*sz == '\\' && *Buffer && Buffer[strlen(Buffer) -1] == '\\') sz++;
				strcat(Buffer, sz);
				strcat(Buffer, szFile);
				if( !_access( Buffer, 04 ) )
				{
					f_OpenMem(&pFile, Buffer);
					if( pFile ) 
					{
						if(i)
						{
							memmove( pPaths->arPaths.pData + 1, pPaths->arPaths.pData, i*sizeof(void*) );
							pPaths->arPaths.pData[0] = sz;						
						}
						pFile->sPathLength = strlen(Buffer) - strlen(szFile);
						idx = NumDirs;
						break;
					}
				}
			}
		}
	}


	if(!pFile) f_OpenMem(&pFile, szFile);
	if(!pFile) pFile = INVALID_HANDLE_VALUE;
#ifdef LDT_LOG_STATISTICS
	StopTimer(&Totalreadtime);
	if(pFile != INVALID_HANDLE_VALUE)
	{
		TotalFileSize += (double)pFile->Size;
		TotalFileCount++;
	}
#endif
	return pFile;
}

/*------------------------------------------------------------------------------
	DESC.	:	gets the name of a disk file
	INPUT	:	filename, buffer to put the full path in
	OUTPUT	:	0 if File Found, !0 on error
	CREATED	:	98/08/25        
	AUTHOR	:	Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_SearchFile( char* szFile, char* ResultBuffer )
{
	LDT_tdst_TypePaths* pPaths = NULL;
	char /**sz,*/ *ext, Buffer[_MAX_PATH];
	
	if( !szFile ) return -1;
	
	ext = strrchr( szFile, '.');

	if(ext)
	{	/* try to get the default path(s) for the file type*/
		int idx;
		ext++;
//		sz=ext;
//		for( ; *sz; sz++ )
//			if( ( *sz>='A') && ( *sz<='Z' ) )
//			*sz+='a'-'A';
		idx = LDT_DSAr_Index( &g_ArPaths, (LDT_tdst_TypePaths*) &ext, NULL);
		if(idx>=0)
			pPaths = (LDT_tdst_TypePaths*) g_ArPaths.pData[idx]; /* search succeeded */
	}

	if( pPaths )
	{
		int NumDirs, idx, i, max;
		char** pDirDatas, *szBaseDir, *dummy = "" ;
		NumDirs = LDT_DSAr_GetSize( &g_ArBaseDirectories );
		pDirDatas = NumDirs? (char**)g_ArBaseDirectories.pData: (NumDirs++,&dummy);
		for(idx = 0; idx<NumDirs; idx++ )
		{
			szBaseDir = pDirDatas[idx];
		
			for( i = 0, max = pPaths->arPaths.nSize; i< max; i++ )
			{
				char* sz = pPaths->arPaths.pData[i];
				strcpy(Buffer, szBaseDir);
				if(*sz == '\\' && *Buffer && Buffer[strlen(Buffer) -1] == '\\') sz++;
				strcat(Buffer, sz);
				strcat(Buffer, szFile);
				if( !_access( Buffer, 04 ) )
				{
					if(ResultBuffer)
						strcpy(ResultBuffer, Buffer);
					return 0;
				}
			}
		}
	}
	
	if( !_access( szFile, 04 ) )
	{
		if(ResultBuffer)
			strcpy(ResultBuffer, szFile);
		return 0;
	}
	return 1;
}

