Test Setup Failed
Push — master ( f2b9b8...38e491 )
by Nikita
02:19
created

BinnAbstract::compressInt()   C

Complexity

Conditions 14
Paths 150

Size

Total Lines 53
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 30
nc 150
nop 2
dl 0
loc 53
rs 5.85
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Knik\Binn;
4
5
abstract class BinnAbstract
6
{
7
    // Consts from original C++ Library
8
    const BINN_LIST         = 0xE0;
9
    const BINN_MAP          = 0xE1;
10
    const BINN_OBJECT       = 0xE2;
11
12
    const BINN_UINT8        = 0x20;
13
    const BINN_INT8         = 0x21;
14
    const BINN_UINT16       = 0x40;
15
    const BINN_INT16        = 0x41;
16
    const BINN_UINT32       = 0x60;
17
    const BINN_INT32        = 0x61;
18
    const BINN_UINT64       = 0x80;
19
    const BINN_INT64        = 0x81;
20
    const BINN_STRING       = 0xA0;
21
22
    const BINN_FLOAT32      = 0x62;  // (DWORD)
23
    const BINN_FLOAT64      = 0x82;  // (QWORD)
24
    const BINN_FLOAT        = self::BINN_FLOAT32;
25
26
    const BINN_BOOL         = 0x80061;
27
28
    const BINN_STORAGE_NOBYTES      = 0x00;
29
    const BINN_STORAGE_BYTE         = 0x20;  //  8 bits
30
    const BINN_STORAGE_WORD         = 0x40;  // 16 bits -- the endianess (byte order) is automatically corrected
31
    const BINN_STORAGE_DWORD        = 0x60;  // 32 bits -- the endianess (byte order) is automatically corrected
32
    const BINN_STORAGE_QWORD        = 0x80;  // 64 bits -- the endianess (byte order) is automatically corrected
33
    const BINN_STORAGE_STRING       = 0xA0;  // Are stored with null termination
34
    const BINN_STORAGE_BLOB         = 0xC0;
35
    const BINN_STORAGE_CONTAINER    = 0xE0;
36
37
    const BINN_NULL                 = 0x00;
38
    const BINN_TRUE                 = 0x01;
39
    const BINN_FALSE                = 0x02;
40
41
    const UINT8_MAX                 = 255;
42
    const UINT16_MAX                = 65535;
43
    const UINT32_MAX                = 4294967295;
44
    const UINT64_MAX                = 18446744073709551615;
45
46
    const INT8_MIN                  = -128;
47
    const INT8_MAX                  = 127;
48
    const INT16_MIN                 = -32768;
49
    const INT16_MAX                 = 32767;
50
    const INT32_MIN                 = -2147483648;
51
    const INT32_MAX                 = 2147483647;
52
    const INT64_MIN                 = -9223372036854775808;
53
    const INT64_MAX                 = 9223372036854775807;
54
55
    const BINN_STORAGE_MASK         = 0xE0;
56
    const BINN_TYPE_MASK            = 0x0F;
57
58
    const MIN_BINN_SIZE             = 3;
59
60
    // PHP Library consts
61
    const KEY_TYPE                 = 0;
62
    const KEY_VAL                  = 1;
63
    const KEY_SIZE                 = 2;
64
    const KEY_KEY                  = 3;
65
66
    /**
67
     * Binn object type: self::BINN_LIST, self::BINN_MAP, self::BINN_OBJECT
68
     *
69
     * @var int $binnType
70
     * @access protected
71
     */
72
    protected $binnType = self::BINN_NULL;
73
74
    /**
75
     * @var string
76
     */
77
    protected $binnClass = null;
78
79
    /**
80
     * Count elements in object
81
     *
82
     * @var int
83
     * @access protected
84
     */
85
    protected $count        = 0;
86
87
    /**
88
     * Data size in bytes
89
     *
90
     * @var int
91
     * @access protected
92
     */
93
    protected $dataSize    = 0;
94
95
    /**
96
     * Meta size in bytes
97
     *
98
     * @var int
99
     */
100
    protected $metaSize    = self::MIN_BINN_SIZE;
101
102
    /**
103
     * Size bin string in bytes
104
     *
105
     * @var int
106
     * @access protected
107
     */
108
    protected $size         = 0;
109
110
    /**
111
     * Bin string
112
     *
113
     * @var string
114
     * @access protected
115
     */
116
    protected $binnString     = "";
117
118
    /**
119
     * Object elements
120
     *
121
     * @var array
122
     * @access protected
123
     */
124
    protected $binnArr = [];
125
126
    /**
127
     * @var array
128
     *
129
     * Associations container int with container classes
130
     *
131
     * Example values:
132
     * [
133
     *  0xE0 => \Knik\Binn\BinnList::class,
134
     *  0xE1 => \Knik\Binn\BinnMap::class,
135
     *  0xE2 => \Knik\Binn\BinnObject::class,
136
     * ]
137
     */
138
    protected $containersClasses = [
139
        0xE0 => \Knik\Binn\BinnList::class,
140
        0xE1 => \Knik\Binn\BinnMap::class,
141
        0xE2 => \Knik\Binn\BinnObject::class,
142
    ];
143
144
    /**
145
     * @param $containersClasses
146
     */
147
    public function setContainersClasses($containersClasses)
148
    {
149
        $this->containersClasses = $containersClasses;
150
    }
151
152
    /**
153
     *
154
     * @param int $intVal
155
     *
156
     * @return string   HEX string
157
     */
158
    protected function getInt32Binsize($intVal = 0)
159
    {
160
        $intVal = ($intVal | (1 << 31)); // Add byte
161
        return $this->pack(self::BINN_UINT32, $intVal);
162
    }
163
164
    /**
165
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
166
     * @return int
167
     */
168
    protected function detectType($value = null)
169
    {
170
        if (is_bool($value)) {
0 ignored issues
show
introduced by
The condition is_bool($value) is always false.
Loading history...
171
            return $value ? self::BINN_TRUE : self::BINN_FALSE;
172
        }
173
174
        if (is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always false.
Loading history...
175
            return self::BINN_STRING;
176
        }
177
178
        if (is_integer($value)) {
0 ignored issues
show
introduced by
The condition is_integer($value) is always false.
Loading history...
179
            return $this->detectInt($value);
180
        }
181
182
        if (is_float($value)) {
0 ignored issues
show
introduced by
The condition is_float($value) is always false.
Loading history...
183
            if (strlen($value) > 4) {
184
                return self::BINN_FLOAT64;
185
            } else {
186
                return self::BINN_FLOAT32;
187
            }
188
        }
189
190
        if (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
191
            foreach ($this->containersClasses as $contanerType => $containersClass) {
192
                if ($containersClass::validArray($value)) {
193
                    return $contanerType;
194
                }
195
            }
196
        }
197
198
        return self::BINN_NULL;
199
    }
200
201
    /**
202
     * Detect integer type
203
     *
204
     * @param $value
205
     * @return int
206
     */
207
    protected function detectInt($value)
208
    {
209
        if ($value < 0) {
210
            // int
211
            if ($value >= self::INT8_MIN) {
212
                return self::BINN_INT8;
213
            } else if ($value >= self::INT16_MIN) {
214
                return self::BINN_INT16;
215
            } else if ($value >= self::INT32_MIN) {
216
                return self::BINN_INT32;
217
            } else {
218
                return self::BINN_INT64;
219
            }
220
        } else {
221
            // uint
222
            if ($value <= self::UINT8_MAX) {
223
                return self::BINN_UINT8;
224
            } else if ($value <= self::UINT16_MAX) {
225
                return self::BINN_UINT16;
226
            } else if ($value <= self::UINT32_MAX) {
227
                return self::BINN_UINT32;
228
            } else {
229
                return self::BINN_UINT64;
230
            }
231
        }
232
    }
233
234
    protected function storageType($type)
235
    {
236
        return $type & ($type ^ self::BINN_TYPE_MASK);
237
    }
238
239
    /**
240
     * @param array $arr
241
     * @return bool
242
     */
243
    protected static function isArrayAssoc($arr)
244
    {
245
        $arr = (array)$arr;
246
        if (array() === $arr) return false;
247
        return array_keys($arr) !== range(0, count($arr) - 1);
248
    }
249
250
    /**
251
     * @param $arr
252
     * @return bool
253
     */
254
    protected static function isArrayObject($arr)
255
    {
256
        foreach(array_keys($arr) as $key) {
257
            if (!is_int($key)) {
258
                return true;
259
            }
260
        }
261
262
        return false;
263
    }
264
265
    /**
266
     *
267
     *  @return int
268
     */
269
    protected function calculateSize()
270
    {
271
        $size = 0;
272
273
        if (($this->dataSize + $this->metaSize) > 127) {
274
            $size += 3;
275
        }
276
277
        if (count($this->binnArr) > 127) {
278
            $size += 3;
279
        }
280
281
        $this->size = ($this->dataSize + $this->metaSize) + $size;
282
        return $this->size;
283
    }
284
285
    /**
286
     *
287
     *  @return array
288
     */
289
    public function getBinnArr()
290
    {
291
        $return = [];
292
293
        foreach ($this->binnArr as $arr) {
294
            $storageType = $this->storageType($arr[self::KEY_TYPE]);
295
296
            if ($storageType === self::BINN_STORAGE_CONTAINER) {
297
                if (isset($arr[self::KEY_KEY])) {
298
                    $key = $arr[self::KEY_KEY];
299
                    $return[$key] = $arr[self::KEY_VAL]->getBinnArr();
300
                } else {
301
                    $return[] = $arr[self::KEY_VAL]->getBinnArr();
302
                }
303
            } else {
304
                if (isset($arr[self::KEY_KEY])) {
305
                    $key = $arr[self::KEY_KEY];
306
                    $return[$key] = $arr[self::KEY_VAL];
307
                } else {
308
                    $return[] = $arr[self::KEY_VAL];
309
                }
310
            }
311
        }
312
313
        return $return;
314
    }
315
316
    /**
317
     * @return int
318
     */
319
    public function binnSize()
320
    {
321
        return $this->calculateSize();
322
    }
323
324
    /**
325
     * @param int   $type
326
     * @param mixed   $val
327
     *
328
     * @return int  $type2
329
     *
330
     */
331
    protected function compressInt($type, $val)
332
    {
333
        $newType = $type;
334
335
        if ($val >= 0) {
336
            // Convert to unsigned
337
            switch ($newType) {
338
                case self::BINN_INT64:
339
                    $newType = self::BINN_UINT64;
340
                    break;
341
342
                case self::BINN_INT32:
343
                    $newType = self::BINN_UINT32;
344
                    break;
345
346
                case self::BINN_INT16:
347
                    $newType = self::BINN_UINT16;
348
                    break;
349
350
                case self::BINN_INT8:
351
                    $newType = self::BINN_UINT8;
352
                    break;
353
            }
354
        }
355
356
        if (in_array($newType, [self::BINN_INT64, self::BINN_INT32, self::BINN_INT16])) {
357
            // Signed
358
            if ($val >= self::INT8_MIN) {
359
                $newType = self::BINN_INT8;
360
            }
361
            elseif ($val >= self::INT16_MIN) {
362
                $newType = self::BINN_INT16;
363
            }
364
            elseif ($val >= self::INT32_MIN) {
365
                $newType = self::BINN_INT32;
366
            }
367
        }
368
369
        if (in_array($newType, [self::BINN_UINT64, self::BINN_UINT32, self::BINN_UINT16])) {
370
            // Unsigned
371
372
            if ($val <= self::UINT8_MAX) {
373
                $newType = self::BINN_UINT8;
374
            }
375
            elseif ($val <= self::UINT16_MAX) {
376
                $newType = self::BINN_UINT16;
377
            }
378
            elseif ($val <= self::UINT32_MAX) {
379
                $newType = self::BINN_UINT32;
380
            }
381
        }
382
383
        return $newType;
384
    }
385
386
    public function binnFree()
387
    {
388
        // $this->binnType     = self::BINN_STORAGE_NOBYTES;
389
390
        $this->count        = 0;
391
        $this->dataSize     = 0;
392
393
        // Initial meta size 3 bytes
394
        // Type byte + Size byte + Item counts byte
395
        $this->metaSize    = self::MIN_BINN_SIZE;
396
397
        $this->size         = 0;
398
        $this->binnString   = "";
399
400
        $this->binnArr      = [];
401
402
        return $this;
403
    }
404
405
    /**
406
     * 
407
     */
408
    protected function unpack($varType, $value)
409
    {
410
        if ($varType === self::BINN_TRUE) {
411
            return true;
412
        } else if ($varType === self::BINN_FALSE) {
413
            return false;
414
        } else if ($varType === self::BINN_UINT64) {
415
            return unpack("J", $value)[1];
416
        } else if ($varType === self::BINN_UINT32) {
417
            return unpack("N", $value)[1];
418
        } else if ($varType === self::BINN_UINT16) {
419
            return unpack("n", $value)[1];
420
        } else if ($varType == self::BINN_UINT8) {
421
            return unpack("C", $value)[1];
422
        } else if ($varType === self::BINN_INT8) {
423
            return unpack("c", $value)[1];
424
        } else if ($varType === self::BINN_INT16) {
425
            return unpack("s", strrev($value))[1];
426
        } else if ($varType === self::BINN_INT32) {
427
            return unpack("i", strrev($value))[1];
428
        } else if ($varType === self::BINN_INT64) {
429
            return unpack("q", strrev($value))[1];
430
        } else if ($varType === self::BINN_FLOAT32) {
431
            return unpack("f", strrev($value))[1];
432
        } else if ($varType === self::BINN_FLOAT64) {
433
            return unpack("d", strrev($value))[1];
434
        } else if ($varType === self::BINN_STRING) {
435
            return unpack("a*", $value)[1];
436
        }
437
        
438
        return null;
439
    }
440
441
    /**
442
     * 
443
     */
444
    protected function pack($varType, $value = null)
445
    {
446
        if ($varType === self::BINN_TRUE) {
447
            return pack("C", self::BINN_TRUE);
448
        } else if ($varType === self::BINN_FALSE) {
449
            return pack("C", self::BINN_FALSE);
450
        } else if ($varType === self::BINN_UINT64) {
451
            return pack("J", $value);
452
        } else if ($varType === self::BINN_UINT32) {
453
            return pack("N", $value);
454
        } else if ($varType === self::BINN_UINT16) {
455
            return pack("n", $value);
456
        } else if ($varType === self::BINN_UINT8) {
457
            return pack("C", $value);
458
        } else if ($varType === self::BINN_INT8) {
459
            return pack("c", $value);
460
        } else if ($varType === self::BINN_INT16) {
461
            return strrev(pack("s", $value));
462
        } else if ($varType === self::BINN_INT32) {
463
            return strrev(pack("i", $value));
464
        } else if ($varType === self::BINN_INT64) {
465
            return strrev(pack("q", $value));
466
        } else if ($varType === self::BINN_FLOAT32) {
467
            return strrev(pack("f", $value));
468
        } else if ($varType === self::BINN_FLOAT64) {
469
            return strrev(pack("d", $value));
470
        } else if ($varType === self::BINN_STRING) {
471
            return pack("a*", $value);
472
        } else if ($varType === self::BINN_NULL) {
473
            return pack("x");
474
        }
475
        
476
        return null;
477
    }
478
479
    /**
480
     * @param $type
481
     * @return string
482
     */
483
    protected function packType($type)
484
    {
485
        return $this->pack(self::BINN_UINT8, $type);
486
    }
487
488
    /**
489
     * @param $type
490
     * @return string
491
     */
492
    protected function packSize($size)
493
    {
494
        return ($size <= 127)
495
            ? $this->pack(self::BINN_UINT8, $size)
496
            : $this->getInt32Binsize($size);
497
    }
498
    
499
    protected function getTypeSize($type, $value = '')
500
    {
501
        $size = ['meta' => 0, 'data' => 0];
502
        $storageType = $this->storageType($type);
503
504
        if ($type == self::BINN_BOOL
505
            || $type == self::BINN_TRUE
506
            || $type == self::BINN_FALSE
507
        ) {
508
            $size = ['meta' => 1, 'data' => 0];
509
        } else if ($storageType === self::BINN_STORAGE_CONTAINER) {
510
            $size = ['meta' => 0, 'data' => $value->binnSize()];
511
        } else if ($storageType === self::BINN_STORAGE_BLOB) {
512
            $dataSize = mb_strlen($value);
513
514
            $metaSize = $dataSize > 127 ? 4 : 1; // size byte
515
            $metaSize += 1; // type byte
516
517
            $size = ['meta' => $metaSize, 'data' => $dataSize];
518
        } else if ($storageType === self::BINN_STORAGE_STRING) {
519
            $dataSize = mb_strlen($value);
520
521
            $metaSize = $dataSize > 127 ? 4 : 1; // size byte
522
            $metaSize += 2; // type byte + null terminated
523
            
524
            $size = ['meta' => $metaSize, 'data' => $dataSize];
525
        } else if ($storageType === self::BINN_STORAGE_QWORD) {
526
            $size = ['meta' => 1, 'data' => 8];
527
        } else if ($storageType === self::BINN_STORAGE_DWORD) {
528
            $size = ['meta' => 1, 'data' => 4];
529
        } else if ($storageType === self::BINN_STORAGE_WORD) {
530
            $size = ['meta' => 1, 'data' => 2];
531
        } else if ($storageType === self::BINN_STORAGE_BYTE) {
532
            $size = ['meta' => 1, 'data' => 1];
533
        } else if ($storageType === self::BINN_STORAGE_NOBYTES) {
534
            $size = ['meta' => 1, 'data' => 0];
535
        }
536
        
537
        return $size;
538
    }
539
}