/* *------------------------------------------------------------------------------- * 4.1 LZSS_CompressData *------------------------------------------------------------------------------- * * LZSS compress data * * This routine compress data from an in buffer using the LZSS algorithm. LZSS is * a dictionary compression method where the dictionary is a sliding window. The * routine uses a look-ahead buffer and finds matches in previously read bytes * stored in a sliding window. * If a match is found an index/length pair is written to the output buffer * (index is the position in the sliding window). If no match is found the read * byte is just bypassed to the out buffer. To indicate if the data is an * index/length pair or a plain text byte a single bit is used as indicator flag * and is written to the out buffer. * To speed up the compression a binary tree is used for storing previously * compressed data. * * param inBuf Input data buffer with byte access * param outBuf output data buffer with bit access * * return void * */ public static byte[] LZSS_CompressData(byte[] inBuf) { /** Index var. for loop */ int i = 0; /** Byte read from input stream */ int inByte = 0; /** Number of bytes in the look head buffer */ int aheadBytes = 0; /** Current position in the window */ int winPos = 1; /** Number of bytes to replace in the window */ int replCnt = 0; /** Length of the data match found in the window */ int matchLen = 0; /** Position in the window of the data match */ int matchPos = 0; /** Indicator of End Of Stream reached */ bool eosReached = false; BitQuery Result = new BitQuery(); BitQuery BQ = new BitQuery(inBuf); /* Start with filling up the look-ahead buffer */ while ((aheadBytes < LZSS_LOOK_AHEAD_SIZE) && (!eosReached)) { /* Get next input byte */ inByte = BQ.GetByte(); /* If input stream is finished, exit */ if (inByte == LZSS_END_OF_INPUT_STREAM) { eosReached = true; } else { /* Add byte to wondow */ LZSS_window[winPos + aheadBytes] = inByte; /* Increase look-ahead bytes*/ aheadBytes = (aheadBytes + 1) & 0xFF; } } /* Initialize the tree */ LZSS_InitTree(winPos); /* While there still are bytes in the look ahead buffer, loop */ while (aheadBytes > 0) { /* If previously match length greater than look ahead bytes it's * not possible to code correctly */ if (matchLen > aheadBytes) { /* Set matched length to look-ahead buffer length */ matchLen = aheadBytes; } /* If the match is smaller than the compressed data (position/length- * pair) there will be negative compression so just output the byte */ if (matchLen <= LZSS_BREAK_EVEN) { /* Set consumed bytes in input stream to 1 */ replCnt = 1; /* Indicate that next byte in output stream is uncompressed * by output a '1' */ Result.PutBit(1); /* Output uncompressed byte */ Result.PutBits(LZSS_window[winPos], 8); } /* The match is larger than a position/length pair, compression can be * done */ else { /* Indicate that the following bits are compressed data by output a * '0' */ Result.PutBit(0); /* Output position in the window */ Result.PutBits(matchPos, LZSS_INDEX_BIT_COUNT); /* Output the length of the match, (length is the number of bytes * that is greater than LZSS_BREAK_EVEN) */ Result.PutBits((matchLen - (LZSS_BREAK_EVEN + 1)), LZSS_LENGTH_BIT_COUNT); /* Set consumed bytes in input stream to the length of the match */ replCnt = matchLen; } /* Delete consumed bytes and add new bytes in the window */ for (i = 0; i < replCnt; i++) { /* Remove consumed byte from the window */ LZSS_DeleteNode(LZSS_MOD_WINDOW(winPos + (UInt16)LZSS_LOOK_AHEAD_SIZE)); /* Get next input byte */ inByte = BQ.GetByte(); /* If input stream is finished */ if (inByte == LZSS_END_OF_INPUT_STREAM) { /* Decrease the look-ahead bytes */ aheadBytes = (aheadBytes - 1) & 0xFF; } else { /* Add the new byte from the input stream to the window */ LZSS_window[LZSS_MOD_WINDOW(winPos + LZSS_LOOK_AHEAD_SIZE)] = inByte; } /* Increase the position in the window */ winPos = LZSS_MOD_WINDOW(winPos + 1); /* If there still are bytes in the look-ahead buffer */ if (aheadBytes != 0) { /* Add byte position to the tree and get the length of the * match */ matchLen = LZSS_AddNode(winPos, ref matchPos); } } } /* Input stream finished, write end of stream to the output buffer * uncompressed */ //OutputBit(outBuf, (Uint8_T)0); Result.PutBit(0); //OutputBits(outBuf, (Uint32_T)LZSS_END_OF_STREAM, LZSS_INDEX_BIT_COUNT); Result.PutBits(LZSS_END_OF_STREAM, LZSS_INDEX_BIT_COUNT); return Result.Export(); }
public static byte[] LZSS_ExpandData(byte[] mInput) { /** Current window position */ int winPos = 1; /** Byte to write to output buffer */ byte outByte = 0; /** Length of the data match found */ int matchLen = 0; /** Position in the window of the data match */ int matchPos = 0; /** Indicator of End Of Stream reached */ bool eosReached = false; //Private Virable BitQuery BQ = new BitQuery(mInput); List<byte> Result = new List<byte>(); byte[] LZSS_window = new byte[LZSS_WINDOW_SIZE]; try { while (!eosReached) { /* If next bit is 1, next byte is uncompressed*/ if (BQ.GetBit() == 1) { /* Get uncompressed byte */ outByte = Convert.ToByte(BQ.GetByte()); /* Output byte*/ Result.Add(outByte); /* Add byte in window */ LZSS_window[winPos] = outByte; /* Increase window position */ winPos = (winPos + 1) & (LZSS_WINDOW_SIZE - 1); } /* If next bit is 0, compressed data follows */ else { /* Get compressed data as window position of match*/ matchPos = BQ.GetBit(LZSS_INDEX_BIT_COUNT); /* If end of stream, exit */ if (matchPos == LZSS_END_OF_STREAM) { eosReached = true; } else { /* Get length of string match */ matchLen = BQ.GetBit(LZSS_LENGTH_BIT_COUNT); /* Add break even + 1 to get the correct length. Length zero and * the break even value are subtracted from the length during * compression to save space. */ matchLen = matchLen + (LZSS_BREAK_EVEN + 1); /* For every byte in match */ for (int i = 0; i < matchLen; i++) { /* Get matching byte from window */ outByte = LZSS_window[(matchPos + i) & (LZSS_WINDOW_SIZE - 1)]; /* Output byte */ Result.Add(outByte); /* Add matched byte to current window position */ LZSS_window[winPos] = outByte; /* Increase window position */ winPos = (winPos + 1) & (LZSS_WINDOW_SIZE - 1); } } } } } catch { return null; } return Result.ToArray<byte>(); }