static char *BLOKCOMP_C =
"$Header: D:/mcl/dx2/squidge/blokcomp.c_v 1.1 19 Jul 1991 11:53:32 mcl $";

/* Mark has been mucking about with the init/terminate stuff -
 I think to do something with sharing buffers between the
 different algorithms. You can probably remove the
 'ifdef Never's...
 */

/*
 Program: Comp
 Author: Graham Toal
 Created: Mon,04 Feb 1991.11:41:44
 LastEdit: Mon,04 Feb 1991.11:41:44

 Purpose: Compress a file for use with random-access (read-only)
 file I/O.

 Description:
 Generates a compressed file, a block at a time. Blocks
 are fixed length though the last one may be a short block.
 An index pointing to the start of each block is stored at
 the end of the file, for fast access to random blocks. The
 index itself is pointed to by the first 4 bytes of the file.
 The block length (stored in the header just after the index
 pointer) has to be fixed so that offsets into the data can
 be calculated quickly.

 File description:

 0: [@idx_start]:4
 [idx_entries]:4
 [block_size]:2
 {
 block_start: [block_len]:2 (includes type byte)
 [block_type]:1
 [block_data]:block_len-1
 }:idx_entries
 [00]:2 (empty blocklen => terminate list)
 idx_start: (optionally aligned to word)
 {
 [@block_start]:4
 }:idx_entries


 $Log: D:/mcl/dx2/squidge/blokcomp.c_v $
 *
 * Rev 1.1 19 Jul 1991 11:53:32 mcl
 *

 */

#include <stdio.h>
#include "grope.h"

#ifdef SYS_MSDOS
/* This is a system to extend the number of files allowed open at any time --
 see extern.h for how it interacts transparently */
#include "xfile.h"
#endif

#include "computil.h"
#include "extern.h"
#ifdef BELL_LICENCE
#include "bellenco.h"
#include "belldeco.h"
#endif
#include "tigrende.h"
#include "wordende.h"
#include "sperror.h"

static int
rcexit(int rc)
{
 exit(rc); /* allows use in expressions :-) */
 return (rc);
}

COMPTYPE
squidge(void *buff, C_DATAINDEX buffsize, void *outbuff, C_DATAINDEX * osize)
{
/* Buffers can have up to 32768 bytes, ie indexes 0..32767 */
C_DATA *ibuff, *obuff;
C_DATAINDEX i;
C_DATAINDEX nbytes;
COMPTYPE comp_type;

 if (buffsize > 32768U) {
 sperror(__LINE__,__FILE__,
 "ERROR: "
 "Parameter 'buffsize' of squidge() is negative, or too large (%u).\n",
 buffsize);
 if (sizeof(C_DATAINDEX) <= 2)
 sperror(__LINE__,__FILE__, " (perhaps you are using an int > 32768 ?)\n");
 return (TYPE_ERR);
 }
 nbytes = buffsize;
 ibuff = (C_DATA *) buff;
 obuff = (C_DATA *) outbuff;
 *osize = (C_DATAINDEX) nbytes;
 comp_type = Word_comp_buff(ibuff, obuff, (C_DATAINDEX) nbytes, osize, buffsize);
 sperror(__LINE__,__FILE__, "Word_comp_buff() -> size=%u\n", *osize);
 if (comp_type == TYPE_UNCOMPRESSED) {
 *osize = (C_DATAINDEX) nbytes;
#ifdef BELL_LICENCE
 comp_type = Bell_comp_buff(ibuff, obuff, (C_DATAINDEX) nbytes, osize, buffsize);
 sperror(__LINE__,__FILE__, "Bell_comp_buff() -> size=%u\n", *osize);
#else
 comp_type = Tigr_comp_buff(ibuff, obuff, (C_DATAINDEX) nbytes, osize, buffsize);
 sperror(__LINE__,__FILE__, "Tigr_comp_buff() -> size=%u\n", *osize);
#endif
 }

 if (comp_type == TYPE_UNCOMPRESSED) {
 /* Not copied by comp_buff */
 for (i = 0; i < nbytes; i++)
 obuff[i] = ibuff[i];
 *osize = (C_DATAINDEX) nbytes;
 }

 return (comp_type);
}

BOOL
unsquidge(
 void *buff,
 C_DATAINDEX buffsize,
 void *outbuff,
 C_DATAINDEX * osize,
 COMPTYPE comp_type,
 C_DATAINDEX max_out_size)
{ /* Buffers can have up to 32768 bytes, ie indexes
 0..32767 */
C_DATA *ibuff, *obuff;
C_DATAINDEX i, nbytes;

 if (buffsize > 32768U) {
 sperror(__LINE__,__FILE__,
 "ERROR: "
 "Parameter 'buffsize' of unsquidge() is negative, or too large (%u).\n",
 buffsize);
 if (sizeof(C_DATAINDEX) <= 2)
 sperror(__LINE__,__FILE__, " (perhaps you are using an int > 32768 ?)\n");
 return (0 != 0);
 }
 nbytes = buffsize;
 ibuff = (C_DATA *) buff;
 obuff = (C_DATA *) outbuff;
 if (comp_type == TYPE_UNCOMPRESSED) {
 for (i = 0; i < nbytes; i++)
 obuff[i] = ibuff[i];
 *osize = nbytes;
 return (0 == 0);
 } else if (comp_type == TYPE_TIGGR_LZ) {
 return (Tigr_decomp_buff(
 comp_type, ibuff, obuff, (C_DATAINDEX) nbytes, osize, max_out_size));
 } else if (comp_type == TYPE_TIM_BELL_LZ) {
#ifdef BELL_LICENCE
 return (Bell_decomp_buff(
 comp_type, ibuff, obuff, (C_DATAINDEX) nbytes, osize, max_out_size));
#else
 sperror(__LINE__,__FILE__, "Sorry - the code to decompress this type of block has to be licenced\n");
 exit(EXIT_FAILURE);
#endif
 } else if (comp_type == TYPE_WORD) {
 return (Word_decomp_buff(
 comp_type, ibuff, obuff, (C_DATAINDEX) nbytes, osize, max_out_size));
 } else {
 sperror(__LINE__,__FILE__, "unsquidge: compression type %d not supported\n", comp_type);
 return (0 != 0);
 }
 return (0 != 0);
}

void comp_init(C_DATAINDEX buffsize)
{
#ifdef Never
#ifdef BELL_LICENCE
 Bell_comp_init(buffsize);
#endif
 Tigr_comp_init(buffsize);
 Word_comp_init(buffsize);
#endif
}

void decomp_init(C_DATAINDEX buffsize)
{
#ifdef Never
#ifdef BELL_LICENCE
 Bell_decomp_init(buffsize);
#endif
 Tigr_decomp_init(buffsize);
 Word_decomp_init(buffsize);
#endif
}

void comp_terminate(void)
{
#ifdef Never
#ifdef BELL_LICENCE
 Bell_comp_terminate();
#endif
 Tigr_comp_terminate();
 Word_comp_terminate();
#endif
}

void decomp_terminate(void)
{
#ifdef Never
#ifdef BELL_LICENCE
 Bell_decomp_terminate();
#endif
 Tigr_decomp_terminate();
 Word_decomp_terminate();
#endif
}



int decomp_file(char *infile, char *outfile)
{
long t_total=0L,this_gap;
#define BUFFSIZE (32U*1024U)
char *inbuff /* [BUFFSIZE] */ ;
char *outbuff /* [BUFFSIZE] */ ;
C_DATAINDEX insize, outsize, expected_outsize;
FILEINDEX idx_pos, idx_entries, expanded_filesize;
COMPTYPE comp_type;
BINARYFILE bin = BADFILE;
BINARYFILE out = BADFILE;
C_DATAINDEX buffsize;
FILEINDEX next_idx_entry;
FILEINDEX next_block;
FILEINDEX blocknum;
long check_magic = 0L;

 if ((infile == NULL) || (*infile == '\0') || (outfile == NULL) || (*outfile == '\0')) {
 sperror(__LINE__,__FILE__, "BlokComp: should not be passed null filenames\n");
 exit(EXIT_ERR);
 }

 bin = FOPEN(infile, RB);
 if (bin == BADFILE) {
 sperror(__LINE__,__FILE__, "unsquidge: cannot open input file '%s'\n", infile);
 return (EXIT_ERR);
 }
 out = FOPEN(outfile, WB);
 if (out == BADFILE) {
 sperror(__LINE__,__FILE__,
 "unsquidge: cannot open output file '%s'\n", outfile);
 return (EXIT_ERR);
 }
 (void) get4(check_magic, bin); /* Start of index */
 if (check_magic != SQUIDGE_MAGIC) {
 sperror(__LINE__,__FILE__, "unsquidge: %s is not a squidged file!\n", infile);
 exit(EXIT_ERR);
 }
 (void) get4(idx_pos, bin); /* Start of index */
 (void) get4(idx_entries, bin); /* Count of index entries */
 (void) get4(expanded_filesize, bin); /* File size once expanded */
 (void) get2(buffsize, bin);
 inbuff = malloc(BUFFSIZE);
 outbuff = malloc(BUFFSIZE);
 if (inbuff == NULL || outbuff == NULL) {
 if (inbuff != NULL)
 free(inbuff);
 if (outbuff != NULL)
 free(outbuff); /* Shouldn't ever be allocated! */
 sperror(__LINE__,__FILE__, "unsquidge: cannot allocate data buffers\n");
 return (EXIT_ERR);
 }
 decomp_init(buffsize);
 for (blocknum = 0L; blocknum < idx_entries; blocknum += 1L) {
 next_idx_entry = idx_pos + (4 * blocknum);
 FSEEK(bin, next_idx_entry, SEEK_SET);
 (void) get4(next_block, bin);
 FSEEK(bin, next_block, SEEK_SET);
 (void) get2(insize, bin);
 (void) get2(expected_outsize, bin);
 (void) get1(comp_type, bin);
 insize = FREAD(inbuff, 1, insize, bin);
 if (FERROR(bin)) {
 sperror(__LINE__,__FILE__, "unsquidge: %s\n", strerror(errno));
 return (EXIT_ERR);
 }
 if (insize == 0U)
 break;
 expected_outsize = buffsize; /****** TEMP FOR THE MOMENT ******/
 if (!unsquidge(inbuff, insize, outbuff, &outsize, comp_type, expected_outsize)) {
 sperror(__LINE__,__FILE__, "Decompression error!\n");
 return (EXIT_ERR);
 }
 if (FWRITE(outbuff, 1, outsize, out) != outsize)
 WRERR(out);
 }

#ifdef Never
#ifdef BELL_LICENCE
 Bell_decomp_terminate();
#endif
 Tigr_decomp_terminate();
 Word_decomp_terminate();
#endif
 if (FCLOSE(out) != 0)
 WRERR(out);
 if (FCLOSE(bin) != 0)
 WRERR(bin);
 free(inbuff);
 free(outbuff);
 return (0);
}


int comp_file(char *infile, char *outfile,C_DATAINDEX testbuff_size)
{
long out_total=0L;
long t_total=0L,this_gap;
#define BUFFSIZE (32U*1024U)
char *inbuff /* [BUFFSIZE] */ ;
char *outbuff /* [BUFFSIZE] */ ;
C_DATAINDEX insize, outsize;
FILEINDEX cur_pos, idx_pos, idx_entries, expanded_filesize = 0L;
COMPTYPE comp_type;
BINARYFILE txt = BADFILE;
BINARYFILE bin = BADFILE;
BINARYFILE idx = BADFILE;
char *temp_file;


 if ((infile == NULL) || (*infile == '\0') || (outfile == NULL) || (*outfile == '\0')) {
 sperror(__LINE__,__FILE__, "BlokComp: should not be passed null filenames\n");
 exit(EXIT_ERR);
 }

 txt = FOPEN(infile, RB);
 if (txt == BADFILE) {
 sperror(__LINE__,__FILE__, "squidge: cannot open input file '%s'\n", infile);
 return (EXIT_ERR);
 }
 FSEEK(txt, 0L, SEEK_END);
 expanded_filesize = FTELL(txt);
 FSEEK(txt, 0L, SEEK_SET);

 bin = FOPEN(outfile, WB);
 if (bin == BADFILE) {
 sperror(__LINE__,__FILE__, "squidge: cannot open output file '%s'\n", outfile);
 return (EXIT_ERR);
 }
 temp_file = TEMP_FILE;
 idx = FOPEN(temp_file, WB);
 if (idx == BADFILE) {
 sperror(__LINE__,__FILE__, "squidge: cannot open temp index file '%s'\n", "tmpidx");
 return (EXIT_ERR);
 }
 inbuff = malloc(BUFFSIZE);
 outbuff = malloc(BUFFSIZE);
 if (inbuff == NULL || outbuff == NULL) {
 if (inbuff != NULL)
 free(inbuff);
 if (outbuff != NULL)
 free(outbuff); /* Shouldn't ever be allocated! */
 sperror(__LINE__,__FILE__, "squidge: cannot allocate data buffers\n");
 return (EXIT_ERR);
 }
 comp_init(testbuff_size);
 (void) put4(0L, bin); /* magic word -- patch when closing. */
 (void) put4(0L, bin); /* Ptr to table -- patch when completed */
 (void) put4(0L, bin); /* Len of table -- ditto */
 (void) put4(expanded_filesize, bin); /* File size once expanded */
 (void) put2(testbuff_size, bin); /* Decompression blocksize */
 idx_entries = 0L;
 for (;;) {

 insize = FREAD(inbuff, 1, testbuff_size, txt);
 if (FERROR(txt)) {
 sperror(__LINE__,__FILE__, "squidge: %s\n", strerror(errno));
 return (EXIT_ERR);
 }
 if (insize == 0)
 break;
 if ((comp_type = squidge(inbuff, insize, outbuff, &outsize)) == TYPE_ERR) {
 sperror(__LINE__,__FILE__, "Compression error!\n");
 return (EXIT_ERR);
 }

 cur_pos = FTELL(bin);
 (void) put2(outsize, bin); /* Compressed size */
 (void) put2(insize, bin); /* Uncompressed size */
 if ( (comp_type != TYPE_TIGGR_LZ)
 && (comp_type != TYPE_TIM_BELL_LZ)
 && (comp_type != TYPE_WORD)) {
 if (comp_type == TYPE_UNCOMPRESSED) {
 /*
 It is part of the spec that if the data is incompressible, you
 have to copy it yourself. This gives the user the option of
 several optimisations without forcing the overhead
 */
 (void) put1(comp_type, bin);
 if (FWRITE(inbuff, 1, insize, bin) != insize)
 WRERR(bin);
 outsize = insize; /* Just in case it is used again later */
 } else {
 sperror(__LINE__,__FILE__, "Programmer warning: new compress type added?\n");
 }
 } else {
 (void) put1(comp_type, bin);
 if (FWRITE(outbuff, 1, outsize, bin) != outsize)
 WRERR(bin);
 }
 idx_entries += 1L;
 (void) put4(cur_pos, idx);
 }
 /* Terminate blocks (in case reading sequentially) */
 (void) put2(0, bin);
#ifdef Never
#ifdef BELL_LICENCE
 Bell_comp_terminate();
#endif
 Tigr_comp_terminate();
 Word_comp_terminate();
#endif
 FCLOSE(idx);
 idx_pos = FTELL(bin); /* Index start */
 idx = FOPEN(temp_file, RB);
 if (idx == BADFILE) {
 sperror(__LINE__,__FILE__, "squidge: cannot open temp index file '%s'\n", "tmpidx");
 return (EXIT_ERR);
 }
 /* Copy index from idx file to end of bin file, and patch start address */
 for (;;) {
int c;

 c = FGETC(idx);
 if (c == EOF)
 break;
 FPUTC(c, bin);
 }
 FSEEK(bin, 0L, SEEK_SET);
 (void) put4(SQUIDGE_MAGIC, bin);
 (void) put4(idx_pos, bin);
 (void) put4(idx_entries, bin);
 FCLOSE(idx);
 FCLOSE(bin);
 FCLOSE(txt);

 remove(temp_file);
 free(inbuff);
 free(outbuff);

 return (0);
}

#ifdef DBMAIN

#define MAINDECL int main(int argc, char **argv)
MAINDECL
{
 sperror(__LINE__,__FILE__, "BlokComp: dbmain temporarily withdrawn\n");
 return(0);
}

#endif

