#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"


#define WRITEBUFFERSIZE (16384)
#define MAXFILENAME (256)

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

      hFind = FindFirstFile(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;
}
#else
#ifdef unix
uLong filetime(f, tmzip, dt)
    char *f;                /* name of file to get info on */
    tm_zip *tmzip;             /* return value: access, modific. and creation times */
    uLong *dt;             /* dostime */
{
  int ret=0;
  struct stat s;        /* results of stat() */
  struct tm* filedate;
  time_t tm_t=0;
  
  if (strcmp(f,"-")!=0)
  {
    char name[MAXFILENAME];
    int len = strlen(f);
    strcpy(name, f);
    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
uLong filetime(f, tmzip, dt)
    char *f;                /* name of file to get info on */
    tm_zip *tmzip;             /* return value: access, modific. and creation times */
    uLong *dt;             /* dostime */
{
    return 0;
}
#endif
#endif




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

void do_banner()
{
	printf("MiniZip 0.15, demo of zLib + Zip package written by Gilles Vollant\n");
	//printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n"); /*{{N.SAWA}}*/
	printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n");
	printf("* 2002/11/27 Changed by Naoyuki Sawa (nsawa@north.hokkai.net)\n\n"); /*{{N.SAWA}}*/
}

void do_help()
{	
	//printf("Usage : minizip [-o] file.zip [files_to_add]\n\n") ; /*{{N.SAWA}}*/
	printf("Usage   : minizip [options] file.zip [files_to_add]\n"); /*{{N.SAWA}}*/
	printf("Options : -o      file.zipが既に存在した場合、問い合わせなしで上書きします。\n"); /*{{N.SAWA}}*/
	printf("          -l0〜9  圧縮レベルを指定します。(既定値=6)\n"); /*{{N.SAWA}}*/
	printf("          -w8〜15 スライドウインドウサイズを指定します。(既定値=15)\n"); /*{{N.SAWA}}*/
	printf("                  ※-w8は正しく機能しません。-w9〜15を使ってください。\n"); /*{{N.SAWA}}*/
	printf("\n"); /*{{N.SAWA}}*/
}

int main(argc,argv)
	int argc;
	char *argv[];
{
	int i;
	int opt_overwrite=0;
    int opt_compress_level=Z_DEFAULT_COMPRESSION;
    int zipfilenamearg = 0;
	char filename_try[MAXFILENAME];
    int zipok;
    int err=0;
    int size_buf=0;
    //void* buf=NULL,
    void* buf=NULL;/*{{N.SAWA}}*/

	/* * Mon Nov 25 22:50:00 JST 2002 Naoyuki Sawa
	 * - コマンドライン引数のワイルドカードを展開するために、
	 *   [プロジェクトの設定]->[リンク]->[オブジェクト/ライブラリモジュール]に
	 *   「setargv.obj」を追加しています。
	 */

	/* * Mon Nov 25 22:50:00 JST 2002 Naoyuki Sawa
	 * - このプログラムはエラー検出後に終了処理を行っていないません。
	 *   そのため、例えば、存在しないファイルを圧縮しようとすると、
	 *   一般保護エラーダイアログが表示され、デバッガが立ち上がってしまいます。
	 *   これを防ぐために、一般保護エラーダイアログを抑制することにします。
	 *   →2002/11/27追記:それぞれのエラー検出個所にexit(1)を追加したので、
	 *     もう一版保護エラーは発生しないと思いますが、念のためSetErrorMode()も残します。
	 */
	SetErrorMode(SEM_NOGPFAULTERRORBOX);

	do_banner();
	if (argc==1)
	{
		do_help();
		exit(0);
        return 0;
	}
	else
	{
		for (i=1;i<argc;i++)
		{
			if ((*argv[i])=='-')
			{
				const char *p=argv[i]+1;
				
				while ((*p)!='\0')
				{			
					//char c=*(p++);; /*{{N.SAWA}}*/
					//if ((c=='o') || (c=='O')) /*{{N.SAWA}}*/
					//	opt_overwrite = 1; /*{{N.SAWA}}*/
                    //if ((c>='0') && (c<='9')) /*{{N.SAWA}}*/
                    //  opt_compress_level = c-'0'; /*{{N.SAWA}}*/
					/*{{N.SAWA:2002/11/26*/
					char c = tolower(*p++);
					if(c == 'o') {
						opt_overwrite = 1;
						//fprintf(stderr, "オーバーライトモードが指定されました。\n");
					} else if(c == 'l') {
						if(!isdigit(*p)) { do_help(); exit(1); }
						opt_compress_level = 0;
						do {
							opt_compress_level = opt_compress_level * 10 + (*p++ - '0');
						} while(isdigit(*p));
						//fprintf(stderr, "圧縮レベル%dが指定されました。\n", opt_compress_level);
					} else if(c == 'w') {
						if(!isdigit(*p)) { do_help(); exit(1); }
						zipWindowBits = 0;
						do {
							zipWindowBits = zipWindowBits * 10 + (*p++ - '0');
						} while(isdigit(*p));
						//fprintf(stderr, "スライドウインドウサイズ%dが指定されました。\n", zipWindowBits);
					} else {
						do_help(); exit(1);
					}
					/*}}N.SAWA:2002/11/26*/
				}
			}
			else
				if (zipfilenamearg == 0)
                    zipfilenamearg = i ;
		}
	}

    size_buf = WRITEBUFFERSIZE;
    buf = (void*)malloc(size_buf);
    if (buf==NULL)
    {
        printf("Error allocating memory\n");
        exit(1); /*{{N.SAWA}}*/
        return ZIP_INTERNALERROR;
    }

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

        zipok = 1 ;
		strcpy(filename_try,argv[zipfilenamearg]);
        len=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==0)
            if (check_exist_file(filename_try)!=0)
			{
                char rep;
				do
				{
					char answer[128];
					printf("The file %s exist. Overwrite ? [y]es, [n]o : ",filename_try);
					scanf("%1s",answer);
					rep = answer[0] ;
					if ((rep>='a') && (rep<='z'))
						rep -= 0x20;
				}
				while ((rep!='Y') && (rep!='N'));
                if (rep=='N')
                    zipok = 0;
			}
    }

    if (zipok==1)
    {
        zipFile zf;
        int errclose;
        zf = zipOpen(filename_try,0);
        if (zf == NULL)
        {
            printf("error opening %s\n",filename_try);
            err= ZIP_ERRNO;
            exit(1); /*{{N.SAWA}}*/
        }
        else 
            printf("creating %s\n",filename_try);

        for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
        {
            if (((*(argv[i]))!='-') && ((*(argv[i]))!='/'))
            {
                FILE * fin;
                int size_read;
                //const char* filenameinzip = argv[i]; /*{{N.SAWA}}*/
                char filenameinzip[_MAX_PATH]; /*{{N.SAWA}}*/
                zip_fileinfo zi;
                /*{{N.SAWA*/
                {
                char* p;
                strncpy(filenameinzip, argv[i], sizeof filenameinzip);
                for(p = filenameinzip; *p != '\0'; *p++) if(*p == '\\') *p = '/';
		}
                /*}}N.SAWA*/

                zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 
                zi.tmz_date.tm_mday = zi.tmz_date.tm_min = 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 (err != ZIP_OK) /*{{N.SAWA}}*/
                if (err != ZIP_OK) { /*{{N.SAWA}}*/
                    printf("error in opening %s in zipfile\n",filenameinzip);
                	exit(1); /*{{N.SAWA}}*/
                //else /*{{N.SAWA}}*/
                } else /*{{N.SAWA}}*/
                {
                    fin = fopen(filenameinzip,"rb");
                    if (fin==NULL)
                    {
                        err=ZIP_ERRNO;
                        printf("error in opening %s for reading\n",filenameinzip);
                        exit(1); /*{{N.SAWA}}*/
                    }
                }

                //if (err == ZIP_OK) /*{{N.SAWA}}*/
                if (err == ZIP_OK) { /*{{N.SAWA}}*/
					printf(" adding: %s\n", filenameinzip); /*{{N.SAWA}}*/
                    do
                    {
                        err = ZIP_OK;
                        size_read = 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;
                            exit(1); /*{{N.SAWA}}*/
                        }

                        if (size_read>0)
                        {
                            err = zipWriteInFileInZip (zf,buf,size_read);
                            if (err<0)
                            {
                                printf("error in writing %s in the zipfile\n",
                                                 filenameinzip);
                                exit(1); /*{{N.SAWA}}*/
                            }
                                
                        }
                    } while ((err == ZIP_OK) && (size_read>0));
				} /*{{N.SAWA}}*/

                fclose(fin);
                //if (err<0) /*{{N.SAWA}}*/
                if (err<0) { /*{{N.SAWA}}*/
                    err=ZIP_ERRNO;
                    exit(1); /*{{N.SAWA}}*/
                } /*{{N.SAWA}}*/
                else
                {                    
                    err = zipCloseFileInZip(zf);
                    //if (err!=ZIP_OK) /*{{N.SAWA}}*/
                    if (err!=ZIP_OK) { /*{{N.SAWA}}*/
                        printf("error in closing %s in the zipfile\n",
                                    filenameinzip);
                        exit(1); /*{{N.SAWA}}*/
                    } /*{{N.SAWA}}*/
                }
            }
        }
        errclose = zipClose(zf,NULL);
        //if (errclose != ZIP_OK) /*{{N.SAWA}}*/
        if (errclose != ZIP_OK) { /*{{N.SAWA}}*/
            printf("error in closing %s\n",filename_try);
            exit(1); /*{{N.SAWA}}*/
        } /*{{N.SAWA}}*/
   }

    free(buf);
    exit(0);
	return 0;  /* to avoid warning */
}
