protected function decodeCanonical(string $input, int $bits) : string { if ($this->symbol === NULL) { list($this->symbol, $this->first) = $this->code->getCanonicalDecoderData(); } $decoded = ''; $buffer = NULL; $len = strlen($input); $byteOffset = 0; $bitOffset = 7; while (true) { $code = 0; $codeLen = 0; do { 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; if ($bitOffset == -1) { $bitOffset = 7; $buffer = NULL; } } while ($code > $this->first[++$codeLen]); if ($bits == 0 && $codeLen == 0) { return $decoded; } $char = $this->symbol[$codeLen][$this->first[$codeLen] - $code] ?? NULL; if ($char !== NULL) { $decoded .= $char; if ($bits == 0) { return $decoded; } continue; } if ($this->isHuffmanPaddingCode($code)) { return $decoded; } break; } throw new \RuntimeException('Invalid Huffman code detected'); }