Completed
Push — master ( f2149a...514e2e )
by Eugene
07:36
created

Packer::packU64()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 7
ccs 0
cts 0
cp 0
rs 9.4285
cc 1
eloc 4
nc 1
nop 2
crap 2
1
<?php
2
3
/*
4
 * This file is part of the rybakit/msgpack.php package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace MessagePack;
13
14
use MessagePack\Exception\PackingFailedException;
15
use MessagePack\TypeTransformer\Collection;
16
17
class Packer
18
{
19
    const NON_UTF8_REGEX = '/(
20
        [\xC0-\xC1] # Invalid UTF-8 Bytes
21
        | [\xF5-\xFF] # Invalid UTF-8 Bytes
22
        | \xE0[\x80-\x9F] # Overlong encoding of prior code point
23
        | \xF0[\x80-\x8F] # Overlong encoding of prior code point
24
        | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
25
        | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
26
        | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
27
        | (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
28
        | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
29
        | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
30
        | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
31
        | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
32
    )/x';
33
34
    /**
35
     * @var Collection
36
     */
37
    private $transformers;
38
39
    /**
40
     * @param Collection|null $transformers
41
     */
42 2
    public function setTransformers(Collection $transformers = null)
43
    {
44 2
        $this->transformers = $transformers;
45 2
    }
46
47
    /**
48
     * @return Collection|null
49
     */
50 1
    public function getTransformers()
51
    {
52 1
        return $this->transformers;
53
    }
54
55 77
    public function pack($value)
56
    {
57 77
        if (\is_int($value)) {
58 43
            return $this->packInt($value);
59
        }
60 48
        if (\is_string($value)) {
61 23
            return \preg_match(self::NON_UTF8_REGEX, $value)
62 23
                ? $this->packBin($value)
63 23
                : $this->packStr($value);
64
        }
65 31
        if (\is_array($value)) {
66 14
            return \array_values($value) === $value
67 14
                ? $this->packArray($value)
68 14
                : $this->packMap($value);
69
        }
70 21
        if (null === $value) {
71 3
            return $this->packNil();
72
        }
73 20
        if (\is_bool($value)) {
74 6
            return $this->packBool($value);
75
        }
76 15
        if (\is_double($value)) {
77 3
            return $this->packFloat($value);
78
        }
79 12
        if ($value instanceof Ext) {
80 9
            return $this->packExt($value);
81
        }
82
83 3
        if ($this->transformers && $transformer = $this->transformers->match($value)) {
84 1
            $ext = new Ext($transformer->getId(), $this->pack($transformer->transform($value)));
85
86 1
            return $this->packExt($ext);
87
        }
88
89 2
        throw new PackingFailedException($value, 'Unsupported type.');
90
    }
91
92 7
    public function packArray(array $array)
93
    {
94 7
        $size = \count($array);
95 7
        $data = self::packArrayHeader($size);
96
97 7
        foreach ($array as $val) {
98 6
            $data .= $this->pack($val);
99 7
        }
100
101 7
        return $data;
102
    }
103
104 7 View Code Duplication
    private static function packArrayHeader($size)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
105
    {
106 7
        if ($size <= 0xf) {
107 4
            return \chr(0x90 | $size);
108
        }
109 3
        if ($size <= 0xffff) {
110 2
            return "\xdc".\chr($size >> 8).\chr($size);
111
        }
112
113 1
        return \pack('CN', 0xdd, $size);
114
    }
115
116 9
    public function packMap(array $map)
117
    {
118 9
        $size = \count($map);
119 9
        $data = self::packMapHeader($size);
120
121 9
        foreach ($map as $key => $val) {
122 9
            $data .= $this->pack($key);
123 9
            $data .= $this->pack($val);
124 9
        }
125
126 9
        return $data;
127
    }
128
129 9 View Code Duplication
    private static function packMapHeader($size)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
    {
131 9
        if ($size <= 0xf) {
132 6
            return \chr(0x80 | $size);
133
        }
134 3
        if ($size <= 0xffff) {
135 2
            return "\xde".\chr($size >> 8).\chr($size);
136
        }
137
138 1
        return \pack('CN', 0xdf, $size);
139
    }
140
141 17
    public function packStr($str)
142
    {
143 17
        $len = \strlen($str);
144
145 17
        if ($len < 32) {
146 10
            return \chr(0xa0 | $len).$str;
147
        }
148 7
        if ($len <= 0xff) {
149 4
            return "\xd9".\chr($len).$str;
150
        }
151 3
        if ($len <= 0xffff) {
152 2
            return "\xda".\chr($len >> 8).\chr($len).$str;
153
        }
154
155 1
        return \pack('CN', 0xdb, $len).$str;
156
    }
157
158 8
    public function packBin($str)
159
    {
160 8
        $len = \strlen($str);
161
162 8
        if ($len <= 0xff) {
163 6
            return "\xc4".\chr($len).$str;
164
        }
165 2
        if ($len <= 0xffff) {
166 1
            return "\xc5".\chr($len >> 8).\chr($len).$str;
167
        }
168
169 1
        return \pack('CN', 0xc6, $len).$str;
170
    }
171
172 10
    public function packExt(Ext $ext)
173
    {
174 10
        $type = $ext->getType();
175 10
        $data = $ext->getData();
176 10
        $len = \strlen($data);
177
178
        switch ($len) {
179 10
            case 1: return "\xd4".\chr($type).$data;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
180 8
            case 2: return "\xd5".\chr($type).$data;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
181 7
            case 4: return "\xd6".\chr($type).$data;
182 6
            case 8: return "\xd7".\chr($type).$data;
183 5
            case 16: return "\xd8".\chr($type).$data;
184
        }
185
186 4
        if ($len <= 0xff) {
187 2
            return "\xc7".\chr($len).\chr($type).$data;
188
        }
189 2
        if ($len <= 0xffff) {
190 1
            return \pack('CnC', 0xc8, $len, $type).$data;
191
        }
192
193 1
        return \pack('CNC', 0xc9, $len, $type).$data;
194
    }
195
196 3
    public function packNil()
197
    {
198 3
        return "\xc0";
199
    }
200
201 6
    public function packBool($val)
202
    {
203 6
        return $val ? "\xc3" : "\xc2";
204
    }
205
206 3
    public function packFloat($num)
207
    {
208 3
        return "\xcb".strrev(pack('d', $num));
209
    }
210
211 43
    public function packInt($num)
212
    {
213 43
        if ($num >= 0) {
214 28
            if ($num <= 0x7f) {
215 16
                return \chr($num);
216
            }
217 16
            if ($num <= 0xff) {
218 6
                return "\xcc".\chr($num);
219
            }
220 12
            if ($num <= 0xffff) {
221 6
                return "\xcd".\chr($num >> 8).\chr($num);
222
            }
223 7
            if ($num <= 0xffffffff) {
224 5
                return \pack('CN', 0xce, $num);
225
            }
226
227 3
            return self::packUint64(0xcf, $num);
228
        }
229
230 16
        if ($num >= -0x20) {
231 4
            return \chr(0xe0 | $num);
232
        }
233 12
        if ($num >= -0x80) {
234 3
            return "\xd0".\chr($num);
235
        }
236 9
        if ($num >= -0x8000) {
237 3
            return "\xd1".\chr($num >> 8).\chr($num);
238
        }
239 6
        if ($num >= -0x80000000) {
240 3
            return \pack('CN', 0xd2, $num);
241
        }
242
243 3
        return self::packUint64(0xd3, $num);
244
    }
245
246 6
    private static function packUint64($code, $num)
247
    {
248 6
        $hi = ($num & 0xffffffff00000000) >> 32;
249 6
        $lo = $num & 0x00000000ffffffff;
250
251 6
        return \pack('CNN', $code, $hi, $lo);
252
    }
253
}
254