Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 403] [Versions 39 and 311]

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