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