shithub: duke3d

Download patch

ref: ce68b45e19a6a013db19fea91bb806b67f744138
parent: de35673be6c8e287fb52170481acf76f882ecada
author: Fabien Sanglard <fabien.sanglard@gmail.com>
date: Thu Jan 31 19:09:02 EST 2013

Started refactoring GRP filesystem.

--- a/Engine/src/filesystem.c
+++ b/Engine/src/filesystem.c
@@ -15,7 +15,12 @@
 
 char game_dir[512];
 
-uint8_t  toupperlookup[256] =
+
+int32_t groupefil_crc32[MAXGROUPFILES];
+
+/*
+
+ 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,
@@ -35,10 +40,37 @@
 	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];
+*/
+
+typedef uint8_t grpIndexEntry_t[16]; //12 bytes for filename + 4 for filesize
+
+typedef struct grpArchive_s{
+    
+    int32_t  numFiles           ;//Number of files in the archive.
+    grpIndexEntry_t  *gfilelist   ;//Array containing the filenames.
+    int32_t  *gfileoffs         ;//Array containing the file offsets.
+    int32_t  *gfilesize         ;//Array containing the file offsets.
+    //uint8_t  *rawData           ;//Mem address from where files offsets start.
+    int fileDescriptor          ;//The fd used for open,read operations.
+    uint32_t crc32              ;//Hash to recognize GRP: Duke Shareware, Duke plutonimum etc...
+    
+} grpArchive_t;
+
+typedef struct grpSet_s{
+    grpArchive_t archives[MAXGROUPFILES];
+    int32_t num;
+} grpSet_t;
+
+// Marking it static gurantee not only invisility outside module
+// but also that the content will be set to 0.
+static grpSet_t grpSet;
+
+/*
 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
@@ -53,102 +85,125 @@
 	-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;
+	uint8_t         buf[16]                 ;
+	int32_t         i, j, k                 ;
+    grpArchive_t*   archive                 ;
+    uint8_t         crcBuffer[ 1 << 20]     ;
     
+    
 	printf("Loading %s ...\n", filename);
     
-	if (numgroupfiles >= MAXGROUPFILES) return(-1);
+	if (grpSet.num == MAXGROUPFILES){
+        printf("Error: Unable to open an extra GRP archive <= No more slot available.\n");
+        return(-1);
+    }
     
-	groupfil_memory[numgroupfiles] = NULL; // addresses of raw GRP files in memory
-	groupefil_crc32[numgroupfiles] = 0;
+    archive = &grpSet.archives[grpSet.num];
     
-	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);
-		}
+    //Init the slot
+    memset(archive, 0, sizeof(grpArchive_t));
+    
+	//groupfil_memory[numgroupfiles] = NULL; // addresses of raw GRP files in memory
+	//groupefil_crc32[numgroupfiles] = 0;
+    
+	archive->fileDescriptor = open(filename,O_BINARY|O_RDWR,S_IREAD);
+    
+    if (archive->fileDescriptor < 0){
+        printf("Error: Unable to open file %s.\n",filename);
+        getchar();
+        exit(0);
+    }
+    
+    
+    read(archive->fileDescriptor,buf,16);
+    
+    //FCS   : The ".grp" file format is just a collection of a lot of files stored into 1 big one.
+	//KS doc: 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
+    
+    // Check the magic number (12 bytes header).
+    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')){
+        printf("Error: File %s is not a GRP archive.\n",filename);
+        return(-1);
+    }
+    
+    
+	
+    
+    // The next 4 bytes of the header feature the number of files in the GRP archive.
+    archive->numFiles = BUILDSWAP_INTEL32(*((int32_t *)&buf[12]));
+    
+    
+    archive->gfilelist = kmalloc(archive->numFiles * sizeof(grpIndexEntry_t));
+    archive->gfileoffs = kmalloc(archive->numFiles * sizeof(int32_t));
+    archive->gfilesize = kmalloc(archive->numFiles * sizeof(int32_t));
+    
+    // Load the full index 16 bytes per file (12bytes for name + 4 bytes for the size).
+    read(archive->fileDescriptor,archive->gfilelist, archive->numFiles * 16);
+    
+    //Initialize all file offset and pointers.
+    j = 12 + archive->numFiles * sizeof(grpIndexEntry_t);
+    for(i=0;i<archive->numFiles;i++){
         
-		//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
+        k = BUILDSWAP_INTEL32(*((int32_t *)&archive->gfilelist[i][12])); // get size
         
-		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);
+        // Now that the filesize has been read, we can replace it with '0' and hence have a
+        // valid, null terminated character string that will be usable.
+        archive->gfilelist[i][12] = '\0';
+        archive->gfilesize[i] = k;
+        archive->gfileoffs[i] = j; // absolute offset list of all files.
+        j += k;
     }
+    //archive->gfileoffs[archive->numFiles-1] = j;
+	
     
-	// Compute CRC32 of thw whole grp and implicitely caches the GRP in memory through windows
-	lseek(groupfil[numgroupfiles], 0, SEEK_SET);
+	// Compute CRC32 of the whole grp and implicitely caches the GRP in memory through windows caching service.
+    // Rewind the fileDescriptor
+	lseek(archive->fileDescriptor, 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]);
+	//i = 1000000;
+	//groupfil_memory[numgroupfiles] = malloc(i);
+    
+    //Load the full GRP in RAM.
+	while((j=read(archive->fileDescriptor, crcBuffer, sizeof(crcBuffer)))){
+		archive->crc32 = crc32_update(crcBuffer,j,archive->crc32);
 	}
     
-	free(groupfil_memory[numgroupfiles]);
-	groupfil_memory[numgroupfiles] = 0;
+    // The game layer seems to absolutely need to access an array int[4] groupefil_crc32
+    // so we need to store the crc32 in there too.
+    groupefil_crc32[grpSet.num] = archive->crc32;
     
-	numgroupfiles++;
-	return(groupfil[numgroupfiles-1]);
+	//free(groupfil_memory[numgroupfiles]);
+	//groupfil_memory[numgroupfiles] = 0;
     
+    grpSet.num++;
+
+	return(grpSet.num-1);
+    
 }
 
 void uninitgroupfile(void)
 {
-	int32_t i;
+	int i;
     
-	for(i=numgroupfiles-1;i>=0;i--)
-		if (groupfil[i] != -1)
-		{
-			kfree(gfilelist[i]);
-			kfree(gfileoffs[i]);
-			close(groupfil[i]);
-			groupfil[i] = -1;
-		}
+	for( i=0 ; i < grpSet.num ;i++){
+        free(grpSet.archives[i].gfilelist);
+        free(grpSet.archives[i].gfileoffs);
+        free(grpSet.archives[i].gfilesize);
+        memset(&grpSet.archives[i], 0, sizeof(grpArchive_t));
+    }
     
 }
 
@@ -233,93 +288,112 @@
     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;
+
+enum fileType_e{ SYSTEM_FILE, GRP_FILE} ;
+
+//An entry in the array tracking open files
+typedef struct openFile_s{
+    enum fileType_e type ;
+    int fd        ;         //This can be either the fileDescriptor or the fileIndex in a GRP.
+    int cursor    ;
+    int grpID     ;
+    int used      ;
+} openFile_t;
+
+
+#define MAXOPENFILES 64
+static openFile_t openFiles[MAXOPENFILES];
+
+int32_t kopen4load(const char  *filename, int openOnlyFromGRP){
     
+	int32_t     i, k;
+    int32_t     newhandle;
+
+    grpArchive_t* archive;
+    
+    //Search a few slot
 	newhandle = MAXOPENFILES-1;
-	while (filehan[newhandle] != -1)
-	{
+	while (openFiles[newhandle].used && newhandle >= 0)
 		newhandle--;
-		if (newhandle < 0)
-		{
-			Error(EXIT_FAILURE, "Too Many files open!\n");
-		}
-	}
+	
+
+    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);
-			}
-		}
+
+    //Try to look in the filesystem first. In this case fd = filedescriptor.
+    if(!openOnlyFromGRP){
+        
+        openFiles[newhandle].fd = open(filename,O_BINARY|O_RDONLY);
+        
+        if (openFiles[newhandle].fd != -1){
+            openFiles[newhandle].type = SYSTEM_FILE;
+            openFiles[newhandle].cursor = 0;
+            openFiles[newhandle].used = 1;
+            return(newhandle); 
+        }
+    }
+
+    //Try to look in the GRP archives. In this case fd = index of the file in the GRP.
+	for(k=grpSet.num-1;k>=0;k--)
+	{
+        archive = &grpSet.archives[k];
+        
+        for(i=archive->numFiles-1;i>=0;i--){
+               
+            if (!strncasecmp((char*)archive->gfilelist[i],filename,12)){
+                
+                openFiles[newhandle].type = GRP_FILE;
+                openFiles[newhandle].used = 1;
+                openFiles[newhandle].cursor = 0;
+                openFiles[newhandle].fd = i;
+                openFiles[newhandle].grpID = k;                
+                return(newhandle);
+            }
+        }
 	}
+    
 	return(-1);
     
 }
 
-int32_t kread(int32_t handle, void *buffer, int32_t leng)
-{
-	int32_t i, filenum, groupnum;
+int32_t kread(int32_t handle, void *buffer, int32_t leng){
     
-	filenum = filehan[handle];
-	groupnum = filegrp[handle];
+    openFile_t      * openFile ;
+    grpArchive_t    * archive  ;
     
-	if (groupnum == 255) // Reading external
-	{
-		return(read(filenum,buffer,leng));
-	}
+    openFile = &openFiles[handle];
     
-	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);
-	}
+    if (!openFile->used){
+        printf("Invalide handle. Unrecoverable error.\n");
+        getchar();
+        exit(0);
+    }
     
-	return(0);
+    //FILESYSTEM ? OS takes care of it !
+    if (openFile->type == SYSTEM_FILE){
+        return(read(openFile->fd,buffer,leng));
+    }
     
+    //File is actually in the GRP
+    archive = & grpSet.archives[openFile->grpID];
+        
+    lseek(archive->fileDescriptor,
+          archive->gfileoffs[openFile->fd] + openFile->cursor,
+          SEEK_SET);
+    
+    //Adjust leng so we cannot read more than filesystem-cursor location.
+    leng = min(leng,archive->gfilesize[openFile->fd]-openFile->cursor);
+    
+    leng = read(archive->fileDescriptor,buffer,leng);
+    
+    openFile->cursor += leng;
+	
+    return leng;
+    
 }
 
-int kread16(int32_t handle, short *buffer)
-{
+int kread16(int32_t handle, short *buffer){
     if (kread(handle, buffer, 2) != 2)
         return(0);
     
@@ -327,8 +401,7 @@
     return(1);
 }
 
-int kread32(int32_t handle, int32_t *buffer)
-{
+int kread32(int32_t handle, int32_t *buffer){
     if (kread(handle, buffer, 4) != 4)
         return(0);
     
@@ -336,8 +409,7 @@
     return(1);
 }
 
-int kread8(int32_t handle, uint8_t  *buffer)
-{
+int kread8(int32_t handle, uint8_t  *buffer){
     if (kread(handle, buffer, 1) != 1)
         return(0);
     
@@ -344,32 +416,37 @@
     return(1);
 }
 
-int32_t klseek(int32_t handle, int32_t offset, int32_t whence)
-{
-	int32_t i, groupnum;
+int32_t klseek(int32_t handle, int32_t offset, int whence){
     
-	groupnum = filegrp[handle];
+    grpArchive_t* archive;
+	
+    if (!openFiles[handle].used){
+        printf("Invalide handle. Unrecoverable error.\n");
+        getchar();
+        exit(0);
+    }
     
-	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);
+    // FILESYSTEM ? OS will take care of it.
+    if (openFiles[handle].type == SYSTEM_FILE){
+        return lseek(openFiles[handle].fd,offset,whence);
+    }
     
+    
+    archive = & grpSet.archives [   openFiles[handle].grpID ];
+	
+    switch(whence){
+        case SEEK_SET: openFiles[handle].cursor = offset; break;
+        case SEEK_END: openFiles[handle].cursor = archive->gfilesize[openFiles[handle].fd]; break;
+        case SEEK_CUR: openFiles[handle].cursor += offset; break;
+    }
+    
+    return(openFiles[handle].cursor);
+	
+	
 }
 
 #ifdef __APPLE__
-int32_t filelength(int32_t fd)
-{
+int32_t filelength(int32_t fd){
     struct stat stats;
     fstat(fd, &stats);
     return (int32_t )stats.st_size;
@@ -378,21 +455,45 @@
 
 int32_t kfilelength(int32_t handle)
 {
-	int32_t i, groupnum;
+	openFile_t* openFile = &openFiles[handle];
     
-	groupnum = filegrp[handle];
-	if (groupnum == 255) return(filelength(filehan[handle]));
-	i = filehan[handle];
-	return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]);
+    if (!openFile->used){
+        printf("Invalide handle. Unrecoverable error.\n");
+        getchar();
+        exit(0);
+    }
     
+    if (openFile->type == SYSTEM_FILE){
+        return(filelength(openFile->fd));
+    }
+    
+    else{
+        grpArchive_t* archive = &grpSet.archives[ openFile->grpID ];
+        return archive->gfilesize[openFile->fd];
+    }
+    
 }
 
 void kclose(int32_t handle)
 {
-	if (handle < 0) return;
-	if (filegrp[handle] == 255) close(filehan[handle]);
-	filehan[handle] = -1;
+    openFile_t* openFile = &openFiles[handle];
     
+    //This is a typical handle for a non existing file.
+    if (handle == -1)
+        return;
+    
+    if (!openFile->used){
+        printf("Invalide handle. Unrecoverable error.\n");
+        getchar();
+        exit(0);
+    }
+    
+    if (openFile->type == SYSTEM_FILE){
+        close(openFile->fd);
+    }
+	
+    memset(openFile, 0, sizeof(openFile_t));
+    
 }
 
 
@@ -670,4 +771,7 @@
     return game_dir;
 }
 
-
+int      getGRPcrc32(int grpID){
+    
+    return grpSet.archives[grpID].crc32;
+}
--- a/Engine/src/filesystem.h
+++ b/Engine/src/filesystem.h
@@ -12,21 +12,23 @@
 #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  */
 
-extern int32_t groupefil_crc32[4];
 
+extern int32_t groupefil_crc32[MAXGROUPFILES];
+
 int32_t  initgroupfile(const char  *filename);
 void     uninitgroupfile(void);
 uint16_t crc16(uint8_t  *data_p, uint16_t length);
 uint32_t crc32_update(uint8_t  *buf, uint32_t length, uint32_t crc_to_update);
-int32_t  kopen4load(const char  *filename, int readfromGRP);
+int32_t  kopen4load(const char  *filename, int openOnlyFromGRP);
 int32_t  kread(int32_t handle, void *buffer, int32_t leng);
 int32_t  kread8(int32_t handle, uint8_t  *buffer);
 int32_t  kread16(int32_t handle, int16_t *buffer);
 int32_t  kread32(int32_t handle, int32_t *buffer);
-int32_t  klseek(int32_t handle, int32_t offset, int32_t whence);
+int32_t  klseek(int32_t handle, int32_t offset, int 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);
@@ -33,6 +35,7 @@
 void     dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil);
 void     dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil);
 
+int      getGRPcrc32(int grpID);
 
 char*    getGameDir(void);
 void     setGameDir(char* gameDir);
--- a/Game/src/duke3d.h
+++ b/Game/src/duke3d.h
@@ -121,9 +121,9 @@
 
 // implies  conVersion == 14 or conVersion == 15
 #define PLUTOPAK  (!VOLUMEONE && !VOLUMEALL) 
-#define VOLUMEONE (groupefil_crc32[0]==CRC_BASE_GRP_SHAREWARE_13)
+#define VOLUMEONE (getGRPcrc32(0)==CRC_BASE_GRP_SHAREWARE_13)
 // VOLUMEALL = 1.3d full
-#define VOLUMEALL (groupefil_crc32[0]==CRC_BASE_GRP_FULL_13 || conVersion == 13 && groupefil_crc32[0]!=CRC_BASE_GRP_SHAREWARE_13 && groupefil_crc32[0]!=CRC_BASE_GRP_PLUTONIUM_14 && groupefil_crc32[0]!=CRC_BASE_GRP_ATOMIC_15)
+#define VOLUMEALL (getGRPcrc32(0)==CRC_BASE_GRP_FULL_13 || conVersion == 13 && getGRPcrc32(0)!=CRC_BASE_GRP_SHAREWARE_13 && getGRPcrc32(0)!=CRC_BASE_GRP_PLUTONIUM_14 && getGRPcrc32(0)!=CRC_BASE_GRP_ATOMIC_15)
 
 #define SCREENSHOTPATH "screenshots"
 
--- a/Game/src/gamedef.c
+++ b/Game/src/gamedef.c
@@ -1588,7 +1588,7 @@
     *script = (int32_t) scriptptr;
 
     if(warning|error)
-        printf("Found %hhd warning(s), %c error(s).\n",warning,error);
+        printf("Found %hhd warning(s), '%c' error(s).\n",warning,error);
 
     if(error)
     {
@@ -1608,8 +1608,8 @@
 			// FIX_00022: Automatically recognize the shareware grp (v1.3) + full version (1.3d) +
 			//            atomic (1.4/1.5 grp) and the con files version (either 1.3 or 1.4) (JonoF's idea)
 
-		if(conVersion != 13 && (groupefil_crc32[0]==CRC_BASE_GRP_SHAREWARE_13 || 
-			groupefil_crc32[0]==CRC_BASE_GRP_FULL_13) && !groupefil_crc32[1])
+		if(conVersion != 13 && (getGRPcrc32(0)==CRC_BASE_GRP_SHAREWARE_13 ||
+			getGRPcrc32(0)==CRC_BASE_GRP_FULL_13) && !getGRPcrc32(1))
 		{
 			printf(	"\nYou are trying to use a v1.3 Shareware/Full *.GRP with v1.4 or v1.5\n"
 					"external *.CON files. You may run in troubles by doing so and/or get\n"
@@ -1627,7 +1627,7 @@
 				loadefs(filenam, mptr, 1); // force GRP con files
 			}
 		}
-		else if(conVersion != 15 && groupefil_crc32[0]==CRC_BASE_GRP_ATOMIC_15 && !groupefil_crc32[1])
+		else if(conVersion != 15 && getGRPcrc32(0)==CRC_BASE_GRP_ATOMIC_15 && !getGRPcrc32(1))
 		{
 			printf(	"\nYou are trying to use a v1.5 ATOMIC *.GRP with v1.4 or v1.3\n"
 					"external *.CON files. You may run in troubles by doing so and/or get\n"
@@ -1643,7 +1643,7 @@
 			{
 				loadefs(filenam, mptr, 1); // force GRP con files
 			}
-		}else if(conVersion != 14 && groupefil_crc32[0]==CRC_BASE_GRP_PLUTONIUM_14 && !groupefil_crc32[1])
+		}else if(conVersion != 14 && getGRPcrc32(0)==CRC_BASE_GRP_PLUTONIUM_14 && !getGRPcrc32(1))
 		{
 			printf(	"\nYou are trying to use a v1.4 PLUTONIUM *.GRP with v1.3 or v1.5\n"
 					"external *.CON files. You may run in troubles by doing so and/or get\n"