Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.87% covered (success)
94.87%
37 / 39
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
LZW
94.87% covered (success)
94.87%
37 / 39
50.00% covered (danger)
50.00%
1 / 2
13.02
0.00% covered (danger)
0.00%
0 / 1
 compress
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
5
 decompress
90.48% covered (success)
90.48%
19 / 21
0.00% covered (danger)
0.00%
0 / 1
8.06
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Utils\Compression
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Utils\Compression;
16
17/**
18 * LZW compression class
19 *
20 * @package phpOMS\Utils\Compression
21 * @license OMS License 2.0
22 * @link    https://jingga.app
23 * @since   1.0.0
24 */
25class LZW implements CompressionInterface
26{
27    /**
28     * {@inheritdoc}
29     */
30    public function compress(string $source) : string
31    {
32        $w          = '';
33        $dictionary = [];
34        $result     = [];
35        $dictSize   = 256;
36
37        for ($i = 0; $i < 256; ++$i) {
38            $dictionary[\chr($i)] = $i;
39        }
40
41        $length = \strlen($source);
42        for ($i = 0; $i < $length; ++$i) {
43            $c  = $source[$i];
44            $wc = $w . $c;
45
46            if (\array_key_exists($w . $c, $dictionary)) {
47                $w .= $c;
48            } else {
49                $result[]        = $dictionary[$w];
50                $dictionary[$wc] = $dictSize++;
51                $w               = $c;
52            }
53        }
54
55        if ($w !== '') {
56            $result[] = $dictionary[$w];
57        }
58
59        return \implode(',', $result);
60    }
61
62    /**
63     * {@inheritdoc}
64     *
65     * @throws \Exception
66     */
67    public function decompress(string $compressed) : string
68    {
69        $compressed = \explode(',', $compressed);
70        $dictionary = [];
71        $entry      = '';
72        $dictSize   = 256;
73
74        if (empty($compressed) || $compressed === ['']) {
75            return '';
76        }
77
78        for ($i = 0; $i < 256; ++$i) {
79            $dictionary[$i] = \chr($i);
80        }
81
82        $w      = \chr((int) $compressed[0]);
83        $result = $dictionary[(int) ($compressed[0])] ?? '';
84        $count  = \count($compressed);
85
86        for ($i = 1; $i < $count; ++$i) {
87            $k = (int) $compressed[$i];
88
89            if (isset($dictionary[$k]) && !empty($dictionary[$k])) {
90                $entry = $dictionary[$k];
91            } elseif ($k === $dictSize) {
92                $entry = $w . $w[0];
93            } else {
94                throw new \Exception('Wrong dictionary size!' . $k . '.' . $dictSize); // @codeCoverageIgnore
95            }
96
97            $result                 .= $entry;
98            $dictionary[$dictSize++] = $w . $entry[0];
99            $w                       = $entry;
100        }
101
102        /** @var string $result */
103        return $result;
104    }
105}