📄 zzip.c
字号:
/*---------------------------------------------*/
/* Zzip/Zzlib compressor zzip.c */
/*---------------------------------------------*/
/*
This file is a part of zzip and/or zzlib, a program and
library for lossless, block-sorting data compression.
Copyright (C) 1999-2001 Damien Debin. All Rights Reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Damien Debin
<damien@debin.net>
This program is based on (at least) the work of: Mike Burrows,
David Wheeler, Peter Fenwick, Alistair Moffat, Ian H. Witten,
Robert Sedgewick, Jon Bentley, Brenton Chapin, Stephen R. Tate,
Szymon Grabowski, Bernhard Balkenhol, Stefan Kurtz
*/
#include <sys/stat.h>
#include <sys/timeb.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#ifdef WIN32
# include <io.h>
#else /* WIN32 */
# include <sys/types.h>
# include <unistd.h>
# include <dirent.h>
#endif /* WIN32 */
#include "zzip.h"
/*---------------------------------------------*/
#ifdef WIN32
# define SEP_PATH '\\'
# define STAR_STR "\\*.*"
#else /* WIN32 */
# define SEP_PATH '/'
# define STAR_STR "/*"
#endif /* WIN32 */
bool verbose = true;
static char **file_list = NULL, *input_filename = NULL, *output_filename = NULL;
static bool with_path = false;
static uint32 nb_input_file = 0;
static actions action = NONE;
#ifdef SFX
static char *exe_filename = NULL;
#else /* SFX */
static uint32 block_size = DEFAULT_BLOCK_SIZE;
static bool recurse = false;
static uint compression_mode = 0;
static bool multimedia_test = false;
#endif /* SFX */
#define IO_ERROR() { last_error = errno; return; }
/*---------------------------------------------*/
static
void PrintVersion()
{
#ifdef SFX
printf(
"*** ZZIP " VERSION_STRING ", SelF-eXtracting archive\n"
"*** Copyright (c)2001 Damien Debin, all rights reserved.\n"
);
#else /* SFX */
printf(
"*** ZZIP " VERSION_STRING ", yet another block-sorting compressor.\n"
"*** Copyright (c)2001 Damien Debin, all rights reserved.\n"
);
#endif /* SFX */
}
/*---------------------------------------------*/
INLINE static
void MyFree(void *p)
{
free(p);
}
INLINE static
void *MyMalloc(uint32 size)
{
void* m = malloc(size);
if (m == NULL) last_error = NOT_ENOUGH_MEMORY;
return m;
}
/*---------------------------------------------*/
#ifdef GET_STAT
static
uint GetCPUIDflags()
{
uint return_value = 0;
asm (
"pushfl;" /* get extended flags */
"popl %%eax;" /* in eax */
"movl %%eax,%%ecx;" /* save origional extended flags */
"xorl $0x00200000,%%eax;" /* flip id bit 21 */
"pushl %%eax;" /* save modified flags */
"popfl;" /* put modified flags in eflag reg */
"pushfl;" /* get flags again */
"popl %%eax;" /* modified flags back to eax */
"pushl %%ecx;"
"popfl;"
"xorl %%eax,%%ecx;" /* if 0, bit 21 was set */
"xorl %%eax,%%eax;"
"andl $0x00200000,%%ecx;"
"jz 0;"
"movl $0x00000001,%%eax;" /* CPUID function 1 */
"cpuid;" /* get signature/std feature flgs */
"movl $0x00000001,%%eax;"
/* Check for time stamp counter support */
"movl $0x00000010,%%ecx;" /* bit 4 indicates TSC support */
"andl %%edx,%%ecx;" /* supports TSC ? CPUID_STD_TSC:0 */
"negl %%ecx;" /* supports TSC ? CY : NC */
"sbb %%ecx,%%ecx;" /* supports TSC ? 0xffffffff:0 */
"andl $0x00000010,%%ecx;" /* supports TSC ? FEATURE_TSC:0 */
"orl %%ecx,%%eax;" /* merge into feature flags */
/* Check for MMX support */
"movl $0x00800000,%%ecx;" /* bit 23 indicates MMX support */
"andl %%edx,%%ecx;" /* supports MMX ? CPUID_STD_MMX:0 */
"negl %%ecx;" /* supports MMX ? CY : NC */
"sbb %%ecx,%%ecx;" /* supports MMX ? 0xffffffff:0 */
"andl $0x00000020,%%ecx;" /* supports MMX ? FEATURE_MMX:0 */
"orl %%ecx,%%eax;" /* merge into feature flags */
/* Check for CMOV support */
"movl $0x00008000,%%ecx;" /* bit 15 indicates CMOV support */
"andl %%edx,%%ecx;" /* supports CMOV?CPUID_STD_CMOV:0 */
"negl %%ecx;" /* supports CMOV ? CY : NC */
"sbb %%ecx,%%ecx;" /* supports CMOV ? 0xffffffff:0 */
"andl $0x00000040,%%ecx;" /* supports CMOV ? FEATURE_CMOV:0 */
"orl %%ecx,%%eax;" /* merge into feature flags */
"0: " : "=a" (return_value) : : "ebx", "ecx", "edx");
return return_value;
}
static
void GetCpuSpeed()
{
struct _timeb timeStart, timeStop;
uint64 StartTicks, EndTicks, TotalTicks;
do _ftime(&timeStart);
while (timeStart.millitm > 700);
GET_TSC(StartTicks);
do _ftime(&timeStop);
while ((timeStop.millitm - timeStart.millitm) < 200);
GET_TSC(EndTicks);
TotalTicks = EndTicks - StartTicks;
time_stat.cpuspeed = /*300;*/ TotalTicks / 200000; /* CPU speed (Mhz) */
time_stat.cpuspeed *= 1000000; /* cycles for 1 second */
}
#endif /* GET_STAT */
/*---------------------------------------------*/
static
void Help()
{
printf("\n");
PrintVersion();
#ifndef SFX
printf(
"\n usage: zzip [<command>] [<sw1><sw2>...] [<archive>] file1 file2 ...\n\n"
" <commands>\n"
" a Add files to archive\n"
" e Extract files from archive\n"
" x eXtract files with full path\n"
" d Delete files from archive\n"
" t Test files in archive\n"
" l List contents of archive\n\n"
" <switches>\n"
" -... Block size (e.g. -3m,-3072k)\n"
" -a Adaptive block size reduction\n"
" -mx MaXimum compression\n"
" -mm MultiMedia compression\n"
" -q Quiet output to screen\n"
" -r Recurse subdirectories\n"
" -s Statistics\n\n"
" http://debin.org/zzip/\n"
" damien@debin.net\n"
);
#else /* !SFX */
printf(
"\n usage: %s [<sw1><sw2>...] [files_to_extract]\n\n"
" <switches>\n"
" -x eXtract files without path\n"
" -t Test files in archive\n"
" -l List contents of archive\n"
" -q Quiet output to screen\n"
, exe_filename);
#endif /* !SFX */
exit(1);
}
/*---------------------------------------------*/
static
void Options(char *s)
{
while (*(++s) != '\0')
switch (*s)
{
#ifndef SFX
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
char *ss = s;
while ((*s >= '0') && (*s <= '9')) s++;
if (*s == 'm')
{ *s = 0; block_size = atoi(ss) * 1024 * 1024; }
else if (*s == 'k')
{ *s = 0; block_size = atoi(ss) * 1024; }
else Help();
}
break;
case 'b': /* for compatibility with older versions */
s++;
{
char *ss = s, c;
while ((*s >= '0') && (*s <= '9')) s++;
c = *s;
*s = 0;
block_size = atoi(ss) * 256 * 1024;
*s = c;
s--;
}
break;
case 'a':
compression_mode |= 2;
break;
case 'm':
s++;
switch (*s)
{
case 'm': multimedia_test = true; break;
case 'x': compression_mode |= 1; break;
default : Help();
}
break;
case 'r':
recurse = true;
break;
#ifdef GET_STAT
case 's':
time_stat.t_stamp = ((GetCPUIDflags() & FEATURE_TSC) == FEATURE_TSC);
break;
#endif /* GET_STAT */
#else /* !SFX */
case 't':
action = TEST;
break;
case 'l':
action = LIST;
break;
case 'x':
with_path = false;
break;
#endif /* !SFX */
case 'q':
verbose = false;
break;
case '-':
Options(s);
break;
default :
Help();
break;
}
}
/*---------------------------------------------*/
static
void CmdLineParameters(int argc,
char **argv)
{
file_list = (char**)MyMalloc(sizeof(char*) * MAX_FILES);
verbose = true;
nb_input_file = 0;
#ifdef SFX
{
sint l;
action = EXTRACT;
with_path = true;
exe_filename = argv[0];
l = strlen(exe_filename) - 4;
if (l < 0 || strcmp(exe_filename + l, ".exe") != 0)
{
exe_filename = (char*)MyMalloc(sizeof(char) * FILENAME_LENGTH_MAX);
strcpy(exe_filename, argv[0]);
strcat(exe_filename, ".exe");
}
file_list[nb_input_file++] = exe_filename;
}
#else /* SFX */
with_path = false;
compression_mode = 0;
recurse = false;
block_size = DEFAULT_BLOCK_SIZE;
action = NONE;
if (argc > 1)
{
if (strlen(argv[1]) == 1)
{
switch (*argv[1])
{
case 'A':
case 'a': action = CREATE; argc--; argv++; break;
case 'D':
case 'd': action = DELETE; argc--; argv++; break;
case 'X':
case 'x': with_path = true;
case 'E':
case 'e': action = EXTRACT; argc--; argv++; break;
case 'L':
case 'l': action = LIST; argc--; argv++; break;
case 'T':
case 't': action = TEST; argc--; argv++; break;
default :;
}
}
}
else Help();
#endif /* SFX */
while ((argc > 1) && (*argv[1] == '-'))
{
Options(argv[1]);
argc--;
argv++;
}
while (argc > 1)
{
file_list[nb_input_file++] = argv[1];
argc--;
argv++;
}
#ifndef SFX
if (nb_input_file == 0) Help();
#endif /* !SFX */
}
/*---------------------------------------------*/
#ifndef SFX
/* use 'file.zz' if 'file.zz' exists and if 'file' doesn't exist */
static
void CheckFilename(char *result,
char *filename)
{
struct stat buf_stat;
strcpy(result, filename);
strcat(result, ".zz");
if (stat(filename, &buf_stat) != -1 || stat(result, &buf_stat) == -1)
strcpy(result, filename);
}
#endif /* !SFX */
/*---------------------------------------------*/
static
void DoFiles()
{
#ifndef SFX
bool single_archive;
struct stat file_stat;
uint32 nb_archive;
#endif /* !SFX */
uint32 i, j;
sint l;
info_s *info;
output_filename = (char*)MyMalloc(sizeof(char) * FILENAME_LENGTH_MAX);
*output_filename = '\0';
input_filename = (char*)MyMalloc(sizeof(char) * FILENAME_LENGTH_MAX);
info = (info_s*)MyMalloc(sizeof(info_s));
#ifndef SFX
if (action == NONE)
{
l = strlen(file_list[0]) - 3;
if (l >= 0 && strcmp(file_list[0] + l, ".zz") == 0) action = EXTRACT;
}
if ((nb_input_file <= 1) && ((action == DELETE) || (action == CREATE))) Help();
#endif /* !SFX */
VERBOSE PrintVersion();
switch (action)
{
#ifndef SFX
case UPDATE:
case CREATE:
/* first filename is archive filename */
strcpy(output_filename, file_list[0]);
file_list++;
nb_input_file--;
case NONE:
/* we process readable files only and recurse directories */
j = 0;
for (i = 0; i < nb_input_file; ++i)
{
bool go_through = false;
char *path;
path = (char*)MyMalloc(sizeof(char) * (strlen(file_list[i]) + FILENAME_LENGTH_MAX));
strcpy(path, file_list[i]);
if (strchr(file_list[i], '*') != NULL) go_through = true;
else
{
if (stat(file_list[i], &file_stat) == -1) IO_ERROR();
if (recurse == true && (file_stat.st_mode & (S_IFDIR | S_IREAD)) == (S_IFDIR | S_IREAD))
{
strcat(path, STAR_STR);
go_through = true;
}
}
if (go_through == true)
{
char *p = strrchr(path, SEP_PATH);
if (p == NULL) p = path;
else p++;
#ifdef WIN32
{
struct _finddata_t file_info;
sint handle;
if ((handle = _findfirst(path, &file_info)) == -1) IO_ERROR();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -