//parser.cpp
//File Parser for the various text-based file formats used by the game.

#include <stdio.h>
#include <string.h>
#include "carphysics.h"
#include "fileio.h"
#include "vectors.h"
#include "gamemem.h"
#include "parser.h"
#include "roads.h"
#include "config.h"
#include "environment.h"
#include "gameinitexit.h"
#include "entities.h"
#include "text.h"
#include "challenges.h"
#include "rendercar.h"
#include "textures.h"
#include "texturesimport.h"
#include "controls.h"

//These functions test if the string in verifyLabel matches the string in label,
//and if it does parses data into the specified format and stores the result in dst.
//Returns true if verifyLabel matches label and false otherwise.

int TestForFloat(char *verifyLabel,char *label,char* data,float *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		sscanf(data,"%f",dst);
		return true;
	}
	else return false;
}

int TestForInt(char *verifyLabel,char *label,char* data,int *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		sscanf(data,"%d",dst);
		return true;
	}
	else return false;
}

int TestForHex(char *verifyLabel,char *label,char* data,int *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		sscanf(data,"0x%x",dst);
		return true;
	}
	else return false;
}

int TestForVector3(char *verifyLabel,char *label,char* data,tVector3 *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		sscanf(data,"{%f,%f,%f}",&dst->x,&dst->y,&dst->z);
		return true;
	}
	else return false;
}

int TestForVector2(char *verifyLabel,char *label,char* data,tVector2 *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		sscanf(data,"{%f,%f}",&dst->x,&dst->y);
		return true;
	}
	else return false;
}

int TestForString(char *verifyLabel,char *label,char* data,char *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		char* str=strchr(data,'"');
		if(str)str++;
		else return false;
		char* end=strchr(str,'"');
		if(end)*end='\0';
		else return false;
		strcpy(dst,str);
		return true;
	}
	else return false;
}

//Stores a File Reference ID for the specified file name in data in dst
tFileRef TestForFile(char *verifyLabel,char *label,char* data,int *dst)
{
	if(!_stricmp(verifyLabel,label))
	{
		char* fileName=strchr(data,'"');
		if(fileName)fileName++;
		else return false;
		char* endName=strchr(fileName,'"');
		if(endName)*endName='\0';
		else return false;
		*dst=FileGetReference(fileName);
		return true;
	}
	else return false;
}





//This file contains one function ParseXXXDescLine for each of the
//different text-based file formats used by the game, which parses a
//string resembling one line of the file
//into the appropiate data fields of the file's structure in memory. 

int ParseRoadTypeDescLine(char *label,char *data,tRoadTypeList *types,int arrayPos,int arrayPos2)
{
	if(TestForInt("numTypes",label,data,&types->numTypes)){
		types->types=(tRoadType*)MemoryAllocateZeroedBlock((types->numTypes+1)*sizeof(tRoadType));
		return true;
	}
	
	if(TestForInt("numVertices",label,data,&types->types[arrayPos].numVertices)){
		types->types[arrayPos].vertices=(tRoadTypeVertex*)MemoryAllocateZeroedBlock((types->types[arrayPos].numVertices+1)*sizeof(tRoadTypeVertex));
		return true;
	}
	if(TestForInt("endTopVertices",label,data,&types->types[arrayPos].endTopVertices))return true;
	if(TestForInt("startTopVertices",label,data,&types->types[arrayPos].startTopVertices))return true;

	if(TestForInt("endShadow",label,data,&types->types[arrayPos].endShadow))return true;
	if(TestForInt("startShadow",label,data,&types->types[arrayPos].startShadow))return true;
	if(TestForFloat("minTrack",label,data,&types->types[arrayPos].minTrack))return true;
	if(TestForFloat("maxTrack",label,data,&types->types[arrayPos].maxTrack))return true;
	if(TestForFloat("reviveX",label,data,&types->types[arrayPos].reviveX))return true;
	if(TestForFloat("reviveY",label,data,&types->types[arrayPos].reviveY))return true;
	if(TestForFloat("traction",label,data,&types->types[arrayPos].traction))return true;
	if(TestForString("name",label,data,types->types[arrayPos].name))return true;	
	
	if(TestForFloat("texZoom",label,data,&types->types[arrayPos].vertices[arrayPos2].texZoom))return true;	
	if(TestForFile("texture",label,data,&types->types[arrayPos].vertices[arrayPos2].texture))return true;	
	if(TestForHex("materialFlags",label,data,&types->types[arrayPos].vertices[arrayPos2].materialFlags))return true;	
	if(TestForInt("surfaceType",label,data,&types->types[arrayPos].vertices[arrayPos2].surfaceType))return true;	
	if(TestForVector2("vertex1",label,data,&types->types[arrayPos].vertices[arrayPos2].vertex1))return true;
	if(TestForVector2("vertex2",label,data,&types->types[arrayPos].vertices[arrayPos2].vertex2))return true;
	if(TestForFloat("texCoord1",label,data,&types->types[arrayPos].vertices[arrayPos2].texCoord1))return true;	
	if(TestForFloat("texCoord2",label,data,&types->types[arrayPos].vertices[arrayPos2].texCoord2))return true;	

	return false;
}

int ParseSurfaceTypeDescLine(char *label,char *data,tSurfaceTypeList *types,int arrayPos)
{
	if(TestForInt("numTypes",label,data,&types->numTypes)){
		types->types=(tSurfaceType*)MemoryAllocateZeroedBlock((types->numTypes+1)*sizeof(tSurfaceType));
		return true;
	}

	if(TestForFloat("grip",label,data,&types->types[arrayPos].grip))return true;	
	if(TestForFloat("slideGrip",label,data,&types->types[arrayPos].slideGrip))return true;	
	if(TestForFloat("bumpHeight",label,data,&types->types[arrayPos].bumpHeight))return true;	
	if(TestForFloat("bumpFreq",label,data,&types->types[arrayPos].bumpFreq))return true;	
	if(TestForInt("smokeEnable",label,data,&types->types[arrayPos].smokeEnable))return true;	
	if(TestForInt("trackEnable",label,data,&types->types[arrayPos].trackEnable))return true;	
	if(TestForInt("soundEnable",label,data,&types->types[arrayPos].soundEnable))return true;	
	if(TestForInt("sparksEnable",label,data,&types->types[arrayPos].sparksEnable))return true;	
	if(TestForInt("squeachEnable",label,data,&types->types[arrayPos].squeachEnable))return true;	
	if(TestForInt("reflectionEnable",label,data,&types->types[arrayPos].reflectionEnable))return true;	
	if(TestForInt("smokeStickEnable",label,data,&types->types[arrayPos].smokeStickEnable))return true;	
	if(TestForInt("soundEcho",label,data,&types->types[arrayPos].soundEcho))return true;	
	if(TestForFloat("brakeFactor",label,data,&types->types[arrayPos].brakeFactor))return true;	
	if(TestForFloat("minSmokeSlideVelo",label,data,&types->types[arrayPos].minSmokeSlideVelo))return true;	
	if(TestForFloat("maxSmokeSlideVelo",label,data,&types->types[arrayPos].maxSmokeSlideVelo))return true;	
	if(TestForFloat("minTrackSlideVelo",label,data,&types->types[arrayPos].minTrackSlideVelo))return true;	
	if(TestForFloat("maxTrackSlideVelo",label,data,&types->types[arrayPos].maxTrackSlideVelo))return true;	
	if(TestForFloat("minSkidPitchSlideVelo",label,data,&types->types[arrayPos].minSkidPitchSlideVelo))return true;	
	if(TestForFloat("maxSkidPitchSlideVelo",label,data,&types->types[arrayPos].maxSkidPitchSlideVelo))return true;	
	if(TestForFloat("minSkidGainSlideVelo",label,data,&types->types[arrayPos].minSkidGainSlideVelo))return true;	
	if(TestForFloat("maxSkidGainSlideVelo",label,data,&types->types[arrayPos].maxSkidGainSlideVelo))return true;	
	if(TestForFile("skidSound",label,data,&types->types[arrayPos].skidSound))return true;	
	if(TestForFile("smokeTexture",label,data,&types->types[arrayPos].smokeTexture))return true;	
	if(TestForFile("trackTexture",label,data,&types->types[arrayPos].trackTexture))return true;	
	if(TestForFloat("smokeSize",label,data,&types->types[arrayPos].smokeSize))return true;	
	if(TestForFloat("smokeGravity",label,data,&types->types[arrayPos].smokeGravity))return true;	
	if(TestForFloat("smokeSpeed",label,data,&types->types[arrayPos].smokeSpeed))return true;	
	if(TestForFloat("smokeSpread",label,data,&types->types[arrayPos].smokeSpread))return true;	
	if(TestForFloat("smokeMaxLife",label,data,&types->types[arrayPos].smokeMaxLife))return true;	
	if(TestForFloat("smokeMaxVelo",label,data,&types->types[arrayPos].smokeMaxVelo))return true;	
		
	return false;
}

int ParseEnvironmentDescLine(char *label,char *data,tEnvironment *env)
{
	if(TestForFile("sky0",label,data,&env->sky0))return true;
	if(TestForFile("sky90",label,data,&env->sky90))return true;
	if(TestForFile("sky180",label,data,&env->sky180))return true;
	if(TestForFile("sky270",label,data,&env->sky270))return true;
	if(TestForFile("skytop",label,data,&env->skytop))return true;
	if(TestForFile("skybot",label,data,&env->skybot))return true;
	if(TestForFile("spheremap",label,data,&env->spheremap))return true;
	if(TestForFile("particlesType",label,data,&env->particlesType))return true;
	if(TestForFile("surfaceTypes",label,data,&env->surfaceTypes))return true;
	if(TestForFile("soundLoop",label,data,&env->soundLoop))return true;
	if(TestForFile("soundRandom",label,data,&env->soundRandom))return true;
	if(TestForFile("dirtMap",label,data,&env->dirtMap))return true;
	if(TestForFile("altEnv",label,data,&env->altEnv))return true;

	if(TestForVector3("fogColor",label,data,&env->fogColor))return true;
	if(TestForVector3("shadowColor",label,data,&env->shadowColor))return true;
	if(TestForVector3("spotLightColor",label,data,&env->spotLightColor))return true;
	if(TestForVector3("ambient",label,data,&env->ambient))return true;
	if(TestForVector3("diffuse",label,data,&env->diffuse))return true;
	if(TestForVector3("specular",label,data,&env->specular))return true;
	if(TestForVector3("instrumentColor",label,data,&env->instrumentColor))return true;
	if(TestForVector3("lightDir",label,data,&env->lightDir)){env->lightDir=!env->lightDir;return true;}
	if(TestForVector3("flareDir",label,data,&env->flareDir)){env->flareDir=!env->flareDir;return true;}
	if(TestForVector3("particlesVelo",label,data,&env->particlesVelo))return true;
	if(TestForVector3("flashColor",label,data,&env->flashColor))return true;

	if(TestForVector2("particlesSize",label,data,&env->particlesSize))return true;
	
	if(TestForFloat("shadowIntensity",label,data,&env->shadowIntensity))return true;
	if(TestForFloat("particlesAmount",label,data,&env->particlesAmount))return true;
	if(TestForFloat("particlesVeloSpread",label,data,&env->particlesVeloSpread))return true;
	if(TestForFloat("flashIntensity",label,data,&env->flashIntensity))return true;
	if(TestForFloat("soundRandomProbility",label,data,&env->soundRandomProbility))return true;
	if(TestForFloat("environmentMapIntensity",label,data,&env->environmentMapIntensity))return true;
	if(TestForFloat("dirtIntensity",label,data,&env->dirtIntensity))return true;
	if(TestForFloat("particlesLife",label,data,&env->particlesLife))return true;
	if(TestForFloat("particlesHeight",label,data,&env->particlesHeight))return true;

	if(TestForFloat("gravity",label,data,&env->gravity))return true;
	if(TestForFloat("airDensity",label,data,&env->airDensity))return true;

	if(TestForHex("envFlags",label,data,&env->envFlags))return true;
	if(TestForInt("environmentMapping",label,data,&env->environmentMapping))return true;
	if(TestForInt("shadowEnable",label,data,&env->shadowEnable))return true;
	if(TestForInt("spotLightEnable",label,data,&env->spotLightEnable))return true;
	if(TestForInt("particlesEnable",label,data,&env->particlesEnable))return true;
	if(TestForInt("screenParticlesEnable",label,data,&env->screenParticlesEnable))return true;
	if(TestForInt("soundLoopEnable",label,data,&env->soundLoopEnable))return true;
	if(TestForInt("soundRandomEnable",label,data,&env->soundRandomEnable))return true;
	if(TestForInt("flaresEnable",label,data,&env->flaresEnable))return true;
	if(TestForInt("dirtEnable",label,data,&env->dirtEnable))return true;
	if(TestForInt("hasAltEnv",label,data,&env->hasAltEnv))return true;

	if(TestForString("name",label,data,env->name))return true;

	return false;
}

int ParseConfigDescLine(char *label,char *data,tSysConfig *config,int arrayPos)
{
	if(TestForInt("screenXSize",label,data,&config->screenXSize))return true;
	if(TestForInt("screenYSize",label,data,&config->screenYSize))return true;
	if(TestForInt("windowX",label,data,&config->windowX))return true;
	if(TestForInt("windowY",label,data,&config->windowY))return true;
	if(TestForInt("allCams",label,data,&config->allCams))return true;
	if(TestForInt("useBetaBuilds",label,data,&config->useBetaBuilds))return true;
	if(TestForInt("noGhost",label,data,&config->noGhost))return true;
	if(TestForInt("onlyRegisteredPlayers",label,data,&config->onlyRegisteredPlayers))return true;
	if(TestForInt("cantGoBackwards",label,data,&config->cantGoBackwards))return true;
	if(TestForInt("fullscreen",label,data,&config->fullscreen))return true;
	if(TestForInt("performanceStats",label,data,&config->performanceStats))return true;
	if(TestForInt("stencil",label,data,&config->stencil))return true;
	if(TestForInt("textureQuality",label,data,&config->textureQuality))return true;
	if(TestForInt("textureFilter",label,data,&config->textureFilter))return true;
	if(TestForInt("soundEnable",label,data,&config->soundEnable))return true;
	if(TestForInt("maxCarSources",label,data,&config->maxCarSources))return true;
	if(TestForInt("fsaa",label,data,&config->fsaa))return true;
	if(TestForInt("ffb",label,data,&config->ffb))return true;
	if(TestForInt("arcade",label,data,&config->arcade))return true;
	if(TestForInt("reverse",label,data,&config->reverse))return true;
	if(TestForInt("color32Bit",label,data,&config->color32Bit))return true;
	if(TestForInt("metricUnits",label,data,&config->metricUnits))return true;
	if(TestForInt("interiorDisplay",label,data,&config->interiorDisplay))return true;
	if(TestForInt("cameraMode",label,data,&config->cameraMode))return true;
	if(TestForInt("carsOnSpeed",label,data,&config->carsOnSpeed))return true;
	if(TestForInt("demolition",label,data,&config->demolition))return true;
	if(TestForInt("guideSigns",label,data,&config->guideSigns))return true;
	if(TestForInt("trackerEnable",label,data,&config->trackerEnable))return true;
	if(TestForInt("maxPlayers",label,data,&config->maxPlayers))return true;
	if(TestForInt("registerLapTimes",label,data,&config->registerLapTimes))return true;
	if(TestForInt("showPlayerNames",label,data,&config->showPlayerNames))return true;
	if(TestForInt("motionBlur",label,data,&config->motionBlur))return true;
	if(TestForHex("challengeData",label,data,&config->challengeData))return true;
	if(TestForInt("dbIndex",label,data,&config->dbIndex))return true;
	if(TestForInt("showReplays",label,data,&config->showReplays))return true;
	if(TestForInt("allowHugeGames",label,data,&config->allowHugeGames))return true;
	if(TestForInt("interfaceSounds",label,data,&config->interfaceSounds))return true;
	if(TestForFloat("gfxDynamics",label,data,&config->gfxDynamics))return true;
	if(TestForInt("seperateGasBrake",label,data,&config->seperateGasBrake))return true;
	if(TestForInt("disableAnalogueTCS",label,data,&config->disableAnalogueTCS))return true;
	if(TestForInt("reverseGas",label,data,&config->reverseGas))return true;

	if(TestForFile("lastCar",label,data,&config->lastCar))return true;
	if(TestForFile("lastEnemy",label,data,&config->lastEnemy))return true;
	if(TestForFile("lastRoad",label,data,&config->lastRoad))return true;
	if(TestForInt("numEnemies",label,data,&config->numEnemies))return true;
	if(TestForInt("automatic",label,data,&config->automatic))return true;
	if(TestForInt("lastLaps",label,data,&config->lastLaps))return true;
	if(TestForInt("lastColor",label,data,&config->lastColor))return true;
	if(TestForFile("lastEnv",label,data,&config->lastEnv))return true;

	if(TestForString("playerName",label,data,config->playerName))return true;
	if(TestForString("gameName",label,data,config->gameName))return true;
	if(TestForString("password",label,data,config->password))return true;
	if(TestForString("confirmedVersion",label,data,config->confirmedVersion))return true;

	if(TestForFloat("hudTransparency",label,data,&config->hudTransparency))return true;
	if(TestForFloat("soundVolume",label,data,&config->soundVolume))return true;
	if(TestForFloat("musicVolume",label,data,&config->musicVolume))return true;
//	if(TestForFloat("clipFarDistance",label,data,&config->clipFarDistance))return true;
	if(TestForFloat("ffbIntensity",label,data,&config->ffbIntensity))return true;

	if(TestForInt("numKeys",label,data,&config->numKeys)){
		config->keys=(tKeyConfig*)MemoryAllocateZeroedBlock(kInputNumControls*sizeof(tKeyConfig));
		if(config->numKeys!=kInputNumControls)
		{
			config->numKeys=kInputNumControls;
			config->keys[kInputLeftIndicator].keyID=-1;
			config->keys[kInputRightIndicator].keyID=-1;
		}
		return true;
	}

	if(TestForHex("keyID",label,data,&config->keys[arrayPos].keyID))return true;
	if(TestForHex("controllerID1",label,data,&config->keys[arrayPos].controllerID1))return true;
	if(TestForHex("controllerID2",label,data,&config->keys[arrayPos].controllerID2))return true;
	if(TestForHex("elementID",label,data,&config->keys[arrayPos].elementID))return true;
	if(TestForString("identifier",label,data,config->keys[arrayPos].identifier))return true;
	if(TestForString("controllerIdentifier",label,data,config->keys[arrayPos].controllerIdentifier))return true;

	if(TestForInt("numAxis",label,data,&config->numAxis)){
		config->numAxis=kInputNumAxis;
		config->axis=(tAxisConfig*)MemoryAllocateZeroedBlock(config->numAxis*sizeof(tAxisConfig));
		return true;
	}
	if(TestForHex("axisControllerID1",label,data,&config->axis[arrayPos].axisControllerID1))return true;
	if(TestForHex("axisControllerID2",label,data,&config->axis[arrayPos].axisControllerID2))return true;
	if(TestForHex("axisElementID",label,data,&config->axis[arrayPos].axisElementID))return true;
	if(TestForString("axisIdentifier",label,data,config->axis[arrayPos].axisIdentifier))return true;
	if(TestForInt("min",label,data,&config->axis[arrayPos].min))return true;
	if(TestForInt("mid",label,data,&config->axis[arrayPos].mid))return true;
	if(TestForInt("max",label,data,&config->axis[arrayPos].max))return true;
	if(TestForFloat("deadzone",label,data,&config->axis[arrayPos].deadzone))return true;

	if(TestForInt("numTaunts",label,data,&config->numTaunts)){
		config->taunts=(char(*)[256])MemoryAllocateZeroedBlock(config->numTaunts*sizeof(char)*256);
		return true;
	}
	if(TestForString("taunts",label,data,config->taunts[arrayPos]))return true;
	if(TestForFile("opponentCars",label,data,&config->opponentCars[arrayPos]))return true;
	if(TestForFile("opponentColors",label,data,&config->opponentColors[arrayPos]))return true;

	if(TestForInt("challengeRecords",label,data,&config->challengeRecords[arrayPos]))return true;

	if(TestForInt("numPersonalRecords",label,data,&config->numPersonalRecords))return true;
	if(TestForFile("records.car",label,data,&config->records[arrayPos].car))return true;
	if(TestForFile("records.map",label,data,&config->records[arrayPos].map))return true;
	if(TestForInt("records.mode",label,data,&config->records[arrayPos].mode))return true;
	if(TestForInt("records.direction",label,data,&config->records[arrayPos].direction))return true;
	if(TestForHex("records.time",label,data,&config->records[arrayPos].time))return true;

	return false;
}

int ParseFontInfoDescLine(char *label,char *data,tFontInfo *font,int arrayPos)
{
	if(TestForFile("fontTexture",label,data,&font->fontTexture))return true;
	if(TestForFloat("ascent",label,data,&font->ascent))return true;
	if(TestForInt("startChar",label,data,&font->startChar))return true;
	if(TestForInt("numChars",label,data,&font->numChars)){
		font->chars=(tFontCharInfo*)MemoryAllocateZeroedBlock(font->numChars*sizeof(tFontCharInfo));
		return true;
	}

	if(TestForFloat("x1",label,data,&font->chars[arrayPos].x1))return true;
	if(TestForFloat("x2",label,data,&font->chars[arrayPos].x2))return true;
	if(TestForFloat("y1",label,data,&font->chars[arrayPos].y1))return true;
	if(TestForFloat("y2",label,data,&font->chars[arrayPos].y2))return true;
	return false;
}

int ParseImageURLDescLine(char *label,char *data,tImageURL *url)
{
	if(TestForString("url",label,data,url->url))return true;
	if(TestForFile("offlineImage",label,data,&url->offlineImage))return true;
	return false;
}

int ParseTexturePriorityDescLine(char *label,char *data,tTexturePriorityList *prior,int arrayPos)
{
	if(TestForInt("numPriorities",label,data,&prior->numPriorities)){
		prior->priorities=(tTexturePriority*)MemoryAllocateZeroedBlock(prior->numPriorities*sizeof(tTexturePriority));
		return true;
	}
	if(TestForFile("texture",label,data,&prior->priorities[arrayPos].texture))return true;
	if(TestForInt("priority",label,data,&prior->priorities[arrayPos].priority))return true;
	return false;
}

int ParseSolidEntityDescLine(char *label,char *data,tSolidEntityPhysics *ent,int arrayPos)
{
	if(TestForFile("model",label,data,&ent->model))return true;
	if(TestForFile("shadowModel",label,data,&ent->shadowModel))return true;
	if(TestForFile("particle",label,data,&ent->particle))return true;
	if(TestForFile("sound",label,data,&ent->sound))return true;

	if(TestForFloat("mass",label,data,&ent->mass))return true;
	if(TestForFloat("inertia",label,data,&ent->inertia))return true;

	if(TestForInt("movable",label,data,&ent->movable))return true;
	if(TestForInt("sparks",label,data,&ent->sparks))return true;
	if(TestForInt("liquid",label,data,&ent->liquid))return true;
	if(TestForInt("particleStick",label,data,&ent->particleStick))return true;
	if(TestForInt("followPath",label,data,&ent->followPath))return true;
	if(TestForInt("pathType",label,data,&ent->pathType))return true;
	if(TestForInt("numColors",label,data,&ent->numColors))return true;
	if(TestForInt("randomColor",label,data,&ent->randomColor))return true;
	if(TestForInt("numSounds",label,data,&ent->numSounds))return true;

	if(TestForFloat("pathSize",label,data,&ent->pathSize))return true;
	if(TestForFloat("pathVelo",label,data,&ent->pathVelo))return true;
	if(TestForFloat("particleSize",label,data,&ent->particleSize))return true;
	if(TestForFloat("particleAmount",label,data,&ent->particleAmount))return true;
	if(TestForVector3("massCenter",label,data,&ent->massCenter))return true;

	if(TestForInt("numCollBoxes",label,data,&ent->numCollBoxes)){
		ent->coll=(tCollBox*)MemoryAllocateZeroedBlock(ent->numCollBoxes*sizeof(tCollBox));
		ent->maxCollRadius=0;
		return true;
	}

	if(TestForVector3("coll.tfr",label,data,&ent->coll[arrayPos].tfr))return true;
	if(TestForVector3("coll.tfl",label,data,&ent->coll[arrayPos].tfl))return true;
	if(TestForVector3("coll.trr",label,data,&ent->coll[arrayPos].trr))return true;
	if(TestForVector3("coll.trl",label,data,&ent->coll[arrayPos].trl))return true;
	if(TestForVector3("coll.bfr",label,data,&ent->coll[arrayPos].bfr))return true;
	if(TestForVector3("coll.bfl",label,data,&ent->coll[arrayPos].bfl))return true;
	if(TestForVector3("coll.brr",label,data,&ent->coll[arrayPos].brr))return true;
	if(TestForVector3("coll.brl",label,data,&ent->coll[arrayPos].brl))return true;

	if(TestForInt("numLights",label,data,&ent->numLights)){
		ent->lights=(tLightDefinition*)MemoryAllocateZeroedBlock(ent->numLights*sizeof(tLightDefinition));
		return true;
	}

	if(TestForVector3("lights.pos",label,data,&ent->lights[arrayPos].pos))return true;
	if(TestForVector3("lights.dir",label,data,&ent->lights[arrayPos].dir)){ent->lights[arrayPos].dir=!ent->lights[arrayPos].dir;return true;}
	if(TestForVector3("lights.rgb",label,data,&ent->lights[arrayPos].rgb))return true;
	if(TestForInt("lights.type",label,data,&ent->lights[arrayPos].type))return true;
	if(TestForFloat("lights.size",label,data,&ent->lights[arrayPos].size))return true;
	if(TestForFloat("lights.radius",label,data,&ent->lights[arrayPos].radius))return true;
	if(TestForHex("lights.onFlags",label,data,&ent->lights[arrayPos].onFlags))return true;
	if(TestForHex("lights.offFlags",label,data,&ent->lights[arrayPos].offFlags))return true;

	return false;
}

int ParseMapInfoDescLine(char *label,char *data,tMapInfo *mapInfo,int arrayPos)
{
	if(TestForFile("road",label,data,&mapInfo->road))return true;
	if(TestForFile("image",label,data,&mapInfo->image))return true;
	if(TestForVector3("startPos",label,data,&mapInfo->startPos))return true;
	if(TestForVector3("finishPos",label,data,&mapInfo->finishPos))return true;

	if(TestForInt("builtIn",label,data,&mapInfo->builtIn))return true;
	if(TestForInt("demoAvailable",label,data,&mapInfo->builtIn))return true;
	if(TestForInt("useEnts",label,data,&mapInfo->demoAvailable))return true;
	if(TestForInt("hideMap",label,data,&mapInfo->hideMap))return true;
	if(TestForInt("dontDrawRoad",label,data,&mapInfo->dontDrawRoad))return true;
	if(TestForInt("loop",label,data,&mapInfo->loop))return true;
	if(TestForInt("reverse",label,data,&mapInfo->reverse))return true;
	if(TestForInt("needsToStop",label,data,&mapInfo->needsToStop))return true;
	if(TestForInt("dirtEnable",label,data,&mapInfo->dirtEnable))return true;
	if(TestForInt("maxPlayers",label,data,&mapInfo->maxPlayers))return true;
	if(TestForInt("playerPos",label,data,&mapInfo->playerPos))return true;
	if(TestForInt("hasOverview",label,data,&mapInfo->hasOverview))return true;
	if(TestForInt("baseSurfaceType",label,data,&mapInfo->baseSurfaceType))return true;
	if(TestForInt("useAltEnv",label,data,&mapInfo->useAltEnv))return true;

	if(TestForVector2("overviewTopLeft",label,data,&mapInfo->overviewTopLeft))return true;
	if(TestForVector2("overviewBotRight",label,data,&mapInfo->overviewBotRight))return true;

	if(TestForFloat("startLineOffset",label,data,&mapInfo->startLineOffset))return true;
	if(TestForFloat("startCenterOffset",label,data,&mapInfo->startCenterOffset))return true;
	if(TestForFloat("carOffset",label,data,&mapInfo->carOffset))return true;
	
	if(TestForFloat("speedFactor",label,data,&mapInfo->speedFactor))return true;
	if(TestForFloat("dirtIntensity",label,data,&mapInfo->dirtIntensity))return true;

	if(TestForFile("roadTypes",label,data,&mapInfo->roadTypes))return true;
	if(TestForFile("dirtMap",label,data,&mapInfo->dirtMap))return true;
	if(TestForFile("overview",label,data,&mapInfo->overview))return true;

	if(TestForString("name",label,data,mapInfo->name))return true;

	if(TestForInt("numObjs",label,data,&mapInfo->numObjs)){
		mapInfo->obj=(tMapObjectDef*)MemoryAllocateZeroedBlock(mapInfo->numObjs*sizeof(tMapObjectDef));
		return true;
	}

	if(TestForInt("numVisWalls",label,data,&mapInfo->numVisWalls)){
		mapInfo->visWalls=(tVisWall*)MemoryAllocateZeroedBlock(mapInfo->numVisWalls*sizeof(tVisWall));
		return true;
	}

	if(TestForInt("numMapEnvs",label,data,&mapInfo->numMapEnvs)){
		mapInfo->mapEnv=(tMapEnv*)MemoryAllocateZeroedBlock(mapInfo->numMapEnvs*sizeof(tMapEnv));
		return true;
	}

	if(TestForVector3("a",label,data,&mapInfo->visWalls[arrayPos].a))return true;
	if(TestForVector3("b",label,data,&mapInfo->visWalls[arrayPos].b))return true;
	if(TestForVector3("c",label,data,&mapInfo->visWalls[arrayPos].c))return true;
	
	if(TestForFile("obj.model",label,data,&mapInfo->obj[arrayPos].model))return true;
	if(TestForVector3("obj.pos",label,data,&mapInfo->obj[arrayPos].pos))return true;
	if(TestForVector3("obj.dir",label,data,&mapInfo->obj[arrayPos].dir))return true;
	if(TestForInt("obj.color",label,data,&mapInfo->obj[arrayPos].color))return true;
	if(TestForInt("obj.untouchable",label,data,&mapInfo->obj[arrayPos].untouchable))return true;
	if(TestForHex("obj.envFlags",label,data,&mapInfo->obj[arrayPos].envFlags))return true;

	if(TestForHex("mapEnv.envFlags",label,data,&mapInfo->mapEnv[arrayPos].envFlags))return true;
	if(TestForInt("mapEnv.lightEnable",label,data,&mapInfo->mapEnv[arrayPos].lightEnable))return true;
	if(TestForFloat("mapEnv.fogBegin",label,data,&mapInfo->mapEnv[arrayPos].fogBegin))return true;
	if(TestForFloat("mapEnv.fogEnd",label,data,&mapInfo->mapEnv[arrayPos].fogEnd))return true;
	if(TestForFloat("mapEnv.fogOscillation",label,data,&mapInfo->mapEnv[arrayPos].fogOscillation))return true;
	if(TestForFloat("mapEnv.fogOscillationSpeed",label,data,&mapInfo->mapEnv[arrayPos].fogOscillationSpeed))return true;
	if(TestForVector3("mapEnv.fogColor",label,data,&mapInfo->mapEnv[arrayPos].fogColor))return true;
	if(TestForFile("mapEnv.sky0",label,data,&mapInfo->mapEnv[arrayPos].sky0))return true;
	if(TestForFile("mapEnv.sky90",label,data,&mapInfo->mapEnv[arrayPos].sky90))return true;
	if(TestForFile("mapEnv.sky180",label,data,&mapInfo->mapEnv[arrayPos].sky180))return true;
	if(TestForFile("mapEnv.sky270",label,data,&mapInfo->mapEnv[arrayPos].sky270))return true;
	if(TestForFile("mapEnv.skytop",label,data,&mapInfo->mapEnv[arrayPos].skytop))return true;
	if(TestForFile("mapEnv.skybot",label,data,&mapInfo->mapEnv[arrayPos].skybot))return true;
	if(TestForFile("mapEnv.spheremap",label,data,&mapInfo->mapEnv[arrayPos].spheremap))return true;
	if(TestForFile("mapEnv.lightMap",label,data,&mapInfo->mapEnv[arrayPos].lightMap))return true;
	if(TestForVector2("mapEnv.lightMapTopLeft",label,data,&mapInfo->mapEnv[arrayPos].lightMapTopLeft))return true;
	if(TestForVector2("mapEnv.lightMapBotRight",label,data,&mapInfo->mapEnv[arrayPos].lightMapBotRight))return true;
	if(TestForVector2("mapEnv.lightMapSpeed",label,data,&mapInfo->mapEnv[arrayPos].lightMapSpeed))return true;
	if(TestForFile("mapEnv.lightMap2",label,data,&mapInfo->mapEnv[arrayPos].lightMap2))return true;
	if(TestForVector2("mapEnv.lightMap2TopLeft",label,data,&mapInfo->mapEnv[arrayPos].lightMap2TopLeft))return true;
	if(TestForVector2("mapEnv.lightMap2BotRight",label,data,&mapInfo->mapEnv[arrayPos].lightMap2BotRight))return true;
	if(TestForVector2("mapEnv.lightMap2Speed",label,data,&mapInfo->mapEnv[arrayPos].lightMap2Speed))return true;
	if(TestForVector3("mapEnv.lightDir",label,data,&mapInfo->mapEnv[arrayPos].lightDir)){mapInfo->mapEnv[arrayPos].lightDir=!mapInfo->mapEnv[arrayPos].lightDir;return true;}
	if(TestForVector3("mapEnv.flareDir",label,data,&mapInfo->mapEnv[arrayPos].flareDir)){mapInfo->mapEnv[arrayPos].flareDir=!mapInfo->mapEnv[arrayPos].flareDir;return true;}
	
	return false;
}

int ParseGaugesListDescLine(char *label,char *data,tGaugesList *gauges,int arrayPos)
{
	if(TestForInt("numGauges",label,data,&gauges->numGauges)){
		gauges->gauges=(tGauge*)MemoryAllocateZeroedBlock(gauges->numGauges*sizeof(tGauge));
		return true;
	}

	if(TestForFile("gaugeTexture",label,data,&gauges->gauges[arrayPos].gaugeTexture))return true;
	if(TestForFile("pointerTexture",label,data,&gauges->gauges[arrayPos].pointerTexture))return true;
	if(TestForFloat("pointerWidth",label,data,&gauges->gauges[arrayPos].pointerWidth))return true;
	if(TestForFloat("gaugeZero",label,data,&gauges->gauges[arrayPos].gaugeZero))return true;
	if(TestForFloat("gaugeMax",label,data,&gauges->gauges[arrayPos].gaugeMax))return true;
	if(TestForInt("type",label,data,&gauges->gauges[arrayPos].type))return true;

	return false;
}

int ParseChallengeListDescLine(char *label,char *data,tChallengeList *challenges,int arrayPos)
{
	if(TestForInt("numChallenges",label,data,&challenges->numChallenges)){
		challenges->challenges=(tChallenge*)MemoryAllocateZeroedBlock(challenges->numChallenges*sizeof(tChallenge));
		return true;
	}

	if(TestForFile("map",label,data,&challenges->challenges[arrayPos].map))return true;
	if(TestForFile("car",label,data,&challenges->challenges[arrayPos].car))return true;
	if(TestForFile("environment",label,data,&challenges->challenges[arrayPos].environment))return true;
	if(TestForFile("replay",label,data,&challenges->challenges[arrayPos].replay))return true;
	if(TestForInt("color",label,data,&challenges->challenges[arrayPos].color))return true;
	if(TestForInt("reverse",label,data,&challenges->challenges[arrayPos].reverse))return true;
	if(TestForFloat("goldTime",label,data,&challenges->challenges[arrayPos].goldTime))return true;
	if(TestForFloat("silverTime",label,data,&challenges->challenges[arrayPos].silverTime))return true;
	if(TestForFloat("bronzeTime",label,data,&challenges->challenges[arrayPos].bronzeTime))return true;
	if(TestForHex("requirements",label,data,&challenges->challenges[arrayPos].requirements))return true;
	if(TestForString("name",label,data,challenges->challenges[arrayPos].name))return true;
	if(TestForString("description",label,data,challenges->challenges[arrayPos].description))return true;

	return false;
}

int ParseCarDescLine(char *label,char *data,tCarDefinition *car,int arrayPos,int arrayPos2)
{
	if(TestForFloat("frontAirResistance",label,data,&car->frontAirResistance))return true;
	if(TestForFloat("sideAirResistance",label,data,&car->sideAirResistance))return true;
	if(TestForFloat("topAirResistance",label,data,&car->topAirResistance))return true;
	if(TestForFloat("frontLift",label,data,&car->frontLift))return true;
	if(TestForFloat("rearLift",label,data,&car->rearLift))return true;

	if(TestForFloat("mass",label,data,&car->mass))return true;
	if(TestForFloat("power",label,data,&car->power))return true;
	if(TestForFloat("torque",label,data,&car->torque))return true;
	if(TestForFloat("powerRPM",label,data,&car->powerRPM))return true;
	if(TestForFloat("torqueRPM",label,data,&car->torqueRPM))return true;
	if(TestForFloat("idleRPM",label,data,&car->idleRPM))return true;
	if(TestForFloat("jerkRPM",label,data,&car->jerkRPM))return true;
	
	if(TestForFloat("clutchRPM",label,data,&car->clutchRPM))return true;
	if(TestForFloat("maxRPM",label,data,&car->maxRPM))return true;
	if(TestForFloat("shiftUpRPM",label,data,&car->shiftUpRPM))return true;
	if(TestForFloat("shiftUpRPMFix",label,data,&car->shiftUpRPMFix))return true;
	if(TestForFloat("shiftDownRPM",label,data,&car->shiftDownRPM))return true;
	if(TestForFloat("engineInertia",label,data,&car->engineInertia))return true;
	if(TestForFloat("engineFriction",label,data,&car->engineFriction))return true;
	if(TestForFloat("engineBaseFriction",label,data,&car->engineBaseFriction))return true;
	if(TestForFloat("engineRPMFriction",label,data,&car->engineRPMFriction))return true;
	if(TestForFloat("finalDriveRatio",label,data,&car->finalDriveRatio))return true;
	if(TestForFloat("differentialLockCoefficient",label,data,&car->differentialLockCoefficient))return true;
	if(TestForFloat("maxClutchTorqueTransfer",label,data,&car->maxClutchTorqueTransfer))return true;
	if(TestForFloat("aiSpeedIndex",label,data,&car->aiSpeedIndex))return true;

	if(TestForFloat("zeroRPMSoundGain",label,data,&car->zeroRPMSoundGain))return true;
	if(TestForFloat("fullRPMSoundGain",label,data,&car->fullRPMSoundGain))return true;
	if(TestForFloat("zeroThrottleSoundGain",label,data,&car->zeroThrottleSoundGain))return true;
	if(TestForFloat("fullThrottleSoundGain",label,data,&car->fullThrottleSoundGain))return true;

	if(TestForFloat("zeroRPMSoundPitch",label,data,&car->zeroRPMSoundPitch))return true;
	if(TestForFloat("fullRPMSoundPitch",label,data,&car->fullRPMSoundPitch))return true;
	if(TestForFloat("zeroThrottleSoundPitch",label,data,&car->zeroThrottleSoundPitch))return true;
	if(TestForFloat("fullThrottleSoundPitch",label,data,&car->fullThrottleSoundPitch))return true;

	if(TestForFloat("turboGain",label,data,&car->turboGain))return true;

	if(TestForVector3("steeringWheelPos",label,data,&car->steeringWheelPos))return true;
	if(TestForVector3("driverPos",label,data,&car->driverPos))return true;
	if(TestForFloat("steeringWheelAngle",label,data,&car->steeringWheelAngle))return true;
	if(TestForFloat("steeringWheelTurns",label,data,&car->steeringWheelTurns))return true;
	if(TestForFloat("steeringWheelRadius",label,data,&car->steeringWheelRadius))return true;
	if(TestForFile("steeringWheelTexture",label,data,&car->steeringWheelTexture))return true;
	if(TestForInt("noDriverModel",label,data,&car->noDriverModel))return true;

	if(TestForVector3("exhaust1Pos",label,data,&car->exhaust1Pos))return true;
	if(TestForVector3("exhaust2Pos",label,data,&car->exhaust2Pos))return true;
	if(TestForFloat("exhaustFire",label,data,&car->exhaustFire))return true;

	if(TestForVector3("frontLicensePlatePos",label,data,&car->frontLicensePlatePos))return true;
	if(TestForVector3("rearLicensePlatePos",label,data,&car->rearLicensePlatePos))return true;

	if(TestForFloat("gearSwitchTime",label,data,&car->gearSwitchTime))return true;

	if(TestForFloat("supsensionFriction",label,data,&car->supsensionFriction))return true;
	if(TestForFloat("damperStrength",label,data,&car->damperStrength))return true;
	
	if(TestForFloat("frontSwayBar",label,data,&car->frontSwayBar))return true;
	if(TestForFloat("rearSwayBar",label,data,&car->rearSwayBar))return true;

	if(TestForInt("suspensionType",label,data,&car->demoAvailable))return true;
	if(TestForInt("builtIn",label,data,&car->builtIn))return true;
	if(TestForInt("demoAvailable",label,data,&car->builtIn))return true;
	if(TestForInt("magic",label,data,&car->magic))return true;
	if(TestForInt("secret",label,data,&car->secret))return true;
	if(TestForHex("initialAddOns",label,data,&car->initialAddOns))return true;
	if(TestForHex("challengeRequirements",label,data,&car->challengeRequirements))return true;

	if(TestForInt("numColors",label,data,&car->numColors)){
		car->colors=(tVector3*)MemoryAllocateZeroedBlock((car->numColors)*sizeof(tVector3));
		car->colorLoaded=(int*)MemoryAllocateZeroedBlock((car->numColors)*sizeof(int));
		return true;
	}
	if(TestForInt("numGears",label,data,&car->numGears)){
		car->gearRatios=(float*)MemoryAllocateZeroedBlock((car->numGears)*sizeof(float));
		return true;
	}
	if(TestForInt("numWheels",label,data,&car->numWheels)){
		car->wheels=(tWheelDefinition*)MemoryAllocateZeroedBlock(car->numWheels*sizeof(tWheelDefinition));
		return true;
	}
	if(TestForInt("numLights",label,data,&car->numLights)){
		car->lights=(tLightDefinition*)MemoryAllocateZeroedBlock(car->numLights*sizeof(tLightDefinition));
		return true;
	}
	if(TestForInt("numAddOns",label,data,&car->numAddOns)){
		car->addOns=(tAddOnDefinition*)MemoryAllocateZeroedBlock((car->numAddOns)*sizeof(tAddOnDefinition));
		return true;
	}
	if(TestForInt("numCollBoxes",label,data,&car->numCollBoxes)){
		car->coll=(tCollBox*)MemoryAllocateZeroedBlock(car->numCollBoxes*sizeof(tCollBox));
		car->maxCollRadius=0;
		return true;
	}

	if(TestForVector3("colors",label,data,&car->colors[arrayPos]))return true;

	if(TestForString("carName",label,data,car->carName))return true;
	if(TestForFloat("displacement",label,data,&car->displacement))return true;
	if(TestForInt("year",label,data,&car->year))return true;
	if(TestForInt("price",label,data,&car->price))return true;

	if(TestForVector3("coll.tfr",label,data,&car->coll[arrayPos].tfr))return true;
	if(TestForVector3("coll.tfl",label,data,&car->coll[arrayPos].tfl))return true;
	if(TestForVector3("coll.trr",label,data,&car->coll[arrayPos].trr))return true;
	if(TestForVector3("coll.trl",label,data,&car->coll[arrayPos].trl))return true;
	if(TestForVector3("coll.bfr",label,data,&car->coll[arrayPos].bfr))return true;
	if(TestForVector3("coll.bfl",label,data,&car->coll[arrayPos].bfl))return true;
	if(TestForVector3("coll.brr",label,data,&car->coll[arrayPos].brr))return true;
	if(TestForVector3("coll.brl",label,data,&car->coll[arrayPos].brl))return true;

	
	if(TestForVector3("massCenter",label,data,&car->massCenter))return true;
	if(TestForVector3("inertia",label,data,&car->inertia))return true;
	if(TestForFile("model",label,data,&car->model))return true;
	if(TestForFile("shadowModel",label,data,&car->shadowModel))return true;
	if(TestForFile("interiorModel",label,data,&car->interiorModel))return true;
	if(TestForFile("engineSample",label,data,&car->engineSample))return true;
	if(TestForFile("hallSample",label,data,&car->hallSample))return true;
	if(TestForFile("turboSample",label,data,&car->turboSample))return true;
	if(TestForFile("hornSample",label,data,&car->hornSample))return true;
	if(TestForFloat("hornPitch",label,data,&car->hornPitch))return true;

	if(TestForFloat("gearRatios",label,data,&car->gearRatios[arrayPos]))return true;

	if(TestForVector3("wheels.pos",label,data,&car->wheels[arrayPos].pos))return true;
	if(TestForFloat("wheels.powered",label,data,&car->wheels[arrayPos].powered))return true;
	if(TestForFloat("wheels.inertia",label,data,&car->wheels[arrayPos].inertia))return true;
	if(TestForFloat("wheels.friction",label,data,&car->wheels[arrayPos].friction))return true;
	if(TestForFloat("wheels.maxAngle",label,data,&car->wheels[arrayPos].maxAngle))return true;
	if(TestForFloat("wheels.maxSuspension",label,data,&car->wheels[arrayPos].maxSuspension))return true;
	if(TestForFloat("wheels.radius",label,data,&car->wheels[arrayPos].radius))return true;
	if(TestForFloat("wheels.width",label,data,&car->wheels[arrayPos].width))return true;
	if(TestForFloat("wheels.rollCenter",label,data,&car->wheels[arrayPos].rollCenter))return true;
	if(TestForFloat("wheels.grip",label,data,&car->wheels[arrayPos].grip))return true;
	if(TestForFloat("wheels.braked",label,data,&car->wheels[arrayPos].braked))return true;
	if(TestForFloat("wheels.handbraked",label,data,&car->wheels[arrayPos].handbraked))return true;
	if(TestForFloat("wheels.tolerance",label,data,&car->wheels[arrayPos].tolerance))return true;
	if(TestForFloat("wheels.tilt",label,data,&car->wheels[arrayPos].tilt))return true;
	if(TestForFloat("wheels.loadSensitivity",label,data,&car->wheels[arrayPos].loadSensitivity))return true;
	if(TestForFloat("wheels.stickyness",label,data,&car->wheels[arrayPos].stickyness))return true;
	if(TestForInt("wheels.texture",label,data,&car->wheels[arrayPos].texture))return true;
	if(TestForInt("wheels.noShadow",label,data,&car->wheels[arrayPos].noShadow))return true;
	if(TestForFile("wheels.model",label,data,&car->wheels[arrayPos].model))return true;
	if(TestForFile("wheels.customBrakeModel",label,data,&car->wheels[arrayPos].customBrakeModel))return true;

	if(TestForVector3("lights.pos",label,data,&car->lights[arrayPos].pos))return true;
	if(TestForVector3("lights.dir",label,data,&car->lights[arrayPos].dir)){car->lights[arrayPos].dir=!car->lights[arrayPos].dir;return true;}
	if(TestForVector3("lights.rgb",label,data,&car->lights[arrayPos].rgb))return true;
	if(TestForInt("lights.type",label,data,&car->lights[arrayPos].type))return true;
	if(TestForFloat("lights.size",label,data,&car->lights[arrayPos].size))return true;
	if(TestForFloat("lights.radius",label,data,&car->lights[arrayPos].radius))return true;
	if(TestForHex("lights.onFlags",label,data,&car->lights[arrayPos].onFlags))return true;
	if(TestForHex("lights.offFlags",label,data,&car->lights[arrayPos].offFlags))return true;

	if(TestForHex("addOns.requirements",label,data,&car->addOns[arrayPos].requirements))return true;
	if(TestForHex("addOns.conflicts",label,data,&car->addOns[arrayPos].conflicts))return true;
	if(TestForFloat("addOns.mass",label,data,&car->addOns[arrayPos].mass))return true;
	if(TestForFloat("addOns.frontLift",label,data,&car->addOns[arrayPos].frontLift))return true;
	if(TestForFloat("addOns.rearLift",label,data,&car->addOns[arrayPos].rearLift))return true;
	if(TestForFloat("addOns.frontSwayBar",label,data,&car->addOns[arrayPos].frontSwayBar))return true;
	if(TestForFloat("addOns.rearSwayBar",label,data,&car->addOns[arrayPos].rearSwayBar))return true;
	if(TestForFloat("addOns.track",label,data,&car->addOns[arrayPos].track))return true;
	if(TestForFloat("addOns.engineInertia",label,data,&car->addOns[arrayPos].engineInertia))return true;
	if(TestForFloat("addOns.topGearRatio",label,data,&car->addOns[arrayPos].topGearRatio))return true;
	if(TestForFloat("addOns.damperStrength",label,data,&car->addOns[arrayPos].damperStrength))return true;
	if(TestForFloat("addOns.exhaustFire",label,data,&car->addOns[arrayPos].exhaustFire))return true;
	if(TestForFloat("addOns.frontMaxSuspension",label,data,&car->addOns[arrayPos].frontMaxSuspension))return true;
	if(TestForFloat("addOns.rearMaxSuspension",label,data,&car->addOns[arrayPos].rearMaxSuspension))return true;
	if(TestForFloat("addOns.frontWheelWidth",label,data,&car->addOns[arrayPos].frontWheelWidth))return true;
	if(TestForFloat("addOns.rearWheelWidth",label,data,&car->addOns[arrayPos].rearWheelWidth))return true;
	if(TestForFloat("addOns.frontAirResistance",label,data,&car->addOns[arrayPos].frontAirResistance))return true;
	if(TestForFloat("addOns.differentialLockCoefficient",label,data,&car->addOns[arrayPos].differentialLockCoefficient))return true;
	if(TestForFloat("addOns.finalDriveRatio",label,data,&car->addOns[arrayPos].finalDriveRatio))return true;
	if(TestForFloat("addOns.gearSwitchTime",label,data,&car->addOns[arrayPos].gearSwitchTime))return true;
	if(TestForFloat("addOns.powerPercent",label,data,&car->addOns[arrayPos].powerPercent))return true;
	if(TestForFloat("addOns.torquePercent",label,data,&car->addOns[arrayPos].torquePercent))return true;
	if(TestForFloat("addOns.maxRPM",label,data,&car->addOns[arrayPos].maxRPM))return true;
	if(TestForVector3("addOns.massCenter",label,data,&car->addOns[arrayPos].massCenter))return true;
	if(TestForInt("addOns.hasGraphic",label,data,&car->addOns[arrayPos].hasGraphic))return true;
	if(TestForInt("addOns.price",label,data,&car->addOns[arrayPos].price))return true;
	if(TestForInt("addOns.group",label,data,&car->addOns[arrayPos].group))return true;
	if(TestForFile("addOns.model",label,data,&car->addOns[arrayPos].model))return true;
	if(TestForString("addOns.name",label,data,car->addOns[arrayPos].name))return true;
	if(TestForString("addOns.describtion",label,data,car->addOns[arrayPos].describtion))return true;

	return false;
}


//Stores the next line of the character buffer at *filePos in the string buffer
//at line, and then updates *filePos to point to the start of the next line.
//
//*fileEnd: a pointer to the end of the characted buffer at *filePos.
//buffersize: the size of the string buffer at line.
void GetLine(char *line,char **filePos,char *fileEnd,int buffersize)
{
	char *lineSeek=*filePos;
	while(*lineSeek!='\n'&&*lineSeek!='\r'&&lineSeek<fileEnd&&lineSeek<*filePos+buffersize-1)
		lineSeek++;
	memcpy(line,*filePos,lineSeek-*filePos);
	line[lineSeek-*filePos]='\0';
	*filePos=lineSeek;
	while(**filePos!='\n'&&**filePos!='\r'&&*filePos<fileEnd)(*filePos)++;
	(*filePos)++;
}

#define kCryptKey 0x42

void CryptData(char *data,int size)
{
	for(int i=0;i<size;i++)
		data[i]^=kCryptKey;
}

int ParseFile(tFileRef fileId, void *dataBuffer,int fileType)
{
	char *fileData=(char*)FileGetDataPtr(fileId);
	char *filePos=fileData;
	
	if(fileType==kParserTypeCareerDataDesc)
		CryptData(fileData,FileGetSize(fileId));
		
	int fileLenght=FileGetSize(fileId);
	int arrayPos=0;
	int arrayPos2=0;
	while(filePos<fileData+fileLenght)
	{
		char line[512];
		GetLine(line,&filePos,fileData+fileLenght,512);
		
		char *label=line;
		while(*label==' '||*label=='\t')
			label++;

		char *data=label;
		while(*data!=' '&&*data!='\0'&&*data!='\t')data++;
		if(*data!='\0')
		{
			*data='\0';
			data++;
		}
		else 
			data=NULL;

		if(data)
			if(label[0]!=';')
				if(label[0]=='#')
					if(label[1]=='#')
						sscanf(data,"%d",&arrayPos2);
					else
						sscanf(data,"%d",&arrayPos);
				else 
					switch(fileType)
					{
						case kParserTypeCarDesc:
							ParseCarDescLine(label,data,(tCarDefinition*)dataBuffer,arrayPos,arrayPos2);
							break;
						case kParserTypeRoadTypeDesc:
							ParseRoadTypeDescLine(label,data,(tRoadTypeList*)dataBuffer,arrayPos,arrayPos2);
							break;
						case kParserTypeConfigDesc:
							ParseConfigDescLine(label,data,(tSysConfig*)dataBuffer,arrayPos);
							break;
						case kParserTypeEnvironmentDesc:
							ParseEnvironmentDescLine(label,data,(tEnvironment*)dataBuffer);
							break;
						case kParserTypeMapInfoDesc:
							ParseMapInfoDescLine(label,data,(tMapInfo*)dataBuffer,arrayPos);
							break;
						case kParserTypeSurfaceTypeDesc:
							ParseSurfaceTypeDescLine(label,data,(tSurfaceTypeList*)dataBuffer,arrayPos);
							break;
						case kParserTypeFontInfoDesc:
							ParseFontInfoDescLine(label,data,(tFontInfo*)dataBuffer,arrayPos);
							break;
						case kParserTypeSolidEntityDesc:
							ParseSolidEntityDescLine(label,data,(tSolidEntityPhysics*)dataBuffer,arrayPos);
							break;
						case kParserTypeGaugesListDesc:
							ParseGaugesListDescLine(label,data,(tGaugesList*)dataBuffer,arrayPos);
							break;
						case kParserTypeChallengeList:
							ParseChallengeListDescLine(label,data,(tChallengeList*)dataBuffer,arrayPos);
							break;
						case kParserTypeTexturePriorityList:
							ParseTexturePriorityDescLine(label,data,(tTexturePriorityList*)dataBuffer,arrayPos);
							break;
						case kParserTypeImageURL:
							ParseImageURLDescLine(label,data,(tImageURL*)dataBuffer);
							break;
					}
	}
	if(fileType==kParserTypeMapInfoDesc)
		if(fileId!=FileGetReference("accelbrake.mapinfo"))
		if(fileId!=FileGetReference("accelbrake2.mapinfo"))
		if(fileId!=FileGetReference("slalom.mapinfo"))
		if(fileId!=FileGetReference("city2.mapinfo"))
		if(fileId!=FileGetReference("highspeed.mapinfo"))
			((tMapInfo*)dataBuffer)->demoAvailable=false;
	if(fileType==kParserTypeCarDesc)
		if(fileId!=FileGetReference("corvette.car"))
		if(fileId!=FileGetReference("dmc12.car"))
		if(fileId!=FileGetReference("gti.car"))
		if(fileId!=FileGetReference("mini.car"))
			((tCarDefinition*)dataBuffer)->demoAvailable=false;
	
}