001/*
002 * Copyright 2003-2008 by Paulo Soares.
003 *
004 * This code was originally released in 2001 by SUN (see class
005 * com.sun.media.imageio.plugins.tiff.TIFFDirectory.java)
006 * using the BSD license in a specific wording. In a mail dating from
007 * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission
008 * to use the code under the following version of the BSD license:
009 *
010 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
011 * 
012 * Redistribution and use in source and binary forms, with or without
013 * modification, are permitted provided that the following conditions
014 * are met: 
015 * 
016 * - Redistribution of source code must retain the above copyright 
017 *   notice, this  list of conditions and the following disclaimer.
018 * 
019 * - Redistribution in binary form must reproduce the above copyright
020 *   notice, this list of conditions and the following disclaimer in 
021 *   the documentation and/or other materials provided with the
022 *   distribution.
023 * 
024 * Neither the name of Sun Microsystems, Inc. or the names of 
025 * contributors may be used to endorse or promote products derived 
026 * from this software without specific prior written permission.
027 * 
028 * This software is provided "AS IS," without a warranty of any 
029 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
030 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
031 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
032 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
033 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
034 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
035 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
036 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
037 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
038 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
039 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
040 * POSSIBILITY OF SUCH DAMAGES. 
041 * 
042 * You acknowledge that this software is not designed or intended for 
043 * use in the design, construction, operation or maintenance of any 
044 * nuclear facility. 
045 *
046 * $Revision: 4540 $
047 * $Date: 2010-07-13 05:57:54 -0700 (Tue, 13 Jul 2010) $
048 * $State: Exp $
049 */
050
051package com.itextpdf.text.pdf.codec;
052
053import java.io.IOException;
054import java.io.OutputStream;
055
056/**
057 * Modified from original LZWCompressor to change interface to passing a
058 * buffer of data to be compressed.
059 * @since 5.0.2
060 */
061public class LZWCompressor
062{
063    /** base underlying code size of data being compressed 8 for TIFF, 1 to 8 for GIF **/
064    int codeSize_;
065
066    /** reserved clear code based on code size **/
067    int clearCode_;
068
069    /** reserved end of data code based on code size **/
070    int endOfInfo_;
071
072    /** current number bits output for each code **/
073    int numBits_;
074
075    /** limit at which current number of bits code size has to be increased **/
076    int limit_;
077
078    /** the prefix code which represents the predecessor string to current input point **/
079    short prefix_;
080
081    /** output destination for bit codes **/
082    BitFile bf_;
083
084    /** general purpose LZW string table **/
085    LZWStringTable lzss_;
086
087    /** modify the limits of the code values in LZW encoding due to TIFF bug / feature **/
088    boolean tiffFudge_;
089
090    /**
091         * @param out destination for compressed data
092         * @param codeSize the initial code size for the LZW compressor
093         * @param TIFF flag indicating that TIFF lzw fudge needs to be applied
094         * @exception IOException if underlying output stream error
095         **/
096    public LZWCompressor(OutputStream out, int codeSize, boolean TIFF) throws IOException
097    {
098        bf_ = new BitFile(out, !TIFF);  // set flag for GIF as NOT tiff
099        codeSize_  = codeSize;
100        tiffFudge_ = TIFF;
101        clearCode_ = 1 << codeSize_;
102        endOfInfo_ = clearCode_ + 1;
103        numBits_   = codeSize_ + 1;
104
105        limit_ = (1 << numBits_) - 1;
106        if (tiffFudge_)
107            --limit_;
108
109        prefix_ = (short)0xFFFF;
110        lzss_ = new LZWStringTable();
111        lzss_.ClearTable(codeSize_);
112        bf_.writeBits(clearCode_, numBits_);
113    }
114
115    /**
116         * @param buf data to be compressed to output stream
117         * @exception IOException if underlying output stream error
118         **/
119    public void compress(byte[] buf, int offset, int length)
120        throws IOException
121    {
122        int idx;
123        byte c;
124        short index;
125
126        int maxOffset = offset + length;
127        for (idx = offset; idx < maxOffset; ++idx)
128            {
129                c = buf[idx];
130                if ((index = lzss_.FindCharString(prefix_, c)) != -1)
131                    prefix_ = index;
132                else
133                    {
134                        bf_.writeBits(prefix_, numBits_);
135                        if (lzss_.AddCharString(prefix_, c) > limit_)
136                            {
137                                if (numBits_ == 12)
138                                    {
139                                        bf_.writeBits(clearCode_, numBits_);
140                                        lzss_.ClearTable(codeSize_);
141                                        numBits_ = codeSize_ + 1;
142                                    }
143                                else
144                                    ++numBits_;
145
146                                limit_ = (1 << numBits_) - 1;
147                                if (tiffFudge_)
148                                    --limit_;
149                            }
150                        prefix_ = (short)((short)c & 0xFF);
151                    }
152            }
153    }
154
155    /**
156         * Indicate to compressor that no more data to go so write out
157         * any remaining buffered data.
158         *
159         * @exception IOException if underlying output stream error
160         **/
161    public void flush() throws IOException
162    {
163        if (prefix_ != -1)
164            bf_.writeBits(prefix_, numBits_);
165                
166        bf_.writeBits(endOfInfo_, numBits_);
167        bf_.flush();
168    }
169}