/*
* Copyright (c) Tony Bybell 2008-2017.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
#include "hierpack.h"
#define VLI_SIZE (10)
static void out_c(unsigned char ch)
{
if((GLOBALS->fmem_buf_offs+1) >= GLOBALS->fmem_buf_siz)
{
GLOBALS->fmem_buf = realloc_2(GLOBALS->fmem_buf, GLOBALS->fmem_buf_siz = 2 * GLOBALS->fmem_buf_siz);
}
GLOBALS->fmem_buf[GLOBALS->fmem_buf_offs++] = ch;
}
static int enc_var(size_t v, unsigned char *buf)
{
size_t nxt;
unsigned char *pnt = buf+VLI_SIZE;
while((nxt = v>>7))
{
*(--pnt) = (v&0x7f) | 0x80;
v = nxt;
}
*(--pnt) = (v&0x7f);
return(buf+VLI_SIZE-pnt);
}
static void out_write(unsigned char *s, int len)
{
int i;
for(i=0;i<len;i++)
{
out_c(s[i]);
}
}
void init_facility_pack(void)
{
if(GLOBALS->do_hier_compress)
{
fprintf(stderr, "FACPACK | Using compressed facilities\n");
GLOBALS->fmem_buf_offs = 0;
GLOBALS->fmem_buf_siz = 1024*1024;
GLOBALS->fmem_buf = malloc_2(GLOBALS->fmem_buf_siz);
GLOBALS->hp_buf_siz = 1024;
GLOBALS->hp_buf = calloc_2(GLOBALS->hp_buf_siz, sizeof(unsigned char));
GLOBALS->hp_offs = calloc_2(GLOBALS->hp_buf_siz, sizeof(size_t));
}
}
void freeze_facility_pack(void)
{
if(GLOBALS->do_hier_compress)
{
free_2(GLOBALS->hp_buf); GLOBALS->hp_buf = NULL;
free_2(GLOBALS->hp_offs); GLOBALS->hp_offs = NULL;
GLOBALS->hp_buf_siz = 0;
if(GLOBALS->fmem_buf)
{
GLOBALS->fmem_buf = realloc_2(GLOBALS->fmem_buf, GLOBALS->hp_prev);
}
fprintf(stderr, "FACPACK | Compressed %lu to %lu bytes.\n", (unsigned long)GLOBALS->fmem_uncompressed_siz, (unsigned long)GLOBALS->hp_prev);
}
}
char *compress_facility(unsigned char *key, unsigned int len)
{
size_t mat = 0;
size_t plen;
size_t i;
unsigned char vli[VLI_SIZE];
if(len > GLOBALS->hp_buf_siz)
{
GLOBALS->hp_buf_siz = len;
GLOBALS->hp_buf = realloc_2(GLOBALS->hp_buf, GLOBALS->hp_buf_siz * sizeof(unsigned char));
GLOBALS->hp_offs = realloc_2(GLOBALS->hp_offs, GLOBALS->hp_buf_siz * sizeof(size_t));
}
GLOBALS->fmem_uncompressed_siz += (len + 1);
for(i=0;i<=len;i++)
{
if(!key[i]) break;
mat = i;
if(key[i] != GLOBALS->hp_buf[i]) break;
}
if(!mat)
{
GLOBALS->hp_prev += (plen = enc_var(mat, vli));
out_write(vli+VLI_SIZE-plen, plen);
}
else
{
size_t back = GLOBALS->hp_prev - GLOBALS->hp_offs[mat-1];
plen = enc_var(back, vli);
if(mat > plen)
{
GLOBALS->hp_prev += plen;
out_write(vli+VLI_SIZE-plen, plen);
}
else
{
mat = 0;
GLOBALS->hp_prev += (plen = enc_var(mat, vli));
out_write(vli+VLI_SIZE-plen, plen);
}
}
out_c(0);
GLOBALS->hp_prev++;
for(i=mat;i<len;i++)
{
out_c(key[i]);
GLOBALS->hp_buf[i] = key[i];
GLOBALS->hp_offs[i] = GLOBALS->hp_prev;
GLOBALS->hp_prev++;
}
GLOBALS->hp_buf[i] = 0; GLOBALS->hp_offs[i] = 0;
return( (((GLOBALS->hp_prev-1)<<1)|1) + ((char *)NULL) ); /* flag value with |1 to indicate is compressed */
}
char *hier_decompress_flagged(char *n, int *was_packed)
{
size_t dcd;
size_t dcd2;
size_t val;
char *str;
int ob;
int shamt;
int avoid_strdup = *was_packed;
*was_packed = GLOBALS->do_hier_compress;
if(!GLOBALS->do_hier_compress)
{
return(n);
}
dcd = n - ((char *)NULL);
if(!(dcd & 1)) /* value was flagged with |1 to indicate is compressed; malloc never returns this */
{
*was_packed = 0;
return(n);
}
dcd >>= 1;
str = GLOBALS->module_tree_c_1;
ob = GLOBALS->longestname + 1;
str[--ob] = 0;
do
{
while(GLOBALS->fmem_buf[dcd])
{
str[--ob] = GLOBALS->fmem_buf[dcd];
dcd--;
}
dcd2 = --dcd;
val = 0;
shamt = 0;
for(;;)
{
val |= ((GLOBALS->fmem_buf[dcd2] & 0x7f) << shamt); shamt += 7;
if(!(GLOBALS->fmem_buf[dcd2] & 0x80)) break;
dcd2--;
}
dcd = dcd2 - val;
} while(val);
return((avoid_strdup != HIER_DEPACK_ALLOC) ? (str+ob) : strdup_2(str+ob));
}
void hier_auto_enable(void)
{
if((!GLOBALS->do_hier_compress) && (!GLOBALS->disable_auto_comphier) && (GLOBALS->numfacs >= HIER_AUTO_ENABLE_CNT))
{
GLOBALS->do_hier_compress = 1;
}
}