#include "stdafx.h"
#include "_zip.h"
#include "igt_error.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
//*****************************************************************************************************
Cigt_zip::Cigt_zip(void)
{
	nivel_compresion=6;
	uf=NULL;
	zf=NULL;
	igt_err=new Cigt_error();
	borrar_error=TRUE;
	nombre_zip[0]='\0';
}
//*****************************************************************************************************
Cigt_zip::Cigt_zip(Cigt_error *err)
{
	nombre_zip[0]='\0';
	nivel_compresion=6;
	uf=NULL;
	zf=NULL;
	borrar_error=FALSE;
	igt_err=err;
}
//*****************************************************************************************************
Cigt_zip::~Cigt_zip(void)
{
	cierra_zip();
	if (borrar_error&&igt_err)
	{
		delete igt_err;
	}
	igt_err=NULL;

}
//*****************************************************************************************************
int Cigt_zip::isLargeFile(char* filename )
{
	int largeFile = 0;
	ZPOS64_T pos = 0;
	FILE* pFile = fopen64(filename, "rb");

	if(pFile != NULL)
	{
		int n = fseeko64(pFile, 0, SEEK_END);

		pos = ftello64(pFile);
		if(pos >= 0xffffffff)
			largeFile = 1;

		fclose(pFile);
	}

	return largeFile;
}
//**************************************************************************************************************
BOOL Cigt_zip::abre_zip( char *filename, int parametro )
{
	int esc;
	zlib_filefunc64_def ffunc;
	fill_win32_filefunc64A(&ffunc);
	if (parametro==READ)
	{
		cierra_zip_uf();
		uf = new unzFile();
		*uf = unzOpen2_64(filename,&ffunc);
		if (uf==NULL)
		{
			Cigt_error::pon_winerror("Cigt_zip",igt_err);
			return FALSE;
		}
		strcpy(nombre_zip,filename);
		return TRUE;
	}
	if (parametro==OWERWRITE)
	{
		esc=0;
	}
	else
		esc=2;
	cierra_zip_zf();
	zf= new zipFile();
	*zf = zipOpen2_64(filename,esc,NULL,&ffunc);//
	if (zf == NULL)//
	{
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
		return FALSE;
	}
	strcpy(nombre_zip,filename);
	return TRUE;
}
//*****************************************************************************
BOOL Cigt_zip::addfile(char *newfile, char *dir_in_zip )
{
	FILE *fin;
	int err=0,size_read=0;
	int zip64=0;
	zip_fileinfo zi;
	unsigned long crcFile=0;
	char *password=NULL;
	int size_buf = WRITEBUFFERSIZE;
	if (!zf)
	{
		igt_err->pon_error("Cigt_zip","puntero del handle nulo",-1);
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
		return FALSE;
	}
	void *buf = (void*)malloc(size_buf);
	
	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(newfile,&zi.tmz_date,(long*)&zi.dosDate);
	err = getFileCrc(newfile,buf,size_buf,&crcFile);//preparamos crc
	zip64 = isLargeFile(newfile);
	err = zipOpenNewFileInZip3_64(*zf,dir_in_zip,&zi,
		NULL,0,NULL,0,NULL /* comment*/,
		8,nivel_compresion,0,
		-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
		password,crcFile, zip64);//preparamos el zip
	if (err != ZIP_OK)
	{
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
	}
	else
	{
		fin = fopen64(newfile,"rb");//abre el archivo a meter en zip
		if (fin==NULL)
		{
			err=ZIP_ERRNO;
			//printf("error in opening %s for reading\n",newfile);
		}
	}
	if (err == ZIP_OK)
	{
		do// bucle para escribir el archivo en zip
		{
			err = ZIP_OK;
			size_read = (int)fread(buf,1,size_buf,fin);//leemos parte
			if (size_read < size_buf)
				if (feof(fin)==0)
				{
					Cigt_error::pon_winerror("Cigt_zip",igt_err);
					err = ZIP_ERRNO;
				}

				if (size_read>0)
				{
					err = zipWriteInFileInZip (*zf,buf,size_read);
					if (err<0)
					{
						Cigt_error::pon_winerror("Cigt_zip",igt_err);
						err = ZIP_ERRNO;
					}
				}
		} while ((err == ZIP_OK) && (size_read>0));
	}
	if (fin)
		fclose(fin);//cierra el archivo metido
	if (buf)
	{
		free(buf);
	}
	if (err<0)//si errores
		return FALSE;
	return TRUE;
}
//*****************************************************************************************************
BOOL Cigt_zip::cierra_zip_zf()
{
	int errclose= ZIP_OK;
	if(zf)
	{
		errclose = zipClose(*zf,NULL);
		if (errclose != ZIP_OK)
		{
			Cigt_error::pon_winerror("Cigt_zip",igt_err);
			return FALSE;
		}
		zf=NULL;
	}
	return TRUE;
	
}
//*****************************************************************************************************
/* calculate the CRC32 of a file,
   because to encrypt a file, we need known the CRC32 of the file before */
int Cigt_zip::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 = fopen64(filenameinzip,"rb");
   unsigned long size_read = 0;
   unsigned long total_read = 0;
   if (fin==NULL)
   {
	   Cigt_error::pon_winerror("Cigt_zip",igt_err);
       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)
            {
               Cigt_error::pon_winerror("Cigt_zip",igt_err);
                err = ZIP_ERRNO;
            }

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

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

    if (fin)
        fclose(fin);

    *result_crc=calculate_crc;
    //printf("file %s crc %lx\n", filenameinzip, calculate_crc);
    return err;
}
//*****************************************************************************************************
int Cigt_zip::filetime( char *f, tm_zip *tmzip, long *dt_ )
{
	uLong *dt=(uLong *)dt_;
	int ret = 0;
	{
		FILETIME ftLocal;
		HANDLE hFind;
		WIN32_FIND_DATAA ff32;
		hFind = FindFirstFileA(f,&ff32);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
			FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
			FindClose(hFind);
			ret = 1;
		}
	}
	return ret;
}
//*****************************************************************************************************
BOOL Cigt_zip::cierra_zip()
{
	BOOL resul;
	resul=cierra_zip_uf();
	return cierra_zip_zf() && resul;
}

//*****************************************************************************************************
BOOL Cigt_zip::descomprimir(char *file, char *fileout,BYTE **bufex,int *nb )
{
	FILE *fout=NULL;
	int err = UNZ_OK;
	int mb;
	BYTE (*bufsal)[];
	bufsal=NULL;
	int size_buf=0;
	const char* password=NULL;
	//zlib_filefunc64_def ffunc;
	void *buf;
	unz_file_info64 file_info;
	char path_inzip[256];
	if (!uf)
	{
		igt_err->pon_error("Cigt_zip","Error al descomprimir: puntero del handle uf nulo",-1);
		return FALSE;
	}
	//int ret_value = do_extract_onefile(uf, file, 0, 0, "\0");
	if (unzLocateFile(uf,file,CASESENSITIVITY)!=UNZ_OK)//comprueba que esta el archivo en el zip
	{
		char str[250];
		sprintf(str,"Cigt_zip","Error al descomprimir: el archivo %s no se encuentra en el zip",file);
		igt_err->pon_error("Cigt_zip",str,-1);
		return FALSE;
	}

	
	err = unzGetCurrentFileInfo64(uf,&file_info,path_inzip,sizeof(path_inzip),NULL,0,NULL,0);
	if (err!=UNZ_OK)
	{
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
		return FALSE;
	}

	size_buf = WRITEBUFFERSIZE;
	buf = (void*)malloc(size_buf);
	if (buf==NULL)
	{
		char str[256];
		sprintf(str,"Cigt_zip","Error al descomprimir: no se puede reservar memoria para buf de %ld bytes",size_buf);
		igt_err->pon_error("Cigt_zip",str,-1);
		return FALSE;
	}
	err = unzOpenCurrentFilePassword(uf,password);
	if (err!=UNZ_OK)
	{
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
		return FALSE;
	}
	if (fileout)
		fout=fopen64(fileout,"wb");
	else
	{
		*nb=0;
		mb=WRITEBUFFERSIZE*5;
		bufsal = (BYTE (*)[])malloc(mb);
	}
	/* some zipfile don't contain directory alone before file */
	if (fout!=NULL||!fileout)
	{
		do//bucle para escribir archivo
		{
			err = unzReadCurrentFile(uf,buf,size_buf);
			if (err<0)
			{
				Cigt_error::pon_winerror("Cigt_zip",igt_err);
				break;
			}
			if (err>0)
				if(fileout)
				{
					if (fwrite(buf,err,1,fout)!=1)
					{
						Cigt_error::pon_winerror("Cigt_zip",igt_err);
						err=UNZ_ERRNO;
						break;
					}
				}
				else
				{
					if ((*nb+err)>=mb)
					{
						mb+=WRITEBUFFERSIZE*5;
						bufsal=(BYTE(*)[])realloc(bufsal,mb);
					}
					memcpy(&(*bufsal)[*nb],buf,err);
					*nb+=err;
				}
		}
		while (err>0);
	}
	if (fout)
		fclose(fout);
	free(buf);
	if (err==UNZ_OK)
	{
		if (fileout)
		{
			change_file_date(fileout,file_info.dosDate,
			file_info.tmu_date);
		}
		else
		{
			*bufex=(BYTE*)bufsal;
		}
		return TRUE;
	}
	if (bufsal)
	{
		free(bufsal);
	}
	return FALSE;
}
//*****************************************************************************************************
BOOL Cigt_zip::descomprimir()
{
	int n;
	Zip_struct (*contenido)[];
	contenido= (Zip_struct(*)[])listar(&n);
	if (n<=0)
		return FALSE;
	for (int i=0; i<n;i++)
	{
		if (!descomprimir2file((*contenido)[i].nombre))
		{
			free(contenido);
			return FALSE;
		}
	}
	free(contenido);
	return TRUE;
}
//*****************************************************************************************************
void Cigt_zip::change_file_date(const char *filename,uLong dosdate,tm_unz tmu_date)
{
	HANDLE hFile;
	FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;

	hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE,
		0,NULL,OPEN_EXISTING,0,NULL);
	GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
	DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
	LocalFileTimeToFileTime(&ftLocal,&ftm);
	SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
	CloseHandle(hFile);
}
//*****************************************************************************************************
BOOL Cigt_zip::descomprimir2file( char *file,char *fileout )
{
	if (fileout)
		return descomprimir(file,fileout,NULL,NULL);
	return FALSE;
}
//*****************************************************************************************************
BOOL Cigt_zip::descomprimir2file( char *file )
{
	char fileout[256];
	int i;
	int j;
	strcpy(fileout,nombre_zip);
	for (i=strlen(fileout);i>=0;i--)
	{
		if(fileout[i]=='\\')
		{
			fileout[i]='\\';
			i++;
			fileout[i]='\0';
			break;
		}
	}
	if (i<0)
		i=0;
	for(j=0; *(file+j); j++)
	{
		if (*(file+j)=='\\')
		{
			*(fileout+j+i)='\0';
			if(!crea_dir(fileout))
			{
				return FALSE;
			}
		}
		*(fileout+j+i)=*(file+j);
	}
	*(fileout+j+i)='\0';
	return descomprimir2file(file,fileout);
}
//*****************************************************************************************************
BOOL Cigt_zip::descomprimir2buff(char *file,BYTE **buf,int *nb )
{
	return descomprimir(file,NULL,buf,nb);
}
//*****************************************************************************************************
Zip_struct* Cigt_zip::listar(int* n)
{
	int err = UNZ_OK;
	//zlib_filefunc64_def ffunc;
	unz_file_info64 file_info;
	uLong i;
	unz_global_info64 gi;
	//char path_inzip[256];
	*n=0;
	Zip_struct (*salida)[];
	salida=NULL;

	err = unzGetGlobalInfo64(uf,&gi);
	if (err!=UNZ_OK)
	{
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
	}
	if (gi.number_entry<=0)
	{
		igt_err->pon_error("Cigt_zip","Error en listar: en número de archivos del zip es <=0");
		return NULL;
	}
	salida=(Zip_struct(*)[])malloc(sizeof(Zip_struct)*gi.number_entry);
	*n=gi.number_entry;
	for (i=0;i<gi.number_entry;i++)
	{
		err = unzGetCurrentFileInfo64(uf,&file_info,(*salida)[i].nombre,sizeof((*salida)[i].nombre),NULL,0,NULL,0);
		if (err!=UNZ_OK)
		{
			Cigt_error::pon_winerror("Cigt_zip",igt_err);
			break;
		}
		if (file_info.uncompressed_size>0)
		{
			(*salida)[i].ratio = (int)((file_info.compressed_size*100)/file_info.uncompressed_size);
			(*salida)[i].size_descom=(int)file_info.uncompressed_size;
		}
		else
		{
			(*salida)[i].ratio = 0;
			(*salida)[i].size_descom=0;
		}
		/* display a '*' if the file is crypted */
		if ((file_info.flag & 1) != 0)
			(*salida)[i].encript=TRUE;
		else
			(*salida)[i].encript=FALSE;

		(*salida)[i].compresion=file_info.compression_method;
		(*salida)[i].size=file_info.compressed_size;

		if ((i+1)<gi.number_entry)
		{
			err = unzGoToNextFile(uf);
			if (err!=UNZ_OK)
			{
				Cigt_error::pon_winerror("Cigt_zip",igt_err);
				break;
			}
		}
	}
	return (Zip_struct *)salida;
}
//*****************************************************************************************************
BOOL Cigt_zip::cierra_zip_uf()
{
	int err=UNZ_OK;
	if (uf)
	{
		err = unzCloseCurrentFile (uf);
		if (err!=UNZ_OK)
		{
			Cigt_error::pon_winerror("Cigt_zip",igt_err);
			return FALSE;
		}
		uf=NULL;
	}
	return TRUE;
}
//*****************************************************************************************************
BOOL Cigt_zip::crea_dir( char *dir )
{
	int k;
	int err=mkdir(dir);
	if (err<0)
	{
		k=errno;
		if(k!=EEXIST)
		{
			igt_err->pon_error("Cigt_zip","Error al crear carpeta: carpeta no encontrada",k);
			return FALSE;
		}
	}
	return TRUE;
}
//*****************************************************************************************************
BOOL Cigt_zip::abre_zip_temp()
{
	char szTempFileName[256];  
	char lpTempPathBuffer[256];
	//char  chBuffer[512]; 
	//LPCTSTR errMsg;
	DWORD dwRetVal = 0;
	//  Gets the temp path env string (no guarantee it's a valid path).
	dwRetVal = GetTempPath(MAX_PATH,          // length of the buffer
		lpTempPathBuffer); // buffer for path 
	if (dwRetVal > MAX_PATH || (dwRetVal == 0))
	{
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
		return FALSE;
	}

	//  Generates a temporary file name. 
	dwRetVal = GetTempFileName(lpTempPathBuffer, // directory for tmp files
		"DEMO",     // temp file name prefix 
		0,                // create unique name 
		szTempFileName);  // buffer for name 
	if (dwRetVal == 0)
	{ 
		Cigt_error::pon_winerror("Cigt_zip",igt_err);
		return FALSE;
	}
	return abre_zip(szTempFileName,OWERWRITE);
}
//*****************************************************************************************************
BOOL lista_file_dir( char *dir,Cstr_array *lista_file, Cigt_error *err)
{
	return lista_file_dir(dir,NULL,lista_file,err);
	/*
	BOOL poner_error;
	char str[256];
	//int k;
	WIN32_FIND_DATA filedat;
	HANDLE hfile;
	if (err)
		poner_error=TRUE;
	else
		poner_error=FALSE;
	if (!lista_file)
	{
		err->pon_error("lista_file_dir","Puntero de lista_file nulo",-1);
		return FALSE;
	}

	strcpy(str,dir);
	if (str[strlen(str)-1] != '\\')
		strcat(str,"\\");
	strcat(str,"*.*");
	hfile = FindFirstFile(str,&filedat);
	
	if (hfile != INVALID_HANDLE_VALUE)//existe dir
	{
		// existe el dir
		do
		{
			if ((strcmp(filedat.cFileName,".")  != 0) &&
				(strcmp(filedat.cFileName,"..") != 0))
			{
				strcpy(str,dir);
				if (str[strlen(str)-1] != '\\')
					strcat(str,"\\");
				strcat(str,filedat.cFileName);
				if (filedat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				{
					if(!lista_file_dir( str, lista_file, err))
					{
						FindClose(hfile);
						return FALSE;
					}
				}
				else
				{
					lista_file->pon_str(str);
				}
			}
		} while (FindNextFile(hfile,&filedat));
		FindClose(hfile);
			
	}
	else
	{
		if (poner_error)
			Igt_error::pon_winerror("lista_file_dir",err);
		return FALSE;
	}
	return TRUE;
	*/
}
//*****************************************************************************************************
BOOL lista_file_dir( char *dir,char *omite,Cstr_array *lista_file,Cigt_error *err )
{
	BOOL poner_error;
	char str[256];
	//int k;
	WIN32_FIND_DATA filedat;
	HANDLE hfile;
	if (err)
		poner_error=TRUE;
	else
		poner_error=FALSE;
	if (!lista_file)
	{
		err->pon_error("lista_file_dir","Puntero de lista_file nulo",-1);
		return FALSE;
	}

	strcpy(str,dir);
	if (str[strlen(str)-1] != '\\')
		strcat(str,"\\");
	strcat(str,"*.*");
	hfile = FindFirstFile(str,&filedat);

	if (hfile != INVALID_HANDLE_VALUE)//existe dir
	{
		// existe el dir
		do
		{
			if ((strcmp(filedat.cFileName,".")  != 0) &&
				(strcmp(filedat.cFileName,"..") != 0))
			{
				if (!omite||strcmp(omite,filedat.cFileName)!=0)
				{
					strcpy(str,dir);
					if (str[strlen(str)-1] != '\\')
						strcat(str,"\\");
					strcat(str,filedat.cFileName);
					if (filedat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
					{
						if(!lista_file_dir( str,NULL, lista_file, err))
						{
							FindClose(hfile);
							return FALSE;
						}
					}
					else
					{
						lista_file->pon_str(str);
					}
				}
			}
		} while (FindNextFile(hfile,&filedat));
		FindClose(hfile);

	}
	else
	{
		if (poner_error)
			Cigt_error::pon_winerror("lista_file_dir",err);
		return FALSE;
	}
	return TRUE;
}
//*****************************************************************************************************
BOOL es_dir(char *dir)
{
	WIN32_FIND_DATA filedat;
	HANDLE hfile;
	hfile = FindFirstFile(dir,&filedat);
	if (hfile != INVALID_HANDLE_VALUE)//existe dir
	{
		if (filedat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			FindClose(hfile);
			return TRUE;
		}
		FindClose(hfile);
	}
	return FALSE;
}
//*****************************************************************************************************
BOOL del_File(char *file,Cigt_error *err)
{
	//borra archivos y carpetas
	BOOL poner_error;
	char str[256];
	int n_aux;
	//int k;
	WIN32_FIND_DATA filedat;
	HANDLE hfile;
	if (err)
		poner_error=TRUE;
	else
		poner_error=FALSE;
	n_aux=strlen(file);

	if (n_aux<3)
	{
		if (poner_error)
		{
			sprintf(str,"Error al borrar archivo: %s. Borrar este archivo puede ser peligroso");
			err->pon_error("del_File",str,-1);
		}
		return FALSE;
	}
	strcpy(str,file);
	if (str[strlen(str)-1] != '\\')
		strcat(str,"\\");
	strcat(str,"*.*");
	hfile = FindFirstFile(str,&filedat);
	if (hfile != INVALID_HANDLE_VALUE)
	{
		// existe el dir
		// borralo y usalo
		do
		{
			if ((strcmp(filedat.cFileName,".")  != 0) &&
				(strcmp(filedat.cFileName,"..") != 0))
			{
				strcpy(str,file);
				if (str[strlen(str)-1] != '\\')
					strcat(str,"\\");
				strcat(str,filedat.cFileName);
				if (filedat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				{
					if(!del_File(str,err))
					{
						FindClose(hfile);
						return FALSE;
					}
				}
				else
				{
					SetFileAttributes(str,FILE_ATTRIBUTE_NORMAL);
					if (!DeleteFile(str))
					{
						Cigt_error::pon_winerror("del_File",err);
						FindClose(hfile);
						return FALSE;
					}
				}
			}
		} while (FindNextFile(hfile,&filedat));
		FindClose(hfile);
		if (!RemoveDirectory(file))
		{
			Cigt_error::pon_winerror("del_File",err);
			FindClose(hfile);
			return FALSE;
		}
	}
	return TRUE;
}
//*****************************************************************************************************
	

