Passed
Pull Request — master (#9)
by Philip
04:44 queued 03:02
created

AbstractCRC::calculateWithTable()   A

Complexity

Conditions 6
Paths 11

Size

Total Lines 36
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
c 0
b 0
f 0
dl 0
loc 36
rs 9.0111
cc 6
nc 11
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PBurggraf\CRC;
6
7
use InvalidArgumentException;
8
use function ord;
9
use function strlen;
10
11
/**
12
 * @author Philip Burggraf <[email protected]>
13
 */
14
abstract class AbstractCRC
15
{
16
    /**
17
     * @var int
18
     */
19
    protected $poly;
20
21
    /**
22
     * @var int
23
     */
24
    protected $init;
25
26
    /**
27
     * @var bool
28
     */
29
    protected $reverseIn;
30
31
    /**
32
     * @var bool
33
     */
34
    protected $reverseOut;
35
36
    /**
37
     * @var int
38
     */
39
    protected $xorOut;
40
41
    /**
42
     * @var int
43
     */
44
    protected $bitLength;
45
46
    public function calculate(string $buffer): int
47
    {
48
        $bufferLength = strlen($buffer);
49
50
        $mask = (((1 << ($this->bitLength - 1)) - 1) << 1) | 1;
51
        $highBit = 1 << ($this->bitLength - 1);
52
53
        $crc = $this->init;
54
55
        for ($iterator = 0; $iterator < $bufferLength; ++$iterator) {
56
            $character = ord($buffer[$iterator]);
57
            if ($this->reverseIn) {
58
                $character = $this->binaryReverse($character, 8);
59
            }
60
61
            for ($j = 0x80; $j; $j >>= 1) {
62
                $bit = $crc & $highBit;
63
                $crc <<= 1;
64
65
                if ($character & $j) {
66
                    $bit ^= $highBit;
67
                }
68
69
                if ($bit) {
70
                    $crc ^= $this->poly;
71
                }
72
            }
73
        }
74
75
        if ($this->reverseOut) {
76
            $crc = $this->binaryReverse($crc, $this->bitLength);
77
        }
78
79
        $crc ^= $this->xorOut;
80
81
        return $crc & $mask;
82
    }
83
84
    public function calculateWithTable(string $buffer, array $table): int
85
    {
86
        $bufferLength = strlen($buffer);
87
88
        if (count($table) !== 256) {
89
            throw new InvalidArgumentException('CRC lookup table not populated');
90
        }
91
92
        $mask = (((1 << ($this->bitLength - 1)) - 1) << 1) | 1;
93
        $highBit = 1 << ($this->bitLength - 1);
0 ignored issues
show
Unused Code introduced by
The assignment to $highBit is dead and can be removed.
Loading history...
94
95
        $crc = $this->init;
96
97
        for ($iterator = 0; $iterator < $bufferLength; ++$iterator) {
98
            $character = ord($buffer[$iterator]);
99
            if ($this->reverseIn) {
100
                $character = $this->binaryReverse($character, 8);
101
            }
102
103
            $tableValue = $table[(($crc >> ($this->bitLength - 8)) ^ $character) & 0xFF];
104
105
            if (($this->bitLength - 8) !== 0) {
106
                $tableValue ^= ($crc << 8);
107
            }
108
109
            $crc = $tableValue;
110
            $crc &= $mask;
111
        }
112
113
        if ($this->reverseOut) {
114
            $crc = $this->binaryReverse($crc, $this->bitLength);
115
        }
116
117
        $crc ^= $this->xorOut;
118
119
        return $crc & $mask;
120
    }
121
122
    /**
123
     * @return int[]
124
     */
125
    public function populateTable(): array
126
    {
127
        $tableSize = 256;
128
129
        $mask = (((1 << ($this->bitLength - 1)) - 1) << 1) | 1;
130
        $highBit = 1 << ($this->bitLength - 1);
131
132
        $table = [];
133
134
        for ($iterator = 0; $iterator < $tableSize; ++$iterator) {
135
            $temp = 0;
136
            $a = ($iterator << ($this->bitLength - 8));
137
            for ($j = 0; $j < 8; ++$j) {
138
                if ((($temp ^ $a) & $highBit) !== 0) {
139
                    $temp = (($temp << 1) ^ $this->poly);
140
                } else {
141
                    $temp <<= 1;
142
                }
143
                $a <<= 1;
144
            }
145
            $table[$iterator] = $temp & $mask;
146
        }
147
148
        return $table;
149
    }
150
151
    protected function binaryReverse(int $binaryInput, int $bitlen): int
152
    {
153
        $cloneBits = $binaryInput;
154
        $binaryInput = 0;
155
        $count = 0;
156
157
        while ($count < $bitlen) {
158
            ++$count;
159
            $binaryInput <<= 1;
160
            $binaryInput |= ($cloneBits & 0x1);
161
            $cloneBits >>= 1;
162
        }
163
164
        return $binaryInput;
165
    }
166
}
167