// Simple library to compress/uncompress data..
// --------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
#include "defines.h"
#include "tpl.h"
#include "lib.h"
#include "lprintf.h"
#define DMID 25
#include "debug.h"
#include "myziplib.h"
#include "../zlib/zlib.h"
void emsg(char * arg_list, ...);
void imsg(char * arg_list, ...);
void dmsg(char * arg_list, ...);

#define CHUNK 16000
int ziplib_compress_file(char *fnamein, char *fnameout, char *reason)
{
	int ret=FALSE;
	FILE *fin,*fout;
	strcpy(reason,"IO issue");
	fin = fout = NULL;
	fin = fopen(fnamein,"rb");
	fout = fopen(fnameout,"wb");
	if (fin==NULL) goto failed;
	if (fout==NULL) goto failed;
	ret = ziplib_compress(fin,fout,reason,0,"\r\ntruncated\r\n");
failed:
	if (fin) fclose(fin);
	if (fout) fclose(fout);
	return ret;
}
int ziplib_uncompress_file(char *fnamein, char *fnameout, char *reason)
{
	int ret=FALSE;
	FILE *fin,*fout;
	fin = fout = NULL;
	fin = fopen(fnamein,"rb");
	fout = fopen(fnameout,"wb");
	if (fin==NULL) goto failed;
	if (fout==NULL) goto failed;
	ret = ziplib_uncompress(fin,fout,reason);
failed:
	if (fin) fclose(fin);
	if (fout) fclose(fout);
	return ret;
}
int ziplib_compress(FILE *fin, FILE *fout, char *reason, int trim, char *msg)
{
	z_stream strm;
	int totin=0,totout=0;
	unsigned int have=0;
	int flush=Z_NO_FLUSH;
	unsigned char *in = malloc(CHUNK+BFSZ); // ];[CHUNK+BFSZ];
	unsigned char *out = malloc(CHUNK+BFSZ); // [CHUNK+BFSZ];
	int ret;

	strcpy(reason,"compress error");
	memset(&strm,0,sizeof(z_stream));
	ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
	if (ret != Z_OK) goto retfalse;

    for (;flush != Z_FINISH;) {
        strm.avail_in = (int)fread(in, 1, CHUNK, fin);
        if (ferror(fin)) { (void)deflateEnd(&strm); goto retfalse;}
		totin += strm.avail_in;
        flush = feof(fin) ? Z_FINISH : Z_NO_FLUSH;
		if (trim!=0) if (totin>trim) {
			strcpy(in+ strm.avail_in,msg);
	        strm.avail_in += strlen(msg);
			flush = Z_FINISH;
		}

        strm.next_in = in;
        for (strm.avail_out = 0;strm.avail_out == 0;) {
            strm.avail_out = CHUNK+BFSZ;
            strm.next_out = out;
            ret = deflate_X(&strm, flush);    /* no bad return va lue */
            have = CHUNK+BFSZ - strm.avail_out;
			totout += have;
            if (fwrite(out, 1, have, fout) != have || ferror(fout)) {  (void)deflateEnd(&strm);  goto retfalse; }
        } 
		if (trim!=0) if (totin>trim) break;
    } 

    (void)deflateEnd(&strm);
	lprintf(reason,BFSZ-1,"compress worked fine %d/%d",totin,totout);
	free(in); free(out);
    return TRUE;
retfalse:
	free(in); free(out);
	return FALSE;
}

int ziplib_uncompress(FILE *fin, FILE *fout, char *reason)
{
	z_stream strm;
	unsigned int have=0;
	int flush=Z_NO_FLUSH;
	unsigned char *in = malloc(CHUNK+BFSZ); // ];[CHUNK+BFSZ];
	unsigned char *out = malloc(CHUNK+BFSZ); // [CHUNK+BFSZ];
	int ret;
	int intot,outtot;
	intot=outtot=0;

	strcpy(reason,"expand error");
	memset(&strm,0,sizeof(z_stream));
	ret = inflateInit(&strm);
	if (ret != Z_OK) goto retfalse;

    for (;flush != Z_FINISH;) {
        strm.avail_in = (int)fread(in, 1, CHUNK, fin);
        if (ferror(fin)) { (void)inflateEnd(&strm); goto retfalse;}
		intot += strm.avail_in;
        flush = feof(fin) ? Z_FINISH : Z_NO_FLUSH;
        strm.next_in = in;
        for (strm.avail_out = 0;strm.avail_out == 0;) {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = inflate(&strm, flush);    /* no bad return value */
            switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strm);
                goto retfalse;
            }
            have = CHUNK - strm.avail_out;
			outtot += have;
            if (fwrite(out, 1, have, fout) != have || ferror(fout)) {  (void)inflateEnd(&strm);  goto retfalse; }
        } 
    } 

    (void)inflateEnd(&strm);
	lprintf(reason,BFSZ-1,"Expand worked %d to %d",intot,outtot);
	free(in); free(out);
    return TRUE;
retfalse:
	free(in); free(out);
    return FALSE;
}
