//////////////////////////////////////////////////////////////////////////////////
// $Source: /cvsroot/cdx/cdx3.0/tools/CDXResourceCompiler/CDXResourceCompiler.cpp,v $
// $Author: hebertjo $
//
// $Log: CDXResourceCompiler.cpp,v $
// Revision 1.1.1.1  2000/04/22 16:01:08  hebertjo
// Initial checkin of v3.0 to SourceForge CVS.
//
// Revision 1.5  1999/05/23 04:02:27  pietro
// format change
//
// Revision 1.4  1999/05/17 21:09:25  pietro
// Added CDXResWorldObject - stores pictures with frames
//
// Revision 1.3  1999/05/17 11:44:58  pietro
// Added IDHFILE keyword for .h file is created for name->ID conversion
//
// Revision 1.2  1999/05/17 00:12:34  pietro
// debuged version.
//
// Revision 1.1  1999/05/16 22:02:21  pietro
// created new tool: CDXResourceCompiler for creating v2 resource files
//
//
// $Revision: 1.1.1.1 $
//////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"

static char rcsid[] = "@(#) $Id: CDXResourceCompiler.cpp,v 1.1.1.1 2000/04/22 16:01:08 hebertjo Exp $";

CDXResDirEntry	*Directory;
UINT	NumOfEntries=0;
UINT	version=3;						//version of resource file
UINT	CurrentID = 1;
UINT	CurrentEntry = 0;
char	*fName;							//name of Resource File
FILE	*fHandle;						//handle of Resource File
FILE	*idhHandle;
BOOL	rSpecified = false;				//already used RESOURCE keyword?

/*---------------------------------------------------------------------------*/
enum KeyNums
{
	kwNotFound = -2,
	kwEof,

	kwPath = 0,
	kwExt,

	kwObjectName,
	kwBitmapFile,
	kwWorldSize,
	kwScreenSize,

	kwFrames,
	kwFrameID,
	kwxyoffset,
	kwEndFrames,
	kwEndObject,
	kwStore,
	kwResource,
	kwIdHFile,

	__LastKeyWord
};

static char *KeyWords[__LastKeyWord] =
{
	"PATH",
	"EXT",

	"ObjectName",
	"BitmapFile",
	"WorldSize",
	"ScreenSize",

	"FRAMES",
	"FrameID",
	"xyoffset",
	"EndFrames",
	"EndObject",
	"Store",
	"Resource",
	"IDHFILE",

};





/*---------------------------------------------------------------------------*/
/*                                                Created: 8.4.1999 15:10:39 */
/* isKeyWord																 */
/*                                                                           */
/*---------------------------------------------------------------------------*/
int isKeyWord(char *key)
{
	if (*key==NULL)
		return kwEof;

	for(int i=0; i < __LastKeyWord; i++)
	{
		if(strlen(key) < strlen(KeyWords[i]))
			continue;

		if(strcmpi(key, KeyWords[i]) == 0)
			return(i);
	}
	return(kwNotFound);
}



/*---------------------------------------------------------------------------*/
/*                                                Created: 8.4.1999 15:32:49 */
/* makename																	 */
/* combines path, fname & extension into one string (fname)                  */
/*---------------------------------------------------------------------------*/
void makename(char *path, char *fname, char *ext)
{
	char buf[200];

	buf[0]='\0';

	if(*path!='\0')
	{
		if(*fname!='\\')
		{
			strcpy(buf,path);
			if(path[strlen(path)-1]!='\\')
				strcat(buf,"\\");
		}
	}
	strcat(buf,fname);
	if(*ext!='\0')
	{
		if(NULL==strstr(fname,"."))
		{
			if(*ext!='.')
				strcat(buf,".");
			strcat(buf,ext);
		}
	}
	strcpy(fname,buf);
}

/*---------------------------------------------------------------------------*/
void WriteResHeader()
{
	unlink(fName);
	if(NULL==(fHandle = fopen(fName, "wb+")))
	{
		printf("\nerror creating %s file\n", fName);
		exit(-1);
	}
	
	CDXRESOURCEFILEHEADER fh;
	fh.NumOfEntries=NumOfEntries;
	fh.Signature='CDXR';
	fh.Version=version;

	fwrite(&fh, sizeof(fh),1, fHandle);
}

/*---------------------------------------------------------------------------*/
void WriteDirectory()
{
	if(NULL==fHandle)
	{
		printf("\nerror %s is not open\n", fName);
		exit(-1);
	}
	
	rewind(fHandle);
	fseek(fHandle, sizeof(CDXRESOURCEFILEHEADER), SEEK_SET);
	//pos,size,type,id
	for(UINT i = 0; i < NumOfEntries; i++)
	{
		fwrite(&Directory[i].pos, sizeof(Directory[i].pos), 1, fHandle);
		fwrite(&Directory[i].size, sizeof(Directory[i].size), 1, fHandle);
		fwrite(&Directory[i].type, sizeof(Directory[i].type), 1, fHandle);
		fwrite(&Directory[i].id, sizeof(Directory[i].id), 1, fHandle);
	}
}

/*---------------------------------------------------------------------------*/
void CreateIDHFile(char *fname)
{
	unlink(fname);
	if(NULL==(idhHandle = fopen(fname, "wt+")))
	{
		printf("\nerror creating IDHFILE %s file\n", fname);
		exit(-1);
	}
	fprintf(idhHandle, "//{{NO_DEPENDENCIES}}\n// CDXResourceCompiler generated include file. Do not edit!\n\n");
}



/*---------------------------------------------------------------------------*/
/*                                               Created: 16.5.1999 23:59:21 */
/* CountEntries																 */
/*                                                                           */
/*---------------------------------------------------------------------------*/
UINT CountEntries(char * fname)
{
	UINT Entries=0;
	int CurrentKeyword;
	char	str[SLEN], CurrentPath[SLEN], CurrentExt[30], ChrBuf[SLEN];
	token in(fname);
	str[0]=CurrentPath[0]=CurrentExt[0]=0;
	//fName = "res.cdr";

	in.GetToken(str);					//read first token
	CurrentKeyword = isKeyWord(str);
	while (CurrentKeyword!=kwEof)
	{
		switch (CurrentKeyword)
		{
			case kwPath:		in.GetToken(CurrentPath); break;
			case kwExt:			in.GetToken(CurrentExt); break;

			case kwResource:	in.GetToken(ChrBuf);
								//fName=strdup(ChrBuf);
								break;
			
			case kwIdHFile:		in.GetToken(ChrBuf);
								//CreateIDHFile(ChrBuf);
								break;

			case kwObjectName:
				in.GetToken(ChrBuf);
				break;
			case kwBitmapFile:
				in.GetToken(ChrBuf);
				break;
			case kwWorldSize:
				in.GetInt();
				in.GetInt();
				in.GetInt();
				break;
			case kwScreenSize:
				in.GetInt();
				in.GetInt();
				break;
			case kwFrames:
				break;
			case kwFrameID:
				in.GetInt();
				break;
			case kwxyoffset:
				in.GetInt();
				in.GetInt();
				break;
			case kwEndFrames:
				break;
			case kwEndObject:
				Entries++;
				break;
			
			case kwStore:
				in.GetToken(ChrBuf);
				Entries++;
				break;

			
			case kwNotFound:
				//syntax error
				printf("\nSyntax Error at 1st pass: %s at line %u\n", str, in.LineNumber-1);
				exit (-1);
				break;
		}
		in.GetToken(str);
		CurrentKeyword = isKeyWord(str);

	}
	return Entries;
}



/*---------------------------------------------------------------------------*/
/*                                               Created: 16.5.1999 23:13:43 */
/* CompileResource                                                           */
/*                                                                           */
/*---------------------------------------------------------------------------*/
BOOL CompileResource(char * fname)
{
	int CurrentKeyword;
	char	str[SLEN], CurrentPath[SLEN], CurrentExt[30], ChrBuf[SLEN], BitmapFile[SLEN];
	UCHAR *tmpb;
	//WPoint	ws;
	//SPoint	ss;
	WOFrame Frame[500];
	WOStockObject CurrentObject;
	int cf;
	UCHAR tmps;
	FILE	*fi;
	char buf[200];

	token in(fname);
	str[0]=CurrentPath[0]=CurrentExt[0]=0;
	
	CurrentObject.name=NULL;
	CurrentObject.TotalFrames=0;
	CurrentObject.Frame=Frame;
	CurrentObject.Surface=NULL;
	
	NumOfEntries = CountEntries(fname);
	Directory = new CDXResDirEntry[NumOfEntries];


	in.GetToken(str);					//read first token
	CurrentKeyword = isKeyWord(str);
	while (CurrentKeyword!=kwEof)
	{
		switch (CurrentKeyword)
		{
			case kwPath:		in.GetToken(CurrentPath); break;
			case kwExt:			in.GetToken(CurrentExt); break;

			case kwResource:	in.GetToken(ChrBuf);
								fName=strdup(ChrBuf);
								rSpecified=true;
								WriteResHeader();
								WriteDirectory();	//placeholder only for this pass
								break;
			
			case kwIdHFile:		in.GetToken(ChrBuf);
								CreateIDHFile(ChrBuf);
								break;


			case kwObjectName:
				in.GetToken(ChrBuf);
				CurrentObject.name=strdup(ChrBuf);
				break;
			case kwBitmapFile:
				in.GetToken(BitmapFile);
				break;
			case kwWorldSize:
				CurrentObject.WorldSize.x=in.GetInt();
				CurrentObject.WorldSize.y=in.GetInt();
				CurrentObject.WorldSize.z=in.GetInt();
				break;
			case kwScreenSize:
				CurrentObject.ScreenSize.x=in.GetInt();
				CurrentObject.ScreenSize.y=in.GetInt();
				break;
			case kwFrames:
				CurrentObject.TotalFrames = 0;
				break;
			case kwFrameID:
				Frame[CurrentObject.TotalFrames].FrameId = in.GetInt();
				break;
			case kwxyoffset:
				Frame[CurrentObject.TotalFrames].xyoffset.x=in.GetInt();
				Frame[CurrentObject.TotalFrames].xyoffset.y=in.GetInt();
				CurrentObject.TotalFrames++;
				break;
			case kwEndFrames:
				//save frame??
				break;
			
			case kwEndObject:
				//save object
				//WriteObject(&CurrentObject,BitmapFile,"\\pietro\\projects\\g\\world");
				if(rSpecified==false)
				{
					printf("\nYou must specify RESOURCE keyword first\n");
					exit(-1);
				}
				fprintf(idhHandle, "#define IDH_%s\t\t\t\t\t%u\n", CurrentObject.name, CurrentID);
				printf("OBJECT:%s [%d frames]\n",
					CurrentObject.name, CurrentObject.TotalFrames);
				
				Directory[CurrentEntry].type=1;
				Directory[CurrentEntry].id=CurrentID++;
				Directory[CurrentEntry].pos=ftell(fHandle);
				
				//write object header
				CurrentObject.id = Directory[CurrentEntry].id;

				fwrite(&CurrentObject.id, sizeof(CurrentObject.id),1,fHandle);
				tmps = strlen(CurrentObject.name);	//string in file is pascal style <len><string>
				fwrite(&tmps, sizeof(tmps),1,fHandle);
				fwrite(CurrentObject.name, tmps,1,fHandle);

				fwrite(&CurrentObject.ScreenSize.x, sizeof(CurrentObject.ScreenSize.x),1,fHandle);
				fwrite(&CurrentObject.ScreenSize.y, sizeof(CurrentObject.ScreenSize.y),1,fHandle);

				fwrite(&CurrentObject.WorldSize.x, sizeof(CurrentObject.WorldSize.x),1,fHandle);
				fwrite(&CurrentObject.WorldSize.y, sizeof(CurrentObject.WorldSize.y),1,fHandle);
				fwrite(&CurrentObject.WorldSize.z, sizeof(CurrentObject.WorldSize.x),1,fHandle);

				fwrite(&CurrentObject.TotalFrames, sizeof(CurrentObject.TotalFrames),1,fHandle);

				for(cf=0;cf<CurrentObject.TotalFrames;cf++)
				{
					fwrite(&CurrentObject.Frame[cf].FrameId, sizeof(CurrentObject.Frame[cf].FrameId),1,fHandle);
					fwrite(&CurrentObject.Frame[cf].xyoffset.x, sizeof(CurrentObject.Frame[cf].xyoffset.x),1,fHandle);
					fwrite(&CurrentObject.Frame[cf].xyoffset.y, sizeof(CurrentObject.Frame[cf].xyoffset.y),1,fHandle);
				}

				strcpy(buf, BitmapFile);
				makename(CurrentPath, buf, CurrentExt);
				if((fi=fopen(buf,"rb"))==NULL)
				{
					printf("\nCould not open %s for reading\n", buf);
					exit (-1);
				}
				fseek(fi, 0, SEEK_END);
				Directory[CurrentEntry].size=ftell(fi);
				rewind(fi);
				tmpb = new UCHAR[Directory[CurrentEntry].size];
				fread(tmpb, 1, Directory[CurrentEntry].size, fi);
				fwrite(tmpb, 1, Directory[CurrentEntry].size, fHandle);
				delete tmpb;
				fclose(fi);
				Directory[CurrentEntry].size += sizeof(CurrentObject.id) +
						sizeof(UCHAR) +
						tmps +
						sizeof(CurrentObject.ScreenSize.x) +
						sizeof(CurrentObject.ScreenSize.y) +
						sizeof(CurrentObject.WorldSize.x) +
						sizeof(CurrentObject.WorldSize.y) +
						sizeof(CurrentObject.WorldSize.x) + 
						( CurrentObject.TotalFrames *
							(	sizeof(CurrentObject.Frame[0].FrameId) +
								sizeof(CurrentObject.Frame[0].xyoffset.x) +
								sizeof(CurrentObject.Frame[cf].xyoffset.y)
							)
						);

				CurrentEntry++;
				break;


			
			case kwStore:
				if(rSpecified==false)
				{
					printf("\nYou must specify RESOURCE keyword first\n");
					exit(-1);
				}
				in.GetToken(ChrBuf);
				
				fprintf(idhHandle, "#define IDH_%s\t\t\t\t\t%u\n", ChrBuf, CurrentID);

				Directory[CurrentEntry].type=0;
				Directory[CurrentEntry].id=CurrentID++;
				//add to IDHFILE
				Directory[CurrentEntry].pos=ftell(fHandle);
				strcpy(buf, ChrBuf);
				makename(CurrentPath, buf, CurrentExt);
				if((fi=fopen(buf,"rb"))==NULL)
				{
					printf("\nCould not open %s for reading\n", buf);
					exit (-1);
				}
				fseek(fi, 0, SEEK_END);
				Directory[CurrentEntry].size=ftell(fi);
				rewind(fi);
				tmpb = new UCHAR[Directory[CurrentEntry].size];
				fread(tmpb, 1, Directory[CurrentEntry].size, fi);
				fwrite(tmpb, 1, Directory[CurrentEntry].size, fHandle);
				delete tmpb;
				fclose(fi);

				printf("STORE: %s [%u bytes]\n", buf, Directory[CurrentEntry].size);
				CurrentEntry++;
				break;

			
			case kwNotFound:
				//syntax error
				printf("\nSyntax Error at 2nd pass: %s at line %u\n", str, in.LineNumber-1);
				exit (-1);
				break;
		}
		in.GetToken(str);
		CurrentKeyword = isKeyWord(str);

	}
	return TRUE;
}



/*---------------------------------------------------------------------------*/
int main(int argc, char* argv[])
{
	printf("CDX RESOURCE COMPILER\n%s\n\n", rcsid);

	if (argc == 2)
	{
		CompileResource(argv[1]);
		WriteDirectory();
		fclose(fHandle);
		fclose(idhHandle);
	}
	else
	{
		printf("Usage: CDXResourceCompiler ResourceBuildDescriptionFile\n");
	}
	return 0;
}
