<?php
//
//  FPDI - Version 1.4.1
//
//    Copyright 2004-2011 Setasign - Jan Slabon
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

if (!class_exists('FilterLZW', false)) {

    class FilterLZW {
        
        var $sTable = array();
        var $data = null;
        var $dataLength = 0;
        var $tIdx;
        var $bitsToGet = 9;
        var $bytePointer;
        var $bitPointer;
        var $nextData = 0;
        var $nextBits = 0;
        var $andTable = array(511, 1023, 2047, 4095);
    
        function error($msg) {
            die($msg);
        }
        
        /**
         * Method to decode LZW compressed data.
         *
         * @param string data    The compressed data.
         */
        function decode($data) {
    
            if($data[0] == 0x00 && $data[1] == 0x01) {
                $this->error('LZW flavour not supported.');
            }
    
            $this->initsTable();
    
            $this->data = $data;
            $this->dataLength = strlen($data);
    
            // Initialize pointers
            $this->bytePointer = 0;
            $this->bitPointer = 0;
    
            $this->nextData = 0;
            $this->nextBits = 0;
    
            $oldCode = 0;
    
            $string = '';
            $uncompData = '';
    
            while (($code = $this->getNextCode()) != 257) {
                if ($code == 256) {
                    $this->initsTable();
                    $code = $this->getNextCode();
    
                    if ($code == 257) {
                        break;
                    }
    
                    $uncompData .= $this->sTable[$code];
                    $oldCode = $code;
    
                } else {
    
                    if ($code < $this->tIdx) {
                        $string = $this->sTable[$code];
                        $uncompData .= $string;
    
                        $this->addStringToTable($this->sTable[$oldCode], $string[0]);
                        $oldCode = $code;
                    } else {
                        $string = $this->sTable[$oldCode];
                        $string = $string.$string[0];
                        $uncompData .= $string;
    
                        $this->addStringToTable($string);
                        $oldCode = $code;
                    }
                }
            }
            
            return $uncompData;
        }
    
    
        /**
         * Initialize the string table.
         */
        function initsTable() {
            $this->sTable = array();
    
            for ($i = 0; $i < 256; $i++)
                $this->sTable[$i] = chr($i);
    
            $this->tIdx = 258;
            $this->bitsToGet = 9;
        }
    
        /**
         * Add a new string to the string table.
         */
        function addStringToTable ($oldString, $newString='') {
            $string = $oldString.$newString;
    
            // Add this new String to the table
            $this->sTable[$this->tIdx++] = $string;
    
            if ($this->tIdx == 511) {
                $this->bitsToGet = 10;
            } else if ($this->tIdx == 1023) {
                $this->bitsToGet = 11;
            } else if ($this->tIdx == 2047) {
                $this->bitsToGet = 12;
            }
        }
    
        // Returns the next 9, 10, 11 or 12 bits
        function getNextCode() {
            if ($this->bytePointer == $this->dataLength) {
                return 257;
            }
    
            $this->nextData = ($this->nextData << 8) | (ord($this->data[$this->bytePointer++]) & 0xff);
            $this->nextBits += 8;
    
            if ($this->nextBits < $this->bitsToGet) {
                $this->nextData = ($this->nextData << 8) | (ord($this->data[$this->bytePointer++]) & 0xff);
                $this->nextBits += 8;
            }
    
            $code = ($this->nextData >> ($this->nextBits - $this->bitsToGet)) & $this->andTable[$this->bitsToGet-9];
            $this->nextBits -= $this->bitsToGet;
    
            return $code;
        }
        
        function encode($in) {
            $this->error("LZW encoding not implemented.");
        }
    }
}
