/* MiniZip 1.00, demo of zLib + Zip package written by Gilles Vollant
	Modifie le 2 juin 2004 JPC
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>

#ifdef unix
# include <unistd.h>
# include <utime.h>
# include <sys/types.h>
# include <sys/stat.h>
#else
# include <direct.h>
# include <io.h>
#endif

#include "zip.h"

#ifdef WIN32
//#define USEWIN32IOAPI
#include "iowin32.h"
#endif



#define WRITEBUFFERSIZE (16384)
#define MAXFILENAME (1024)

int g_Verbose = 1;


/*****************************/
uLong filetime(
	const char *filename,	/* name of file to get info on */
	tm_zip *tmzip,			/* return value: access, modific. and creation times */
	uLong *dt)				/* dostime */
/*****************************/
#ifdef WIN32
{
  int ret = 0;
  {
	  FILETIME ftLocal;
	  HANDLE hFind;
	  WIN32_FIND_DATA  ff32;

	  hFind = FindFirstFile(filename,&ff32);
	  if (hFind != INVALID_HANDLE_VALUE)
	  {
		FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
		FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
		FindClose(hFind);
		ret = 1;
	  }
  }
  return ret;
}
#else
#ifdef unix
{
int ret=0;
struct stat s;		/* results of stat() */
struct tm* filedate;
time_t tm_t=0;

  if (strcmp(filename,"-")!=0)
  {
	char name[MAXFILENAME+10];
	int len = strlen(filename);

	strncpy(name, filename,MAXFILENAME);
	/* strncpy doesnt append the trailing NULL, of the string is too long. */
	name[ MAXFILENAME ] = '\0';

	if (name[len - 1] == '/')
	  name[len - 1] = '\0';
	/* not all systems allow stat'ing a file with / appended */
	if (stat(name,&s)==0)
	{
	  tm_t = s.st_mtime;
	  ret = 1;
	}
  }
  filedate = localtime(&tm_t);

  tmzip->tm_sec  = filedate->tm_sec;
  tmzip->tm_min  = filedate->tm_min;
  tmzip->tm_hour = filedate->tm_hour;
  tmzip->tm_mday = filedate->tm_mday;
  tmzip->tm_mon  = filedate->tm_mon ;
  tmzip->tm_year = filedate->tm_year;

  return ret;
}
#else
{
	return 0;
}
#endif
#endif



/*******************************************/
int check_exist_file( const char* filename)
/*******************************************/
{
	FILE* ftestexist;
	int ret = 1;
	ftestexist = fopen(filename,"rb");
	if (ftestexist == NULL) ret = 0;
	else fclose(ftestexist);
	return ret;
}

/* calculate the CRC32 of a file,
   because to encrypt a file, we need known the CRC32 of the file before */
int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc)
{
unsigned long calculate_crc=0;
int err=ZIP_OK;
FILE * fin = fopen(filenameinzip,"rb");
unsigned long size_read = 0;
unsigned long total_read = 0;
	
   if (fin==NULL)
   {
	   err = ZIP_ERRNO;
   }

	if (err == ZIP_OK)
		do
		{
			err = ZIP_OK;
			size_read = (int)fread(buf,1,size_buf,fin);
			if (size_read < size_buf)
				if (feof(fin)==0)
			{
				printf("error in reading %s\n",filenameinzip);
				err = ZIP_ERRNO;
			}

			if (size_read>0)
				calculate_crc = crc32(calculate_crc,buf,size_read);
			total_read += size_read;

		} while ((err == ZIP_OK) && (size_read>0));

	if (fin)
		fclose(fin);

	*result_crc=calculate_crc;
	if ( g_Verbose ) printf("file %s crc %lx\n",filenameinzip,calculate_crc);
	return err;
}

/********************************/
int main( int argc, char *argv[])
/********************************/
{
int i;
int opt_overwrite=0;
int opt_compress_level=Z_DEFAULT_COMPRESSION;
int zipfilenamearg = 0;
char filename_try[MAXFILENAME+16];
int zipok;
int err=0;
int size_buf=0;
void* buf=NULL;
const char* password=NULL;

	if (argc <= 1)
	{
		printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] file.zip [files_to_add]\n\n" \
		   "  -o  Overwrite existing file.zip\n" \
		   "  -a  Append to existing file.zip\n" \
		   "  -0  Store only, -1  Compress faster, -9  Compress better [5]\n\n");
		return 0;
	}

	for (i = 1; i < argc; i++)
	{
		if ((*argv[i])=='-')	/* Find options */
		{
			const char *p=argv[i]+1;

			while ((*p)!='\0')
			{
				char c=*(p++);
				if ((c=='o') || (c=='O'))
					opt_overwrite = 1;
				else if ((c=='a') || (c=='A'))
					opt_overwrite = 2;
				else if ((c>='0') && (c<='9'))
					opt_compress_level = c-'0';

				else if (((c=='p') || (c=='P')) && (i+1<argc))
				{
					password=argv[i+1];
					i++;
				}
				else
				{
					printf ( "Unknown option %c\n", c);
					err = 1;
				}
			}
		}
		else if (zipfilenamearg == 0) zipfilenamearg = i ;
	}
	
	if ( err ) return 0;

	size_buf = WRITEBUFFERSIZE;
	buf = (void*)malloc(size_buf);
	if (buf==NULL)
	{
		printf("Error allocating memory\n");
		return ZIP_INTERNALERROR;
	}

	if (zipfilenamearg==0) zipok=0;
	else
	{
		int len;
		int dot_found=0;

		zipok = 1 ;
		strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME);
		/* strncpy doesnt append the trailing NULL, of the string is too long. */
		filename_try[ MAXFILENAME ] = '\0';

		len=(int)strlen(filename_try);
		for (i=0;i<len;i++)
			if (filename_try[i]=='.')
				dot_found=1;

		if (dot_found==0)
			strcat(filename_try,".zip");

		if (opt_overwrite==2)
		{
			/* if the file don't exist, we not append file */
			if (check_exist_file(filename_try)==0)
				opt_overwrite=1;
		}
		else
		if (opt_overwrite==0)
			if (check_exist_file(filename_try)!=0)
			{
				char rep=0;
				do
				{
					char answer[128];
					printf("The file %s exist. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try);
					scanf("%1s",answer);
					rep = answer[0] ;
					if ((rep>='a') && (rep<='z'))
						rep -= 0x20;
				}
				while ((rep!='Y') && (rep!='N') && (rep!='A'));
				if (rep=='N') zipok = 0;
				if (rep=='A') opt_overwrite = 2;
			}
	}

	if (zipok==1)
	{
		zipFile zf;
		int errclose;
#ifdef USEWIN32IOAPI
		zlib_filefunc_def ffunc;
		fill_win32_filefunc(&ffunc);
		zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc);
#else
		zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0);
#endif

		if (zf == NULL)
		{
			printf("error opening %s\n",filename_try);
			err= ZIP_ERRNO;
		}
		else
			if ( g_Verbose ) printf("creating %s\n",filename_try);

		for (i=zipfilenamearg+1; (i<argc) && (err==ZIP_OK); i++)
		{
			if (((*(argv[i]))!='-') && ((*(argv[i]))!='/'))
			{
				FILE * fin = NULL;
				int size_read;
				const char* filenameinzip = argv[i];
				zip_fileinfo zi;
				unsigned long crcFile=0;

				zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
				zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
				zi.dosDate = 0;
				zi.internal_fa = 0;
				zi.external_fa = 0;
				filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);

/*
				err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
								 NULL,0,NULL,0,NULL / * comment * /,
								 (opt_compress_level != 0) ? Z_DEFLATED : 0,
								 opt_compress_level);
*/
				if ((password != NULL) && (err==ZIP_OK))
					err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);

				err = zipOpenNewFileInZip3(zf,filenameinzip,&zi,
								 NULL,0,NULL,0,NULL /* comment*/,
								 (opt_compress_level != 0) ? Z_DEFLATED : 0,
								 opt_compress_level,0,
								 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
								 password,crcFile);

				if (err != ZIP_OK)
					printf("error in opening %s in zipfile\n",filenameinzip);
				else
				{
					fin = fopen(filenameinzip,"rb");
					if (fin==NULL)
					{
						err=ZIP_ERRNO;
						printf("error in opening %s for reading\n",filenameinzip);
					}
				}

				if (err == ZIP_OK)
					do
					{
						err = ZIP_OK;
						size_read = (int)fread(buf,1,size_buf,fin);
						if (size_read < size_buf)
							if (feof(fin)==0)
						{
							printf("error in reading %s\n",filenameinzip);
							err = ZIP_ERRNO;
						}

						if (size_read>0)
						{
							err = zipWriteInFileInZip (zf,buf,size_read);
							if (err<0)
							{
								printf("error in writing %s in the zipfile\n",
												 filenameinzip);
							}

						}
					} while ((err == ZIP_OK) && (size_read>0));

				if (fin) fclose(fin);

				if (err<0) err=ZIP_ERRNO;
				else
				{
					err = zipCloseFileInZip(zf);
					if (err!=ZIP_OK)
						printf("error in closing %s in the zipfile\n",
									filenameinzip);
				}
			}
		}
		errclose = zipClose(zf,NULL);
		if (errclose != ZIP_OK)
			printf("error in closing %s\n",filename_try);
   }

	free(buf);
	return 0;
}
