Ecoji::encode()   C
last analyzed

Complexity

Conditions 13
Paths 31

Size

Total Lines 71
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 53
CRAP Score 13

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 52
c 1
b 0
f 0
nc 31
nop 1
dl 0
loc 71
ccs 53
cts 53
cp 1
crap 13
rs 6.6166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * (c) Dennis Meckel
5
 *
6
 * For the full copyright and license information,
7
 * please view the LICENSE file that was distributed with this source code.
8
 */
9
10
namespace Rayne\Ecoji;
11
12
use InvalidArgumentException;
13
use RuntimeException;
14
15
/**
16
 *
17
 */
18 1
class Ecoji
19
{
20
    /**
21
     * @var EmojiMappingInterface
22
     */
23
    private $mapping;
24
25
    /**
26
     * @param EmojiMappingInterface|null $mapping
27
     */
28 4284
    public function __construct(EmojiMappingInterface $mapping = null)
29
    {
30 4284
        $this->mapping = $mapping ?: new EmojiMapping;
31 4284
    }
32
33
    /**
34
     * @param string $input
35
     * @return string
36
     */
37 2116
    public function encode(string $input): string
38
    {
39 2116
        $textRemaining = $input;
40 2116
        $output = '';
41
42 2116
        while (strlen($textRemaining)) {
43 2116
            $buffer = [];
44 2116
            $textCurrent = substr($textRemaining, 0, 5);
45 2116
            $textRemaining = substr($textRemaining, 5);
46
47 2116
            for ($i = 0; $i < 5; $i++) {
48 2116
                $buffer[$i] = strlen($textCurrent) > $i ? ord($textCurrent[$i]) : 0;
49
            }
50
51 2116
            switch (strlen($textCurrent)) {
52 2116
                case 1:
53 1040
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
54 1040
                    $output .= $this->mapping->getPadding();
55 1040
                    $output .= $this->mapping->getPadding();
56 1040
                    $output .= $this->mapping->getPadding();
57 1040
                    break;
58 1108
                case 2:
59 16
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
60 16
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
61 16
                    $output .= $this->mapping->getPadding();
62 16
                    $output .= $this->mapping->getPadding();
63 16
                    break;
64 1100
                case 3:
65 16
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
66 16
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
67 16
                    $output .= $this->mapping->getEmoji(($buffer[2] & 0x0f) << 6 | $buffer[3] >> 2);
68 16
                    $output .= $this->mapping->getPadding();
69 16
                    break;
70 1092
                case 4:
71 1044
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
72 1044
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
73 1044
                    $output .= $this->mapping->getEmoji(($buffer[2] & 0x0f) << 6 | $buffer[3] >> 2);
74
75
                    // Look at the last two bits to determine the padding.
76 1044
                    switch ($buffer[3] & 0x03) {
77 1044
                        case 0:
78 248
                            $output .= $this->mapping->getPadding40();
79 248
                            break;
80 796
                        case 1:
81 280
                            $output .= $this->mapping->getPadding41();
82 280
                            break;
83 516
                        case 2:
84 264
                            $output .= $this->mapping->getPadding42();
85 264
                            break;
86 252
                        case 3:
87 252
                            $output .= $this->mapping->getPadding43();
88 252
                            break;
89
                    }
90 1044
                    break;
91 72
                case 5:
92
                    // use 8 bits from 1st byte and 2 bits from 2nd byte to lookup emoji
93 72
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
94
95
                    // use 6 bits from 2nd byte and 4 bits from 3rd byte to lookup emoji
96 72
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
97
98
                    // use 4 bits from 3rd byte and 6 bits from 4th byte to lookup emoji
99 72
                    $output .= $this->mapping->getEmoji(($buffer[2] & 0x0f) << 6 | $buffer[3] >> 2);
100
101
                    // use 2 bits from 4th byte and 8 bits from 5th byte to lookup emoji
102 72
                    $output .= $this->mapping->getEmoji(($buffer[3] & 0x03) << 8 | $buffer[4]);
103 72
                    break;
104
            }
105
        }
106
107 2116
        return $output;
108
    }
109
110
    /**
111
     * @param string $input Ecoji encoded information.
112
     * @return string
113
     */
114 2148
    public function decode(string $input): string
115
    {
116 2148
        $textRemaining = str_replace("\n", '', $input);
117 2148
        $result = '';
118
119 2148
        while (strlen($textRemaining)) {
120 2148
            if (mb_strlen($textRemaining) < 4) {
121 36
                throw new InvalidArgumentException('Unexpected end of data. Expected blocks of four emojis.');
122
            }
123
124 531
            $runes = [
125 2124
                mb_substr($textRemaining, 0, 1),
126 2124
                mb_substr($textRemaining, 1, 1),
127 2124
                mb_substr($textRemaining, 2, 1),
128 2124
                mb_substr($textRemaining, 3, 1),
129
            ];
130
131 2124
            $textRemaining = mb_substr($textRemaining, 4);
132
133 2124
            $bits1 = $this->mapping->getId($runes[0]);
134 2116
            $bits2 = $this->mapping->getId($runes[1]);
135 2116
            $bits3 = $this->mapping->getId($runes[2]);
136 2116
            $bits4 = null;
137
138 2116
            switch ($runes[3]) {
139 2116
                case $this->mapping->getPadding40():
140 248
                    $bits4 = 0;
141 248
                    break;
142 1868
                case $this->mapping->getPadding41():
143 280
                    $bits4 = 1 << 8;
144 280
                    break;
145 1604
                case $this->mapping->getPadding42():
146 264
                    $bits4 = 2 << 8;
147 264
                    break;
148 1348
                case $this->mapping->getPadding43():
149 256
                    $bits4 = 3 << 8;
150 256
                    break;
151
                default:
152 1092
                    $bits4 = $this->mapping->getId($runes[3]);
153
            }
154
155 529
            $out = [
156 2116
                $bits1 >> 2,
157 2116
                (($bits1 & 0x3) << 6) | ($bits2 >> 4),
158 2116
                (($bits2 & 0xf) << 4) | ($bits3 >> 6),
159 2116
                (($bits3 & 0x3f) << 2) | ($bits4 >> 8),
160 2116
                $bits4 & 0xff,
161
            ];
162
163 2116
            if ($runes[1] == $this->mapping->getPadding()) {
164 1020
                $out = array_slice($out, 0, 1);
165 1108
            } elseif ($runes[2] == $this->mapping->getPadding()) {
166 16
                $out = array_slice($out, 0, 2);
167 1100
            } elseif ($runes[3] == $this->mapping->getPadding()) {
168 16
                $out = array_slice($out, 0, 3);
169 1092
            } elseif ($runes[3] == $this->mapping->getPadding40() || $runes[3] == $this->mapping->getPadding41() || $runes[3] == $this->mapping->getPadding42() || $runes[3] == $this->mapping->getPadding43()) {
170 1048
                $out = array_slice($out, 0, 4);
171
            }
172
173 2116
            foreach ($out as $v) {
174 2116
                $result .= chr($v);
175
            }
176
        }
177
178 2104
        return $result;
179
    }
180
}
181