#define __DACT_C
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "dact.h"
#include "parse.h"
#include "dendian.h"
#ifdef DACT_OLD_ALGO
#include "algorithms.h"
#endif
extern char *optarg;
extern int optind, opterr, optopt;
uint32_t DACT_BLK_SIZE=4088;
int print_help(int argc, char **argv) {
printf("DACT %i.%i.%i-%s by Netfuel Design.\n", DACT_VER_MAJOR, \
DACT_VER_MINOR, DACT_VER_REVISION,
#ifdef DEBUG
"dev"
#else
"rel"
#endif
);
printf("usage: %s [-dsfh] [file ...]\n",argv[0]);
printf(" -d Decompress instead of compressing.\n");
printf(" -s Give statistics rather than compress or decompress.\n");
printf(" -f Force unsafe things to happen.\n");
printf(" -h Give this help.\n");
printf(" file... File(s) to (de)compress. (If none given, use standard input).\n");
return(0);
}
char *dact_getoutfilename(const char *orig, const int mode) {
char *ret=NULL;
switch (mode) {
case DACT_MODE_COMPR:
ret=malloc(strlen(orig)+5);
strcpy(ret,orig);
strcat(ret,".dct");
break;
case DACT_MODE_DECMP:
if (strcmp(&orig[strlen(orig)-4],".dct")) {
return(NULL);
}
ret=malloc(strlen(orig)-3);
strncpy(ret,orig,strlen(orig)-4);
break;
case DACT_MODE_STAT:
return(NULL);
break;
}
return(ret);
}
uint32_t dact_select_best_algo(int *algo, char *ret, const char *srcbuf, const uint32_t size, const char *options) {
#ifdef DACT_OLD_ALGO
char *tmpbuf, *smallbuf=NULL;
int i, highest_algo=0;
int smallest_algo;
uint32_t smallest_size=-1, x;
if ((tmpbuf=malloc(size*2))==NULL) { PERROR("malloc"); return(0); }
for (i=0;i<256;i++) {
if (algorithms[i]!=NULL && algorithms[i]!=DACT_FAILED_ALGO) highest_algo=i;
}
for (i=0;i<=highest_algo;i++) {
if (algorithms[i]!=NULL && algorithms[i]!=DACT_FAILED_ALGO) {
x=algorithms[i](DACT_MODE_COMPR, NULL, srcbuf, tmpbuf, size);
if ((x<smallest_size || smallest_size==-1) && x!=-1) {
smallest_size=x;
smallest_algo=i;
if (smallbuf!=NULL) free(smallbuf);
if ((smallbuf=malloc(smallest_size))==NULL) { PERROR("malloc"); free(tmpbuf); return(0); }
memcpy(smallbuf, tmpbuf, smallest_size);
}
if (options[DACT_OPT_VERB]>1) {
PRINT_LINE; fprintf(stderr, "dact: \033[%im----| %03i | %-7i | %s\033[0m\n", (smallest_algo==i)*7 , i, x, algorithm_names[i]);
}
}
}
free(tmpbuf);
memcpy(algo, &smallest_algo, sizeof(int));
memcpy(ret, smallbuf, smallest_size);
return(smallest_size);
#else
return(size);
#endif
}
uint32_t dact_process_file(const int src, const int dest, const int mode, const char *options) {
char *in_buf, *out_buf;
char version[3]={DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION};
int algo;
uint32_t bytes_read, retsize;
uint32_t filesize=0, blk_cnt=0;
if (mode==DACT_MODE_COMPR) {
if (((in_buf=malloc(DACT_BLK_SIZE))==NULL) || \
((out_buf=malloc(DACT_BLK_SIZE*2))==NULL)) {
PERROR("malloc");
return(-1);
}
/* XXX: WRITE FILE HEADERS FEWLIO */
// SANITY(write, dest, DACT_MAGIC_NUMBER, 4);
SHOWVAL(write(dest, "DACT", 4));
SHOWVAL(write(dest, &version[0], 1));
SHOWVAL(write(dest, &version[1], 1));
SHOWVAL(write(dest, &version[2], 1));
SHOWVAL(write_de(dest, 0, 4)); /* Place holder for ORIG FILE SIZE */
SHOWVAL(write_de(dest, 0, 4)); /* Place holder for NUM BLOCKS */
SHOWVAL(write_de(dest, DACT_BLK_SIZE, 4));
SHOWVAL(write_de(dest, 0, 1)); /* XXX: Option byte... Or not? */
SHOWVAL(write_de(dest, 0, 4)); /* Place holder for SIZEOF EXTENDED DATA */
if (options[DACT_OPT_VERB]) {
PRINTERR("Blk | Algo | Size | Name");
PRINTERR("----+------+---------+---------------------------");
}
while ( (bytes_read=read(src, in_buf, DACT_BLK_SIZE))>0) {
filesize+=bytes_read;
blk_cnt++;
retsize=dact_select_best_algo(&algo, out_buf, in_buf, DACT_BLK_SIZE, options);
if (retsize>0) {
if (options[DACT_OPT_VERB]) {
if (options[DACT_OPT_VERB]>1) {
PRINTERR("^^^\\ /^^^^\\ /^^^^^^^\\ /^^^^^^^^^^^^^^^^^^^^^^^^^^");
}
PRINT_LINE; fprintf(stderr, "dact: %03i | %03i | %-7i | %s\n",blk_cnt,algo,retsize,algorithm_names[algo]);
if (options[DACT_OPT_VERB]>1) {
PRINTERR("___/ \\____/ \\_______/ \\__________________________");
}
}
/* XXX: WRITE BLOCK HEADERS FEWLIO */
if (write(dest, out_buf, retsize)!=retsize) {
PERROR("write");
free(in_buf);
free(out_buf);
return(0);
}
} else {
PRINTERR("Compression resulted in 0-byte block.");
free(in_buf);
free(out_buf);
return(0);
}
}
if (bytes_read<0) {
PERROR("read");
}
free(in_buf);
free(out_buf);
return(filesize);
}
if (mode==DACT_MODE_DECMP) {
/* XXX: Make this do something */
PRINTERR("This does nothing.");
}
if (mode==DACT_MODE_STAT) {
/* XXX: Make this do something, too*/
PRINTERR("This does nothing.");
}
return(0);
}
int main(int argc, char **argv) {
unsigned char options[8]={0,0,0,0,0,0,0,0};
signed char opt;
char **in_files, *in_file=NULL, *out_file=NULL;
int filecnt=0;
int in_fd, out_fd;
int mode=DACT_MODE_COMPR;
uint32_t i;
while ((opt=getopt(argc,argv,"dfsvcb:h"))!=-1) {
switch (opt) {
case 'd':
mode=DACT_MODE_DECMP;
break;
case 'f':
options[DACT_OPT_FORCE]++;
break;
case 's':
mode=DACT_MODE_STAT;
break;
case 'c':
options[DACT_OPT_STDOUT]=!options[DACT_OPT_STDOUT];
break;
case 'b':
i=atoi2(optarg);
if (i<DACT_BLK_SIZE_MAX) DACT_BLK_SIZE=i;
break;
case 'v':
options[DACT_OPT_VERB]++;
break;
case '?':
case 'h':
return(print_help(argc,argv));
}
}
in_files=&argv[optind];
/* Loop through extra parameters (files ...) and setup FDs for them */
do {
in_fd=-1;
out_fd=-1;
in_file=in_files[filecnt];
if (in_file!=NULL) {
/* Determine resulting file name */
out_file=dact_getoutfilename(in_file,mode);
if ((in_fd=open(in_file,O_RDONLY))==-1) {
fprintf(stderr, "dact: Can't open %s.\n",in_file);
PERROR("open");
continue;
}
if (out_file!=NULL) {
if (access(out_file,F_OK)!=-1 && options[DACT_OPT_FORCE]==0 && options[DACT_OPT_STDOUT]==0) {
fprintf(stderr, "dact: %s exists.\n",out_file);
close(in_fd);
continue;
}
if (options[DACT_OPT_STDOUT]) {
out_fd=STDOUT_FILENO;
} else {
if ((out_fd=open(out_file,O_WRONLY|O_CREAT|O_TRUNC,0644))==-1) {
fprintf(stderr, "dact: Can't open %s for writing.\n",out_file);
PERROR("open");
continue;
}
}
}
}
/* Use STDIN/STDOUT if no files specified ... */
if (in_file==NULL && filecnt==0) {
/* ... But only if STDOUT isn't a terminal */
if (isatty(STDOUT_FILENO)) {
fprintf(stderr, "dact: Refusing to write compressed output to a terminal.\n");
} else {
out_fd=STDOUT_FILENO;
in_fd=STDIN_FILENO;
}
}
/* Okay, we're all done, now pass these to something to do the real stuff */
if (in_fd!=-1 && (out_fd!=-1 || mode==DACT_MODE_STAT)) {
if (dact_process_file(in_fd, out_fd, mode, options)==0 && mode!=DACT_MODE_STAT) {
close(in_fd);
close(out_fd);
return(-1);
}
}
/* Cleanup */
if (out_fd!=-1) close(out_fd);
if (in_fd!=-1) close(in_fd);
} while (in_files[filecnt++]!=NULL);
return(0);
}