common/recipes-utils/jbi/files/code/jbicomp.c (269 lines of code) (raw):
/****************************************************************************/
/* */
/* Module: jbicomp.c */
/* */
/* Copyright (C) Altera Corporation 1997-2001 */
/* */
/* Description: Contains the code for compressing and uncompressing */
/* Boolean array data. */
/* */
/* This algorithm works by searching previous bytes in the */
/* data that match the current data. If a match is found, */
/* then the offset and length of the matching data can */
/* replace the actual data in the output. */
/* */
/* Revisions: 2.2 fixed /W4 warnings */
/* */
/****************************************************************************/
#include "jbiport.h"
#include "jbiexprt.h"
#include "jbicomp.h"
#define SHORT_BITS 16
#define CHAR_BITS 8
#define DATA_BLOB_LENGTH 3
#define MATCH_DATA_LENGTH 8192
#define JBI_ACA_REQUEST_SIZE 1024
#define JBI_ACA_BUFFER_SIZE (MATCH_DATA_LENGTH + JBI_ACA_REQUEST_SIZE)
unsigned long jbi_in_length = 0L;
unsigned long jbi_in_index = 0L; /* byte index into compressed array */
unsigned int jbi_bits_avail = CHAR_BITS;
#if PORT == DOS
int jbi_current_variable_id = -1;
int jbi_current_page = -1;
int jbi_version = 0;
unsigned long jbi_out_length = 0L;
unsigned int jbi_out_index = 0; /* byte index into jbi_aca_out_buffer[] */
unsigned long jbi_aca_in_offset = 0L;
unsigned char jbi_aca_out_buffer[JBI_ACA_BUFFER_SIZE];
#endif
/****************************************************************************/
/* */
/* The following functions implement incremental decompression of Boolean */
/* array data, using a small memory window. */
/* */
/* This algorithm works by searching previous bytes in the data that match */
/* the current data. If a match is found, then the offset and length of */
/* the matching data can replace the actual data in the output. */
/* */
/* Memory usage is reduced by maintaining a "window" buffer which contains */
/* the uncompressed data for one 8K page, plus some extra amount specified */
/* by JBI_ACA_REQUEST_SIZE. The function jbi_uncompress_page() is used to */
/* request a subrange of the uncompressed data, starting at a particular */
/* bit position and extending a maximum of JBI_ACA_REQUEST_SIZE bytes. */
/* */
/****************************************************************************/
/****************************************************************************/
/* */
unsigned int jbi_bits_required(unsigned int n)
/* */
/* Description: Calculate the minimum number of bits required to */
/* represent n. */
/* */
/* Returns: Number of bits. */
/* */
/****************************************************************************/
{
unsigned int result = SHORT_BITS;
if (n == 0)
{
result = 1;
}
else
{
/* Look for the highest non-zero bit position */
while ((n & (1 << (SHORT_BITS - 1))) == 0)
{
n <<= 1;
--result;
}
}
return (result);
}
/****************************************************************************/
/* */
unsigned int jbi_read_packed
(
#if PORT!=DOS
unsigned char *buffer,
#endif
unsigned int bits
)
/* */
/* Description: Read the next value from the input array "buffer". */
/* Read only "bits" bits from the array. The amount of */
/* bits that have already been read from "buffer" is */
/* stored internally to this function. */
/* */
/* Returns: Up to 16 bit value. -1 if buffer overrun. */
/* */
/****************************************************************************/
{
unsigned int result = 0;
unsigned int shift = 0;
unsigned int databyte = 0;
while (bits > 0)
{
#if PORT==DOS
databyte = GET_BYTE(jbi_aca_in_offset + jbi_in_index);
#else
databyte = buffer[jbi_in_index];
#endif
result |= (((databyte >> (CHAR_BITS - jbi_bits_avail))
& (0xFF >> (CHAR_BITS - jbi_bits_avail))) << shift);
if (bits <= jbi_bits_avail)
{
result &= (0xFFFF >> (SHORT_BITS - (bits + shift)));
jbi_bits_avail -= bits;
bits = 0;
}
else
{
++jbi_in_index;
shift += jbi_bits_avail;
bits -= jbi_bits_avail;
jbi_bits_avail = CHAR_BITS;
}
}
return (result);
}
#if PORT==DOS
/****************************************************************************/
/* */
void jbi_uncompress_next_page(int version)
/* */
/* Description: Uncompresses one page of compressed data, using */
/* data page as reference for repeated sections. */
/* Overwrites previous page of data in buffer. */
/* */
/* Returns: TRUE for success, FALSE if error encountered */
/* */
/****************************************************************************/
{
unsigned int i, j, offset, length;
unsigned int end_index;
unsigned long tmp_in_index = jbi_in_index;
unsigned int tmp_out_index = jbi_out_index;
unsigned int tmp_bits_avail = jbi_bits_avail;
unsigned int prev[3];
unsigned long long_end;
unsigned int match_data_length = MATCH_DATA_LENGTH;
if (version > 0) --match_data_length;
if (jbi_current_page < 0)
{
/* this is the first page of the array */
jbi_current_page = 0;
jbi_in_index = 4; /* skip over length field */
jbi_out_index = 0;
end_index = (jbi_out_length < JBI_ACA_BUFFER_SIZE) ?
(unsigned int) jbi_out_length : JBI_ACA_BUFFER_SIZE;
}
else
{
/* this is not the first page */
++jbi_current_page;
jbi_out_index -= MATCH_DATA_LENGTH;
long_end = jbi_out_length -
((long) jbi_current_page * (long) MATCH_DATA_LENGTH);
end_index = (long_end < JBI_ACA_BUFFER_SIZE) ?
(unsigned int) long_end : JBI_ACA_BUFFER_SIZE;
/* copy extra data from end of circular buffer to beginning */
for (i = 0; i < jbi_out_index; ++i)
{
jbi_aca_out_buffer[i] = jbi_aca_out_buffer[i + MATCH_DATA_LENGTH];
}
}
while (jbi_out_index < end_index)
{
/* save state so we can undo the last packet when we reach the end */
tmp_in_index = jbi_in_index;
tmp_out_index = jbi_out_index;
tmp_bits_avail = jbi_bits_avail;
/* A 0 bit indicates literal data. */
if (jbi_read_packed(1) == 0)
{
for (i = 0; i < DATA_BLOB_LENGTH; ++i)
{
if (jbi_out_index < end_index)
{
if (version == 0)
{
prev[i] = jbi_aca_out_buffer[jbi_out_index] & 0xff;
}
jbi_aca_out_buffer[jbi_out_index++] =
(unsigned char) jbi_read_packed(CHAR_BITS);
}
}
}
else
{
/* A 1 bit indicates offset/length to follow. */
offset = jbi_read_packed(jbi_bits_required(
(jbi_current_page > 0) ? match_data_length :
(jbi_out_index > match_data_length ? match_data_length :
jbi_out_index)));
length = jbi_read_packed(CHAR_BITS);
if ((version == 0) && (offset == match_data_length + 3))
{
jbi_aca_out_buffer[jbi_out_index++] = (unsigned char) prev[0];
jbi_aca_out_buffer[jbi_out_index++] = (unsigned char) prev[1];
jbi_aca_out_buffer[jbi_out_index++] = (unsigned char) prev[2];
length -= 3;
}
for (i = 0; i < length; ++i)
{
if (jbi_out_index < end_index)
{
if (offset > jbi_out_index)
{
j = jbi_out_index + MATCH_DATA_LENGTH - offset;
}
else j = jbi_out_index - offset;
jbi_aca_out_buffer[jbi_out_index] = jbi_aca_out_buffer[j];
++jbi_out_index;
}
}
if (version == 0)
{
prev[0] = jbi_aca_out_buffer[jbi_out_index - 3] & 0xff;
prev[1] = jbi_aca_out_buffer[jbi_out_index - 2] & 0xff;
prev[2] = jbi_aca_out_buffer[jbi_out_index - 1] & 0xff;
}
}
}
/* restore the state before the previous packet */
jbi_in_index = tmp_in_index;
jbi_out_index = tmp_out_index;
jbi_bits_avail = tmp_bits_avail;
}
/****************************************************************************/
/* */
void jbi_uncompress_page
(
int variable_id,
int page,
int version
)
/* */
/* Description: Uncompress requested page of variable data. Stores */
/* uncompressed data in jbi_aca_out_buffer[]. */
/* */
/* Returns: TRUE if successful, otherwise FALSE if: */
/* 1) variable is not a compressed array */
/* 2) compressed data is illegal or corrupted */
/* 3) requested page is beyond the end of the array */
/* 4) internal error in the code */
/* */
/****************************************************************************/
{
unsigned long symbol_table;
unsigned long data_section;
unsigned long offset;
unsigned long value;
int delta = version * 2;
if (variable_id != jbi_current_variable_id)
{
/* initialize to uncompress the desired variable */
symbol_table = GET_DWORD(16 + (version * 8));
data_section = GET_DWORD(20 + (version * 8));
offset = symbol_table + ((11 + delta) * variable_id);
value = GET_DWORD(offset + 3 + delta);
jbi_current_variable_id = variable_id;
jbi_current_page = -1;
jbi_bits_avail = CHAR_BITS;
jbi_in_length = GET_DWORD(offset + 7 + delta);
jbi_out_length =
(((unsigned long) GET_BYTE(data_section + value)) |
(((unsigned long) GET_BYTE(data_section + value + 1)) << 8) |
(((unsigned long) GET_BYTE(data_section + value + 2)) << 16) |
(((unsigned long) GET_BYTE(data_section + value + 3)) << 24));
jbi_in_index = 4; /* skip over length field */
jbi_out_index = 0;
jbi_aca_in_offset = data_section + value;
}
/* to look back at an earlier page, start over at the beginning */
if (page < jbi_current_page)
{
jbi_current_page = -1;
jbi_in_index = 4; /* skip over length field */
jbi_bits_avail = CHAR_BITS;
}
/* uncompress sequentially up to the desired page */
while (page > jbi_current_page)
{
jbi_uncompress_next_page(version);
}
}
#else
/****************************************************************************/
/* */
unsigned long jbi_uncompress
(
unsigned char *in,
unsigned long in_length,
unsigned char *out,
unsigned long out_length,
int version
)
/* */
/* Description: Uncompress data in "in" and write result to "out". */
/* */
/* Returns: Length of uncompressed data. -1 if: */
/* 1) out_length is too small */
/* 2) Internal error in the code */
/* 3) in doesn't contain ACA compressed data. */
/* */
/****************************************************************************/
{
unsigned long i, j, data_length = 0L;
unsigned int offset, length;
unsigned int match_data_length = MATCH_DATA_LENGTH;
if (version > 0) --match_data_length;
jbi_in_length = in_length;
jbi_bits_avail = CHAR_BITS;
jbi_in_index = 0L;
for (i = 0; i < out_length; ++i) out[i] = 0;
/* Read number of bytes in data. */
for (i = 0; i < sizeof (in_length); ++i)
{
data_length = data_length | ((unsigned long)
jbi_read_packed(in, CHAR_BITS) << (i * CHAR_BITS));
}
if (data_length > out_length)
{
data_length = 0L;
}
else
{
i = 0;
while (i < data_length)
{
/* A 0 bit indicates literal data. */
if (jbi_read_packed(in, 1) == 0)
{
for (j = 0; j < DATA_BLOB_LENGTH; ++j)
{
if (i < data_length)
{
out[i] = (unsigned char) jbi_read_packed(in, CHAR_BITS);
i++;
}
}
}
else
{
/* A 1 bit indicates offset/length to follow. */
offset = jbi_read_packed(in, jbi_bits_required((short) (i > match_data_length ? match_data_length : i)));
length = jbi_read_packed(in, CHAR_BITS);
for (j = 0; j < length; ++j)
{
if (i < data_length)
{
out[i] = out[i - offset];
i++;
}
}
}
}
}
return (data_length);
}
#endif