1 | <?php |
||
2 | /** |
||
3 | * Binn. Serialize to bin string. |
||
4 | * Binn Specification: https://github.com/liteserver/binn/blob/master/spec.md |
||
5 | * |
||
6 | * Note! This class not support Map and Object, only List support. Sorry, i am working on this. |
||
7 | * |
||
8 | * Original Binn Library for C++ - https://github.com/liteserver/binn |
||
9 | * |
||
10 | * |
||
11 | * @author Nikita Kuznetsov (NiK) |
||
12 | * @copyright Copyright (c) 2016, Nikita Kuznetsov ([email protected]) |
||
13 | * @license GNU GPL |
||
14 | * @link http://www.gameap.ru |
||
15 | * |
||
16 | */ |
||
17 | |||
18 | namespace knik; |
||
19 | |||
20 | /** |
||
21 | * @method Binn add_bool(boolean $value) |
||
22 | * @method Binn add_uint8(integer $value) |
||
23 | * @method Binn add_uint16(integer $value) |
||
24 | * @method Binn add_uint32(integer $value) |
||
25 | * @method Binn add_uint64(integer $value) |
||
26 | * @method Binn add_int8(integer $value) |
||
27 | * @method Binn add_int16(integer $value) |
||
28 | * @method Binn add_int32(integer $value) |
||
29 | * @method Binn add_int64(integer $value) |
||
30 | * @method Binn add_str(string $value) |
||
31 | * @method Binn add_list(Binn $value) |
||
32 | * @method Binn add_map(Binn $value) |
||
33 | * @method Binn add_object(Binn $value) |
||
34 | * |
||
35 | */ |
||
36 | class Binn { |
||
37 | |||
38 | // Consts from original C++ Library |
||
39 | const BINN_LIST = 0xE0; |
||
40 | const BINN_MAP = 0xE1; |
||
41 | const BINN_OBJECT = 0xE2; |
||
42 | |||
43 | const BINN_UINT8 = 0x20; |
||
44 | const BINN_INT8 = 0x21; |
||
45 | const BINN_UINT16 = 0x40; |
||
46 | const BINN_INT16 = 0x41; |
||
47 | const BINN_UINT32 = 0x60; |
||
48 | const BINN_INT32 = 0x61; |
||
49 | const BINN_UINT64 = 0x80; |
||
50 | const BINN_INT64 = 0x81; |
||
51 | const BINN_STRING = 0xA0; |
||
52 | |||
53 | const BINN_BOOL = 0x80061; |
||
54 | |||
55 | const BINN_STORAGE_NOBYTES = 0x00; |
||
56 | const BINN_STORAGE_BYTE = 0x20; // 8 bits |
||
57 | const BINN_STORAGE_WORD = 0x40; // 16 bits -- the endianess (byte order) is automatically corrected |
||
58 | const BINN_STORAGE_DWORD = 0x60; // 32 bits -- the endianess (byte order) is automatically corrected |
||
59 | const BINN_STORAGE_QWORD = 0x80; // 64 bits -- the endianess (byte order) is automatically corrected |
||
60 | const BINN_STORAGE_STRING = 0xA0; // Are stored with null termination |
||
61 | const BINN_STORAGE_BLOB = 0xC0; |
||
62 | const BINN_STORAGE_CONTAINER = 0xE0; |
||
63 | |||
64 | const BINN_NULL = 0x00; |
||
65 | const BINN_TRUE = 0x01; |
||
66 | const BINN_FALSE = 0x02; |
||
67 | |||
68 | const UINT8_MAX = 255; |
||
69 | const UINT16_MAX = 65535; |
||
70 | const UINT32_MAX = 4294967295; |
||
71 | const UINT64_MAX = 18446744073709551615; |
||
72 | |||
73 | const INT8_MIN = -128; |
||
74 | const INT8_MAX = 127; |
||
75 | const INT16_MIN = -32768; |
||
76 | const INT16_MAX = 32767; |
||
77 | const INT32_MIN = -2147483648; |
||
78 | const INT32_MAX = 2147483647; |
||
79 | const INT64_MIN = -9223372036854775808; |
||
80 | const INT64_MAX = 9223372036854775807; |
||
81 | |||
82 | const MIN_BINN_SIZE = 3; |
||
83 | |||
84 | // PHP Library consts |
||
85 | const KEY_TYPE = 0; |
||
86 | const KEY_VAL = 1; |
||
87 | const KEY_SIZE = 2; |
||
88 | |||
89 | /** |
||
90 | * @var array |
||
91 | */ |
||
92 | private $methods_assignments = [ |
||
93 | 'add_bool' => self::BINN_BOOL, |
||
94 | 'add_uint8' => self::BINN_UINT8, |
||
95 | 'add_uint16' => self::BINN_UINT16, |
||
96 | 'add_uint32' => self::BINN_UINT32, |
||
97 | 'add_uint64' => self::BINN_UINT64, |
||
98 | 'add_int8' => self::BINN_INT8, |
||
99 | 'add_int16' => self::BINN_INT16, |
||
100 | 'add_int32' => self::BINN_INT32, |
||
101 | 'add_int64' => self::BINN_INT64, |
||
102 | 'add_str' => self::BINN_STRING, |
||
103 | 'add_list' => self::BINN_LIST, |
||
104 | 'add_map' => self::BINN_MAP, |
||
105 | 'add_object' => self::BINN_OBJECT, |
||
106 | ]; |
||
107 | |||
108 | /** |
||
109 | * Binn object type: self::BINN_LIST, self::BINN_MAP, self::BINN_OBJECT |
||
110 | * |
||
111 | * @var int $binn_type |
||
112 | * @access protected |
||
113 | */ |
||
114 | protected $binn_type; |
||
115 | |||
116 | /** |
||
117 | * Count elements in object |
||
118 | * |
||
119 | * @var int |
||
120 | * @access protected |
||
121 | */ |
||
122 | protected $count = 0; |
||
123 | |||
124 | /** |
||
125 | * Data size in bytes |
||
126 | * |
||
127 | * @var int |
||
128 | * @access protected |
||
129 | */ |
||
130 | protected $data_size = 0; |
||
131 | |||
132 | /** |
||
133 | * Meta size in bytes |
||
134 | * |
||
135 | * @var int |
||
136 | */ |
||
137 | protected $meta_size = self::MIN_BINN_SIZE; |
||
138 | |||
139 | /** |
||
140 | * Size bin string in bytes |
||
141 | * |
||
142 | * @var int |
||
143 | * @access protected |
||
144 | */ |
||
145 | protected $size = 0; |
||
146 | |||
147 | /** |
||
148 | * Bin string |
||
149 | * |
||
150 | * @var string |
||
151 | * @access protected |
||
152 | */ |
||
153 | protected $binn_string = ""; |
||
154 | |||
155 | /** |
||
156 | * Object elements |
||
157 | * |
||
158 | * @var array |
||
159 | * @access protected |
||
160 | */ |
||
161 | protected $binn_arr = []; |
||
162 | |||
163 | // ----------------------------------------------------------------- |
||
164 | |||
165 | public function __construct($binstring = '') |
||
166 | { |
||
167 | $this->binn_list(); |
||
168 | |||
169 | if ($binstring != '') { |
||
170 | $this->_binn_load($binstring); |
||
171 | } |
||
172 | } |
||
173 | |||
174 | // ----------------------------------------------------------------- |
||
175 | |||
176 | /** |
||
177 | * @param int $type |
||
178 | * @param mixed $val |
||
179 | * |
||
180 | * @return int $type2 |
||
181 | * |
||
182 | */ |
||
183 | protected function compress_int($type, $val) |
||
184 | { |
||
185 | $type2 = $type; |
||
186 | |||
187 | if ($val >= 0) { |
||
188 | // Convert to unsigned |
||
189 | switch ($type) { |
||
190 | case self::BINN_INT64: |
||
191 | $type = self::BINN_UINT64; |
||
192 | break; |
||
193 | |||
194 | case self::BINN_INT32: |
||
195 | $type = self::BINN_UINT32; |
||
196 | break; |
||
197 | |||
198 | case self::BINN_INT16: |
||
199 | $type = self::BINN_UINT16; |
||
200 | break; |
||
201 | } |
||
202 | } |
||
203 | |||
204 | if (in_array($type, [self::BINN_INT64, self::BINN_INT32, self::BINN_INT16])) { |
||
205 | // Signed |
||
206 | if ($val >= self::INT8_MIN) { |
||
207 | $type2 = self::BINN_INT8; |
||
208 | } |
||
209 | elseif ($val >= self::INT16_MIN) { |
||
210 | $type2 = self::BINN_INT16; |
||
211 | } |
||
212 | elseif ($val >= self::INT32_MIN) { |
||
213 | $type2 = self::BINN_INT32; |
||
214 | } |
||
215 | } |
||
216 | |||
217 | if (in_array($type, [self::BINN_UINT64, self::BINN_UINT32, self::BINN_UINT16])) { |
||
218 | // Unsigned |
||
219 | |||
220 | if ($val <= self::UINT8_MAX) { |
||
221 | $type2 = self::BINN_UINT8; |
||
222 | } |
||
223 | elseif ($val <= self::UINT16_MAX) { |
||
224 | $type2 = self::BINN_UINT16; |
||
225 | } |
||
226 | elseif ($val <= self::UINT32_MAX) { |
||
227 | $type2 = self::BINN_UINT32; |
||
228 | } |
||
229 | } |
||
230 | |||
231 | return $type2; |
||
232 | } |
||
233 | |||
234 | // ----------------------------------------------------------------- |
||
235 | |||
236 | public function binn_free() |
||
237 | { |
||
238 | $this->binn_type = self::BINN_STORAGE_NOBYTES; |
||
239 | |||
240 | $this->count = 0; |
||
241 | $this->data_size = 0; |
||
242 | |||
243 | // Initial meta size 3 bytes |
||
244 | // Type byte + Size byte + Item counts byte |
||
245 | $this->meta_size = 3; |
||
246 | |||
247 | $this->size = 0; |
||
248 | $this->binn_string = ""; |
||
249 | |||
250 | $this->sub_objects = []; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
251 | $this->binn_arr = []; |
||
252 | |||
253 | return $this; |
||
254 | } |
||
255 | |||
256 | // ----------------------------------------------------------------- |
||
257 | |||
258 | /** |
||
259 | * @param string @bindstring |
||
0 ignored issues
–
show
|
|||
260 | * @return $this |
||
261 | */ |
||
262 | public function binn_open($binstring = "") |
||
263 | { |
||
264 | $this->_binn_load($binstring); |
||
265 | return $this; |
||
266 | } |
||
267 | |||
268 | // ----------------------------------------------------------------- |
||
269 | |||
270 | /** |
||
271 | * |
||
272 | * @return int |
||
273 | */ |
||
274 | private function _calculate_size() |
||
275 | { |
||
276 | $size = 0; |
||
277 | |||
278 | if (($this->data_size + $this->meta_size) > 127) { |
||
279 | $size += 3; |
||
280 | } |
||
281 | |||
282 | if (count($this->binn_arr) > 127) { |
||
283 | $size += 3; |
||
284 | } |
||
285 | |||
286 | $this->size = ($this->data_size + $this->meta_size) + $size; |
||
287 | return $this->size; |
||
288 | } |
||
289 | |||
290 | // ----------------------------------------------------------------- |
||
291 | |||
292 | /** |
||
293 | * @param int $type |
||
294 | * @param mixed $value |
||
295 | */ |
||
296 | private function _add_val($type, $value) |
||
297 | { |
||
298 | if (in_array($type, |
||
299 | [self::BINN_INT64, self::BINN_INT32, self::BINN_INT16, |
||
300 | self::BINN_UINT64,self::BINN_UINT32, self::BINN_UINT16]) |
||
301 | ) { |
||
302 | $type = $this->compress_int($type, $value); |
||
303 | } |
||
304 | |||
305 | // Data size |
||
306 | switch ($type) { |
||
307 | case self::BINN_BOOL: |
||
308 | case self::BINN_TRUE: |
||
309 | case self::BINN_FALSE: |
||
310 | $meta_size = 1; |
||
311 | $data_size = 0; |
||
312 | break; |
||
313 | |||
314 | case self::BINN_INT8: |
||
315 | case self::BINN_UINT8: |
||
316 | $meta_size = 1; |
||
317 | $data_size = 1; |
||
318 | break; |
||
319 | |||
320 | case self::BINN_INT16: |
||
321 | case self::BINN_UINT16: |
||
322 | $meta_size = 1; |
||
323 | $data_size = 2; |
||
324 | break; |
||
325 | |||
326 | case self::BINN_INT32: |
||
327 | case self::BINN_UINT32: |
||
328 | $meta_size = 1; |
||
329 | $data_size = 4; |
||
330 | break; |
||
331 | |||
332 | case self::BINN_INT64: |
||
333 | case self::BINN_UINT64: |
||
334 | $meta_size = 1; |
||
335 | $data_size = 8; |
||
336 | break; |
||
337 | |||
338 | case self::BINN_STRING: |
||
339 | $data_size = strlen($value); |
||
340 | |||
341 | $meta_size = $data_size > 127 ? 4 : 1; // size byte |
||
342 | $meta_size += 2; // type byte + null terminated |
||
343 | break; |
||
344 | |||
345 | case self::BINN_LIST: |
||
346 | $data_size = $value->binn_size(); |
||
347 | $meta_size = 0; |
||
348 | break; |
||
349 | |||
350 | default: |
||
351 | // Unknown type |
||
352 | return false; |
||
353 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other ![]() |
|||
354 | } |
||
355 | |||
356 | $this->data_size += $data_size; |
||
357 | $this->meta_size += $meta_size; |
||
358 | |||
359 | $this->count++; |
||
360 | |||
361 | $this->binn_arr[] = [ |
||
362 | self::KEY_TYPE => $type, |
||
363 | self::KEY_VAL => $value, |
||
364 | self::KEY_SIZE => $data_size |
||
365 | ]; |
||
366 | } |
||
367 | |||
368 | // ----------------------------------------------------------------- |
||
369 | |||
370 | /** |
||
371 | * |
||
372 | * @return array |
||
373 | */ |
||
374 | public function get_binn_arr() |
||
375 | { |
||
376 | $return = []; |
||
377 | |||
378 | foreach ($this->binn_arr as &$arr) { |
||
379 | switch ($arr[self::KEY_TYPE]) { |
||
380 | case self::BINN_LIST: |
||
381 | $return[] = $arr[self::KEY_VAL]->get_binn_arr(); |
||
382 | break; |
||
383 | |||
384 | case self::BINN_BOOL: |
||
385 | case self::BINN_TRUE: |
||
386 | case self::BINN_FALSE: |
||
387 | case self::BINN_INT64: |
||
388 | case self::BINN_UINT64: |
||
389 | case self::BINN_INT32: |
||
390 | case self::BINN_UINT32: |
||
391 | case self::BINN_INT16: |
||
392 | case self::BINN_UINT16: |
||
393 | case self::BINN_INT8: |
||
394 | case self::BINN_UINT8: |
||
395 | case self::BINN_STRING: |
||
396 | $return[] = $arr[self::KEY_VAL]; |
||
397 | break; |
||
398 | } |
||
399 | } |
||
400 | |||
401 | return $return; |
||
402 | } |
||
403 | |||
404 | // ----------------------------------------------------------------- |
||
405 | |||
406 | /** |
||
407 | * @return int |
||
408 | */ |
||
409 | public function binn_size() |
||
410 | { |
||
411 | $this->_calculate_size(); |
||
412 | return $this->size; |
||
413 | } |
||
414 | |||
415 | // ----------------------------------------------------------------- |
||
416 | |||
417 | /** |
||
418 | * |
||
419 | * @param int $int_val |
||
420 | * |
||
421 | * @return string HEX string |
||
422 | */ |
||
423 | private function _get_int32_binsize($int_val = 0) |
||
424 | { |
||
425 | $int_val = ($int_val | (1 << 31)); // Add byte |
||
426 | return pack("N", $int_val); |
||
427 | } |
||
428 | |||
429 | // ----------------------------------------------------------------- |
||
430 | |||
431 | /** |
||
432 | * Get binary string |
||
433 | * |
||
434 | * @return string |
||
435 | */ |
||
436 | public function get_binn_val() |
||
437 | { |
||
438 | $this->_calculate_size(); |
||
439 | |||
440 | $this->binn_string = ''; |
||
441 | $this->binn_string .= pack("C", $this->binn_type); |
||
442 | |||
443 | $this->binn_string .= ($this->size <= 127) |
||
444 | ? pack("C", $this->size) |
||
445 | : $this->_get_int32_binsize($this->size); |
||
446 | |||
447 | $count = count($this->binn_arr); |
||
448 | $this->binn_string .= ($count <= 127) |
||
449 | ? pack("C", $count) |
||
450 | : $this->_get_int32_binsize($count); |
||
451 | |||
452 | foreach ($this->binn_arr as &$arr) { |
||
453 | switch ($arr[self::KEY_TYPE]) { |
||
454 | case self::BINN_BOOL: |
||
455 | $this->binn_string .= $arr[self::KEY_VAL] ? pack("C", self::BINN_TRUE) : pack("C", self::BINN_FALSE); |
||
456 | break; |
||
457 | |||
458 | case self::BINN_TRUE: |
||
459 | $this->binn_string .= pack("C", self::BINN_TRUE); |
||
460 | break; |
||
461 | |||
462 | case self::BINN_FALSE: |
||
463 | $this->binn_string .= pack("C", self::BINN_FALSE); |
||
464 | break; |
||
465 | |||
466 | case self::BINN_UINT8: |
||
467 | $this->binn_string .= pack("C", self::BINN_UINT8); |
||
468 | $this->binn_string .= pack("C", $arr[self::KEY_VAL]); |
||
469 | break; |
||
470 | |||
471 | case self::BINN_UINT16: |
||
472 | $this->binn_string .= pack("C", self::BINN_UINT16); |
||
473 | $this->binn_string .= pack("n", $arr[self::KEY_VAL]); |
||
474 | break; |
||
475 | |||
476 | case self::BINN_UINT32: |
||
477 | $this->binn_string .= pack("C", self::BINN_UINT32); |
||
478 | $this->binn_string .= pack("N", $arr[self::KEY_VAL]); |
||
479 | break; |
||
480 | |||
481 | case self::BINN_UINT64: |
||
482 | $this->binn_string .= pack("C", self::BINN_UINT64); |
||
483 | $this->binn_string .= pack("J", $arr[self::KEY_VAL]); |
||
484 | break; |
||
485 | |||
486 | case self::BINN_INT8: |
||
487 | $this->binn_string .= pack("C", self::BINN_UINT8); |
||
488 | $this->binn_string .= pack("c", $arr[self::KEY_VAL]); |
||
489 | break; |
||
490 | |||
491 | case self::BINN_INT16: |
||
492 | $this->binn_string .= pack("C", self::BINN_INT16); |
||
493 | $this->binn_string .= strrev(pack("s", $arr[self::KEY_VAL])); |
||
494 | break; |
||
495 | |||
496 | case self::BINN_INT32: |
||
497 | $this->binn_string .= pack("C", self::BINN_INT32); |
||
498 | $this->binn_string .= strrev(pack("l", $arr[self::KEY_VAL])); |
||
499 | break; |
||
500 | |||
501 | case self::BINN_INT64: |
||
502 | $this->binn_string .= pack("C", self::BINN_INT64); |
||
503 | $this->binn_string .= strrev(pack("q", $arr[self::KEY_VAL])); |
||
504 | break; |
||
505 | |||
506 | case self::BINN_STRING: |
||
507 | $this->binn_string .= pack("C", self::BINN_STRING); |
||
508 | |||
509 | if ($arr[self::KEY_SIZE] <= 127) { |
||
510 | $this->binn_string .= pack("C", $arr[self::KEY_SIZE]); |
||
511 | } else { |
||
512 | $this->binn_string .= $this->_get_int32_binsize($arr[self::KEY_SIZE]); |
||
513 | } |
||
514 | |||
515 | $this->binn_string .= pack("a*x", $arr[self::KEY_VAL]); |
||
516 | break; |
||
517 | |||
518 | case self::BINN_LIST: |
||
519 | $this->binn_string .= $arr[self::KEY_VAL]->get_binn_val(); |
||
520 | break; |
||
521 | } |
||
522 | } |
||
523 | |||
524 | return $this->binn_string; |
||
525 | } |
||
526 | |||
527 | // ----------------------------------------------------------------- |
||
528 | |||
529 | /** |
||
530 | * @param string $name |
||
531 | * @param mixed $arguments |
||
532 | */ |
||
533 | public function __call($name, $arguments) |
||
534 | { |
||
535 | if (array_key_exists($name, $this->methods_assignments)) { |
||
536 | $this->_add_val($this->methods_assignments[$name], $arguments[0]); |
||
537 | return $this; |
||
538 | } |
||
539 | |||
540 | throw new \Exception("Call to undefined method {$name}"); |
||
541 | } |
||
542 | |||
543 | // ----------------------------------------------------------------- |
||
544 | |||
545 | public function binn_list() |
||
546 | { |
||
547 | $this->binn_type = self::BINN_LIST; |
||
548 | return $this; |
||
549 | } |
||
550 | |||
551 | // ----------------------------------------------------------------- |
||
552 | |||
553 | /** |
||
554 | * @param string |
||
555 | */ |
||
556 | private function _binn_load($binstring) |
||
557 | { |
||
558 | $pos = 1; // Position |
||
559 | $size_bytes = unpack("C", $binstring[$pos])[1]; |
||
560 | |||
561 | // Size |
||
562 | if ($size_bytes & 1 << 7) { |
||
563 | $size_bytes = unpack("N", substr($binstring, $pos, 4))[1]; |
||
564 | $this->size = ($size_bytes &~ (1 << 31)); // Cut bit |
||
565 | $pos += 4; |
||
566 | } else { |
||
567 | $this->size = $size_bytes; |
||
568 | $pos += 1; |
||
569 | } |
||
570 | |||
571 | unset($size_bytes); |
||
572 | |||
573 | $count_bytes = unpack("C", $binstring[$pos])[1]; |
||
574 | |||
575 | // Size |
||
576 | if ($count_bytes & 1 << 7) { |
||
577 | $count_bytes = unpack("N", substr($binstring,$pos, 4))[1]; |
||
578 | $this->count = ($count_bytes &~ (1 << 31)); // Cut bit |
||
579 | $pos += 4; |
||
580 | } else { |
||
581 | $this->count = $count_bytes; |
||
582 | $pos += 1; |
||
583 | } |
||
584 | |||
585 | unset($count_bytes); |
||
586 | |||
587 | // Data |
||
588 | $stop_while = false; |
||
589 | while ($pos < $this->size && !$stop_while) { |
||
590 | $byte_var_type = @unpack("C", $binstring[$pos])[1]; |
||
591 | $pos += 1; |
||
592 | |||
593 | |||
594 | // $cur_type = strtotime(base_convert($byte_var_type, 10, 16)); |
||
595 | |||
596 | switch ($byte_var_type) { |
||
597 | case self::BINN_TRUE: |
||
598 | $this->_add_val(self::BINN_BOOL, true); |
||
599 | break; |
||
600 | |||
601 | case self::BINN_FALSE: |
||
602 | $this->_add_val(self::BINN_BOOL, false); |
||
603 | break; |
||
604 | |||
605 | case self::BINN_UINT64: |
||
606 | $this->_add_val(self::BINN_UINT64, unpack("J", substr($binstring, $pos, 8))[1]); |
||
607 | $pos += 8; |
||
608 | break; |
||
609 | |||
610 | case self::BINN_UINT32: |
||
611 | $this->_add_val(self::BINN_UINT32, unpack("N", substr($binstring, $pos, 4))[1]); |
||
612 | $pos += 4; |
||
613 | break; |
||
614 | |||
615 | case self::BINN_UINT16: |
||
616 | $this->_add_val(self::BINN_UINT16, unpack("n", substr($binstring, $pos, 2))[1]); |
||
617 | $pos += 2; |
||
618 | break; |
||
619 | |||
620 | case self::BINN_UINT8: |
||
621 | $this->_add_val(self::BINN_UINT8, unpack("C", substr($binstring, $pos, 1))[1]); |
||
622 | $pos += 1; |
||
623 | break; |
||
624 | |||
625 | case self::BINN_INT8: |
||
626 | $this->_add_val(self::BINN_INT8, unpack("c", substr($binstring, $pos, 1))[1]); |
||
627 | $pos += 1; |
||
628 | break; |
||
629 | |||
630 | case self::BINN_INT16: |
||
631 | $this->_add_val(self::BINN_INT16, unpack("s", strrev(substr($binstring, $pos, 2)))[1]); |
||
632 | $pos += 2; |
||
633 | break; |
||
634 | |||
635 | case self::BINN_INT32: |
||
636 | $this->_add_val(self::BINN_INT16, unpack("i", strrev(substr($binstring, $pos, 4)))[1]); |
||
637 | $pos += 4; |
||
638 | break; |
||
639 | |||
640 | case self::BINN_INT64: |
||
641 | $this->_add_val(self::BINN_INT16, unpack("q", strrev(substr($binstring, $pos, 8)))[1]); |
||
642 | $pos += 8; |
||
643 | break; |
||
644 | |||
645 | case self::BINN_STRING: |
||
646 | $string_size = unpack("C", $binstring[$pos])[1]; |
||
647 | |||
648 | // Size |
||
649 | if ($string_size & 1 << 7) { |
||
650 | $string_size = unpack("N", substr($binstring, $pos, 4))[1]; |
||
651 | $string_size = ($string_size &~ (1 << 31)); // Cut bit |
||
652 | $pos += 4; |
||
653 | } else { |
||
654 | $pos += 1; |
||
655 | } |
||
656 | |||
657 | $this->_add_val(self::BINN_STRING, unpack("a*", substr($binstring, $pos, $string_size))[1]); |
||
658 | $pos += $string_size; |
||
659 | $pos += 1; // Null byte |
||
660 | break; |
||
661 | |||
662 | case self::BINN_LIST: |
||
663 | $list_size = unpack("C", $binstring[$pos])[1]; |
||
664 | |||
665 | // Size |
||
666 | if ($list_size & 1 << 7) { |
||
667 | $list_size = unpack("N", substr($binstring, $pos, 4))[1]; |
||
668 | $list_size = ($list_size &~ (1 << 31)); // Cut bit |
||
669 | } |
||
670 | |||
671 | $substring = substr($binstring, $pos-1, $list_size); |
||
672 | $this->_add_val(self::BINN_LIST, new Binn($substring)); |
||
673 | |||
674 | $pos += ($list_size-1); |
||
675 | |||
676 | break; |
||
677 | |||
678 | default: |
||
679 | $stop_while = true; |
||
680 | break; |
||
681 | } |
||
682 | |||
683 | } |
||
684 | } |
||
685 | } |