Completed
Pull Request — master (#21)
by Eugene
09:40
created

Packer::packFloat32()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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\Packable;
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 Packable[]|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
    public function registerTransformer(Packable $transformer)
61
    {
62
        $this->transformers[] = $transformer;
63 2
    }
64
65 2
    public function pack($value)
66 2
    {
67
        if (\is_int($value)) {
68
            return $this->packInt($value);
69
        }
70
        if (\is_string($value)) {
71 1
            if ($this->isDetectStrBin) {
72
                return \preg_match(self::UTF8_REGEX, $value)
73 1
                    ? $this->packStr($value)
74
                    : $this->packBin($value);
75
            }
76 98
77
            return $this->isForceStr ? $this->packStr($value) : $this->packBin($value);
78 98
        }
79 53
        if (\is_array($value)) {
80
            if ($this->isDetectArrMap) {
81 69
                return \array_values($value) === $value
82 33
                    ? $this->packArray($value)
83 27
                    : $this->packMap($value);
84 19
            }
85 27
86
            return $this->isForceArr ? $this->packArray($value) : $this->packMap($value);
87
        }
88 6
        if (null === $value) {
89
            return $this->packNil();
90 46
        }
91 26
        if (\is_bool($value)) {
92 19
            return $this->packBool($value);
93 10
        }
94 19
        if (\is_float($value)) {
95
            return $this->packFloat($value);
96
        }
97 7
        if ($value instanceof Ext) {
98
            return $this->packExt($value->type, $value->data);
99 24
        }
100 3
        if ($this->transformers) {
101
            foreach ($this->transformers as $transformer) {
102 23
                if (null !== $packed = $transformer->pack($this, $value)) {
103 6
                    return $packed;
104
                }
105 18
            }
106 6
        }
107 1
108 6
        throw new PackingFailedException($value, 'Unsupported type.');
109
    }
110 12
111 9
    public function packNil()
112
    {
113
        return "\xc0";
114 3
    }
115 1
116
    public function packBool($bool)
117 1
    {
118
        return $bool ? "\xc3" : "\xc2";
119
    }
120 2
121
    public function packInt($int)
122
    {
123 13
        if ($int >= 0) {
124
            if ($int <= 0x7f) {
125 13
                return \chr($int);
126
            }
127 13
            if ($int <= 0xff) {
128 10
                return "\xcc".\chr($int);
129 3
            }
130 2
            if ($int <= 0xffff) {
131
                return "\xcd".\chr($int >> 8).\chr($int);
132 1
            }
133
            if ($int <= 0xffffffff) {
134
                return \pack('CN', 0xce, $int);
135 13
            }
136 12
137
            return self::packUintInt64(0xcf, $int);
138
        }
139 13
140
        if ($int >= -0x20) {
141
            return \chr(0xe0 | $int);
142 15
        }
143
        if ($int >= -0x80) {
144 15
            return "\xd0".\chr($int);
145
        }
146 15
        if ($int >= -0x8000) {
147 12
            return "\xd1".\chr($int >> 8).\chr($int);
148 3
        }
149 2
        if ($int >= -0x80000000) {
150
            return \pack('CN', 0xd2, $int);
151 1
        }
152
153
        return self::packUintInt64(0xd3, $int);
154 15
    }
155 15
156 15
    public function packFloat($float)
157
    {
158
        return $this->isForceFloat32
159 15
            ? "\xca".\strrev(\pack('f', $float))
160
            : "\xcb".\strrev(\pack('d', $float));
161
    }
162 22
163
    public function packStr($str)
164 22
    {
165
        $length = \strlen($str);
166 22
167 15
        if ($length < 32) {
168
            return \chr(0xa0 | $length).$str;
169 7
        }
170 4
        if ($length <= 0xff) {
171
            return "\xd9".\chr($length).$str;
172 3
        }
173 2 View Code Duplication
        if ($length <= 0xffff) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
174
            return "\xda".\chr($length >> 8).\chr($length).$str;
175
        }
176 1
177
        return \pack('CN', 0xdb, $length).$str;
178
    }
179 13
180
    public function packBin($str)
181 13
    {
182
        $length = \strlen($str);
183 13
184 11
        if ($length <= 0xff) {
185
            return "\xc4".\chr($length).$str;
186 2
        }
187 1 View Code Duplication
        if ($length <= 0xffff) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
188
            return "\xc5".\chr($length >> 8).\chr($length).$str;
189
        }
190 1
191
        return \pack('CN', 0xc6, $length).$str;
192
    }
193 10
194
    public function packArray(array $array)
195 10
    {
196
        $data = $this->packArrayHeader(\count($array));
197 10
198 10
        foreach ($array as $val) {
199 8
            $data .= $this->pack($val);
200 7
        }
201 6
202 5
        return $data;
203
    }
204
205 4 View Code Duplication
    public 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...
206 2
    {
207
        if ($size <= 0xf) {
208 2
            return \chr(0x90 | $size);
209 1
        }
210
        if ($size <= 0xffff) {
211
            return "\xdc".\chr($size >> 8).\chr($size);
212 1
        }
213
214
        return \pack('CN', 0xdd, $size);
215 3
    }
216
217 3
    public function packMap(array $map)
218
    {
219
        $data = $this->packMapHeader(\count($map));
220 6
221
        foreach ($map as $key => $val) {
222 6
            $data .= $this->pack($key);
223
            $data .= $this->pack($val);
224
        }
225 3
226
        return $data;
227 3
    }
228
229 View Code Duplication
    public 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...
230 5
    {
231
        if ($size <= 0xf) {
232 5
            return \chr(0x80 | $size);
233
        }
234
        if ($size <= 0xffff) {
235 53
            return "\xde".\chr($size >> 8).\chr($size);
236
        }
237 53
238 38
        return \pack('CN', 0xdf, $size);
239 26
    }
240
241 16
    public function packExt($type, $data)
242 6
    {
243
        $length = \strlen($data);
244 12
245 6
        switch ($length) {
246
            case 1: return "\xd4".\chr($type).$data;
247 7
            case 2: return "\xd5".\chr($type).$data;
248 5
            case 4: return "\xd6".\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...
249
            case 8: return "\xd7".\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...
250
            case 16: return "\xd8".\chr($type).$data;
251 3
        }
252
253 View Code Duplication
        if ($length <= 0xff) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
254 16
            return "\xc7".\chr($length).\chr($type).$data;
255 4
        }
256
        if ($length <= 0xffff) {
257 12
            return \pack('CnC', 0xc8, $length, $type).$data;
258 3
        }
259
260 9
        return \pack('CNC', 0xc9, $length, $type).$data;
261 3
    }
262
263 6
    private static function packUintInt64($code, $int)
264 3
    {
265
        $hi = ($int & 0xffffffff00000000) >> 32;
266
        $lo = $int & 0x00000000ffffffff;
267 3
268
        return \pack('CNN', $code, $hi, $lo);
269
    }
270
}
271