|
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\InsufficientDataException; |
|
15
|
|
|
use MessagePack\Exception\IntegerOverflowException; |
|
16
|
|
|
use MessagePack\Exception\InvalidCodeException; |
|
17
|
|
|
use MessagePack\Exception\InvalidOptionException; |
|
18
|
|
|
use MessagePack\Exception\UnpackingFailedException; |
|
19
|
|
|
use MessagePack\TypeTransformer\Extension; |
|
20
|
|
|
|
|
21
|
|
|
class BufferUnpacker |
|
22
|
|
|
{ |
|
23
|
|
|
private $buffer; |
|
24
|
|
|
private $offset = 0; |
|
25
|
|
|
private $isBigIntAsStr; |
|
26
|
|
|
private $isBigIntAsGmp; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* @var Extension[]|null |
|
30
|
|
|
*/ |
|
31
|
|
|
private $transformers; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* @param string $buffer |
|
35
|
|
|
* @param UnpackOptions|int|null $options |
|
36
|
|
|
* |
|
37
|
|
|
* @throws InvalidOptionException |
|
38
|
123 |
|
*/ |
|
39
|
|
|
public function __construct($buffer = '', $options = null) |
|
40
|
123 |
|
{ |
|
41
|
123 |
|
if (!$options instanceof UnpackOptions) { |
|
42
|
|
|
$options = UnpackOptions::fromBitmask($options); |
|
43
|
|
|
} |
|
44
|
123 |
|
|
|
45
|
123 |
|
$this->isBigIntAsStr = $options->isBigIntAsStrMode(); |
|
46
|
|
|
$this->isBigIntAsGmp = $options->isBigIntAsGmpMode(); |
|
47
|
123 |
|
|
|
48
|
123 |
|
$this->buffer = $buffer; |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
public function registerTransformer(Extension $ext) |
|
52
|
|
|
{ |
|
53
|
2 |
|
$this->transformers[$ext->getType()] = $ext; |
|
54
|
|
|
} |
|
55
|
2 |
|
|
|
56
|
2 |
|
/** |
|
57
|
|
|
* @param string $data |
|
58
|
|
|
* |
|
59
|
|
|
* @return $this |
|
60
|
|
|
*/ |
|
61
|
1 |
|
public function append($data) |
|
62
|
|
|
{ |
|
63
|
1 |
|
$this->buffer .= $data; |
|
64
|
|
|
|
|
65
|
|
|
return $this; |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* @param string $buffer |
|
70
|
|
|
* |
|
71
|
5 |
|
* @return $this |
|
72
|
|
|
*/ |
|
73
|
5 |
|
public function reset($buffer = '') |
|
74
|
|
|
{ |
|
75
|
5 |
|
$this->buffer = $buffer; |
|
76
|
|
|
$this->offset = 0; |
|
77
|
|
|
|
|
78
|
|
|
return $this; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* @return array |
|
83
|
109 |
|
*/ |
|
84
|
|
|
public function tryUnpack() |
|
85
|
109 |
|
{ |
|
86
|
109 |
|
$data = []; |
|
87
|
|
|
$offset = $this->offset; |
|
88
|
109 |
|
|
|
89
|
|
|
try { |
|
90
|
|
|
do { |
|
91
|
|
|
$data[] = $this->unpack(); |
|
92
|
|
|
$offset = $this->offset; |
|
93
|
|
|
} while (isset($this->buffer[$this->offset])); |
|
94
|
3 |
|
} catch (InsufficientDataException $e) { |
|
95
|
|
|
$this->offset = $offset; |
|
96
|
3 |
|
} |
|
97
|
3 |
|
|
|
98
|
|
|
if ($this->offset) { |
|
99
|
|
|
$this->buffer = isset($this->buffer[$this->offset]) ? \substr($this->buffer, $this->offset) : ''; |
|
100
|
|
|
$this->offset = 0; |
|
101
|
3 |
|
} |
|
102
|
3 |
|
|
|
103
|
3 |
|
return $data; |
|
104
|
1 |
|
} |
|
105
|
1 |
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* @throws UnpackingFailedException |
|
108
|
3 |
|
* |
|
109
|
3 |
|
* @return mixed |
|
110
|
3 |
|
*/ |
|
111
|
|
|
public function unpack() |
|
112
|
|
|
{ |
|
113
|
3 |
|
if (!isset($this->buffer[$this->offset])) { |
|
114
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
$c = \ord($this->buffer[$this->offset]); |
|
118
|
|
|
++$this->offset; |
|
119
|
|
|
|
|
120
|
|
|
// fixint |
|
121
|
118 |
|
if ($c <= 0x7f) { |
|
122
|
|
|
return $c; |
|
123
|
118 |
|
} |
|
124
|
4 |
|
// fixstr |
|
125
|
|
View Code Duplication |
if ($c >= 0xa0 && $c <= 0xbf) { |
|
|
|
|
|
|
126
|
|
|
return ($c & 0x1f) ? $this->unpackStrData($c & 0x1f) : ''; |
|
127
|
116 |
|
} |
|
128
|
116 |
|
// fixarray |
|
129
|
|
|
if ($c >= 0x90 && $c <= 0x9f) { |
|
130
|
|
|
return ($c & 0xf) ? $this->unpackArrayData($c & 0xf) : []; |
|
131
|
116 |
|
} |
|
132
|
20 |
|
// fixmap |
|
133
|
|
|
if ($c >= 0x80 && $c <= 0x8f) { |
|
134
|
|
|
return ($c & 0xf) ? $this->unpackMapData($c & 0xf) : []; |
|
135
|
113 |
|
} |
|
136
|
13 |
|
// negfixint |
|
137
|
|
|
if ($c >= 0xe0) { |
|
138
|
|
|
return $c - 256; |
|
139
|
107 |
|
} |
|
140
|
6 |
|
|
|
141
|
|
|
switch ($c) { |
|
142
|
|
|
case 0xc0: return null; |
|
|
|
|
|
|
143
|
104 |
|
case 0xc2: return false; |
|
|
|
|
|
|
144
|
11 |
|
case 0xc3: return true; |
|
|
|
|
|
|
145
|
|
|
|
|
146
|
|
|
// MP_BIN |
|
147
|
100 |
|
case 0xc4: return $this->unpackStrData($this->unpackUint8()); |
|
|
|
|
|
|
148
|
4 |
|
case 0xc5: return $this->unpackStrData($this->unpackUint16()); |
|
|
|
|
|
|
149
|
|
|
case 0xc6: return $this->unpackStrData($this->unpackUint32()); |
|
|
|
|
|
|
150
|
|
|
|
|
151
|
96 |
|
// MP_FLOAT |
|
152
|
96 |
|
case 0xca: return $this->unpackFloat32(); |
|
|
|
|
|
|
153
|
95 |
|
case 0xcb: return $this->unpackFloat64(); |
|
|
|
|
|
|
154
|
93 |
|
|
|
155
|
|
|
// MP_UINT |
|
156
|
|
|
case 0xcc: return $this->unpackUint8(); |
|
|
|
|
|
|
157
|
88 |
|
case 0xcd: return $this->unpackUint16(); |
|
|
|
|
|
|
158
|
84 |
|
case 0xce: return $this->unpackUint32(); |
|
|
|
|
|
|
159
|
83 |
|
case 0xcf: return $this->unpackUint64(); |
|
|
|
|
|
|
160
|
|
|
|
|
161
|
|
|
// MP_INT |
|
162
|
82 |
|
case 0xd0: return $this->unpackInt8(); |
|
|
|
|
|
|
163
|
79 |
|
case 0xd1: return $this->unpackInt16(); |
|
|
|
|
|
|
164
|
|
|
case 0xd2: return $this->unpackInt32(); |
|
|
|
|
|
|
165
|
|
|
case 0xd3: return $this->unpackInt64(); |
|
|
|
|
|
|
166
|
75 |
|
|
|
167
|
71 |
|
// MP_STR |
|
168
|
66 |
|
case 0xd9: return $this->unpackStrData($this->unpackUint8()); |
|
|
|
|
|
|
169
|
62 |
|
case 0xda: return $this->unpackStrData($this->unpackUint16()); |
|
|
|
|
|
|
170
|
|
|
case 0xdb: return $this->unpackStrData($this->unpackUint32()); |
|
|
|
|
|
|
171
|
|
|
|
|
172
|
52 |
|
// MP_ARRAY |
|
173
|
47 |
|
case 0xdc: return $this->unpackArrayData($this->unpackUint16()); |
|
|
|
|
|
|
174
|
42 |
|
case 0xdd: return $this->unpackArrayData($this->unpackUint32()); |
|
|
|
|
|
|
175
|
37 |
|
|
|
176
|
|
|
// MP_MAP |
|
177
|
|
|
case 0xde: return $this->unpackMapData($this->unpackUint16()); |
|
|
|
|
|
|
178
|
32 |
|
case 0xdf: return $this->unpackMapData($this->unpackUint32()); |
|
|
|
|
|
|
179
|
28 |
|
|
|
180
|
26 |
|
// MP_EXT |
|
181
|
|
|
case 0xd4: return $this->unpackExtData(1); |
|
|
|
|
|
|
182
|
|
|
case 0xd5: return $this->unpackExtData(2); |
|
|
|
|
|
|
183
|
25 |
|
case 0xd6: return $this->unpackExtData(4); |
|
|
|
|
|
|
184
|
23 |
|
case 0xd7: return $this->unpackExtData(8); |
|
|
|
|
|
|
185
|
|
|
case 0xd8: return $this->unpackExtData(16); |
|
|
|
|
|
|
186
|
|
|
case 0xc7: return $this->unpackExtData($this->unpackUint8()); |
|
|
|
|
|
|
187
|
22 |
|
case 0xc8: return $this->unpackExtData($this->unpackUint16()); |
|
|
|
|
|
|
188
|
20 |
|
case 0xc9: return $this->unpackExtData($this->unpackUint32()); |
|
|
|
|
|
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
19 |
|
throw InvalidCodeException::fromUnknownCode($c); |
|
192
|
16 |
|
} |
|
193
|
14 |
|
|
|
194
|
12 |
|
public function unpackNil() |
|
195
|
10 |
|
{ |
|
196
|
8 |
|
if (!isset($this->buffer[$this->offset])) { |
|
197
|
5 |
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
198
|
3 |
|
} |
|
199
|
|
|
|
|
200
|
|
|
if (0xc0 === \ord($this->buffer[$this->offset++])) { |
|
201
|
1 |
|
return null; |
|
202
|
|
|
} |
|
203
|
|
|
|
|
204
|
18 |
|
throw InvalidCodeException::fromExpectedType('nil', \ord($this->buffer[$this->offset - 1])); |
|
205
|
|
|
} |
|
206
|
18 |
|
|
|
207
|
2 |
|
public function unpackBool() |
|
208
|
|
|
{ |
|
209
|
|
|
if (!isset($this->buffer[$this->offset])) { |
|
210
|
16 |
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
211
|
16 |
|
} |
|
212
|
|
|
|
|
213
|
16 |
|
$c = \ord($this->buffer[$this->offset++]); |
|
214
|
|
|
|
|
215
|
|
|
if (0xc2 === $c) { |
|
216
|
15 |
|
return false; |
|
217
|
|
|
} |
|
218
|
15 |
|
if (0xc3 === $c) { |
|
219
|
2 |
|
return true; |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
13 |
|
throw InvalidCodeException::fromExpectedType('bool', $c); |
|
223
|
13 |
|
} |
|
224
|
13 |
|
|
|
225
|
|
|
public function unpackInt() |
|
226
|
13 |
|
{ |
|
227
|
|
|
if (!isset($this->buffer[$this->offset])) { |
|
228
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
229
|
11 |
|
} |
|
230
|
|
|
|
|
231
|
11 |
|
$c = \ord($this->buffer[$this->offset++]); |
|
232
|
2 |
|
|
|
233
|
|
|
// fixint |
|
234
|
|
|
if ($c <= 0x7f) { |
|
235
|
9 |
|
return $c; |
|
236
|
9 |
|
} |
|
237
|
|
|
// negfixint |
|
238
|
9 |
|
if ($c >= 0xe0) { |
|
239
|
|
|
return $c - 256; |
|
240
|
9 |
|
} |
|
241
|
|
|
|
|
242
|
|
|
switch ($c) { |
|
243
|
10 |
|
// MP_UINT |
|
244
|
|
|
case 0xcc: return $this->unpackUint8(); |
|
|
|
|
|
|
245
|
10 |
|
case 0xcd: return $this->unpackUint16(); |
|
|
|
|
|
|
246
|
1 |
|
case 0xce: return $this->unpackUint32(); |
|
|
|
|
|
|
247
|
|
|
case 0xcf: return $this->unpackUint64(); |
|
|
|
|
|
|
248
|
|
|
|
|
249
|
9 |
|
// MP_INT |
|
250
|
9 |
|
case 0xd0: return $this->unpackInt8(); |
|
|
|
|
|
|
251
|
|
|
case 0xd1: return $this->unpackInt16(); |
|
|
|
|
|
|
252
|
|
|
case 0xd2: return $this->unpackInt32(); |
|
|
|
|
|
|
253
|
|
|
case 0xd3: return $this->unpackInt64(); |
|
|
|
|
|
|
254
|
9 |
|
} |
|
255
|
9 |
|
|
|
256
|
|
|
throw InvalidCodeException::fromExpectedType('int', $c); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
public function unpackFloat() |
|
260
|
|
|
{ |
|
261
|
9 |
|
if (!isset($this->buffer[$this->offset])) { |
|
262
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
263
|
|
|
} |
|
264
|
15 |
|
|
|
265
|
|
|
$c = \ord($this->buffer[$this->offset++]); |
|
266
|
15 |
|
|
|
267
|
1 |
|
if (0xcb === $c) { |
|
268
|
|
|
return $this->unpackFloat64(); |
|
269
|
|
|
} |
|
270
|
14 |
|
if (0xca === $c) { |
|
271
|
14 |
|
return $this->unpackFloat32(); |
|
272
|
|
|
} |
|
273
|
14 |
|
|
|
274
|
3 |
|
throw InvalidCodeException::fromExpectedType('float', $c); |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
11 |
|
public function unpackStr() |
|
278
|
|
|
{ |
|
279
|
|
|
if (!isset($this->buffer[$this->offset])) { |
|
280
|
5 |
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
281
|
|
|
} |
|
282
|
5 |
|
|
|
283
|
1 |
|
$c = \ord($this->buffer[$this->offset++]); |
|
284
|
|
|
|
|
285
|
|
View Code Duplication |
if ($c >= 0xa0 && $c <= 0xbf) { |
|
|
|
|
|
|
286
|
4 |
|
return ($c & 0x1f) ? $this->unpackStrData($c & 0x1f) : ''; |
|
287
|
4 |
|
} |
|
288
|
4 |
|
if (0xd9 === $c) { |
|
289
|
|
|
return $this->unpackStrData($this->unpackUint8()); |
|
290
|
4 |
|
} |
|
291
|
3 |
|
if (0xda === $c) { |
|
292
|
|
|
return $this->unpackStrData($this->unpackUint16()); |
|
293
|
|
|
} |
|
294
|
1 |
|
if (0xdb === $c) { |
|
295
|
|
|
return $this->unpackStrData($this->unpackUint32()); |
|
296
|
|
|
} |
|
297
|
5 |
|
|
|
298
|
|
|
throw InvalidCodeException::fromExpectedType('str', $c); |
|
299
|
5 |
|
} |
|
300
|
1 |
|
|
|
301
|
|
|
public function unpackBin() |
|
302
|
|
|
{ |
|
303
|
4 |
|
if (!isset($this->buffer[$this->offset])) { |
|
304
|
4 |
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
305
|
|
|
} |
|
306
|
4 |
|
|
|
307
|
|
|
$c = \ord($this->buffer[$this->offset++]); |
|
308
|
4 |
|
|
|
309
|
|
|
if (0xc4 === $c) { |
|
310
|
|
|
return $this->unpackStrData($this->unpackUint8()); |
|
311
|
5 |
|
} |
|
312
|
|
|
if (0xc5 === $c) { |
|
313
|
5 |
|
return $this->unpackStrData($this->unpackUint16()); |
|
314
|
1 |
|
} |
|
315
|
|
|
if (0xc6 === $c) { |
|
316
|
|
|
return $this->unpackStrData($this->unpackUint32()); |
|
317
|
4 |
|
} |
|
318
|
4 |
|
|
|
319
|
|
|
throw InvalidCodeException::fromExpectedType('bin', $c); |
|
320
|
4 |
|
} |
|
321
|
|
|
|
|
322
|
4 |
|
public function unpackArray() |
|
323
|
|
|
{ |
|
324
|
|
|
$size = $this->unpackArrayHeader(); |
|
325
|
3 |
|
|
|
326
|
|
|
$array = []; |
|
327
|
3 |
|
while ($size--) { |
|
328
|
1 |
|
$array[] = $this->unpack(); |
|
329
|
|
|
} |
|
330
|
|
|
|
|
331
|
2 |
|
return $array; |
|
332
|
2 |
|
} |
|
333
|
|
|
|
|
334
|
2 |
View Code Duplication |
public function unpackArrayHeader() |
|
|
|
|
|
|
335
|
|
|
{ |
|
336
|
2 |
|
if (!isset($this->buffer[$this->offset])) { |
|
337
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
338
|
|
|
} |
|
339
|
4 |
|
|
|
340
|
|
|
$c = \ord($this->buffer[$this->offset++]); |
|
341
|
4 |
|
|
|
342
|
1 |
|
if ($c >= 0x90 && $c <= 0x9f) { |
|
343
|
|
|
return $c & 0xf; |
|
344
|
|
|
} |
|
345
|
3 |
|
if (0xdc === $c) { |
|
346
|
3 |
|
return $this->unpackUint16(); |
|
347
|
|
|
} |
|
348
|
3 |
|
if (0xdd === $c) { |
|
349
|
|
|
return $this->unpackUint32(); |
|
350
|
3 |
|
} |
|
351
|
|
|
|
|
352
|
|
|
throw InvalidCodeException::fromExpectedType('array header', $c); |
|
353
|
25 |
|
} |
|
354
|
|
|
|
|
355
|
25 |
|
public function unpackMap() |
|
356
|
1 |
|
{ |
|
357
|
|
|
$size = $this->unpackMapHeader(); |
|
358
|
|
|
|
|
359
|
25 |
|
$map = []; |
|
360
|
25 |
|
while ($size--) { |
|
361
|
|
|
$map[$this->unpack()] = $this->unpack(); |
|
362
|
25 |
|
} |
|
363
|
|
|
|
|
364
|
|
|
return $map; |
|
365
|
8 |
|
} |
|
366
|
|
|
|
|
367
|
8 |
View Code Duplication |
public function unpackMapHeader() |
|
|
|
|
|
|
368
|
8 |
|
{ |
|
369
|
8 |
|
if (!isset($this->buffer[$this->offset])) { |
|
370
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
371
|
|
|
} |
|
372
|
8 |
|
|
|
373
|
|
|
$c = \ord($this->buffer[$this->offset++]); |
|
374
|
|
|
|
|
375
|
13 |
|
if ($c >= 0x80 && $c <= 0x8f) { |
|
376
|
|
|
return $c & 0xf; |
|
377
|
13 |
|
} |
|
378
|
13 |
|
if (0xde === $c) { |
|
379
|
13 |
|
return $this->unpackUint16(); |
|
380
|
|
|
} |
|
381
|
|
|
if (0xdf === $c) { |
|
382
|
13 |
|
return $this->unpackUint32(); |
|
383
|
|
|
} |
|
384
|
|
|
|
|
385
|
15 |
|
throw InvalidCodeException::fromExpectedType('map header', $c); |
|
386
|
|
|
} |
|
387
|
15 |
|
|
|
388
|
5 |
|
public function unpackExt() |
|
389
|
|
|
{ |
|
390
|
|
|
if (!isset($this->buffer[$this->offset])) { |
|
391
|
10 |
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
392
|
|
|
} |
|
393
|
10 |
|
|
|
394
|
1 |
|
$c = \ord($this->buffer[$this->offset++]); |
|
395
|
|
|
|
|
396
|
|
|
switch ($c) { |
|
397
|
9 |
|
case 0xd4: return $this->unpackExtData(1); |
|
|
|
|
|
|
398
|
9 |
|
case 0xd5: return $this->unpackExtData(2); |
|
|
|
|
|
|
399
|
|
|
case 0xd6: return $this->unpackExtData(4); |
|
|
|
|
|
|
400
|
9 |
|
case 0xd7: return $this->unpackExtData(8); |
|
|
|
|
|
|
401
|
|
|
case 0xd8: return $this->unpackExtData(16); |
|
|
|
|
|
|
402
|
|
|
case 0xc7: return $this->unpackExtData($this->unpackUint8()); |
|
|
|
|
|
|
403
|
5 |
|
case 0xc8: return $this->unpackExtData($this->unpackUint16()); |
|
|
|
|
|
|
404
|
|
|
case 0xc9: return $this->unpackExtData($this->unpackUint32()); |
|
|
|
|
|
|
405
|
5 |
|
} |
|
406
|
3 |
|
|
|
407
|
|
|
throw InvalidCodeException::fromExpectedType('ext header', $c); |
|
408
|
2 |
|
} |
|
409
|
1 |
|
|
|
410
|
|
|
private function unpackUint8() |
|
411
|
|
|
{ |
|
412
|
1 |
|
if (!isset($this->buffer[$this->offset])) { |
|
413
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
414
|
|
|
} |
|
415
|
|
|
|
|
416
|
|
|
return \ord($this->buffer[$this->offset++]); |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
private function unpackUint16() |
|
420
|
|
|
{ |
|
421
|
|
|
if (!isset($this->buffer[$this->offset + 1])) { |
|
422
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 2); |
|
423
|
|
|
} |
|
424
|
|
|
|
|
425
|
|
|
$hi = \ord($this->buffer[$this->offset]); |
|
426
|
|
|
$lo = \ord($this->buffer[$this->offset + 1]); |
|
427
|
|
|
$this->offset += 2; |
|
428
|
|
|
|
|
429
|
|
|
return $hi << 8 | $lo; |
|
430
|
|
|
} |
|
431
|
|
|
|
|
432
|
|
View Code Duplication |
private function unpackUint32() |
|
|
|
|
|
|
433
|
|
|
{ |
|
434
|
|
|
if (!isset($this->buffer[$this->offset + 3])) { |
|
435
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 4); |
|
436
|
|
|
} |
|
437
|
|
|
|
|
438
|
|
|
$num = \substr($this->buffer, $this->offset, 4); |
|
439
|
|
|
$this->offset += 4; |
|
440
|
|
|
|
|
441
|
|
|
$num = \unpack('N', $num); |
|
442
|
|
|
|
|
443
|
|
|
return $num[1]; |
|
444
|
|
|
} |
|
445
|
|
|
|
|
446
|
|
|
private function unpackUint64() |
|
447
|
|
|
{ |
|
448
|
|
|
if (!isset($this->buffer[$this->offset + 7])) { |
|
449
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 8); |
|
450
|
|
|
} |
|
451
|
|
|
|
|
452
|
|
|
$num = \substr($this->buffer, $this->offset, 8); |
|
453
|
|
|
$this->offset += 8; |
|
454
|
|
|
|
|
455
|
|
|
//$num = \unpack('J', $num); |
|
|
|
|
|
|
456
|
|
|
|
|
457
|
|
|
$set = \unpack('N2', $num); |
|
458
|
|
|
$value = $set[1] << 32 | $set[2]; |
|
459
|
|
|
|
|
460
|
|
|
// PHP does not support unsigned integers. |
|
461
|
|
|
// If a number is bigger than 2^63, it will be interpreted as a float. |
|
462
|
|
|
// @link http://php.net/manual/en/language.types.integer.php#language.types.integer.overflow |
|
463
|
|
|
|
|
464
|
|
|
return $value < 0 ? $this->handleIntOverflow($value) : $value; |
|
465
|
|
|
} |
|
466
|
|
|
|
|
467
|
|
|
private function unpackInt8() |
|
468
|
|
|
{ |
|
469
|
|
|
if (!isset($this->buffer[$this->offset])) { |
|
470
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 1); |
|
471
|
|
|
} |
|
472
|
|
|
|
|
473
|
|
|
$num = \ord($this->buffer[$this->offset]); |
|
474
|
|
|
++$this->offset; |
|
475
|
|
|
|
|
476
|
|
|
return $num > 0x7f ? $num - 256 : $num; |
|
477
|
|
|
} |
|
478
|
|
|
|
|
479
|
|
|
private function unpackInt16() |
|
480
|
|
|
{ |
|
481
|
|
|
if (!isset($this->buffer[$this->offset + 1])) { |
|
482
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 2); |
|
483
|
|
|
} |
|
484
|
|
|
|
|
485
|
|
|
$hi = \ord($this->buffer[$this->offset]); |
|
486
|
|
|
$lo = \ord($this->buffer[$this->offset + 1]); |
|
487
|
|
|
$this->offset += 2; |
|
488
|
|
|
|
|
489
|
|
|
if ($hi > 0x7f) { |
|
490
|
|
|
return -(0x010000 - ($hi << 8 | $lo)); |
|
491
|
|
|
} |
|
492
|
|
|
|
|
493
|
|
|
return $hi << 8 | $lo; |
|
494
|
|
|
} |
|
495
|
|
|
|
|
496
|
|
View Code Duplication |
private function unpackInt32() |
|
|
|
|
|
|
497
|
|
|
{ |
|
498
|
|
|
if (!isset($this->buffer[$this->offset + 3])) { |
|
499
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 4); |
|
500
|
|
|
} |
|
501
|
|
|
|
|
502
|
|
|
$num = \substr($this->buffer, $this->offset, 4); |
|
503
|
|
|
$this->offset += 4; |
|
504
|
|
|
|
|
505
|
|
|
$num = \unpack('i', \strrev($num)); |
|
506
|
|
|
|
|
507
|
|
|
return $num[1]; |
|
508
|
|
|
} |
|
509
|
|
|
|
|
510
|
|
View Code Duplication |
private function unpackInt64() |
|
|
|
|
|
|
511
|
|
|
{ |
|
512
|
|
|
if (!isset($this->buffer[$this->offset + 7])) { |
|
513
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 8); |
|
514
|
|
|
} |
|
515
|
|
|
|
|
516
|
|
|
$num = \substr($this->buffer, $this->offset, 8); |
|
517
|
|
|
$this->offset += 8; |
|
518
|
|
|
|
|
519
|
|
|
$set = \unpack('N2', $num); |
|
520
|
|
|
|
|
521
|
|
|
return $set[1] << 32 | $set[2]; |
|
522
|
|
|
} |
|
523
|
|
|
|
|
524
|
|
View Code Duplication |
private function unpackFloat32() |
|
|
|
|
|
|
525
|
|
|
{ |
|
526
|
|
|
if (!isset($this->buffer[$this->offset + 3])) { |
|
527
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 4); |
|
528
|
|
|
} |
|
529
|
|
|
|
|
530
|
|
|
$num = \substr($this->buffer, $this->offset, 4); |
|
531
|
|
|
$this->offset += 4; |
|
532
|
|
|
|
|
533
|
|
|
$num = \unpack('f', \strrev($num)); |
|
534
|
|
|
|
|
535
|
|
|
return $num[1]; |
|
536
|
|
|
} |
|
537
|
|
|
|
|
538
|
|
View Code Duplication |
private function unpackFloat64() |
|
|
|
|
|
|
539
|
|
|
{ |
|
540
|
|
|
if (!isset($this->buffer[$this->offset + 7])) { |
|
541
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, 8); |
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
$num = \substr($this->buffer, $this->offset, 8); |
|
545
|
|
|
$this->offset += 8; |
|
546
|
|
|
|
|
547
|
|
|
$num = \unpack('d', \strrev($num)); |
|
548
|
|
|
|
|
549
|
|
|
return $num[1]; |
|
550
|
|
|
} |
|
551
|
|
|
|
|
552
|
|
|
private function unpackStrData($length) |
|
553
|
|
|
{ |
|
554
|
|
|
if (!isset($this->buffer[$this->offset + $length - 1])) { |
|
555
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, $length); |
|
556
|
|
|
} |
|
557
|
|
|
|
|
558
|
|
|
$str = \substr($this->buffer, $this->offset, $length); |
|
559
|
|
|
$this->offset += $length; |
|
560
|
|
|
|
|
561
|
|
|
return $str; |
|
562
|
|
|
} |
|
563
|
|
|
|
|
564
|
|
|
private function unpackArrayData($size) |
|
565
|
|
|
{ |
|
566
|
|
|
$array = []; |
|
567
|
|
|
while ($size--) { |
|
568
|
|
|
$array[] = $this->unpack(); |
|
569
|
|
|
} |
|
570
|
|
|
|
|
571
|
|
|
return $array; |
|
572
|
|
|
} |
|
573
|
|
|
|
|
574
|
|
|
private function unpackMapData($size) |
|
575
|
|
|
{ |
|
576
|
|
|
$map = []; |
|
577
|
|
|
while ($size--) { |
|
578
|
|
|
$map[$this->unpack()] = $this->unpack(); |
|
579
|
|
|
} |
|
580
|
|
|
|
|
581
|
|
|
return $map; |
|
582
|
|
|
} |
|
583
|
|
|
|
|
584
|
|
|
private function unpackExtData($length) |
|
585
|
|
|
{ |
|
586
|
|
|
if (!isset($this->buffer[$this->offset + $length - 1])) { |
|
587
|
|
|
throw InsufficientDataException::fromOffset($this->buffer, $this->offset, $length); |
|
588
|
|
|
} |
|
589
|
|
|
|
|
590
|
|
|
// int8 |
|
591
|
|
|
$num = \ord($this->buffer[$this->offset]); |
|
592
|
|
|
++$this->offset; |
|
593
|
|
|
|
|
594
|
|
|
$type = $num > 0x7f ? $num - 256 : $num; |
|
595
|
|
|
|
|
596
|
|
|
if (isset($this->transformers[$type])) { |
|
597
|
|
|
return $this->transformers[$type]->unpack($this, $length); |
|
598
|
|
|
} |
|
599
|
|
|
|
|
600
|
|
|
$data = \substr($this->buffer, $this->offset, $length); |
|
601
|
|
|
$this->offset += $length; |
|
602
|
|
|
|
|
603
|
|
|
return new Ext($type, $data); |
|
604
|
|
|
} |
|
605
|
|
|
|
|
606
|
|
|
private function handleIntOverflow($value) |
|
607
|
|
|
{ |
|
608
|
|
|
if ($this->isBigIntAsStr) { |
|
609
|
|
|
return \sprintf('%u', $value); |
|
610
|
|
|
} |
|
611
|
|
|
if ($this->isBigIntAsGmp) { |
|
612
|
|
|
return \gmp_init(\sprintf('%u', $value)); |
|
613
|
|
|
} |
|
614
|
|
|
|
|
615
|
|
|
throw new IntegerOverflowException($value); |
|
616
|
|
|
} |
|
617
|
|
|
} |
|
618
|
|
|
|
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.