Passed
Branch php70 (a6ded4)
by Dennis
08:04
created

Ecoji::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
eloc 1
nc 1
nop 1
crap 2
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
class Ecoji
19
{
20
    /**
21
     * @var EmojiMappingInterface
22
     */
23
    private $mapping;
24
25
    /**
26
     * @param EmojiMappingInterface|null $mapping
27
     */
28 1599
    public function __construct(EmojiMappingInterface $mapping = null)
29
    {
30 1599
        $this->mapping = $mapping ?: new EmojiMapping;
31 1599
    }
32
33
    /**
34
     * @param string $input
35
     * @return string
36
     */
37 786
    public function encode(string $input): string
38
    {
39 786
        $textRemaining = $input;
40 786
        $output = '';
41
42 786
        while (strlen($textRemaining)) {
43 786
            $buffer = [];
44 786
            $textCurrent = substr($textRemaining, 0, 5);
45 786
            $textRemaining = substr($textRemaining, 5);
46
47 786
            for ($i = 0; $i < 5; $i++) {
48 786
                $buffer[$i] = strlen($textCurrent) > $i ? ord($textCurrent[$i]) : 0;
49
            }
50
51 786
            switch (strlen($textCurrent)) {
52 524
                case 1:
53 381
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
54 381
                    $output .= $this->mapping->getPadding();
55 381
                    $output .= $this->mapping->getPadding();
56 381
                    $output .= $this->mapping->getPadding();
57 381
                    break;
58 272
                case 2:
59 6
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
60 6
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
61 6
                    $output .= $this->mapping->getPadding();
62 6
                    $output .= $this->mapping->getPadding();
63 6
                    break;
64 270
                case 3:
65 6
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
66 6
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
67 6
                    $output .= $this->mapping->getEmoji(($buffer[2] & 0x0f) << 6 | $buffer[3] >> 2);
68 6
                    $output .= $this->mapping->getPadding();
69 6
                    break;
70 268
                case 4:
71 393
                    $output .= $this->mapping->getEmoji($buffer[0] << 2 | $buffer[1] >> 6);
72 393
                    $output .= $this->mapping->getEmoji(($buffer[1] & 0x3f) << 4 | $buffer[2] >> 4);
73 393
                    $output .= $this->mapping->getEmoji(($buffer[2] & 0x0f) << 6 | $buffer[3] >> 2);
74
75
                    // Look at the last two bits to determine the padding.
76 393
                    switch ($buffer[3] & 0x03) {
77 393
                        case 0:
78 93
                            $output .= $this->mapping->getPadding40();
79 93
                            break;
80 300
                        case 1:
81 105
                            $output .= $this->mapping->getPadding41();
82 105
                            break;
83 195
                        case 2:
84 99
                            $output .= $this->mapping->getPadding42();
85 99
                            break;
86 96
                        case 3:
87 96
                            $output .= $this->mapping->getPadding43();
88 96
                            break;
89
                    }
90 393
                    break;
91 12
                case 5:
92
                    // use 8 bits from 1st byte and 2 bits from 2nd byte to lookup emoji
93 18
                    $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 18
                    $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 18
                    $output .= $this->mapping->getEmoji(($buffer[2] & 0x0f) << 6 | $buffer[3] >> 2);
100
101
                    //user 2 bits from 4th byte and 8 bits from 5th byte to lookup emoji
102 18
                    $output .= $this->mapping->getEmoji(($buffer[3] & 0x03) << 8 | $buffer[4]);
103 18
                    break;
104
            }
105
        }
106
107 786
        return $output;
108
    }
109
110
    /**
111
     * @param string $input Ecoji/Encoji encoded information.
112
     * @return string
113
     */
114 816
    public function decode(string $input): string
115
    {
116 816
        $textRemaining = $input;
117 816
        $result = '';
118
119 816
        while (strlen($textRemaining)) {
120 816
            if (mb_strlen($textRemaining) < 4) {
121 27
                throw new InvalidArgumentException('Unexpected end of data. Expected blocks of four emojis.');
122
            }
123
124
            $runes = [
125 798
                mb_substr($textRemaining, 0, 1),
126 798
                mb_substr($textRemaining, 1, 1),
127 798
                mb_substr($textRemaining, 2, 1),
128 798
                mb_substr($textRemaining, 3, 1),
129
            ];
130
131 798
            $textRemaining = mb_substr($textRemaining, 4);
132
133 798
            $bits1 = $this->mapping->getId($runes[0]);
134 795
            $bits2 = $this->mapping->getId($runes[1]);
135 795
            $bits3 = $this->mapping->getId($runes[2]);
136 795
            $bits4 = null;
137
138 795
            switch ($runes[3]) {
139 795
                case $this->mapping->getPadding40():
140 93
                    $bits4 = 0;
141 93
                    break;
142 702
                case $this->mapping->getPadding41():
143 105
                    $bits4 = 1 << 8;
144 105
                    break;
145 603
                case $this->mapping->getPadding42():
146 99
                    $bits4 = 2 << 8;
147 99
                    break;
148 507
                case $this->mapping->getPadding43():
149 96
                    $bits4 = 3 << 8;
150 96
                    break;
151
                default:
152 411
                    $bits4 = $this->mapping->getId($runes[3]);
153
            }
154
155
            $out = [
156 795
                $bits1 >> 2,
157 795
                (($bits1 & 0x3) << 6) | ($bits2 >> 4),
158 795
                (($bits2 & 0xf) << 4) | ($bits3 >> 6),
159 795
                (($bits3 & 0x3f) << 2) | ($bits4 >> 8),
160 795
                $bits4 & 0xff,
161
            ];
162
163 795
            if ($runes[1] == $this->mapping->getPadding()) {
164 381
                $out = array_slice($out, 0, 1);
165 417
            } elseif ($runes[2] == $this->mapping->getPadding()) {
166 6
                $out = array_slice($out, 0, 2);
167 414
            } elseif ($runes[3] == $this->mapping->getPadding()) {
168 6
                $out = array_slice($out, 0, 3);
169 411
            } elseif ($runes[3] == $this->mapping->getPadding40() || $runes[3] == $this->mapping->getPadding41() || $runes[3] == $this->mapping->getPadding42() || $runes[3] == $this->mapping->getPadding43()) {
170 393
                $out = array_slice($out, 0, 4);
171
            }
172
173 795
            foreach ($out as $v) {
174 795
                $result .= chr($v);
175
            }
176
        }
177
178 786
        return $result;
179
    }
180
}
181