Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  /**
   3   * This file is part of FPDI
   4   *
   5   * @package   setasign\Fpdi
   6   * @copyright Copyright (c) 2019 Setasign - Jan Slabon (https://www.setasign.com)
   7   * @license   http://opensource.org/licenses/mit-license The MIT License
   8   */
   9  
  10  namespace setasign\Fpdi\PdfParser\Filter;
  11  
  12  /**
  13   * Class for handling LZW encoded data
  14   *
  15   * @package setasign\Fpdi\PdfParser\Filter
  16   */
  17  class Lzw implements FilterInterface
  18  {
  19      /**
  20       * @var null|string
  21       */
  22      protected $data;
  23  
  24      /**
  25       * @var array
  26       */
  27      protected $sTable = [];
  28  
  29      /**
  30       * @var int
  31       */
  32      protected $dataLength = 0;
  33  
  34      /**
  35       * @var int
  36       */
  37      protected $tIdx;
  38  
  39      /**
  40       * @var int
  41       */
  42      protected $bitsToGet = 9;
  43  
  44      /**
  45       * @var int
  46       */
  47      protected $bytePointer;
  48  
  49      /**
  50       * @var int
  51       */
  52      protected $nextData = 0;
  53  
  54      /**
  55       * @var int
  56       */
  57      protected $nextBits = 0;
  58  
  59      /**
  60       * @var array
  61       */
  62      protected $andTable = [511, 1023, 2047, 4095];
  63  
  64      /**
  65       * Method to decode LZW compressed data.
  66       *
  67       * @param string $data The compressed data
  68       * @return string The uncompressed data
  69       * @throws LzwException
  70       */
  71      public function decode($data)
  72      {
  73          if ($data[0] === "\x00" && $data[1] === "\x01") {
  74              throw new LzwException(
  75                  'LZW flavour not supported.',
  76                  LzwException::LZW_FLAVOUR_NOT_SUPPORTED
  77              );
  78          }
  79  
  80          $this->initsTable();
  81  
  82          $this->data = $data;
  83          $this->dataLength = \strlen($data);
  84  
  85          // Initialize pointers
  86          $this->bytePointer = 0;
  87  
  88          $this->nextData = 0;
  89          $this->nextBits = 0;
  90  
  91          $oldCode = 0;
  92  
  93          $uncompData = '';
  94  
  95          while (($code = $this->getNextCode()) !== 257) {
  96              if ($code === 256) {
  97                  $this->initsTable();
  98                  $code = $this->getNextCode();
  99  
 100                  if ($code === 257) {
 101                      break;
 102                  }
 103  
 104                  $uncompData .= $this->sTable[$code];
 105                  $oldCode = $code;
 106  
 107              } else {
 108                  if ($code < $this->tIdx) {
 109                      $string = $this->sTable[$code];
 110                      $uncompData .= $string;
 111  
 112                      $this->addStringToTable($this->sTable[$oldCode], $string[0]);
 113                      $oldCode = $code;
 114                  } else {
 115                      $string = $this->sTable[$oldCode];
 116                      $string .= $string[0];
 117                      $uncompData .= $string;
 118  
 119                      $this->addStringToTable($string);
 120                      $oldCode = $code;
 121                  }
 122              }
 123          }
 124  
 125          return $uncompData;
 126      }
 127  
 128      /**
 129       * Initialize the string table.
 130       */
 131      protected function initsTable()
 132      {
 133          $this->sTable = [];
 134  
 135          for ($i = 0; $i < 256; $i++) {
 136              $this->sTable[$i] = \chr($i);
 137          }
 138  
 139          $this->tIdx = 258;
 140          $this->bitsToGet = 9;
 141      }
 142  
 143      /**
 144       * Add a new string to the string table.
 145       *
 146       * @param string $oldString
 147       * @param string $newString
 148       */
 149      protected function addStringToTable($oldString, $newString = '')
 150      {
 151          $string = $oldString . $newString;
 152  
 153          // Add this new String to the table
 154          $this->sTable[$this->tIdx++] = $string;
 155  
 156          if ($this->tIdx === 511) {
 157              $this->bitsToGet = 10;
 158          } elseif ($this->tIdx === 1023) {
 159              $this->bitsToGet = 11;
 160          } elseif ($this->tIdx === 2047) {
 161              $this->bitsToGet = 12;
 162          }
 163      }
 164  
 165      /**
 166       * Returns the next 9, 10, 11 or 12 bits.
 167       *
 168       * @return integer
 169       */
 170      protected function getNextCode()
 171      {
 172          if ($this->bytePointer === $this->dataLength) {
 173              return 257;
 174          }
 175  
 176          $this->nextData = ($this->nextData << 8) | (\ord($this->data[$this->bytePointer++]) & 0xff);
 177          $this->nextBits += 8;
 178  
 179          if ($this->nextBits < $this->bitsToGet) {
 180              $this->nextData = ($this->nextData << 8) | (\ord($this->data[$this->bytePointer++]) & 0xff);
 181              $this->nextBits += 8;
 182          }
 183  
 184          $code = ($this->nextData >> ($this->nextBits - $this->bitsToGet)) & $this->andTable[$this->bitsToGet - 9];
 185          $this->nextBits -= $this->bitsToGet;
 186  
 187          return $code;
 188      }
 189  }