/*************************************************************************** * Lempel, Ziv, Storer, and Szymanski Decoding * * File : lzdecode.c * Purpose : Use lzss coding (Storer and Szymanski's modified LZ77) to * decompress lzss encoded files. * Author : Michael Dipperstein * Date : November 07, 2004 * **************************************************************************** * UPDATES * * Date Change * 12/10/03 Changed handling of sliding window to better match standard * algorithm description. * 12/11/03 Remebered to copy encoded characters to the sliding window * even when there are no more characters in the input stream. * * * Revision 1.2 2004/02/22 17:14:26 michael * - Separated encode/decode, match finding, and main. * - Use bitfiles for reading/writing files * - Use traditional LZSS encoding where the coded/uncoded bits * precede the symbol they are associated with, rather than * aggregating the bits. * * Revision 1.1.1.1 2004/01/21 06:25:49 michael * Initial version * * 11/07/04 Separated encode and decode functions for improved * modularity. * * $Id: lzdecode.c,v 1.7 2007/09/20 04:34:25 michael Exp $ * $Log: lzdecode.c,v $ * Revision 1.7 2007/09/20 04:34:25 michael * Changes required for LGPL v3. * * Revision 1.6 2007/03/25 05:11:32 michael * Corrected file closure error reported by "Carl@Yahoo" . Now both input * and output files are closed. * * Revision 1.5 2006/12/26 04:09:09 michael * Updated e-mail address and minor text clean-up. * * Revision 1.4 2006/12/26 02:05:00 michael * Corrected bug identified by Andrej Sinicyn which resulted in stdin being * used as the default output for decoded data. * * Revision 1.3 2005/12/28 06:03:30 michael * Use slower but clearer Get/PutBitsInt for reading/writing bits. * Replace mod with conditional Wrap macro. * * Revision 1.2 2004/11/13 22:51:00 michael * Provide distinct names for by file and by name functions and add some * comments to make their usage clearer. * * Revision 1.1 2004/11/08 05:54:18 michael * 1. Split encode and decode routines for smarter linking * 2. Renamed lzsample.c sample.c to match my other samples * 3. Makefile now builds code as libraries for better LGPL compliance. * * * **************************************************************************** * * LZDecode: An ANSI C LZSS Decoding Routines * Copyright (C) 2003-2007 by * Michael Dipperstein (mdipper@alumni.engr.ucsb.edu) * * This file is part of the lzss library. * * The lzss library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * The lzss library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * ***************************************************************************/ /*************************************************************************** * INCLUDED FILES ***************************************************************************/ #include #include #include #include "lzlocal.h" #include "bitfile.h" /*************************************************************************** * TYPE DEFINITIONS ***************************************************************************/ /*************************************************************************** * CONSTANTS ***************************************************************************/ /*************************************************************************** * GLOBAL VARIABLES ***************************************************************************/ /* cyclic buffer sliding window of already read characters */ extern unsigned char slidingWindow[]; extern unsigned char uncodedLookahead[]; /*************************************************************************** * PROTOTYPES ***************************************************************************/ /*************************************************************************** * FUNCTIONS ***************************************************************************/ /**************************************************************************** * Function : DecodeLZSSByFile * Description: This function will read an LZSS encoded input file and * write an output file. This algorithm encodes strings as 16 * bits (a 12 bit offset + a 4 bit length). * Parameters : fpIn - pointer to the open binary file to decode * fpOut - pointer to the open binary file to write decoded * output * Effects : fpIn is decoded and written to fpOut. Neither file is * closed after exit. * Returned : EXIT_SUCCESS or EXIT_FAILURE ****************************************************************************/ int DecodeLZSSByFile(FILE *fpIn, FILE *fpOut) { bit_file_t *bfpIn; int c; unsigned int i, nextChar; encoded_string_t code; /* offset/length code for string */ if (fpIn == NULL) { /* use stdin if no input file */ bfpIn = MakeBitFile(stdin, BF_READ); } else { /* convert output file to bitfile */ bfpIn = MakeBitFile(fpIn, BF_READ); } /* use stdout if no output file */ if (fpOut == NULL) { fpOut = stdout; } /************************************************************************ * Fill the sliding window buffer with some known vales. EncodeLZSS must * use the same values. If common characters are used, there's an * increased chance of matching to the earlier strings. ************************************************************************/ memset(slidingWindow, ' ', WINDOW_SIZE * sizeof(unsigned char)); nextChar = 0; while (TRUE) { if ((c = BitFileGetBit(bfpIn)) == EOF) { /* we hit the EOF */ break; } if (c == UNCODED) { /* uncoded character */ if ((c = BitFileGetChar(bfpIn)) == EOF) { break; } /* write out byte and put it in sliding window */ putc(c, fpOut); slidingWindow[nextChar] = c; nextChar = Wrap((nextChar + 1), WINDOW_SIZE); } else { /* offset and length */ code.offset = 0; code.length = 0; if ((BitFileGetBitsInt(bfpIn, &code.offset, OFFSET_BITS, sizeof(unsigned int))) == EOF) { break; } if ((BitFileGetBitsInt(bfpIn, &code.length, LENGTH_BITS, sizeof(unsigned int))) == EOF) { break; } code.length += MAX_UNCODED + 1; /**************************************************************** * Write out decoded string to file and lookahead. It would be * nice to write to the sliding window instead of the lookahead, * but we could end up overwriting the matching string with the * new string if abs(offset - next char) < match length. ****************************************************************/ for (i = 0; i < code.length; i++) { c = slidingWindow[Wrap((code.offset + i), WINDOW_SIZE)]; putc(c, fpOut); uncodedLookahead[i] = c; } /* write out decoded string to sliding window */ for (i = 0; i < code.length; i++) { slidingWindow[(nextChar + i) % WINDOW_SIZE] = uncodedLookahead[i]; } nextChar = Wrap((nextChar + code.length), WINDOW_SIZE); } } /* we've decoded everything, free bitfile structure */ BitFileToFILE(bfpIn); return (EXIT_SUCCESS); } /**************************************************************************** * Function : DecodeLZSSByName * Description: This function is provided to maintain compatibility with * older versions of my LZSS implementation which used file * names instead of file pointers. * Parameters : inFile - name of file to decode * outFile - name of file to write decoded output * Effects : inFile is decoded and written to outFile * Returned : EXIT_SUCCESS or EXIT_FAILURE ****************************************************************************/ int DecodeLZSSByName(char *inFile, char *outFile) { FILE *fpIn, *fpOut; int returnValue; if (inFile == NULL) { fpIn = stdin; } if ((fpIn = fopen(inFile, "rb")) == NULL) { perror(inFile); return (EXIT_FAILURE); } if (outFile == NULL) { fpOut = stdout; } else { if ((fpOut = fopen(outFile, "wb")) == NULL) { fclose(fpIn); perror(outFile); return (EXIT_FAILURE); } } returnValue = DecodeLZSSByFile(fpIn, fpOut); /* close files */ fclose(fpIn); fclose(fpOut); return (returnValue); }