Пример #1
0
 protected function decodeGeneric(string $input, int $bits) : string
 {
     if ($this->symbol === NULL) {
         list($this->symbol, $this->codes, $this->codeLengths, $this->first, $this->steps) = $this->code->getDecoderData();
         $this->stepCount = count($this->steps);
     }
     $len = strlen($input);
     $decoded = '';
     $buffer = NULL;
     $byteOffset = 0;
     $bitOffset = 7;
     while (true) {
         $code = 0;
         $codeLen = 0;
         // Increment in steps to avoid checking codes with a length that is not used by Huffman codes.
         for ($step = 0; $step < $this->stepCount; $step++) {
             for ($i = 0; $i < $this->steps[$step]; $i++) {
                 if ($bits-- == 0) {
                     break;
                 }
                 if ($buffer === NULL) {
                     if ($byteOffset == $len) {
                         if ($code === 0 || $this->isHuffmanPaddingCode($code)) {
                             return $decoded;
                         }
                         throw new \RuntimeException('Cannot read beyond end of Huffman-encoded string');
                     }
                     $buffer = ord($input[$byteOffset]);
                 }
                 // Read next bit and and append it as LSB (least significant bit) to the code.
                 $code = $code << 1 | $buffer >> $bitOffset-- & 1;
                 $codeLen++;
                 if ($bitOffset == -1) {
                     $byteOffset++;
                     $bitOffset = 7;
                     $buffer = NULL;
                 }
             }
             // Match code against all codes with the same length.
             for ($i = 0; $i < $this->codeLengths[$codeLen]; $i++) {
                 if ($this->codes[$this->first[$codeLen] + $i] == $code) {
                     $decoded .= $this->symbol[sprintf('%0' . $codeLen . 'b', $code)];
                     if ($bits == 0) {
                         return $decoded;
                     }
                     continue 3;
                 }
             }
             if ($bits == 0) {
                 if ($codeLen == 0) {
                     return $decoded;
                 }
                 break;
             }
         }
         if ($this->isHuffmanPaddingCode($code)) {
             return $decoded;
         }
         break;
     }
     throw new \RuntimeException('Invalid Huffman code detected');
 }