Completed
Push — master ( d13485...5b0b5b )
by Eugene
07:33
created

src/Packer.php (2 issues)

Check for correct position of case body

Coding Style Informational

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\InvalidOptionException;
15
use MessagePack\Exception\PackingFailedException;
16
use MessagePack\TypeTransformer\Collection;
17
18
class Packer
19
{
20
    const UTF8_REGEX = '/\A(?:
21
          [\x00-\x7F]++                      # ASCII
22
        | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
23
        |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
24
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
25
        |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
26
        |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
27
        | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
28
        |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
29
        )*+\z/x';
30
31
    private $isDetectStrBin;
32
    private $isForceStr;
33
    private $isDetectArrMap;
34
    private $isForceArr;
35
    private $isForceFloat32;
36
37
    /**
38
     * @var Collection|null
39
     */
40
    private $transformers;
41
42
    /**
43
     * @param PackOptions|int|null $options
44
     *
45
     * @throws InvalidOptionException
46
     */
47 106
    public function __construct($options = null)
48
    {
49 106
        if (!$options instanceof PackOptions) {
50 106
            $options = PackOptions::fromBitmask($options);
51
        }
52
53 106
        $this->isDetectStrBin = $options->isDetectStrBinMode();
54 106
        $this->isForceStr = $options->isForceStrMode();
55 106
        $this->isDetectArrMap = $options->isDetectArrMapMode();
56 106
        $this->isForceArr = $options->isForceArrMode();
57 106
        $this->isForceFloat32 = $options->isForceFloat32Mode();
58 106
    }
59
60
    /**
61
     * @param Collection|null $transformers
62
     */
63 2
    public function setTransformers(Collection $transformers = null)
64
    {
65 2
        $this->transformers = $transformers;
66 2
    }
67
68
    /**
69
     * @return Collection|null
70
     */
71 1
    public function getTransformers()
72
    {
73 1
        return $this->transformers;
74
    }
75
76 98
    public function pack($value)
77
    {
78 98
        if (\is_int($value)) {
79 53
            return $this->packInt($value);
80
        }
81 69
        if (\is_string($value)) {
82 33
            if ($this->isDetectStrBin) {
83 27
                return \preg_match(self::UTF8_REGEX, $value)
84 19
                    ? $this->packStr($value)
85 27
                    : $this->packBin($value);
86
            }
87
88 6
            return $this->isForceStr ? $this->packStr($value) : $this->packBin($value);
89
        }
90 46
        if (\is_array($value)) {
91 26
            if ($this->isDetectArrMap) {
92 19
                return \array_values($value) === $value
93 10
                    ? $this->packArray($value)
94 19
                    : $this->packMap($value);
95
            }
96
97 7
            return $this->isForceArr ? $this->packArray($value) : $this->packMap($value);
98
        }
99 24
        if (null === $value) {
100 3
            return $this->packNil();
101
        }
102 23
        if (\is_bool($value)) {
103 6
            return $this->packBool($value);
104
        }
105 18
        if (\is_float($value)) {
106 6
            return $this->isForceFloat32
107 1
                ? $this->packFloat32($value)
108 6
                : $this->packFloat64($value);
109
        }
110 12
        if ($value instanceof Ext) {
111 9
            return $this->packExt($value);
112
        }
113
114 3
        if ($this->transformers && $transformer = $this->transformers->match($value)) {
115 1
            $ext = new Ext($transformer->getId(), $this->pack($transformer->transform($value)));
116
117 1
            return $this->packExt($ext);
118
        }
119
120 2
        throw new PackingFailedException($value, 'Unsupported type.');
121
    }
122
123 13
    public function packArray(array $array)
124
    {
125 13
        $size = \count($array);
126 13
        $data = self::packArrayHeader($size);
127
128 13
        foreach ($array as $val) {
129 12
            $data .= $this->pack($val);
130
        }
131
132 13
        return $data;
133
    }
134
135 13 View Code Duplication
    private static function packArrayHeader($size)
136
    {
137 13
        if ($size <= 0xf) {
138 10
            return \chr(0x90 | $size);
139
        }
140 3
        if ($size <= 0xffff) {
141 2
            return "\xdc".\chr($size >> 8).\chr($size);
142
        }
143
144 1
        return \pack('CN', 0xdd, $size);
145
    }
146
147 15
    public function packMap(array $map)
148
    {
149 15
        $size = \count($map);
150 15
        $data = self::packMapHeader($size);
151
152 15
        foreach ($map as $key => $val) {
153 15
            $data .= $this->pack($key);
154 15
            $data .= $this->pack($val);
155
        }
156
157 15
        return $data;
158
    }
159
160 15 View Code Duplication
    private static function packMapHeader($size)
161
    {
162 15
        if ($size <= 0xf) {
163 12
            return \chr(0x80 | $size);
164
        }
165 3
        if ($size <= 0xffff) {
166 2
            return "\xde".\chr($size >> 8).\chr($size);
167
        }
168
169 1
        return \pack('CN', 0xdf, $size);
170
    }
171
172 22
    public function packStr($str)
173
    {
174 22
        $len = \strlen($str);
175
176 22
        if ($len < 32) {
177 15
            return \chr(0xa0 | $len).$str;
178
        }
179 7
        if ($len <= 0xff) {
180 4
            return "\xd9".\chr($len).$str;
181
        }
182 3
        if ($len <= 0xffff) {
183 2
            return "\xda".\chr($len >> 8).\chr($len).$str;
184
        }
185
186 1
        return \pack('CN', 0xdb, $len).$str;
187
    }
188
189 13
    public function packBin($str)
190
    {
191 13
        $len = \strlen($str);
192
193 13
        if ($len <= 0xff) {
194 11
            return "\xc4".\chr($len).$str;
195
        }
196 2
        if ($len <= 0xffff) {
197 1
            return "\xc5".\chr($len >> 8).\chr($len).$str;
198
        }
199
200 1
        return \pack('CN', 0xc6, $len).$str;
201
    }
202
203 10
    public function packExt(Ext $ext)
204
    {
205 10
        $type = $ext->getType();
206 10
        $data = $ext->getData();
207 10
        $len = \strlen($data);
208
209 10
        switch ($len) {
210 10
            case 1: return "\xd4".\chr($type).$data;
0 ignored issues
show
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...
211 8
            case 2: return "\xd5".\chr($type).$data;
0 ignored issues
show
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...
212 7
            case 4: return "\xd6".\chr($type).$data;
213 6
            case 8: return "\xd7".\chr($type).$data;
214 5
            case 16: return "\xd8".\chr($type).$data;
215
        }
216
217 4
        if ($len <= 0xff) {
218 2
            return "\xc7".\chr($len).\chr($type).$data;
219
        }
220 2
        if ($len <= 0xffff) {
221 1
            return \pack('CnC', 0xc8, $len, $type).$data;
222
        }
223
224 1
        return \pack('CNC', 0xc9, $len, $type).$data;
225
    }
226
227 3
    public function packNil()
228
    {
229 3
        return "\xc0";
230
    }
231
232 6
    public function packBool($val)
233
    {
234 6
        return $val ? "\xc3" : "\xc2";
235
    }
236
237 3
    public function packFloat32($num)
238
    {
239 3
        return "\xca".\strrev(\pack('f', $num));
240
    }
241
242 5
    public function packFloat64($num)
243
    {
244 5
        return "\xcb".\strrev(\pack('d', $num));
245
    }
246
247 53
    public function packInt($num)
248
    {
249 53
        if ($num >= 0) {
250 38
            if ($num <= 0x7f) {
251 26
                return \chr($num);
252
            }
253 16
            if ($num <= 0xff) {
254 6
                return "\xcc".\chr($num);
255
            }
256 12
            if ($num <= 0xffff) {
257 6
                return "\xcd".\chr($num >> 8).\chr($num);
258
            }
259 7
            if ($num <= 0xffffffff) {
260 5
                return \pack('CN', 0xce, $num);
261
            }
262
263 3
            return self::packUint64(0xcf, $num);
264
        }
265
266 16
        if ($num >= -0x20) {
267 4
            return \chr(0xe0 | $num);
268
        }
269 12
        if ($num >= -0x80) {
270 3
            return "\xd0".\chr($num);
271
        }
272 9
        if ($num >= -0x8000) {
273 3
            return "\xd1".\chr($num >> 8).\chr($num);
274
        }
275 6
        if ($num >= -0x80000000) {
276 3
            return \pack('CN', 0xd2, $num);
277
        }
278
279 3
        return self::packUint64(0xd3, $num);
280
    }
281
282 6
    private static function packUint64($code, $num)
283
    {
284 6
        $hi = ($num & 0xffffffff00000000) >> 32;
285 6
        $lo = $num & 0x00000000ffffffff;
286
287 6
        return \pack('CNN', $code, $hi, $lo);
288
    }
289
}
290