/* MoleInvasion - Copyright (C) - Guillaume Chambraud (linuxprocess@free.fr)

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version. */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#ifndef WIN32
	#include <sys/mman.h>
	#include <pwd.h>
#endif
 
#include "tool.h"

#include <errno.h>

/* see : http://www.w3.org/TR/PNG/#D-CRCAppendix */
/* Table of CRCs of all 8-bit messages. */
unsigned long crc_table[256];

/* Flag: has the table been computed? Initially false. */
int crc_table_computed = 0;

/* Make the table for a fast CRC. */
void make_crc_table(void)
{
  unsigned long c;
  int n, k;

  for (n = 0; n < 256; n++) {
    c = (unsigned long) n;
    for (k = 0; k < 8; k++) {
      if (c & 1)
	c = 0xedb88320L ^ (c >> 1);
      else
	c = c >> 1;
    }
    crc_table[n] = c;
  }
  crc_table_computed = 1;
}


/* Update a running CRC with the bytes buf[0..len-1]--the CRC
   should be initialized to all 1's, and the transmitted value
   is the 1's complement of the final running CRC (see the
   crc() routine below). */

unsigned long update_crc(unsigned long crc, unsigned char *buf,
			 int len)
{
  unsigned long c = crc;
  int n;

  if (!crc_table_computed)
    make_crc_table();
  for (n = 0; n < len; n++) {
    c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
  }
  return c;
}

/* calcule le CRC32 du fichier fourni */
unsigned long fileCRC(char * file_name)
{	void * ptr;
	unsigned long ret;
	struct stat statb;
	int fd,mapfailed;
	
	fd=open(file_name,O_RDONLY);
	if(fd<0)
	{	fprintf(stderr,"Cannot open %s : %s\n",file_name,strerror(errno));
		return 0;
	}
	if(fstat(fd,&statb))
	{	fprintf(stderr,"Cannot fstat %s : %s\n",file_name,strerror(errno));
		return 0;
	}
	mapfailed=0;
/* is mmap() available ? */
#ifdef _POSIX_MAPPED_FILES
	ptr=mmap(0,statb.st_size,PROT_READ,MAP_PRIVATE,fd,0);
	if(ptr==MAP_FAILED)
#endif
	{	mapfailed=1;
		/* no nmap() ... do it myself */
		unsigned char *ptr2,buff[256];
		int lu;
		ptr=malloc(statb.st_size);
		ptr2=ptr;
		while((lu=read(fd,buff,sizeof(buff)))==sizeof(buff))
		{	memcpy(ptr2,buff,lu);
			ptr2+=lu;
		}
		memcpy(ptr2,buff,lu);
	}

	ret=update_crc(0xffffffffL, ptr, statb.st_size) ^ 0xffffffffL;
	
	if(mapfailed)
		free(ptr);
#ifdef _POSIX_MAPPED_FILES
	else
		munmap(ptr,statb.st_size);
#endif
	close(fd);

	return ret;
}

char * get_config_directory(char * filename)
{	char *dir_ch, *ret_ch;
#ifndef WIN32
	struct passwd * user;
#endif
	assert(filename);
	
/* recuperation du home directory */
#ifndef WIN32
	user=getpwuid(getuid());
	dir_ch=(char*)malloc(strlen(user->pw_dir)+2+strlen(APP_NAME)+1);
	assert(dir_ch);
	sprintf(dir_ch,"%s/.%s",user->pw_dir,APP_NAME);
	mkdir(dir_ch, 0777);
#else
	if(getenv("APPDATA"))
	{	dir_ch=(char*)malloc(strlen(getenv("APPDATA"))+1+strlen(APP_NAME)+1);
		assert(dir_ch);
		sprintf(dir_ch,"%s/%s",getenv("APPDATA"),APP_NAME);
	}
	else
	{	dir_ch=(char*)malloc(512);
		assert(dir_ch);
		getcwd(dir_ch,512);
		assert(dir_ch);
		snprintf(dir_ch,512,"%s/%s",dir_ch,APP_NAME);
	}
	mkdir(dir_ch);
#endif
	ret_ch=(char*)malloc(strlen(dir_ch)+1+strlen(filename)+1);
	assert(ret_ch);
	sprintf(ret_ch,"%s/%s",dir_ch,filename);
	free(dir_ch);
	
	return ret_ch;
}
