PHP Classes

File: lzwc.php

Recommend this page to a friend!
  Classes of Sam S   LZW   lzwc.php   Download  
File: lzwc.php
Role: Class source
Content type: text/plain
Description: The compression class
Class: LZW
Compress and uncompress data with LZW algorithm
Author: By
Last change: Updated comments
Date: 17 years ago
Size: 11,551 bytes
 

Contents

Class file image Download
<?php /** * This PHP implementation of the LZW compression algorithm allows for * the compression of bytes using the Adobe PDF characteristics according * to the "PDF Reference Second Edition" by Adobe Systems Incorporated (2000) * * This code is primarily a conversion from Mark Nelson's LZW.c which can be found here: * http://marknelson.us/attachments/lzw-data-compression/lzw.c * Do not contact Mr. Nelson regarding this package, because this code was written by Samuel Shull * */ /** * @package LZW * @example /lzwexample.php Example usage of this class. * @category Numbers * @author Sam Shull <samshull@samshull.com> * @copyright Copyright (c) 2007, Sam Shull * @license http://www.samshull.com/bsdlicense.txt BSD License * @link http://samshull.com/lzwexample.php * @version 0.9 * @access public */ class LZW{ /** * Table for storing codes * * @var array * @access protected */ var $code_value = array(); /** * Table for storing prefixes to codes * * @var array * @access protected */ var $prefix_code = array(); /** * Table for storing individual characters * * @var array * @access protected */ var $append_character = array(); /** * Output * * @var string * @access protected */ var $out = ""; /** * Total size of table of values * * @var integer * @access protected */ var $TABLE_SIZE = 5021; /** * Number of bits available for encoding * * @var integer * @access protected */ var $output_bit_count = 0; /** * The actual bits for encoding * * @var string * @access protected */ var $output_bit_buffer = "0"; /** * Next code in the table * * @var integer * @access protected */ var $next_code = 258; /** * Decoding: the table * * @var array * @access protected */ var $sTable = array(); /** * Data to be decoded * * @var string * @access protected */ var $data = NULL; /** * Decoding: next code (same as $next_code) * * @var integer * @access protected */ var $tIdx; /** * bits in next code * * @var integer * @access protected */ var $bitsToGet = 9; /** * Position holder within data string * * @var string * @access protected */ var $bytePointer; /** * Position holder for bits in data string * * @var string * @access protected */ var $bitPointer; /** * Next value to be decoded * * @var integer * @access protected */ var $nextData = 0; /** * Next number of bits to be decoded * * @var string * @access protected */ var $nextBits = 0; /** * Table of max bit values per number of bits * * @var string * @access protected */ var $andTable = array(511, 1023, 2047, 4095); /** * Method: compress * The primary method used by this class, accepts only a string as input and * returns the string compressed. */ function compress($string){ $this->output_code(256); $this->input = $string; $this->next_code=258; /* Next code is the next available string code*/ $string_code=ord($this->input{0}); /* Get the first code */ for($i=1;$i<=strlen($this->input);$i++) { $character=ord($this->input{$i}); $index=$this->find_match($string_code,$character);/* See if the string is in */ if (isset($this->code_value[$index])) /* the table. If it is, */ $string_code=$this->code_value[$index]; /* get the code value. If */ else /* the string is not in the*/ { /* table, try to add it. */ if ($this->next_code <= 4094) { $this->code_value[$index]=$this->next_code; $this->prefix_code[$index]=$string_code; $this->append_character[$index]=$character; $this->next_code++; }else{ $this->output_code(256); $this->next_code = 258; $this->code_value = array(); $this->prefix_code = array(); $this->append_character = array(); $this->code_value[$index]=$this->next_code; $this->prefix_code[$index]=$string_code; $this->append_character[$index]=$character; $this->next_code++; } $this->output_code($string_code); /* When a string is found */ $string_code=$character; /* that is not in the table*/ } /* I output the last string*/ } /* after adding the new one*/ $this->output_code(257); $this->output_code(0); //Clean up return $this->out; } /** * Method: find_match - if PHP5 mark as private or protected * Finds the matching index of the character with the table * @param string $hash_prefix * @param char $hash_character * @return int */ function find_match($hash_prefix,$hash_character){ $index = ($hash_character << 4 ) ^ $hash_prefix; if ($index == 0) $offset = 1; else $offset = $this->TABLE_SIZE - $index; while (1){ if (!isset($this->code_value[$index])) return $index; if ($this->prefix_code[$index] == $hash_prefix && $this->append_character[$index] == $hash_character) return $index; $index -= $offset; if ($index < 0) $index += $this->TABLE_SIZE; } } /** * Method: output_code - if PHP5 mark as private or protected * Adds the input to the output buffer and * Adds the char code of next 8 bits of the output buffer * @param int $code */ function output_code($code){ $len = ($code < 512 ? 9 : ($code < 1024 ? 10 : ($code < 2048 ? 11 : 12))); $this->output_bit_buffer = $this->bitOR($this->lshift(decbin($code),(32 - $len - $this->output_bit_count)),$this->output_bit_buffer); $this->output_bit_count += $len; while ($this->output_bit_count >= 8){ $this->out .= chr($this->rshift($this->output_bit_buffer,24)); $this->output_bit_buffer = $this->lshift($this->output_bit_buffer,8); $this->output_bit_count -= 8; } } /*/ // The following methods are adapted directly from FPDI - Version 1.1 and are only included here in order to effect the decompression of the above encoding algorithm // // Copyright 2004,2005 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. /*/ function decode($data) { if(ord($data{0}) == 0x00 && ord($data{1}) == 0x01) { die("LZW flavour not supported."); } $this->initsTable(); $this->data =& $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. - if PHP5 mark as private or protected */ 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. - if PHP5 mark as private or protected */ 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 - if PHP5 mark as private or protected function getNextCode() { if ($this->bytePointer == strlen($this->data)+1) 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; } /** * The following methods allow PHP to deal with unsigned longs. * They support the above primary methods. They are not warranted or guaranteed. */ /** * Method: lshift - if PHP5 mark as private or protected * Used to allow class to deal with unsigned longs, bitwise left shift * Two parameters, number to be shifted, and how much to shift * @param binary string $n * @param int $b * @return binary string **/ function lshift($n,$b){ return str_pad($n,($b+strlen($n)),"0");} /** * Method: rshift - if PHP5 mark as private or protected * Used to allow class to deal with unsigned longs, bitwise right shift * Two parameters, number to be shifted, and how much to shift * @param binary string $n * @param int $b * @return int */ function rshift($n,$b){ $ret = substr($n,0,(strlen($n) - $b)); return ((int)bindec($ret)); } /** * Method: bitOR - if PHP5 mark as private or protected * Used to allow class to deal with unsigned longs, bitwise OR (|) * Bitwise comparison of two parameters, return string representation of not more than 32 bits * @param binary string $a * @param binary string $b * @return binary string */ function bitOR($a,$b){ $long = strlen($a) > strlen($b) ? $a : $b; $short = $long == $a ? $b : $a; $l = strrev($long); $s = strrev($short); for($r=0;$r<strlen($l);$r++){ $re[$r] = ($s{$r} == "1" || $l{$r} == "1") ? "1" : "0"; } $ret = implode("",$re); $ret = strrev(substr($ret,0,32)); return $ret; } } ?>