Data::int32ToDword()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 17
nc 5
nop 2
dl 0
loc 26
rs 9.3888
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Data.php.
5
 */
6
7
namespace Bmatovu\Conversion;
8
9
/**
10
 * Class Data.
11
 *
12
 * Working with primitive data types in PHP
13
 *
14
 * @author  Brian Matovu <[email protected]>
15
 *
16
 * @link http://php.net/manual/en/language.types.integer.php PHP Integer Data Type
17
 * @link http://php.net/manual/en/function.pack.php PHP Pack()
18
 * @link http://php.net/manual/en/function.unpack.php PHP Unpack()
19
 * @link http://www.binaryhexconverter.com/binary-to-decimal-converter Bin2Dec Converter
20
 * @link http://www.binaryhexconverter.com/decimal-to-hex-converter Dec2Hex Converter
21
 * @link http://www.binaryhexconverter.com/hex-to-decimal-converter Hex2Dec Converter
22
 * @link http://www.exploringbinary.com/twos-complement-converter/ 2's Complement Converter
23
 * @link http://php.net/manual/en/function.bindec.php#97102 2's Complement Conversion Eg. #1
24
 * @link https://stackoverflow.com/a/16127799/2732184 2's Complement Conversion Eg. #2
25
 * @link https://betterexplained.com/articles/understanding-big-and-little-endian-byte-order/ Machine Byte Order (Endianness)
26
 * @link https://www.scadacore.com/tools/programming-calculators/online-hex-converter/ Endianness Aware Converter
27
 */
28
class Data
29
{
30
    // Signedness
31
    const SIGNED = 1;
32
    const UNSIGNED = 0;
33
34
    // Endianness
35
    const BIG_ENDIAN = 1;
36
    const MID_BIG_ENDIAN = 2;
37
    const LITTLE_ENDIAN = 3;
38
    const MID_LITTLE_ENDIAN = 4;
39
40
    /**
41
     * Convert BYTE to INT8.
42
     *
43
     * @param string $byte       BYTE
44
     * @param int    $signedness Signedness, default 1
45
     *
46
     * @var int Signedness => 1 (Signed)
47
     * @var int Signedness => 0 (Unsigned)
48
     *
49
     * @see Data::int8ToByte() Converting INT8 to BYTE
50
     *
51
     * @return int INT8
52
     */
53
    public static function byteToInt8($byte, $signedness = 1)
54
    {
55
        // Pack byte into raw
56
        $raw = pack('H*', $byte);
57
58
        // Unpack raw to integer
59
        $int8 = unpack('C', $raw)[1];
60
61
        // Determine 2's complement
62
        if ($signedness && $int8 >= 0x80) {
63
            if (0x80 & $int8) {
64
                return -(($int8 ^ 0xFF) + 1);
65
            }
66
        }
67
68
        return $int8;
69
    }
70
71
    /**
72
     * Convert INT8 to BYTE.
73
     *
74
     * @param int $int8 INT8 Range: (-127 to 255)
75
     *
76
     * @see Data::byteToInt8() Converting BYTE to INT8
77
     *
78
     * @return bool|string BYTE or false if integer provided is out of range
79
     */
80
    public static function int8ToByte($int8)
81
    {
82
        if ($int8 < -128 || $int8 > 255) {
83
            return false;
84
        }
85
86
        // int to integer (dec)
87
        $int8 = (int) $int8 & 0xFF;
88
89
        // Convert Integer (dec) to Hex
90
        return base_convert($int8, 10, 16);
91
    }
92
93
    /**
94
     * Convert WORD to INT16.
95
     *
96
     * @param string $word       WORD (2 bytes)
97
     * @param int    $endianness Machine Byte Order, default 1
98
     *
99
     * @var int Endianness => 1 (Big Endian)
100
     * @var int Endianness => 2 (Mid-Big Endian) *Not supported
101
     * @var int Endianness => 3 (Little Endian)
102
     * @var int Endianness => 4 (Mid-Little Endian) *Not supported
103
     *
104
     * @param int $signedness Signedness, default 1
105
     *
106
     * @var int Signedness => 1 (Signed)
107
     * @var int Signedness => 0 (Unsigned)
108
     *
109
     * @see Data::int16ToWord() Converting INT16 to WORD
110
     *
111
     * @return bool|int INT16 or false if invalid, or non supported endianness is given
112
     */
113
    public static function wordToInt16($word, $endianness = 1, $signedness = 1)
114
    {
115
116
        // unpack hex str to raw bytes
117
        $bin = pack('H*', $word);
118
        $raw = unpack('c*', $bin);
119
120
        $msb = $lsb = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $msb is dead and can be removed.
Loading history...
121
        if ($endianness == 1) {
122
            $msb = ($raw[1] << 8) & 0xFF00;
123
            $lsb = ($raw[2] << 0) & 0x00FF;
124
        } elseif ($endianness == 3) {
125
            $msb = ($raw[2] << 8) & 0xFF00;
126
            $lsb = ($raw[1] << 0) & 0x00FF;
127
        } else {
128
            return false;
129
        }
130
131
        $int16 = $msb + $lsb;
132
        if ($signedness && $int16 & 0x8000) {
133
            return -(($int16 ^ 0xFFFF) + 1);
134
        }
135
136
        return $int16;
137
    }
138
139
    /**
140
     * Convert INT16 to WORD (2 bytes).
141
     *
142
     * @param int $int16      INT16 Range: (-32768 to 65535)
143
     * @param int $endianness Machine Byte Order, default 1
144
     *
145
     * @var int Endianness => 1 (Big Endian)
146
     * @var int Endianness => 2 (Mid-Big Endian) *Not supported
147
     * @var int Endianness => 3 (Little Endian)
148
     * @var int Endianness => 4 (Mid-Little Endian) *Not supported
149
     *
150
     * @see Data::dwordToInt32() Converting WORD to INT16
151
     *
152
     * @return bool|string WORD or false if invalid, or non supported endianness is given
153
     */
154
    public static function int16ToWord($int16, $endianness = 1)
155
    {
156
        // Unpack INT16 to bytes (INT8)
157
        $msb = ($int16 >> 8) & 0xFF;
158
        $lsb = ($int16 >> 0) & 0xFF;
159
160
        // Convert bytes (INT8) to hex
161
        $msb = str_pad(base_convert($msb, 10, 16), 2, '0', STR_PAD_LEFT);
162
        $lsb = str_pad(base_convert($lsb, 10, 16), 2, '0', STR_PAD_LEFT);
163
164
        // Pack bytes into word according endianness
165
        if ($endianness == 1) {
166
            return $msb.$lsb;
167
        } elseif ($endianness == 3) {
168
            return $lsb.$msb;
169
        }
170
171
        return false;
172
    }
173
174
    /**
175
     * Convert DWORD to INT32.
176
     *
177
     * @param string $dword      DWORD (4 bytes)
178
     * @param int    $endianness Machine Byte Order, default 1
179
     *
180
     * @var int Endianness => 1 (Big Endian)
181
     * @var int Endianness => 2 (Mid-Big Endian)
182
     * @var int Endianness => 3 (Little Endian)
183
     * @var int Endianness => 4 (Mid-Little Endian)
184
     *
185
     * @param int $signedness signedness, default 1
186
     *
187
     * @var int Signedness => 1 (Signed)
188
     * @var int Signedness => 0 (Unsigned)
189
     *
190
     * @see Data::int32ToDword() Converting INT32 to DWORD
191
     *
192
     * @return int INT32
193
     */
194
    public static function dwordToInt32($dword, $endianness = 1, $signedness = 1)
195
    {
196
        // unpack hex str to raw bytes
197
        $bin = pack('H*', $dword);
198
        $raw = unpack('c*', $bin);
199
200
        $msb1 = $lsb1 = $msb2 = $lsb2 = 0;
201
202
        // Pack raw bytes according to endianness
203
        if ($endianness == 1) {
204
            $msb1 = ($raw[1] << 24) & 0xFF000000;
205
            $lsb1 = ($raw[2] << 16) & 0x00FF0000;
206
            $msb2 = ($raw[3] << 8) & 0x0000FF00;
207
            $lsb2 = ($raw[4] << 0) & 0x000000FF;
208
        } elseif ($endianness == 2) {
209
            $msb1 = ($raw[2] << 24) & 0xFF000000;
210
            $lsb1 = ($raw[1] << 16) & 0x00FF0000;
211
            $msb2 = ($raw[4] << 8) & 0x0000FF00;
212
            $lsb2 = ($raw[3] << 0) & 0x000000FF;
213
        } elseif ($endianness == 3) {
214
            $msb1 = ($raw[4] << 24) & 0xFF000000;
215
            $lsb1 = ($raw[3] << 16) & 0x00FF0000;
216
            $msb2 = ($raw[2] << 8) & 0x0000FF00;
217
            $lsb2 = ($raw[1] << 0) & 0x000000FF;
218
        } elseif ($endianness == 4) {
219
            $msb1 = ($raw[3] << 24) & 0xFF000000;
220
            $lsb1 = ($raw[4] << 16) & 0x00FF0000;
221
            $msb2 = ($raw[1] << 8) & 0x0000FF00;
222
            $lsb2 = ($raw[2] << 0) & 0x000000FF;
223
        }
224
225
        $int32 = $msb1 + $lsb1 + $msb2 + $lsb2;
226
        if ($signedness && $int32 & 0x80000000) {
227
            return -(($int32 ^ 0xFFFFFFFF) + 1);
228
        }
229
230
        return $int32;
231
    }
232
233
    /**
234
     * Convert INT32 to DWORD (4 bytes).
235
     *
236
     * @param int $int32      INT32 Range: (-2147483648 to 4294967295)
237
     * @param int $endianness Machine Byte Order, default 1
238
     *
239
     * @var int Endianness => 1 (Big Endian)
240
     * @var int Endianness => 2 (Mid-Big Endian)
241
     * @var int Endianness => 3 (Little Endian)
242
     * @var int Endianness => 4 (Mid-Little Endian)
243
     *
244
     * @see Data::dwordToInt32() Converting DWORD to INT32
245
     *
246
     * @return bool|string DWORD or false if invalid endianness is given
247
     */
248
    public static function int32ToDword($int32, $endianness = 1)
249
    {
250
        // Unpack INT32 to bytes (INT8)
251
        $msb1 = ($int32 >> 24) & 0xFF;
252
        $lsb1 = ($int32 >> 16) & 0xFF;
253
        $msb2 = ($int32 >> 8) & 0xFF;
254
        $lsb2 = ($int32 >> 0) & 0xFF;
255
256
        // Convert bytes (INT8) to hex
257
        $msb1 = str_pad(base_convert($msb1, 10, 16), 2, '0', STR_PAD_LEFT);
258
        $lsb1 = str_pad(base_convert($lsb1, 10, 16), 2, '0', STR_PAD_LEFT);
259
        $msb2 = str_pad(base_convert($msb2, 10, 16), 2, '0', STR_PAD_LEFT);
260
        $lsb2 = str_pad(base_convert($lsb2, 10, 16), 2, '0', STR_PAD_LEFT);
261
262
        // Pack bytes into dword according endianness
263
        if ($endianness == 1) {
264
            return $msb1.$lsb1.$msb2.$lsb2;
265
        } elseif ($endianness == 2) {
266
            return $lsb1.$msb1.$lsb2.$msb2;
267
        } elseif ($endianness == 3) {
268
            return $lsb2.$msb2.$lsb1.$msb1;
269
        } elseif ($endianness == 4) {
270
            return $msb2.$lsb2.$msb1.$lsb1;
271
        }
272
273
        return false;
274
    }
275
}
276