Completed
Push — master ( 4cfd67...386efc )
by Sam
01:57
created

Utils::widthToBytes()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.0123

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 15
ccs 8
cts 9
cp 0.8889
crap 3.0123
rs 9.9666
1
<?php
2
3
namespace SPSS;
4
5
use SPSS\Sav\Record\Variable;
6
7
class Utils
8
{
9
    /**
10
     * SPSS represents a date as the number of seconds since the epoch, midnight, Oct. 14, 1582.
11
     *
12
     * @param $timestamp
13
     * @param string $format
14
     * @return false|int
15
     */
16
    public static function formatDate($timestamp, $format = 'Y M d')
17
    {
18
        return date($format, strtotime('1582-10-04 00:00:00') + $timestamp);
0 ignored issues
show
Bug Best Practice introduced by
The expression return date($format, str...0:00:00') + $timestamp) returns the type string which is incompatible with the documented return type false|integer.
Loading history...
19
    }
20
21
    /**
22
     * Rounds X up to the next multiple of Y.
23
     *
24
     * @param int $x
25
     * @param int $y
26
     * @return int
27
     */
28 1005
    public static function roundUp($x, $y)
29
    {
30 1005
        return ceil($x / $y) * $y;
31
    }
32
33
    /**
34
     * Rounds X down to the prev multiple of Y.
35
     *
36
     * @param int $x
37
     * @param int $y
38
     * @return int
39
     */
40
    public static function roundDown($x, $y)
41
    {
42
        return floor($x / $y) * $y;
43
    }
44
45
    /**
46
     * Convert bytes to string
47
     *
48
     * @param array $bytes
49
     * @return string
50
     */
51 1005
    public static function bytesToString(array $bytes)
52
    {
53 1005
        $str = '';
54 1005
        foreach ($bytes as $byte) {
55 1005
            $str .= chr($byte);
56
        }
57
58 1005
        return $str;
59
    }
60
61
    /**
62
     * Convert double to string
63
     *
64
     * @param double $num
65
     * @return string
66
     */
67
    public static function doubleToString($num)
68
    {
69
        return self::bytesToString(unpack('C8', pack('d', $num)));
0 ignored issues
show
Bug introduced by
It seems like unpack('C8', pack('d', $num)) can also be of type false; however, parameter $bytes of SPSS\Utils::bytesToString() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

69
        return self::bytesToString(/** @scrutinizer ignore-type */ unpack('C8', pack('d', $num)));
Loading history...
70
    }
71
72
    /**
73
     * @param string $str
74
     * @return double
75
     */
76
    public static function stringToDouble($str)
77
    {
78
        // if (strlen($str) < 8) {
79
        //     throw new Exception('String must be a 8 length');
80
        // }
81
82
        return unpack('d', pack('A8', $str))[1];
83
    }
84
85
    /**
86
     * @param array $bytes
87
     * @param bool $unsigned
88
     * @return int
89
     */
90 1005
    public static function bytesToInt(array $bytes, $unsigned = true)
91
    {
92 1005
        $bytes = array_reverse($bytes);
93 1005
        $value = 0;
94 1005
        foreach ($bytes as $i => $b) {
95 1005
            $value |= $b << $i * 8;
96
        }
97
98 1005
        return $unsigned ? $value : self::unsignedToSigned($value, count($bytes) * 8);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $unsigned ? $valu...lue, count($bytes) * 8) also could return the type string which is incompatible with the documented return type integer.
Loading history...
99
    }
100
101
    /**
102
     * @param $int
103
     * @param int $size
104
     * @return array
105
     */
106 1005
    public static function intToBytes($int, $size = 32)
107
    {
108 1005
        $size = self::roundUp($size, 8);
109 1005
        $bytes = [];
110 1005
        for ($i = 0; $i < $size; $i += 8) {
111 1005
            $bytes[] = 0xFF & $int >> $i;
112
        }
113 1005
        $bytes = array_reverse($bytes);
114
115 1005
        return $bytes;
116
    }
117
118
    /**
119
     * @param int $value
120
     * @param int $size
121
     * @return string
122
     */
123
    public static function unsignedToSigned($value, $size = 32)
124
    {
125
        $size = self::roundUp($size, 8);
126
        if (bccomp($value, bcpow(2, $size - 1)) >= 0) {
127
            $value = bcsub($value, bcpow(2, $size));
128
        }
129
130
        return $value;
131
    }
132
133
    /**
134
     * @param int $value
135
     * @param int $size
136
     * @return string
137
     */
138
    public static function signedToUnsigned($value, $size = 32)
139
    {
140
        return $value + bcpow(2, $size);
141
    }
142
143
    /**
144
     * Returns the number of 8-byte units (octs) used to write data for a variable of the given WIDTH.
145
     *
146
     * @param int $width
147
     * @return int
148
     */
149 1005
    public static function widthToOcts($width)
150
    {
151 1005
        $result = 0;
152 1005
        foreach(self::getSegments($width) as $segmentWidth) {
153 1005
            $result += ceil($segmentWidth / 8);
154
        }
155 1005
        return (int) max(1, $result);
156
    }
157
158
    /**
159
     * Returns the number of "segments" used for writing case data for a variable of the given WIDTH.
160
     * A segment is a physical variable in the system file that represents some piece of a logical variable.
161
     * Only very long string variables have more than one segment.
162
     *
163
     * @param int $width
164
     * @return int
165
     */
166 1005
    public static function widthToSegments(int $width): int
167
    {
168 1005
        return (int) Variable::isVeryLong($width) ? ceil($width / Variable::EFFECTIVE_VLS_CHUNK) : 1;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (int)SPSS\Sav\Rec...FFECTIVE_VLS_CHUNK) : 1 could return the type double which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
169
    }
170
171 1005
    public static function getSegments(int $width): iterable
172
    {
173 1005
        $count = self::widthToSegments($width);
174 1005
        for($i = 1; $i < $count; $i++) {
175 427
            yield 255;
176
        }
177 1005
        yield $width - ($count - 1) * Variable::EFFECTIVE_VLS_CHUNK;
178 1005
    }
179
180
181
182
}
183