shithub: duke3d

Download patch

ref: 2f596a36010a5d6c4d7a2ece6d314b9bbaf6dc9d
parent: a398442d41ed928c12632909a02fd5f3052b7d27
author: Fabien Sanglard <[email protected]>
date: Wed Dec 19 13:55:18 EST 2012

Created filesystem module.

--- a/Engine/src/cache.c
+++ b/Engine/src/cache.c
@@ -223,639 +223,3 @@
 	Error(EXIT_FAILURE, "");
 }
 
-
-uint8_t  toupperlookup[256] =
-{
-	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
-	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
-	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
-	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
-	0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
-	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
-	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
-	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
-	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
-	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
-	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
-	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
-	0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
-	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
-};
-
-int32_t numgroupfiles = 0;			// number of GRP files actually used.
-int32_t gnumfiles[MAXGROUPFILES];	// number of files on grp
-int32_t groupfil[MAXGROUPFILES] = {-1,-1,-1,-1}; // grp file handles
-int32_t groupfilpos[MAXGROUPFILES];
-uint8_t  *gfilelist[MAXGROUPFILES];	// name list + size list of all the files in grp
-int32_t *gfileoffs[MAXGROUPFILES];	// offset of the files
-uint8_t  *groupfil_memory[MAXGROUPFILES]; // addresses of raw GRP files in memory
-int32_t groupefil_crc32[MAXGROUPFILES];
-
-uint8_t  filegrp[MAXOPENFILES];
-int32_t filepos[MAXOPENFILES];
-int32_t filehan[MAXOPENFILES] =
-{
-	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-};
-
-
-
-int32_t initgroupfile(const char  *filename)
-{
-	uint8_t  buf[16];
-	int32_t i, j, k;
-
-	printf("Loading %s ...\n", filename);
-
-	if (numgroupfiles >= MAXGROUPFILES) return(-1);
-
-	groupfil_memory[numgroupfiles] = NULL; // addresses of raw GRP files in memory
-	groupefil_crc32[numgroupfiles] = 0;
-
-	groupfil[numgroupfiles] = open(filename,O_BINARY|O_RDWR,S_IREAD);
-	if (groupfil[numgroupfiles] >= 0)
-	{
-		groupfilpos[numgroupfiles] = 0;
-		read(groupfil[numgroupfiles],buf,16);
-		if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') ||
-			 (buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') ||
-			 (buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') ||
-			 (buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n'))
-		{
-			close(groupfil[numgroupfiles]);
-			groupfil[numgroupfiles] = -1;
-			return(-1);
-		}
-
-		//FCS: The ".grp" file format is just a collection of a lot of files stored into 1 big one. 
-		//I tried to make the format as simple as possible: The first 12 bytes contains my name, 
-		//"KenSilverman". The next 4 bytes is the number of files that were compacted into the 
-		//group file. Then for each file, there is a 16 byte structure, where the first 12 
-		//bytes are the filename, and the last 4 bytes are the file's size. The rest of the 
-		//group file is just the raw data packed one after the other in the same order as the list 
-		//of files. - ken
-
-		gnumfiles[numgroupfiles] = BUILDSWAP_INTEL32(*((int32_t *)&buf[12]));
-
-		if ((gfilelist[numgroupfiles] = (uint8_t  *)kmalloc(gnumfiles[numgroupfiles]<<4)) == 0)
-			{ Error(EXIT_FAILURE, "Not enough memory for file grouping system\n"); }
-		if ((gfileoffs[numgroupfiles] = (int32_t *)kmalloc((gnumfiles[numgroupfiles]+1)<<2)) == 0)
-			{ Error(EXIT_FAILURE, "Not enough memory for file grouping system\n"); }
-
-		// load index (name+size)
-		read(groupfil[numgroupfiles],gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4);
-
-		j = 0;
-		for(i=0;i<gnumfiles[numgroupfiles];i++)
-		{
-			k = BUILDSWAP_INTEL32(*((int32_t *)&gfilelist[numgroupfiles][(i<<4)+12])); // get size
-			gfilelist[numgroupfiles][(i<<4)+12] = 0;
-			gfileoffs[numgroupfiles][i] = j; // absolute offset list of all files. 0 for 1st file
-			j += k;
-		}
-		gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j;
-	}
-    else
-    {
-        printf("Unable to find GRP file %s.\n",filename);
-		//Let user see the message
-		getchar();
-        exit(0);
-    }
-
-	// Compute CRC32 of thw whole grp and implicitely caches the GRP in memory through windows
-	lseek(groupfil[numgroupfiles], 0, SEEK_SET);
-
-	i = 1000000; // FIX_00086: grp loaded by smaller sucessive chunks to avoid overloading low ram computers
-	groupfil_memory[numgroupfiles] = malloc(i);
-	while((j=read(groupfil[numgroupfiles], groupfil_memory[numgroupfiles], i)))
-	{
-		groupefil_crc32[numgroupfiles] = crc32_update((uint8_t *)groupfil_memory[numgroupfiles], j, groupefil_crc32[numgroupfiles]);
-	}
-
-	free(groupfil_memory[numgroupfiles]);  
-	groupfil_memory[numgroupfiles] = 0;
-
-	numgroupfiles++;
-	return(groupfil[numgroupfiles-1]);
-
-}
-
-void uninitgroupfile(void)
-{
-	int32_t i;
-
-	for(i=numgroupfiles-1;i>=0;i--)
-		if (groupfil[i] != -1)
-		{
-			kfree(gfilelist[i]);
-			kfree(gfileoffs[i]);
-			close(groupfil[i]);
-			groupfil[i] = -1;
-		}
-
-}
-
-void crc32_table_gen(unsigned int* crc32_table) /* build CRC32 table */
-{
-    unsigned int crc, poly;
-    int	i, j;
-
-    poly = 0xEDB88320L;
-    for (i = 0; i < 256; i++)
-    {
-		crc = i;
-		for (j = 8; j > 0; j--)
-		{
-			if (crc & 1)
-				crc = (crc >> 1) ^ poly;
-			else
-				crc >>= 1;
-		}
-		crc32_table[i] = crc;
-    }
-}
-
-unsigned int crc32(uint8_t  *buf, unsigned int length)
-{
-	unsigned int initial_crc;
-
-	initial_crc = 0;
-	return(crc32_update(buf, length, initial_crc));
-}
-
-unsigned int crc32_update(uint8_t  *buf, unsigned int length, unsigned int crc_to_update)
-{
-	unsigned int crc32_table[256];
-
-	crc32_table_gen(crc32_table);
-
-	crc_to_update ^= 0xFFFFFFFF;
-
-	while (length--)
-		crc_to_update = crc32_table[(crc_to_update ^ *buf++) & 0xFF] ^ (crc_to_update >> 8);
-	
-	return crc_to_update ^ 0xFFFFFFFF;
-}
-
-
-/*
- *                                      16   12   5
- * this is the CCITT CRC 16 polynomial X  + X  + X  + 1.
- * This is 0x1021 when x is 2, but the way the algorithm works
- * we use 0x8408 (the reverse of the bit pattern).  The high
- * bit is always assumed to be set, thus we only use 16 bits to
- * represent the 17 bit value.
-*/
-
-#define POLY 0x8408   /* 1021H bit reversed */
-
-uint16_t crc16(uint8_t  *data_p, uint16_t length)
-{
-      uint8_t  i;
-      unsigned int data;
-      unsigned int crc = 0xffff;
-
-      if (length == 0)
-            return (~crc);
-      do
-      {
-            for (i=0, data=(unsigned int)0xff & *data_p++;
-                 i < 8; 
-                 i++, data >>= 1)
-            {
-                  if ((crc & 0x0001) ^ (data & 0x0001))
-                        crc = (crc >> 1) ^ POLY;
-                  else  crc >>= 1;
-            }
-      } while (--length);
-
-      crc = ~crc;
-      data = crc;
-      crc = (crc << 8) | (data >> 8 & 0xff);
-
-      return (crc);
-}
-
-int32_t kopen4load(const char  *filename, int readfromGRP)
-{ // FIX_00072: all files are now 1st searched in Duke's root folder and then in the GRP.
-	int32_t i, j, k, fil, newhandle;
-	uint8_t  bad;
-	uint8_t  *gfileptr;
-
-	newhandle = MAXOPENFILES-1;
-	while (filehan[newhandle] != -1)
-	{
-		newhandle--;
-		if (newhandle < 0)
-		{
-			Error(EXIT_FAILURE, "Too Many files open!\n");
-		}
-	}
-
-	if(!readfromGRP)
-		if ((fil = open(filename,O_BINARY|O_RDONLY)) != -1)
-		{
-			filegrp[newhandle] = 255;
-			filehan[newhandle] = fil;
-			filepos[newhandle] = 0;
-			printf("Reading external %s \n", filename);
-			return(newhandle);
-		}
-
-	for(k=numgroupfiles-1;k>=0;k--)
-	{
-		if (groupfil[k] != -1)
-		{
-			for(i=gnumfiles[k]-1;i>=0;i--)
-			{
-				gfileptr = (uint8_t  *)&gfilelist[k][i<<4];
-
-				bad = 0;
-				for(j=0;j<13;j++)
-				{
-					if (!filename[j]) break;
-					if (toupperlookup[(int) filename[j]] != toupperlookup[(int) gfileptr[j]])
-						{ bad = 1; break; }
-				}
-				if (bad) continue;
-
-				filegrp[newhandle] = (uint8_t ) k;
-				filehan[newhandle] = i;
-				filepos[newhandle] = 0;
-				return(newhandle);
-			}
-		}
-	}
-	return(-1);
-
-}
-
-int32_t kread(int32_t handle, void *buffer, int32_t leng)
-{
-	int32_t i, filenum, groupnum;
-
-	filenum = filehan[handle];
-	groupnum = filegrp[handle];
-
-	if (groupnum == 255) // Reading external
-	{
-		return(read(filenum,buffer,leng));
-	}
-
-	if (groupfil[groupnum] != -1)
-	{
-		i = gfileoffs[groupnum][filenum]+filepos[handle];
-		if (i != groupfilpos[groupnum])
-		{
-			lseek(groupfil[groupnum],i+((gnumfiles[groupnum]+1)<<4),SEEK_SET);
-			groupfilpos[groupnum] = i;
-		}
-		leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-filepos[handle]);
-		leng = read(groupfil[groupnum],buffer,leng);
-		filepos[handle] += leng;
-		groupfilpos[groupnum] += leng;
-		return(leng);
-	}
-
-	return(0);
-
-}
-
-int kread16(int32_t handle, short *buffer)
-{
-    if (kread(handle, buffer, 2) != 2)
-        return(0);
-
-    *buffer = BUILDSWAP_INTEL16(*buffer);
-    return(1);
-}
-
-int kread32(int32_t handle, int32_t *buffer)
-{
-    if (kread(handle, buffer, 4) != 4)
-        return(0);
-
-    *buffer = BUILDSWAP_INTEL32(*buffer);
-    return(1);
-}
-
-int kread8(int32_t handle, uint8_t  *buffer)
-{
-    if (kread(handle, buffer, 1) != 1)
-        return(0);
-
-    return(1);
-}
-
-int32_t klseek(int32_t handle, int32_t offset, int32_t whence)
-{
-	int32_t i, groupnum;
-
-	groupnum = filegrp[handle];
-
-	if (groupnum == 255) return((int32_t )lseek(filehan[handle],offset,whence));
-	if (groupfil[groupnum] != -1)
-	{
-		switch(whence)
-		{
-			case SEEK_SET: filepos[handle] = offset; break;
-			case SEEK_END: i = filehan[handle];
-								filepos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset;
-								break;
-			case SEEK_CUR: filepos[handle] += offset; break;
-		}
-		return(filepos[handle]);
-	}
-	return(-1);
-
-}
-
-#ifdef __APPLE__
-int32_t filelength(int32_t fd)
-{
-    struct stat stats;
-    fstat(fd, &stats);
-    return (int32_t )stats.st_size;
-}
-#endif
-
-int32_t kfilelength(int32_t handle)
-{
-	int32_t i, groupnum;
-
-	groupnum = filegrp[handle];
-	if (groupnum == 255) return(filelength(filehan[handle]));
-	i = filehan[handle];
-	return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]);
-
-}
-
-void kclose(int32_t handle)
-{
-	if (handle < 0) return;
-	if (filegrp[handle] == 255) close(filehan[handle]);
-	filehan[handle] = -1;
-
-}
-
-
-
-
-	/* Internal LZW variables */
-#define LZWSIZE 16384           /* Watch out for shorts! */
-static uint8_t  *lzwbuf1, *lzwbuf4, *lzwbuf5;
-static uint8_t  lzwbuflock[5];
-static short *lzwbuf2, *lzwbuf3;
-
-void kdfread(void *buffer, size_t dasizeof, size_t count, int32_t fil)
-{
-	size_t i, j;
-	int32_t k, kgoal;
-	short leng;
-	uint8_t  *ptr;
-
-	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
-	if (lzwbuf1 == NULL) allocache((int32_t *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
-	if (lzwbuf2 == NULL) allocache((int32_t *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
-	if (lzwbuf3 == NULL) allocache((int32_t *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
-	if (lzwbuf4 == NULL) allocache((int32_t *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
-	if (lzwbuf5 == NULL) allocache((int32_t *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
-
-	if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
-	ptr = (uint8_t  *)buffer;
-
-	kread(fil,&leng,2); kread(fil,lzwbuf5,(int32_t )leng);
-	k = 0;
-	kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
-
-	copybufbyte(lzwbuf4,ptr,(int32_t )dasizeof);
-	k += (int32_t )dasizeof;
-
-	for(i=1;i<count;i++)
-	{
-		if (k >= kgoal)
-		{
-			kread(fil,&leng,2); kread(fil,lzwbuf5,(int32_t )leng);
-			k = 0; kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
-		}
-		for(j=0;j<dasizeof;j++) ptr[j+dasizeof] = (uint8_t ) ((ptr[j]+lzwbuf4[j+k])&255);
-		k += dasizeof;
-		ptr += dasizeof;
-	}
-	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
-}
-
-void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil)
-{
-	size_t i, j;
-	int32_t k, kgoal;
-	short leng;
-	uint8_t  *ptr;
-
-	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
-	if (lzwbuf1 == NULL) allocache((int32_t *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
-	if (lzwbuf2 == NULL) allocache((int32_t *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
-	if (lzwbuf3 == NULL) allocache((int32_t *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
-	if (lzwbuf4 == NULL) allocache((int32_t *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
-	if (lzwbuf5 == NULL) allocache((int32_t *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
-
-	if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
-	ptr = (uint8_t  *)buffer;
-
-	fread(&leng,2,1,fil); fread(lzwbuf5,(int32_t )leng,1,fil);
-	k = 0; kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
-
-	copybufbyte(lzwbuf4,ptr,(int32_t )dasizeof);
-	k += (int32_t )dasizeof;
-
-	for(i=1;i<count;i++)
-	{
-		if (k >= kgoal)
-		{
-			fread(&leng,2,1,fil); fread(lzwbuf5,(int32_t )leng,1,fil);
-			k = 0; kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
-		}
-		for(j=0;j<dasizeof;j++) ptr[j+dasizeof] = (uint8_t ) ((ptr[j]+lzwbuf4[j+k])&255);
-		k += dasizeof;
-		ptr += dasizeof;
-	}
-	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
-}
-
-void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil)
-{
-	size_t i, j, k;
-	short leng;
-	uint8_t  *ptr;
-
-	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
-	if (lzwbuf1 == NULL) allocache((int32_t *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
-	if (lzwbuf2 == NULL) allocache((int32_t *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
-	if (lzwbuf3 == NULL) allocache((int32_t *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
-	if (lzwbuf4 == NULL) allocache((int32_t *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
-	if (lzwbuf5 == NULL) allocache((int32_t *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
-
-	if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
-	ptr = (uint8_t  *)buffer;
-
-	copybufbyte(ptr,lzwbuf4,(int32_t )dasizeof);
-	k = dasizeof;
-
-	if (k > LZWSIZE-dasizeof)
-	{
-		leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0;
-		fwrite(&leng,2,1,fil); fwrite(lzwbuf5,(int32_t )leng,1,fil);
-	}
-
-	for(i=1;i<count;i++)
-	{
-		for(j=0;j<dasizeof;j++) lzwbuf4[j+k] = (uint8_t ) ((ptr[j+dasizeof]-ptr[j])&255);
-		k += dasizeof;
-		if (k > LZWSIZE-dasizeof)
-		{
-			leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0;
-			fwrite(&leng,2,1,fil); fwrite(lzwbuf5,(int32_t )leng,1,fil);
-		}
-		ptr += dasizeof;
-	}
-	if (k > 0)
-	{
-		leng = (short)compress(lzwbuf4,k,lzwbuf5);
-		fwrite(&leng,2,1,fil); fwrite(lzwbuf5,(int32_t )leng,1,fil);
-	}
-	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
-}
-
-int32_t compress(uint8_t  *lzwinbuf, int32_t uncompleng, uint8_t  *lzwoutbuf)
-{
-	int32_t i, addr, newaddr, addrcnt, zx, *longptr;
-	int32_t bytecnt1, bitcnt, numbits, oneupnumbits;
-	short *shortptr;
-
-	for(i=255;i>=0;i--) { lzwbuf1[i] = (uint8_t ) i; lzwbuf3[i] = (short) ((i+1)&255); }
-	clearbuf((void *) FP_OFF(lzwbuf2),256>>1,0xffffffff);
-	clearbuf((void *) FP_OFF(lzwoutbuf),((uncompleng+15)+3)>>2,0L);
-
-	addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3);
-	numbits = 8; oneupnumbits = (1<<8);
-	do
-	{
-		addr = lzwinbuf[bytecnt1];
-		do
-		{
-			bytecnt1++;
-			if (bytecnt1 == uncompleng) break;
-			if (lzwbuf2[addr] < 0) {lzwbuf2[addr] = (short) addrcnt; break;}
-			newaddr = lzwbuf2[addr];
-			while (lzwbuf1[newaddr] != lzwinbuf[bytecnt1])
-			{
-				zx = lzwbuf3[newaddr];
-				if (zx < 0) {lzwbuf3[newaddr] = (short) addrcnt; break;}
-				newaddr = zx;
-			}
-			if (lzwbuf3[newaddr] == addrcnt) break;
-			addr = newaddr;
-		} while (addr >= 0);
-		lzwbuf1[addrcnt] = lzwinbuf[bytecnt1];
-		lzwbuf2[addrcnt] = -1;
-		lzwbuf3[addrcnt] = -1;
-
-		longptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
-		longptr[0] |= (addr<<(bitcnt&7));
-		bitcnt += numbits;
-		if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
-			bitcnt--;
-
-		addrcnt++;
-		if (addrcnt > oneupnumbits) { numbits++; oneupnumbits <<= 1; }
-	} while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3)));
-
-	longptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
-	longptr[0] |= (addr<<(bitcnt&7));
-	bitcnt += numbits;
-	if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
-		bitcnt--;
-
-	shortptr = (short *)lzwoutbuf;
-	shortptr[0] = (short)uncompleng;
-	if (((bitcnt+7)>>3) < uncompleng)
-	{
-		shortptr[1] = (short)addrcnt;
-		return((bitcnt+7)>>3);
-	}
-	shortptr[1] = (short)0;
-	for(i=0;i<uncompleng;i++) lzwoutbuf[i+4] = lzwinbuf[i];
-	return(uncompleng+4);
-}
-
-int32_t uncompress(uint8_t  *lzwinbuf, int32_t compleng, uint8_t  *lzwoutbuf)
-{
-	int32_t strtot, currstr, numbits, oneupnumbits;
-	int32_t i, dat, leng, bitcnt, outbytecnt, *longptr;
-	short *shortptr;
-
-	shortptr = (short *)lzwinbuf;
-	strtot = (int32_t )shortptr[1];
-	if (strtot == 0)
-	{
-		copybuf((void *)(FP_OFF(lzwinbuf)+4),(void *)(FP_OFF(lzwoutbuf)),((compleng-4)+3)>>2);
-		return((int32_t )shortptr[0]); /* uncompleng */
-	}
-	for(i=255;i>=0;i--) { lzwbuf2[i] = (short) i; lzwbuf3[i] = (short) i; }
-	currstr = 256; bitcnt = (4<<3); outbytecnt = 0;
-	numbits = 8; oneupnumbits = (1<<8);
-	do
-	{
-		longptr = (int32_t *)&lzwinbuf[bitcnt>>3];
-		dat = ((longptr[0]>>(bitcnt&7)) & (oneupnumbits-1));
-		bitcnt += numbits;
-		if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1)))
-			{ dat &= ((oneupnumbits>>1)-1); bitcnt--; }
-
-		lzwbuf3[currstr] = (short) dat;
-
-		for(leng=0;dat>=256;leng++,dat=lzwbuf3[dat])
-			lzwbuf1[leng] = (uint8_t ) lzwbuf2[dat];
-
-		lzwoutbuf[outbytecnt++] = (uint8_t ) dat;
-		for(i=leng-1;i>=0;i--) lzwoutbuf[outbytecnt++] = lzwbuf1[i];
-
-		lzwbuf2[currstr-1] = (short) dat; lzwbuf2[currstr] = (short) dat;
-		currstr++;
-		if (currstr > oneupnumbits) { numbits++; oneupnumbits <<= 1; }
-	} while (currstr < strtot);
-	return((int32_t )shortptr[0]); /* uncompleng */
-}
-
-int SafeFileExists ( const char  * _filename );
-int32_t TCkopen4load(const char  *filename, int readfromGRP)
-{
-	char  fullfilename[512];
-	int32_t result = 0;
- 
-	if(game_dir[0] != '\0' && !readfromGRP)
-	{
-		sprintf(fullfilename, "%s\\%s", game_dir, filename);		
-		if (!SafeFileExists(fullfilename)) // try root
-			sprintf(fullfilename, "%s", filename);
-	}
-	else
-	{
-		sprintf(fullfilename, "%s", filename);
-	}
-
-	result = kopen4load(fullfilename, readfromGRP);
-
-	if(g_CV_DebugFileAccess != 0)
-	{
-		printf("FILE ACCESS: [read] File: (%s) Result: %d, clock: %d\n", fullfilename, result, totalclock);
-	}
-
-	return result;
-}
--- a/Engine/src/cache.h
+++ b/Engine/src/cache.h
@@ -17,9 +17,6 @@
 #ifndef _INCLUDE_CACHE1D_H_
 #define _INCLUDE_CACHE1D_H_
 
-#define MAXGROUPFILES 4     /* Warning: Fix groupfil if this is changed */
-#define MAXOPENFILES 64     /* Warning: Fix filehan if this is changed  */
-
 void initcache(int32_t dacachestart, int32_t dacachesize);
 void allocache (int32_t *newhandle, int32_t newbytes, uint8_t  *newlockptr);
 void suckcache (int32_t *suckptr);
@@ -30,26 +27,7 @@
 
 
 //Filesystem
-int32_t initgroupfile(const char  *filename);
-void uninitgroupfile(void);
-uint16_t crc16(uint8_t  *data_p, uint16_t length);
-unsigned int crc32_update(uint8_t  *buf, unsigned int length, unsigned int crc_to_update);
-int32_t kopen4load(const char  *filename, int readfromGRP);
-int32_t kread(int32_t handle, void *buffer, int32_t leng);
-int kread8(int32_t handle, uint8_t  *buffer);
-int kread16(int32_t handle, short *buffer);
-int kread32(int32_t handle, int32_t *buffer);
-int32_t klseek(int32_t handle, int32_t offset, int32_t whence);
-int32_t kfilelength(int32_t handle);
-void kclose(int32_t handle);
-void kdfread(void *buffer, size_t dasizeof, size_t count, int32_t fil);
-void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil);
-void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil);
-int32_t compress(uint8_t  *lzwinbuf, int32_t uncompleng, uint8_t  *lzwoutbuf);
-int32_t uncompress(uint8_t  *lzwinbuf, int32_t compleng, uint8_t  *lzwoutbuf);
 
-extern char  game_dir[512];
-extern int32_t TCkopen4load(const char  *filename, int readfromGRP);
 
 
 #endif
\ No newline at end of file
--- a/Engine/src/engine.c
+++ b/Engine/src/engine.c
@@ -30,6 +30,7 @@
 
 #include "build.h"
 #include "cache.h"
+#include "filesystem.h"
 
 #include "engine.h"
 
--- /dev/null
+++ b/Engine/src/filesystem.c
@@ -1,0 +1,645 @@
+//
+//  filesystem.c
+//  Duke3D
+//
+//  Created by fabien sanglard on 12-12-19.
+//  Copyright (c) 2012 fabien sanglard. All rights reserved.
+//
+
+#include "filesystem.h"
+
+#include "platform.h"
+#include "cache.h"
+#include "pragmas.h"
+#include "global.h"
+
+uint8_t  toupperlookup[256] =
+{
+	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+	0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
+	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+	0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
+};
+
+int32_t numgroupfiles = 0;			// number of GRP files actually used.
+int32_t gnumfiles[MAXGROUPFILES];	// number of files on grp
+int32_t groupfil[MAXGROUPFILES] = {-1,-1,-1,-1}; // grp file handles
+int32_t groupfilpos[MAXGROUPFILES];
+uint8_t  *gfilelist[MAXGROUPFILES];	// name list + size list of all the files in grp
+int32_t *gfileoffs[MAXGROUPFILES];	// offset of the files
+uint8_t  *groupfil_memory[MAXGROUPFILES]; // addresses of raw GRP files in memory
+int32_t groupefil_crc32[MAXGROUPFILES];
+
+uint8_t  filegrp[MAXOPENFILES];
+int32_t filepos[MAXOPENFILES];
+int32_t filehan[MAXOPENFILES] =
+{
+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+};
+
+
+
+int32_t initgroupfile(const char  *filename)
+{
+	uint8_t  buf[16];
+	int32_t i, j, k;
+    
+	printf("Loading %s ...\n", filename);
+    
+	if (numgroupfiles >= MAXGROUPFILES) return(-1);
+    
+	groupfil_memory[numgroupfiles] = NULL; // addresses of raw GRP files in memory
+	groupefil_crc32[numgroupfiles] = 0;
+    
+	groupfil[numgroupfiles] = open(filename,O_BINARY|O_RDWR,S_IREAD);
+	if (groupfil[numgroupfiles] >= 0)
+	{
+		groupfilpos[numgroupfiles] = 0;
+		read(groupfil[numgroupfiles],buf,16);
+		if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') ||
+            (buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') ||
+            (buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') ||
+            (buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n'))
+		{
+			close(groupfil[numgroupfiles]);
+			groupfil[numgroupfiles] = -1;
+			return(-1);
+		}
+        
+		//FCS: The ".grp" file format is just a collection of a lot of files stored into 1 big one.
+		//I tried to make the format as simple as possible: The first 12 bytes contains my name,
+		//"KenSilverman". The next 4 bytes is the number of files that were compacted into the
+		//group file. Then for each file, there is a 16 byte structure, where the first 12
+		//bytes are the filename, and the last 4 bytes are the file's size. The rest of the
+		//group file is just the raw data packed one after the other in the same order as the list
+		//of files. - ken
+        
+		gnumfiles[numgroupfiles] = BUILDSWAP_INTEL32(*((int32_t *)&buf[12]));
+        
+		if ((gfilelist[numgroupfiles] = (uint8_t  *)kmalloc(gnumfiles[numgroupfiles]<<4)) == 0)
+        { Error(EXIT_FAILURE, "Not enough memory for file grouping system\n"); }
+		if ((gfileoffs[numgroupfiles] = (int32_t *)kmalloc((gnumfiles[numgroupfiles]+1)<<2)) == 0)
+        { Error(EXIT_FAILURE, "Not enough memory for file grouping system\n"); }
+        
+		// load index (name+size)
+		read(groupfil[numgroupfiles],gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4);
+        
+		j = 0;
+		for(i=0;i<gnumfiles[numgroupfiles];i++)
+		{
+			k = BUILDSWAP_INTEL32(*((int32_t *)&gfilelist[numgroupfiles][(i<<4)+12])); // get size
+			gfilelist[numgroupfiles][(i<<4)+12] = 0;
+			gfileoffs[numgroupfiles][i] = j; // absolute offset list of all files. 0 for 1st file
+			j += k;
+		}
+		gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j;
+	}
+    else
+    {
+        printf("Unable to find GRP file %s.\n",filename);
+		//Let user see the message
+		getchar();
+        exit(0);
+    }
+    
+	// Compute CRC32 of thw whole grp and implicitely caches the GRP in memory through windows
+	lseek(groupfil[numgroupfiles], 0, SEEK_SET);
+    
+	i = 1000000; // FIX_00086: grp loaded by smaller sucessive chunks to avoid overloading low ram computers
+	groupfil_memory[numgroupfiles] = malloc(i);
+	while((j=read(groupfil[numgroupfiles], groupfil_memory[numgroupfiles], i)))
+	{
+		groupefil_crc32[numgroupfiles] = crc32_update((uint8_t *)groupfil_memory[numgroupfiles], j, groupefil_crc32[numgroupfiles]);
+	}
+    
+	free(groupfil_memory[numgroupfiles]);
+	groupfil_memory[numgroupfiles] = 0;
+    
+	numgroupfiles++;
+	return(groupfil[numgroupfiles-1]);
+    
+}
+
+void uninitgroupfile(void)
+{
+	int32_t i;
+    
+	for(i=numgroupfiles-1;i>=0;i--)
+		if (groupfil[i] != -1)
+		{
+			kfree(gfilelist[i]);
+			kfree(gfileoffs[i]);
+			close(groupfil[i]);
+			groupfil[i] = -1;
+		}
+    
+}
+
+void crc32_table_gen(unsigned int* crc32_table) /* build CRC32 table */
+{
+    unsigned int crc, poly;
+    int	i, j;
+    
+    poly = 0xEDB88320L;
+    for (i = 0; i < 256; i++)
+    {
+		crc = i;
+		for (j = 8; j > 0; j--)
+		{
+			if (crc & 1)
+				crc = (crc >> 1) ^ poly;
+			else
+				crc >>= 1;
+		}
+		crc32_table[i] = crc;
+    }
+}
+
+unsigned int crc32(uint8_t  *buf, unsigned int length)
+{
+	unsigned int initial_crc;
+    
+	initial_crc = 0;
+	return(crc32_update(buf, length, initial_crc));
+}
+
+unsigned int crc32_update(uint8_t  *buf, unsigned int length, unsigned int crc_to_update)
+{
+	unsigned int crc32_table[256];
+    
+	crc32_table_gen(crc32_table);
+    
+	crc_to_update ^= 0xFFFFFFFF;
+    
+	while (length--)
+		crc_to_update = crc32_table[(crc_to_update ^ *buf++) & 0xFF] ^ (crc_to_update >> 8);
+	
+	return crc_to_update ^ 0xFFFFFFFF;
+}
+
+
+/*
+ *                                      16   12   5
+ * this is the CCITT CRC 16 polynomial X  + X  + X  + 1.
+ * This is 0x1021 when x is 2, but the way the algorithm works
+ * we use 0x8408 (the reverse of the bit pattern).  The high
+ * bit is always assumed to be set, thus we only use 16 bits to
+ * represent the 17 bit value.
+ */
+
+#define POLY 0x8408   /* 1021H bit reversed */
+
+uint16_t crc16(uint8_t  *data_p, uint16_t length)
+{
+    uint8_t  i;
+    unsigned int data;
+    unsigned int crc = 0xffff;
+    
+    if (length == 0)
+        return (~crc);
+    do
+    {
+        for (i=0, data=(unsigned int)0xff & *data_p++;
+             i < 8;
+             i++, data >>= 1)
+        {
+            if ((crc & 0x0001) ^ (data & 0x0001))
+                crc = (crc >> 1) ^ POLY;
+            else  crc >>= 1;
+        }
+    } while (--length);
+    
+    crc = ~crc;
+    data = crc;
+    crc = (crc << 8) | (data >> 8 & 0xff);
+    
+    return (crc);
+}
+
+int32_t kopen4load(const char  *filename, int readfromGRP)
+{ // FIX_00072: all files are now 1st searched in Duke's root folder and then in the GRP.
+	int32_t i, j, k, fil, newhandle;
+	uint8_t  bad;
+	uint8_t  *gfileptr;
+    
+	newhandle = MAXOPENFILES-1;
+	while (filehan[newhandle] != -1)
+	{
+		newhandle--;
+		if (newhandle < 0)
+		{
+			Error(EXIT_FAILURE, "Too Many files open!\n");
+		}
+	}
+    
+	if(!readfromGRP)
+		if ((fil = open(filename,O_BINARY|O_RDONLY)) != -1)
+		{
+			filegrp[newhandle] = 255;
+			filehan[newhandle] = fil;
+			filepos[newhandle] = 0;
+			printf("Reading external %s \n", filename);
+			return(newhandle);
+		}
+    
+	for(k=numgroupfiles-1;k>=0;k--)
+	{
+		if (groupfil[k] != -1)
+		{
+			for(i=gnumfiles[k]-1;i>=0;i--)
+			{
+				gfileptr = (uint8_t  *)&gfilelist[k][i<<4];
+                
+				bad = 0;
+				for(j=0;j<13;j++)
+				{
+					if (!filename[j]) break;
+					if (toupperlookup[(int) filename[j]] != toupperlookup[(int) gfileptr[j]])
+                    { bad = 1; break; }
+				}
+				if (bad) continue;
+                
+				filegrp[newhandle] = (uint8_t ) k;
+				filehan[newhandle] = i;
+				filepos[newhandle] = 0;
+				return(newhandle);
+			}
+		}
+	}
+	return(-1);
+    
+}
+
+int32_t kread(int32_t handle, void *buffer, int32_t leng)
+{
+	int32_t i, filenum, groupnum;
+    
+	filenum = filehan[handle];
+	groupnum = filegrp[handle];
+    
+	if (groupnum == 255) // Reading external
+	{
+		return(read(filenum,buffer,leng));
+	}
+    
+	if (groupfil[groupnum] != -1)
+	{
+		i = gfileoffs[groupnum][filenum]+filepos[handle];
+		if (i != groupfilpos[groupnum])
+		{
+			lseek(groupfil[groupnum],i+((gnumfiles[groupnum]+1)<<4),SEEK_SET);
+			groupfilpos[groupnum] = i;
+		}
+		leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-filepos[handle]);
+		leng = read(groupfil[groupnum],buffer,leng);
+		filepos[handle] += leng;
+		groupfilpos[groupnum] += leng;
+		return(leng);
+	}
+    
+	return(0);
+    
+}
+
+int kread16(int32_t handle, short *buffer)
+{
+    if (kread(handle, buffer, 2) != 2)
+        return(0);
+    
+    *buffer = BUILDSWAP_INTEL16(*buffer);
+    return(1);
+}
+
+int kread32(int32_t handle, int32_t *buffer)
+{
+    if (kread(handle, buffer, 4) != 4)
+        return(0);
+    
+    *buffer = BUILDSWAP_INTEL32(*buffer);
+    return(1);
+}
+
+int kread8(int32_t handle, uint8_t  *buffer)
+{
+    if (kread(handle, buffer, 1) != 1)
+        return(0);
+    
+    return(1);
+}
+
+int32_t klseek(int32_t handle, int32_t offset, int32_t whence)
+{
+	int32_t i, groupnum;
+    
+	groupnum = filegrp[handle];
+    
+	if (groupnum == 255) return((int32_t )lseek(filehan[handle],offset,whence));
+	if (groupfil[groupnum] != -1)
+	{
+		switch(whence)
+		{
+			case SEEK_SET: filepos[handle] = offset; break;
+			case SEEK_END: i = filehan[handle];
+                filepos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset;
+                break;
+			case SEEK_CUR: filepos[handle] += offset; break;
+		}
+		return(filepos[handle]);
+	}
+	return(-1);
+    
+}
+
+#ifdef __APPLE__
+int32_t filelength(int32_t fd)
+{
+    struct stat stats;
+    fstat(fd, &stats);
+    return (int32_t )stats.st_size;
+}
+#endif
+
+int32_t kfilelength(int32_t handle)
+{
+	int32_t i, groupnum;
+    
+	groupnum = filegrp[handle];
+	if (groupnum == 255) return(filelength(filehan[handle]));
+	i = filehan[handle];
+	return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]);
+    
+}
+
+void kclose(int32_t handle)
+{
+	if (handle < 0) return;
+	if (filegrp[handle] == 255) close(filehan[handle]);
+	filehan[handle] = -1;
+    
+}
+
+
+
+
+/* Internal LZW variables */
+#define LZWSIZE 16384           /* Watch out for shorts! */
+static uint8_t  *lzwbuf1, *lzwbuf4, *lzwbuf5;
+static uint8_t  lzwbuflock[5];
+static short *lzwbuf2, *lzwbuf3;
+
+void kdfread(void *buffer, size_t dasizeof, size_t count, int32_t fil)
+{
+	size_t i, j;
+	int32_t k, kgoal;
+	short leng;
+	uint8_t  *ptr;
+    
+	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
+	if (lzwbuf1 == NULL) allocache((int32_t *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
+	if (lzwbuf2 == NULL) allocache((int32_t *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
+	if (lzwbuf3 == NULL) allocache((int32_t *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
+	if (lzwbuf4 == NULL) allocache((int32_t *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
+	if (lzwbuf5 == NULL) allocache((int32_t *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
+    
+	if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
+	ptr = (uint8_t  *)buffer;
+    
+	kread(fil,&leng,2); kread(fil,lzwbuf5,(int32_t )leng);
+	k = 0;
+	kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
+    
+	copybufbyte(lzwbuf4,ptr,(int32_t )dasizeof);
+	k += (int32_t )dasizeof;
+    
+	for(i=1;i<count;i++)
+	{
+		if (k >= kgoal)
+		{
+			kread(fil,&leng,2); kread(fil,lzwbuf5,(int32_t )leng);
+			k = 0; kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
+		}
+		for(j=0;j<dasizeof;j++) ptr[j+dasizeof] = (uint8_t ) ((ptr[j]+lzwbuf4[j+k])&255);
+		k += dasizeof;
+		ptr += dasizeof;
+	}
+	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
+}
+
+void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil)
+{
+	size_t i, j;
+	int32_t k, kgoal;
+	short leng;
+	uint8_t  *ptr;
+    
+	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
+	if (lzwbuf1 == NULL) allocache((int32_t *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
+	if (lzwbuf2 == NULL) allocache((int32_t *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
+	if (lzwbuf3 == NULL) allocache((int32_t *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
+	if (lzwbuf4 == NULL) allocache((int32_t *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
+	if (lzwbuf5 == NULL) allocache((int32_t *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
+    
+	if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
+	ptr = (uint8_t  *)buffer;
+    
+	fread(&leng,2,1,fil); fread(lzwbuf5,(int32_t )leng,1,fil);
+	k = 0; kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
+    
+	copybufbyte(lzwbuf4,ptr,(int32_t )dasizeof);
+	k += (int32_t )dasizeof;
+    
+	for(i=1;i<count;i++)
+	{
+		if (k >= kgoal)
+		{
+			fread(&leng,2,1,fil); fread(lzwbuf5,(int32_t )leng,1,fil);
+			k = 0; kgoal = uncompress(lzwbuf5,(int32_t )leng,lzwbuf4);
+		}
+		for(j=0;j<dasizeof;j++) ptr[j+dasizeof] = (uint8_t ) ((ptr[j]+lzwbuf4[j+k])&255);
+		k += dasizeof;
+		ptr += dasizeof;
+	}
+	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
+}
+
+void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil)
+{
+	size_t i, j, k;
+	short leng;
+	uint8_t  *ptr;
+    
+	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
+	if (lzwbuf1 == NULL) allocache((int32_t *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
+	if (lzwbuf2 == NULL) allocache((int32_t *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
+	if (lzwbuf3 == NULL) allocache((int32_t *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
+	if (lzwbuf4 == NULL) allocache((int32_t *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
+	if (lzwbuf5 == NULL) allocache((int32_t *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
+    
+	if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
+	ptr = (uint8_t  *)buffer;
+    
+	copybufbyte(ptr,lzwbuf4,(int32_t )dasizeof);
+	k = dasizeof;
+    
+	if (k > LZWSIZE-dasizeof)
+	{
+		leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0;
+		fwrite(&leng,2,1,fil); fwrite(lzwbuf5,(int32_t )leng,1,fil);
+	}
+    
+	for(i=1;i<count;i++)
+	{
+		for(j=0;j<dasizeof;j++) lzwbuf4[j+k] = (uint8_t ) ((ptr[j+dasizeof]-ptr[j])&255);
+		k += dasizeof;
+		if (k > LZWSIZE-dasizeof)
+		{
+			leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0;
+			fwrite(&leng,2,1,fil); fwrite(lzwbuf5,(int32_t )leng,1,fil);
+		}
+		ptr += dasizeof;
+	}
+	if (k > 0)
+	{
+		leng = (short)compress(lzwbuf4,k,lzwbuf5);
+		fwrite(&leng,2,1,fil); fwrite(lzwbuf5,(int32_t )leng,1,fil);
+	}
+	lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
+}
+
+int32_t compress(uint8_t  *lzwinbuf, int32_t uncompleng, uint8_t  *lzwoutbuf)
+{
+	int32_t i, addr, newaddr, addrcnt, zx, *longptr;
+	int32_t bytecnt1, bitcnt, numbits, oneupnumbits;
+	short *shortptr;
+    
+	for(i=255;i>=0;i--) { lzwbuf1[i] = (uint8_t ) i; lzwbuf3[i] = (short) ((i+1)&255); }
+	clearbuf((void *) FP_OFF(lzwbuf2),256>>1,0xffffffff);
+	clearbuf((void *) FP_OFF(lzwoutbuf),((uncompleng+15)+3)>>2,0L);
+    
+	addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3);
+	numbits = 8; oneupnumbits = (1<<8);
+	do
+	{
+		addr = lzwinbuf[bytecnt1];
+		do
+		{
+			bytecnt1++;
+			if (bytecnt1 == uncompleng) break;
+			if (lzwbuf2[addr] < 0) {lzwbuf2[addr] = (short) addrcnt; break;}
+			newaddr = lzwbuf2[addr];
+			while (lzwbuf1[newaddr] != lzwinbuf[bytecnt1])
+			{
+				zx = lzwbuf3[newaddr];
+				if (zx < 0) {lzwbuf3[newaddr] = (short) addrcnt; break;}
+				newaddr = zx;
+			}
+			if (lzwbuf3[newaddr] == addrcnt) break;
+			addr = newaddr;
+		} while (addr >= 0);
+		lzwbuf1[addrcnt] = lzwinbuf[bytecnt1];
+		lzwbuf2[addrcnt] = -1;
+		lzwbuf3[addrcnt] = -1;
+        
+		longptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
+		longptr[0] |= (addr<<(bitcnt&7));
+		bitcnt += numbits;
+		if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
+			bitcnt--;
+        
+		addrcnt++;
+		if (addrcnt > oneupnumbits) { numbits++; oneupnumbits <<= 1; }
+	} while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3)));
+    
+	longptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
+	longptr[0] |= (addr<<(bitcnt&7));
+	bitcnt += numbits;
+	if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
+		bitcnt--;
+    
+	shortptr = (short *)lzwoutbuf;
+	shortptr[0] = (short)uncompleng;
+	if (((bitcnt+7)>>3) < uncompleng)
+	{
+		shortptr[1] = (short)addrcnt;
+		return((bitcnt+7)>>3);
+	}
+	shortptr[1] = (short)0;
+	for(i=0;i<uncompleng;i++) lzwoutbuf[i+4] = lzwinbuf[i];
+	return(uncompleng+4);
+}
+
+int32_t uncompress(uint8_t  *lzwinbuf, int32_t compleng, uint8_t  *lzwoutbuf)
+{
+	int32_t strtot, currstr, numbits, oneupnumbits;
+	int32_t i, dat, leng, bitcnt, outbytecnt, *longptr;
+	short *shortptr;
+    
+	shortptr = (short *)lzwinbuf;
+	strtot = (int32_t )shortptr[1];
+	if (strtot == 0)
+	{
+		copybuf((void *)(FP_OFF(lzwinbuf)+4),(void *)(FP_OFF(lzwoutbuf)),((compleng-4)+3)>>2);
+		return((int32_t )shortptr[0]); /* uncompleng */
+	}
+	for(i=255;i>=0;i--) { lzwbuf2[i] = (short) i; lzwbuf3[i] = (short) i; }
+	currstr = 256; bitcnt = (4<<3); outbytecnt = 0;
+	numbits = 8; oneupnumbits = (1<<8);
+	do
+	{
+		longptr = (int32_t *)&lzwinbuf[bitcnt>>3];
+		dat = ((longptr[0]>>(bitcnt&7)) & (oneupnumbits-1));
+		bitcnt += numbits;
+		if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1)))
+        { dat &= ((oneupnumbits>>1)-1); bitcnt--; }
+        
+		lzwbuf3[currstr] = (short) dat;
+        
+		for(leng=0;dat>=256;leng++,dat=lzwbuf3[dat])
+			lzwbuf1[leng] = (uint8_t ) lzwbuf2[dat];
+        
+		lzwoutbuf[outbytecnt++] = (uint8_t ) dat;
+		for(i=leng-1;i>=0;i--) lzwoutbuf[outbytecnt++] = lzwbuf1[i];
+        
+		lzwbuf2[currstr-1] = (short) dat; lzwbuf2[currstr] = (short) dat;
+		currstr++;
+		if (currstr > oneupnumbits) { numbits++; oneupnumbits <<= 1; }
+	} while (currstr < strtot);
+	return((int32_t )shortptr[0]); /* uncompleng */
+}
+
+int SafeFileExists ( const char  * _filename );
+int32_t TCkopen4load(const char  *filename, int readfromGRP)
+{
+	char  fullfilename[512];
+	int32_t result = 0;
+    
+	if(game_dir[0] != '\0' && !readfromGRP)
+	{
+		sprintf(fullfilename, "%s\\%s", game_dir, filename);
+		if (!SafeFileExists(fullfilename)) // try root
+			sprintf(fullfilename, "%s", filename);
+	}
+	else
+	{
+		sprintf(fullfilename, "%s", filename);
+	}
+    
+	result = kopen4load(fullfilename, readfromGRP);
+    
+	return result;
+}
--- /dev/null
+++ b/Engine/src/filesystem.h
@@ -1,0 +1,43 @@
+//
+//  filesystem.h
+//  Duke3D
+//
+//  Created by fabien sanglard on 12-12-19.
+//  Copyright (c) 2012 fabien sanglard. All rights reserved.
+//
+
+#ifndef Duke3D_filesystem_h
+#define Duke3D_filesystem_h
+
+#include "stdio.h"
+#include "platform.h"
+
+#define MAXGROUPFILES 4     /* Warning: Fix groupfil if this is changed */
+#define MAXOPENFILES 64     /* Warning: Fix filehan if this is changed  */
+
+int32_t initgroupfile(const char  *filename);
+void uninitgroupfile(void);
+uint16_t crc16(uint8_t  *data_p, uint16_t length);
+unsigned int crc32_update(uint8_t  *buf, unsigned int length, unsigned int crc_to_update);
+int32_t kopen4load(const char  *filename, int readfromGRP);
+int32_t kread(int32_t handle, void *buffer, int32_t leng);
+int kread8(int32_t handle, uint8_t  *buffer);
+int kread16(int32_t handle, short *buffer);
+int kread32(int32_t handle, int32_t *buffer);
+int32_t klseek(int32_t handle, int32_t offset, int32_t whence);
+int32_t kfilelength(int32_t handle);
+void kclose(int32_t handle);
+void kdfread(void *buffer, size_t dasizeof, size_t count, int32_t fil);
+void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil);
+void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil);
+int32_t compress(uint8_t  *lzwinbuf, int32_t uncompleng, uint8_t  *lzwoutbuf);
+int32_t uncompress(uint8_t  *lzwinbuf, int32_t compleng, uint8_t  *lzwoutbuf);
+
+extern char  game_dir[512];
+extern int32_t TCkopen4load(const char  *filename, int readfromGRP);
+
+#ifdef __APPLE__
+    int32_t filelength(int32_t fd);
+#endif
+
+#endif
--- a/Engine/src/macos_compat.h
+++ b/Engine/src/macos_compat.h
@@ -11,6 +11,8 @@
 
 #define PLATFORM_SUPPORTS_SDL
 
+#include <stdlib.h>
+
 #define kmalloc(x) malloc(x)
 #define kkmalloc(x) malloc(x)
 #define kfree(x) free(x)
@@ -48,9 +50,11 @@
 #define strcmpi strcasecmp
 
 #include <assert.h>
-
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#include <fcntl.h>
+
 
 #endif
--- a/Game/src/config.c
+++ b/Game/src/config.c
@@ -37,6 +37,7 @@
 #include "duke3d.h"
 #include "scriplib.h"
 #include "cache.h"
+#include "filesystem.h"
 
 // we load this in to get default button and key assignments
 // as well as setting up function mappings
--- a/Game/src/duke3d.h
+++ b/Game/src/duke3d.h
@@ -92,7 +92,7 @@
 
 extern uint8_t  conVersion;
 extern uint8_t  grpVersion;
-extern int32_t groupefil_crc32[MAXGROUPFILES];
+extern int32_t* groupefil_crc32;
 
 #define RANCID_ID 1
 #define	XDUKE_ID  2
@@ -418,7 +418,7 @@
 	// FIX_00015: Backward compliance with older demos (down to demos v27, 28, 116 and 117 only)
 	uint8_t  playing_demo_rev;
 
-	uint32_t groupefil_crc32[MAXPLAYERS][MAXGROUPFILES];
+	uint32_t* groupefil_crc32[MAXPLAYERS];
 	uint16_t conSize[MAXPLAYERS];
 
 #ifdef CHECK_XDUKE_REV
--- a/Game/src/game.c
+++ b/Game/src/game.c
@@ -56,6 +56,7 @@
 #include "global.h"
 
 #include "cache.h"
+#include "filesystem.h"
 
 #define MINITEXT_BLUE	0
 #define MINITEXT_RED	2
@@ -7683,9 +7684,9 @@
 {
 	char  userconfilename[512];
 
-   mymembuf = (uint8_t  *)&hittype[0];
+   mymembuf = (char  *)hittype;
    labelcode = (int32_t *)&sector[0];
-   label = (uint8_t  *)&sprite[0];
+   label = (char  *)sprite;
 
 	sprintf(userconfilename, "%s", confilename);
 
--- a/Game/src/global.c
+++ b/Game/src/global.c
@@ -556,8 +556,7 @@
 #if (defined PLATFORM_WIN32)
     handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_APPEND );
 #else
-	handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_APPEND
-	, S_IREAD | S_IWRITE);
+	handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_APPEND , S_IREAD | S_IWRITE);
 #endif
 
 	if (handle == -1)
--- a/Game/src/global.h
+++ b/Game/src/global.h
@@ -58,4 +58,6 @@
 #define Swapint32_t IntelLong
 #endif
 
+void Error (int errorType, char  *error, ...);
+
 #endif
--- a/Game/src/menues.c
+++ b/Game/src/menues.c
@@ -28,7 +28,8 @@
 #include "mouse.h"
 #include "animlib.h"
 #include "control.h"
-#include "cache.h"
+
+#include "filesystem.h"
 #include "SDL.h"
 #include "premap.h"
 
--- a/Game/src/premap.c
+++ b/Game/src/premap.c
@@ -25,7 +25,7 @@
 //-------------------------------------------------------------------------
 
 #include "duke3d.h"
-#include "cache.h"
+#include "filesystem.h"
 #include "game.h"
 
 extern uint8_t  everyothertime;
--- a/xcode/Duke3D.xcodeproj/project.pbxproj
+++ b/xcode/Duke3D.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		2D2A07CA168286D500064107 /* filesystem.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D2A07C9168286D400064107 /* filesystem.c */; };
 		2D4FB6FF167D430F00915887 /* sdl_midi.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D4FB6FE167D430F00915887 /* sdl_midi.c */; };
 		2D7B621D1678885A00E35E54 /* draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B61F11678885A00E35E54 /* draw.c */; };
 		2D7B621E1678885A00E35E54 /* cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B61F41678885A00E35E54 /* cache.c */; };
@@ -73,6 +74,8 @@
 		2D2A07B8167EFA4900064107 /* music.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = music.h; path = ../../Game/src/audiolib/music.h; sourceTree = "<group>"; };
 		2D2A07BA167EFB5500064107 /* premap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = premap.h; path = ../../Game/src/premap.h; sourceTree = "<group>"; };
 		2D2A07BB167F1ABA00064107 /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = global.h; path = ../../Game/src/global.h; sourceTree = "<group>"; };
+		2D2A07C9168286D400064107 /* filesystem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = filesystem.c; path = ../../Engine/src/filesystem.c; sourceTree = "<group>"; };
+		2D2A07CB168286F200064107 /* filesystem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = filesystem.h; path = ../../Engine/src/filesystem.h; sourceTree = "<group>"; };
 		2D4FB6FE167D430F00915887 /* sdl_midi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdl_midi.c; sourceTree = "<group>"; };
 		2D7B61DE167886FB00E35E54 /* Duke3D */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Duke3D; sourceTree = BUILT_PRODUCTS_DIR; };
 		2D7B61F11678885A00E35E54 /* draw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = draw.c; path = ../../Engine/src/draw.c; sourceTree = "<group>"; };
@@ -190,6 +193,48 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		2D2A07CC1682870D00064107 /* headers */ = {
+			isa = PBXGroup;
+			children = (
+				2D2A07CE1682875B00064107 /* enet */,
+				2D7B622F1678895A00E35E54 /* macos_compat.h */,
+				2D7B61F21678885A00E35E54 /* draw.h */,
+				2D7B61F31678885A00E35E54 /* build.h */,
+				2D2A07CB168286F200064107 /* filesystem.h */,
+				2D7B61F51678885A00E35E54 /* cache.h */,
+				2D7B61F61678885A00E35E54 /* display.h */,
+				2D7B620F1678885A00E35E54 /* engine_protos.h */,
+				2D7B62111678885A00E35E54 /* engine.h */,
+				2D7B62121678885A00E35E54 /* icon.h */,
+				2D7B62191678885A00E35E54 /* platform.h */,
+				2D7B621B1678885A00E35E54 /* pragmas.h */,
+			);
+			name = headers;
+			sourceTree = "<group>";
+		};
+		2D2A07CD1682871200064107 /* implementations */ = {
+			isa = PBXGroup;
+			children = (
+				2D7B61F71678885A00E35E54 /* enet */,
+				2D7B61F11678885A00E35E54 /* draw.c */,
+				2D2A07C9168286D400064107 /* filesystem.c */,
+				2D7B61F41678885A00E35E54 /* cache.c */,
+				2D7B62101678885A00E35E54 /* engine.c */,
+				2D7B621A1678885A00E35E54 /* pragmas.c */,
+				2D7B621C1678885A00E35E54 /* sdl_driver.c */,
+				2D7B630016791C0200E35E54 /* dummy_multi.c */,
+			);
+			name = implementations;
+			sourceTree = "<group>";
+		};
+		2D2A07CE1682875B00064107 /* enet */ = {
+			isa = PBXGroup;
+			children = (
+				2D7B61FB1678885A00E35E54 /* include */,
+			);
+			name = enet;
+			sourceTree = "<group>";
+		};
 		2D7B61D3167886FB00E35E54 = {
 			isa = PBXGroup;
 			children = (
@@ -224,23 +269,8 @@
 		2D7B61F01678884400E35E54 /* Engine */ = {
 			isa = PBXGroup;
 			children = (
-				2D7B61F21678885A00E35E54 /* draw.h */,
-				2D7B61F11678885A00E35E54 /* draw.c */,
-				2D7B61F31678885A00E35E54 /* build.h */,
-				2D7B61F41678885A00E35E54 /* cache.c */,
-				2D7B61F51678885A00E35E54 /* cache.h */,
-				2D7B61F61678885A00E35E54 /* display.h */,
-				2D7B61F71678885A00E35E54 /* enet */,
-				2D7B620F1678885A00E35E54 /* engine_protos.h */,
-				2D7B62101678885A00E35E54 /* engine.c */,
-				2D7B62111678885A00E35E54 /* engine.h */,
-				2D7B62121678885A00E35E54 /* icon.h */,
-				2D7B62191678885A00E35E54 /* platform.h */,
-				2D7B621A1678885A00E35E54 /* pragmas.c */,
-				2D7B621B1678885A00E35E54 /* pragmas.h */,
-				2D7B621C1678885A00E35E54 /* sdl_driver.c */,
-				2D7B622F1678895A00E35E54 /* macos_compat.h */,
-				2D7B630016791C0200E35E54 /* dummy_multi.c */,
+				2D2A07CC1682870D00064107 /* headers */,
+				2D2A07CD1682871200064107 /* implementations */,
 			);
 			name = Engine;
 			sourceTree = "<group>";
@@ -249,7 +279,6 @@
 			isa = PBXGroup;
 			children = (
 				2D7B61FA1678885A00E35E54 /* host.c */,
-				2D7B61FB1678885A00E35E54 /* include */,
 				2D7B62061678885A00E35E54 /* list.c */,
 				2D7B62071678885A00E35E54 /* memory.c */,
 				2D7B62081678885A00E35E54 /* packet.c */,
@@ -275,7 +304,8 @@
 				2D7B62031678885A00E35E54 /* utility.h */,
 				2D7B62041678885A00E35E54 /* win32.h */,
 			);
-			path = include;
+			name = include;
+			path = ../../Engine/src/enet/include;
 			sourceTree = "<group>";
 		};
 		2D7B623916788F7900E35E54 /* Game */ = {
@@ -460,6 +490,7 @@
 				2D7C17DE167AD6A500E1BBA1 /* user.c in Sources */,
 				2D7C17E0167ADE2000E1BBA1 /* pitch.c in Sources */,
 				2D4FB6FF167D430F00915887 /* sdl_midi.c in Sources */,
+				2D2A07CA168286D500064107 /* filesystem.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};