Issues (807)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

phpthumb/phpthumb.bmp.php (6 issues)

1
<?php
2
/////////////////////////////////////////////////////////////////
3
/// getID3() by James Heinrich <[email protected]>               //
4
//  available at http://getid3.sourceforge.net                 //
5
//            or http://www.getid3.org                         //
6
/////////////////////////////////////////////////////////////////
7
// See readme.txt for more details                             //
8
/////////////////////////////////////////////////////////////////
9
//                                                             //
10
// module.graphic.bmp.php                                      //
11
// module for analyzing BMP Image files                        //
12
// dependencies: NONE                                          //
13
//                                                            ///
14
/////////////////////////////////////////////////////////////////
15
//                                                             //
16
// Modified for use in phpThumb() - James Heinrich 2004.07.27  //
17
//                                                             //
18
/////////////////////////////////////////////////////////////////
19
20
class phpthumb_bmp
21
{
22
    public function phpthumb_bmp2gd(&$BMPdata, $truecolor = true)
23
    {
24
        $ThisFileInfo = [];
25
        if ($this->getid3_bmp($BMPdata, $ThisFileInfo, true, true)) {
26
            $gd = $this->PlotPixelsGD($ThisFileInfo['bmp'], $truecolor);
27
            return $gd;
28
        }
29
        return false;
30
    }
31
32
    public function phpthumb_bmpfile2gd($filename, $truecolor = true)
33
    {
34
        if ($fp = @fopen($filename, 'rb')) {
35
            $BMPdata = fread($fp, filesize($filename));
36
            fclose($fp);
37
            return $this->phpthumb_bmp2gd($BMPdata, $truecolor);
38
        }
39
        return false;
40
    }
41
42
    public function GD2BMPstring(&$gd_image)
43
    {
44
        $imageX = imagesx($gd_image);
45
        $imageY = imagesy($gd_image);
46
47
        $BMP = '';
48
        for ($y = ($imageY - 1); $y >= 0; $y--) {
49
            $thisline = '';
50
            for ($x = 0; $x < $imageX; $x++) {
51
                $argb     = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
52
                $thisline .= chr($argb['blue']) . chr($argb['green']) . chr($argb['red']);
53
            }
54
            while (strlen($thisline) % 4) {
55
                $thisline .= "\x00";
56
            }
57
            $BMP .= $thisline;
58
        }
59
60
        $bmpSize = strlen($BMP) + 14 + 40;
61
        // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
62
        $BITMAPFILEHEADER = 'BM';                                                           // WORD    bfType;
63
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String($bmpSize, 4); // DWORD   bfSize;
64
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String(0, 2); // WORD    bfReserved1;
65
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String(0, 2); // WORD    bfReserved2;
66
        $BITMAPFILEHEADER .= phpthumb_functions::LittleEndian2String(54, 4); // DWORD   bfOffBits;
67
68
        // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
69
        $BITMAPINFOHEADER = phpthumb_functions::LittleEndian2String(40, 4); // DWORD  biSize;
70
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String($imageX, 4); // LONG   biWidth;
71
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String($imageY, 4); // LONG   biHeight;
72
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(1, 2); // WORD   biPlanes;
73
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(24, 2); // WORD   biBitCount;
74
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biCompression;
75
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biSizeImage;
76
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(2835, 4); // LONG   biXPelsPerMeter;
77
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(2835, 4); // LONG   biYPelsPerMeter;
78
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biClrUsed;
79
        $BITMAPINFOHEADER .= phpthumb_functions::LittleEndian2String(0, 4); // DWORD  biClrImportant;
80
81
        return $BITMAPFILEHEADER . $BITMAPINFOHEADER . $BMP;
82
    }
83
84
    public function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette = false, $ExtractData = false)
85
    {
86
        // shortcuts
87
        $ThisFileInfo['bmp']['header']['raw'] = [];
88
        $thisfile_bmp                         = &$ThisFileInfo['bmp'];
89
        $thisfile_bmp_header                  = &$thisfile_bmp['header'];
90
        $thisfile_bmp_header_raw              = &$thisfile_bmp_header['raw'];
91
92
        // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
93
        // all versions
94
        // WORD    bfType;
95
        // DWORD   bfSize;
96
        // WORD    bfReserved1;
97
        // WORD    bfReserved2;
98
        // DWORD   bfOffBits;
99
100
        $offset        = 0;
101
        $overalloffset = 0;
102
        $BMPheader     = substr($BMPdata, $overalloffset, 14 + 40);
103
        $overalloffset += (14 + 40);
104
105
        $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
106
        $offset                                += 2;
107
108
        if ($thisfile_bmp_header_raw['identifier'] != 'BM') {
109
            $ThisFileInfo['error'][] = 'Expecting "BM" at offset ' . (int)(@$ThisFileInfo['avdataoffset']) . ', found "' . $thisfile_bmp_header_raw['identifier'] . '"';
110
            unset($ThisFileInfo['fileformat']);
111
            unset($ThisFileInfo['bmp']);
112
            return false;
113
        }
114
115
        $thisfile_bmp_header_raw['filesize']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
116
        $offset                                 += 4;
117
        $thisfile_bmp_header_raw['reserved1']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
118
        $offset                                 += 2;
119
        $thisfile_bmp_header_raw['reserved2']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
120
        $offset                                 += 2;
121
        $thisfile_bmp_header_raw['data_offset'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
122
        $offset                                 += 4;
123
        $thisfile_bmp_header_raw['header_size'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
124
        $offset                                 += 4;
125
126
        // check if the hardcoded-to-1 "planes" is at offset 22 or 26
127
        $planes22 = $this->LittleEndian2Int(substr($BMPheader, 22, 2));
128
        $planes26 = $this->LittleEndian2Int(substr($BMPheader, 26, 2));
129
        if (($planes22 == 1) && ($planes26 != 1)) {
130
            $thisfile_bmp['type_os']      = 'OS/2';
131
            $thisfile_bmp['type_version'] = 1;
132
        } elseif (($planes26 == 1) && ($planes22 != 1)) {
133
            $thisfile_bmp['type_os']      = 'Windows';
134
            $thisfile_bmp['type_version'] = 1;
135
        } elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
136
            $thisfile_bmp['type_os']      = 'OS/2';
137
            $thisfile_bmp['type_version'] = 1;
138
        } elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
139
            $thisfile_bmp['type_os']      = 'Windows';
140
            $thisfile_bmp['type_version'] = 1;
141
        } elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
142
            $thisfile_bmp['type_os']      = 'Windows';
143
            $thisfile_bmp['type_version'] = 4;
144
        } elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
145
            $thisfile_bmp['type_os']      = 'Windows';
146
            $thisfile_bmp['type_version'] = 5;
147
        } else {
148
            $ThisFileInfo['error'][] = 'Unknown BMP subtype (or not a BMP file)';
149
            unset($ThisFileInfo['fileformat']);
150
            unset($ThisFileInfo['bmp']);
151
            return false;
152
        }
153
154
        $ThisFileInfo['fileformat']                  = 'bmp';
155
        $ThisFileInfo['video']['dataformat']         = 'bmp';
156
        $ThisFileInfo['video']['lossless']           = true;
157
        $ThisFileInfo['video']['pixel_aspect_ratio'] = (float)1;
158
159
        if ($thisfile_bmp['type_os'] == 'OS/2') {
160
            // OS/2-format BMP
161
            // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
162
163
            // DWORD  Size;             /* Size of this structure in bytes */
164
            // DWORD  Width;            /* Bitmap width in pixels */
165
            // DWORD  Height;           /* Bitmap height in pixel */
166
            // WORD   NumPlanes;        /* Number of bit planes (color depth) */
167
            // WORD   BitsPerPixel;     /* Number of bits per pixel per plane */
168
169
            $thisfile_bmp_header_raw['width']          = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
170
            $offset                                    += 2;
171
            $thisfile_bmp_header_raw['height']         = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
172
            $offset                                    += 2;
173
            $thisfile_bmp_header_raw['planes']         = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
174
            $offset                                    += 2;
175
            $thisfile_bmp_header_raw['bits_per_pixel'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
176
            $offset                                    += 2;
177
178
            $ThisFileInfo['video']['resolution_x']    = $thisfile_bmp_header_raw['width'];
179
            $ThisFileInfo['video']['resolution_y']    = $thisfile_bmp_header_raw['height'];
180
            $ThisFileInfo['video']['codec']           = 'BI_RGB ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
181
            $ThisFileInfo['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
182
183
            if ($thisfile_bmp['type_version'] >= 2) {
184
                // DWORD  Compression;      /* Bitmap compression scheme */
185
                // DWORD  ImageDataSize;    /* Size of bitmap data in bytes */
186
                // DWORD  XResolution;      /* X resolution of display device */
187
                // DWORD  YResolution;      /* Y resolution of display device */
188
                // DWORD  ColorsUsed;       /* Number of color table indices used */
189
                // DWORD  ColorsImportant;  /* Number of important color indices */
190
                // WORD   Units;            /* Type of units used to measure resolution */
191
                // WORD   Reserved;         /* Pad structure to 4-byte boundary */
192
                // WORD   Recording;        /* Recording algorithm */
193
                // WORD   Rendering;        /* Halftoning algorithm used */
194
                // DWORD  Size1;            /* Reserved for halftoning algorithm use */
195
                // DWORD  Size2;            /* Reserved for halftoning algorithm use */
196
                // DWORD  ColorEncoding;    /* Color model used in bitmap */
197
                // DWORD  Identifier;       /* Reserved for application use */
198
199
                $thisfile_bmp_header_raw['compression']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
200
                $offset                                      += 4;
201
                $thisfile_bmp_header_raw['bmp_data_size']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
202
                $offset                                      += 4;
203
                $thisfile_bmp_header_raw['resolution_h']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
204
                $offset                                      += 4;
205
                $thisfile_bmp_header_raw['resolution_v']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
206
                $offset                                      += 4;
207
                $thisfile_bmp_header_raw['colors_used']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
208
                $offset                                      += 4;
209
                $thisfile_bmp_header_raw['colors_important'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
210
                $offset                                      += 4;
211
                $thisfile_bmp_header_raw['resolution_units'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
212
                $offset                                      += 2;
213
                $thisfile_bmp_header_raw['reserved1']        = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
214
                $offset                                      += 2;
215
                $thisfile_bmp_header_raw['recording']        = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
216
                $offset                                      += 2;
217
                $thisfile_bmp_header_raw['rendering']        = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
218
                $offset                                      += 2;
219
                $thisfile_bmp_header_raw['size1']            = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
220
                $offset                                      += 4;
221
                $thisfile_bmp_header_raw['size2']            = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
222
                $offset                                      += 4;
223
                $thisfile_bmp_header_raw['color_encoding']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
224
                $offset                                      += 4;
225
                $thisfile_bmp_header_raw['identifier']       = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
226
                $offset                                      += 4;
227
228
                $thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
229
230
                $ThisFileInfo['video']['codec'] = $thisfile_bmp_header['compression'] . ' ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
231
            }
232
        } elseif ($thisfile_bmp['type_os'] == 'Windows') {
233
            // Windows-format BMP
234
235
            // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
236
            // all versions
237
            // DWORD  biSize;
238
            // LONG   biWidth;
239
            // LONG   biHeight;
240
            // WORD   biPlanes;
241
            // WORD   biBitCount;
242
            // DWORD  biCompression;
243
            // DWORD  biSizeImage;
244
            // LONG   biXPelsPerMeter;
245
            // LONG   biYPelsPerMeter;
246
            // DWORD  biClrUsed;
247
            // DWORD  biClrImportant;
248
249
            $thisfile_bmp_header_raw['width']            = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
250
            $offset                                      += 4;
251
            $thisfile_bmp_header_raw['height']           = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
252
            $offset                                      += 4;
253
            $thisfile_bmp_header_raw['planes']           = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
254
            $offset                                      += 2;
255
            $thisfile_bmp_header_raw['bits_per_pixel']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 2));
256
            $offset                                      += 2;
257
            $thisfile_bmp_header_raw['compression']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
258
            $offset                                      += 4;
259
            $thisfile_bmp_header_raw['bmp_data_size']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
260
            $offset                                      += 4;
261
            $thisfile_bmp_header_raw['resolution_h']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
262
            $offset                                      += 4;
263
            $thisfile_bmp_header_raw['resolution_v']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
264
            $offset                                      += 4;
265
            $thisfile_bmp_header_raw['colors_used']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
266
            $offset                                      += 4;
267
            $thisfile_bmp_header_raw['colors_important'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
268
            $offset                                      += 4;
269
270
            $thisfile_bmp_header['compression']       = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
271
            $ThisFileInfo['video']['resolution_x']    = $thisfile_bmp_header_raw['width'];
272
            $ThisFileInfo['video']['resolution_y']    = $thisfile_bmp_header_raw['height'];
273
            $ThisFileInfo['video']['codec']           = $thisfile_bmp_header['compression'] . ' ' . $thisfile_bmp_header_raw['bits_per_pixel'] . '-bit';
274
            $ThisFileInfo['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
275
276
            if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) {
277
                // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
278
                $BMPheader     .= substr($BMPdata, $overalloffset, 44);
279
                $overalloffset += 44;
280
281
                // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
282
                // Win95+, WinNT4.0+
283
                // DWORD        bV4RedMask;
284
                // DWORD        bV4GreenMask;
285
                // DWORD        bV4BlueMask;
286
                // DWORD        bV4AlphaMask;
287
                // DWORD        bV4CSType;
288
                // CIEXYZTRIPLE bV4Endpoints;
289
                // DWORD        bV4GammaRed;
290
                // DWORD        bV4GammaGreen;
291
                // DWORD        bV4GammaBlue;
292
                $thisfile_bmp_header_raw['red_mask']     = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
293
                $offset                                  += 4;
294
                $thisfile_bmp_header_raw['green_mask']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
295
                $offset                                  += 4;
296
                $thisfile_bmp_header_raw['blue_mask']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
297
                $offset                                  += 4;
298
                $thisfile_bmp_header_raw['alpha_mask']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
299
                $offset                                  += 4;
300
                $thisfile_bmp_header_raw['cs_type']      = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
301
                $offset                                  += 4;
302
                $thisfile_bmp_header_raw['ciexyz_red']   = substr($BMPheader, $offset, 4);
303
                $offset                                  += 4;
304
                $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
305
                $offset                                  += 4;
306
                $thisfile_bmp_header_raw['ciexyz_blue']  = substr($BMPheader, $offset, 4);
307
                $offset                                  += 4;
308
                $thisfile_bmp_header_raw['gamma_red']    = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
309
                $offset                                  += 4;
310
                $thisfile_bmp_header_raw['gamma_green']  = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
311
                $offset                                  += 4;
312
                $thisfile_bmp_header_raw['gamma_blue']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
313
                $offset                                  += 4;
314
315
                $thisfile_bmp_header['ciexyz_red']   = $this->FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
316
                $thisfile_bmp_header['ciexyz_green'] = $this->FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
317
                $thisfile_bmp_header['ciexyz_blue']  = $this->FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
318
            }
319
320
            if ($thisfile_bmp['type_version'] >= 5) {
321
                $BMPheader     .= substr($BMPdata, $overalloffset, 16);
322
                $overalloffset += 16;
323
324
                // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
325
                // Win98+, Win2000+
326
                // DWORD        bV5Intent;
327
                // DWORD        bV5ProfileData;
328
                // DWORD        bV5ProfileSize;
329
                // DWORD        bV5Reserved;
330
                $thisfile_bmp_header_raw['intent']              = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
331
                $offset                                         += 4;
332
                $thisfile_bmp_header_raw['profile_data_offset'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
333
                $offset                                         += 4;
334
                $thisfile_bmp_header_raw['profile_data_size']   = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
335
                $offset                                         += 4;
336
                $thisfile_bmp_header_raw['reserved3']           = $this->LittleEndian2Int(substr($BMPheader, $offset, 4));
337
                $offset                                         += 4;
338
            }
339
        } else {
340
            $ThisFileInfo['error'][] = 'Unknown BMP format in header.';
341
            return false;
342
        }
343
344
        if ($ExtractPalette || $ExtractData) {
345
            $PaletteEntries = 0;
346
            if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
347
                $PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
348
            } elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
349
                $PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
350
            }
351
            if ($PaletteEntries > 0) {
352
                $BMPpalette    = substr($BMPdata, $overalloffset, 4 * $PaletteEntries);
353
                $overalloffset += 4 * $PaletteEntries;
354
355
                $paletteoffset = 0;
356
                for ($i = 0; $i < $PaletteEntries; $i++) {
357
                    // RGBQUAD          - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
358
                    // BYTE    rgbBlue;
359
                    // BYTE    rgbGreen;
360
                    // BYTE    rgbRed;
361
                    // BYTE    rgbReserved;
362
                    $blue  = $this->LittleEndian2Int($BMPpalette[$paletteoffset++]);
363
                    $green = $this->LittleEndian2Int($BMPpalette[$paletteoffset++]);
364
                    $red   = $this->LittleEndian2Int($BMPpalette[$paletteoffset++]);
365
                    if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) {
366
                        // no padding byte
367
                    } else {
368
                        $paletteoffset++; // padding byte
369
                    }
370
                    $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue);
371
                }
372
            }
373
        }
374
375
        if ($ExtractData) {
376
            $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundary
377
378
            $BMPpixelData  = substr($BMPdata, $thisfile_bmp_header_raw['data_offset'], $thisfile_bmp_header_raw['height'] * $RowByteLength);
0 ignored issues
show
$thisfile_bmp_header_raw...ight'] * $RowByteLength of type double is incompatible with the type integer|null expected by parameter $length of substr(). ( Ignorable by Annotation )

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

378
            $BMPpixelData  = substr($BMPdata, $thisfile_bmp_header_raw['data_offset'], /** @scrutinizer ignore-type */ $thisfile_bmp_header_raw['height'] * $RowByteLength);
Loading history...
379
            $overalloffset = $thisfile_bmp_header_raw['data_offset'] + ($thisfile_bmp_header_raw['height'] * $RowByteLength);
0 ignored issues
show
The assignment to $overalloffset is dead and can be removed.
Loading history...
380
381
            $pixeldataoffset = 0;
382
            switch (@$thisfile_bmp_header_raw['compression']) {
383
                case 0: // BI_RGB
384
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
385
                        case 1:
386
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
387
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
388
                                    $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]);
389
                                    for ($i = 7; $i >= 0; $i--) {
390
                                        $paletteindex                     = ($paletteindexbyte & (0x01 << $i)) >> $i;
391
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
392
                                        $col++;
393
                                    }
394
                                }
395
                                while (($pixeldataoffset % 4) != 0) {
396
                                    // lines are padded to nearest DWORD
397
                                    $pixeldataoffset++;
398
                                }
399
                            }
400
                            break;
401
402
                        case 4:
403
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
404
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
405
                                    $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]);
406
                                    for ($i = 1; $i >= 0; $i--) {
407
                                        $paletteindex                     = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
408
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
409
                                        $col++;
410
                                    }
411
                                }
412
                                while (($pixeldataoffset % 4) != 0) {
413
                                    // lines are padded to nearest DWORD
414
                                    $pixeldataoffset++;
415
                                }
416
                            }
417
                            break;
418
419
                        case 8:
420
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
421
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
422
                                    $paletteindex                     = ord($BMPpixelData[$pixeldataoffset++]);
423
                                    $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
424
                                }
425
                                while (($pixeldataoffset % 4) != 0) {
426
                                    // lines are padded to nearest DWORD
427
                                    $pixeldataoffset++;
428
                                }
429
                            }
430
                            break;
431
432
                        case 24:
433
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
434
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
435
                                    $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset + 2]) << 16) | (ord($BMPpixelData[$pixeldataoffset + 1]) << 8) | ord($BMPpixelData[$pixeldataoffset]);
436
                                    $pixeldataoffset                  += 3;
437
                                }
438
                                while (($pixeldataoffset % 4) != 0) {
439
                                    // lines are padded to nearest DWORD
440
                                    $pixeldataoffset++;
441
                                }
442
                            }
443
                            break;
444
445
                        case 32:
446
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
447
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
448
                                    $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset + 3]) << 24) | (ord($BMPpixelData[$pixeldataoffset + 2]) << 16) | (ord($BMPpixelData[$pixeldataoffset + 1]) << 8) | ord($BMPpixelData[$pixeldataoffset]);
449
                                    $pixeldataoffset                  += 4;
450
                                }
451
                                while (($pixeldataoffset % 4) != 0) {
452
                                    // lines are padded to nearest DWORD
453
                                    $pixeldataoffset++;
454
                                }
455
                            }
456
                            break;
457
458
                        case 16:
459
                            // ?
460
                            break;
461
462
                        default:
463
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
464
                            break;
465
                    }
466
                    break;
467
468
                case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
469
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
470
                        case 8:
471
                            $pixelcounter = 0;
472
                            while ($pixeldataoffset < strlen($BMPpixelData)) {
473
                                $firstbyte  = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
474
                                $secondbyte = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
475
                                if ($firstbyte == 0) {
476
                                    // escaped/absolute mode - the first byte of the pair can be set to zero to
477
                                    // indicate an escape character that denotes the end of a line, the end of
478
                                    // a bitmap, or a delta, depending on the value of the second byte.
479
                                    switch ($secondbyte) {
480
                                        case 0:
481
                                            // end of line
482
                                            // no need for special processing, just ignore
483
                                            break;
484
485
                                        case 1:
486
                                            // end of bitmap
487
                                            $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
488
                                            break;
489
490
                                        case 2:
491
                                            // delta - The 2 bytes following the escape contain unsigned values
492
                                            // indicating the horizontal and vertical offsets of the next pixel
493
                                            // from the current position.
494
                                            $colincrement = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
495
                                            $rowincrement = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
496
                                            $col          = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
497
                                            $row          = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
498
                                            $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
499
                                            break;
500
501
                                        default:
502
                                            // In absolute mode, the first byte is zero and the second byte is a
503
                                            // value in the range 03H through FFH. The second byte represents the
504
                                            // number of bytes that follow, each of which contains the color index
505
                                            // of a single pixel. Each run must be aligned on a word boundary.
506
                                            for ($i = 0; $i < $secondbyte; $i++) {
507
                                                $paletteindex                     = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
508
                                                $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
509
                                                $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
510
                                                $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
511
                                                $pixelcounter++;
512
                                            }
513
                                            while (($pixeldataoffset % 2) != 0) {
514
                                                // Each run must be aligned on a word boundary.
515
                                                $pixeldataoffset++;
516
                                            }
517
                                            break;
518
                                    }
519
                                } else {
520
                                    // encoded mode - the first byte specifies the number of consecutive pixels
521
                                    // to be drawn using the color index contained in the second byte.
522
                                    for ($i = 0; $i < $firstbyte; $i++) {
523
                                        $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
524
                                        $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
525
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
526
                                        $pixelcounter++;
527
                                    }
528
                                }
529
                            }
530
                            break;
531
532
                        default:
533
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
534
                            break;
535
                    }
536
                    break;
537
538
                case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
539
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
540
                        case 4:
541
                            $pixelcounter = 0;
542
                            while ($pixeldataoffset < strlen($BMPpixelData)) {
543
                                $firstbyte  = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
544
                                $secondbyte = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
545
                                if ($firstbyte == 0) {
546
                                    // escaped/absolute mode - the first byte of the pair can be set to zero to
547
                                    // indicate an escape character that denotes the end of a line, the end of
548
                                    // a bitmap, or a delta, depending on the value of the second byte.
549
                                    switch ($secondbyte) {
550
                                        case 0:
551
                                            // end of line
552
                                            // no need for special processing, just ignore
553
                                            break;
554
555
                                        case 1:
556
                                            // end of bitmap
557
                                            $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
558
                                            break;
559
560
                                        case 2:
561
                                            // delta - The 2 bytes following the escape contain unsigned values
562
                                            // indicating the horizontal and vertical offsets of the next pixel
563
                                            // from the current position.
564
                                            $colincrement = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
565
                                            $rowincrement = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
566
                                            $col          = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
567
                                            $row          = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
568
                                            $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
569
                                            break;
570
571
                                        default:
572
                                            // In absolute mode, the first byte is zero. The second byte contains the number
573
                                            // of color indexes that follow. Subsequent bytes contain color indexes in their
574
                                            // high- and low-order 4 bits, one color index for each pixel. In absolute mode,
575
                                            // each run must be aligned on a word boundary.
576
                                            $paletteindexes = [];
577
                                            for ($i = 0, $iMax = ceil($secondbyte / 2); $i < $iMax; $i++) {
578
                                                $paletteindexbyte = $this->LittleEndian2Int($BMPpixelData[$pixeldataoffset++]);
579
                                                $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
580
                                                $paletteindexes[] = ($paletteindexbyte & 0x0F);
581
                                            }
582
                                            while (($pixeldataoffset % 2) != 0) {
583
                                                // Each run must be aligned on a word boundary.
584
                                                $pixeldataoffset++;
585
                                            }
586
587
                                            foreach ($paletteindexes as $dummy => $paletteindex) {
588
                                                $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
589
                                                $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
590
                                                $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
591
                                                $pixelcounter++;
592
                                            }
593
                                            break;
594
                                    }
595
                                } else {
596
                                    // encoded mode - the first byte of the pair contains the number of pixels to be
597
                                    // drawn using the color indexes in the second byte. The second byte contains two
598
                                    // color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
599
                                    // The first of the pixels is drawn using the color specified by the high-order
600
                                    // 4 bits, the second is drawn using the color in the low-order 4 bits, the third
601
                                    // is drawn using the color in the high-order 4 bits, and so on, until all the
602
                                    // pixels specified by the first byte have been drawn.
603
                                    $paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
604
                                    $paletteindexes[1] = ($secondbyte & 0x0F);
605
                                    for ($i = 0; $i < $firstbyte; $i++) {
606
                                        $col                              = $pixelcounter % $thisfile_bmp_header_raw['width'];
607
                                        $row                              = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
608
                                        $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[$i % 2]];
609
                                        $pixelcounter++;
610
                                    }
611
                                }
612
                            }
613
                            break;
614
615
                        default:
616
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
617
                            break;
618
                    }
619
                    break;
620
621
                case 3: // BI_BITFIELDS
622
                    switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
623
                        case 16:
624
                        case 32:
625
                            $redshift   = 0;
626
                            $greenshift = 0;
627
                            $blueshift  = 0;
628
                            if (!$thisfile_bmp_header_raw['red_mask'] || !$thisfile_bmp_header_raw['green_mask'] || !$thisfile_bmp_header_raw['blue_mask']) {
629
                                $ThisFileInfo['error'][] = 'missing $thisfile_bmp_header_raw[(red|green|blue)_mask]';
630
                                return false;
631
                            }
632
                            while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) {
633
                                $redshift++;
634
                            }
635
                            while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) {
636
                                $greenshift++;
637
                            }
638
                            while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) {
639
                                $blueshift++;
640
                            }
641
                            for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
642
                                for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
643
                                    $pixelvalue      = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
644
                                    $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
645
646
                                    $red                              = (int)round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255);
647
                                    $green                            = (int)round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255);
648
                                    $blue                             = (int)round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255);
649
                                    $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | $blue);
650
                                }
651
                                while (($pixeldataoffset % 4) != 0) {
652
                                    // lines are padded to nearest DWORD
653
                                    $pixeldataoffset++;
654
                                }
655
                            }
656
                            break;
657
658
                        default:
659
                            $ThisFileInfo['error'][] = 'Unknown bits-per-pixel value (' . $thisfile_bmp_header_raw['bits_per_pixel'] . ') - cannot read pixel data';
660
                            break;
661
                    }
662
                    break;
663
664
                default: // unhandled compression type
665
                    $ThisFileInfo['error'][] = 'Unknown/unhandled compression type value (' . $thisfile_bmp_header_raw['compression'] . ') - cannot decompress pixel data';
666
                    break;
667
            }
668
        }
669
670
        return true;
671
    }
672
673
    public function IntColor2RGB($color)
674
    {
675
        $red   = ($color & 0x00FF0000) >> 16;
676
        $green = ($color & 0x0000FF00) >> 8;
677
        $blue  = ($color & 0x000000FF);
678
        return [$red, $green, $blue];
679
    }
680
681
    public function PlotPixelsGD(&$BMPdata, $truecolor = true)
682
    {
683
        $imagewidth  = $BMPdata['header']['raw']['width'];
684
        $imageheight = $BMPdata['header']['raw']['height'];
685
686
        if ($truecolor) {
687
            $gd = @imagecreatetruecolor($imagewidth, $imageheight);
688
        } else {
689
            $gd = @imagecreate($imagewidth, $imageheight);
690
            if (!empty($BMPdata['palette'])) {
691
                // create GD palette from BMP palette
692
                foreach ($BMPdata['palette'] as $dummy => $color) {
693
                    [$r, $g, $b] = $this->IntColor2RGB($color);
694
                    imagecolorallocate($gd, $r, $g, $b);
0 ignored issues
show
It seems like $gd can also be of type false; however, parameter $image of imagecolorallocate() does only seem to accept GdImage|resource, 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

694
                    imagecolorallocate(/** @scrutinizer ignore-type */ $gd, $r, $g, $b);
Loading history...
695
                }
696
            } else {
697
                // create 216-color websafe palette
698
                for ($r = 0x00; $r <= 0xFF; $r += 0x33) {
699
                    for ($g = 0x00; $g <= 0xFF; $g += 0x33) {
700
                        for ($b = 0x00; $b <= 0xFF; $b += 0x33) {
701
                            imagecolorallocate($gd, $r, $g, $b);
702
                        }
703
                    }
704
                }
705
            }
706
        }
707
        if (!is_resource($gd) && !(is_object($gd) && $gd instanceof \GdImage)) {
708
            return false;
709
        }
710
711
        foreach ($BMPdata['data'] as $row => $colarray) {
712
            if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
713
                set_time_limit(30);
714
            }
715
            foreach ($colarray as $col => $color) {
716
                [$red, $green, $blue] = $this->IntColor2RGB($color);
717
                if ($truecolor) {
718
                    $pixelcolor = imagecolorallocate($gd, $red, $green, $blue);
719
                } else {
720
                    $pixelcolor = imagecolorclosest($gd, $red, $green, $blue);
721
                }
722
                imagesetpixel($gd, $col, $row, $pixelcolor);
723
            }
724
        }
725
        return $gd;
726
    }
727
728
    public function PlotBMP(&$BMPinfo)
729
    {
730
        $starttime = time();
731
        if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
732
            echo 'ERROR: no pixel data<BR>';
733
            return false;
734
        }
735
        if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) {
736
            set_time_limit((int)round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000));
737
        }
738
        $im = $this->PlotPixelsGD($BMPinfo['bmp']);
739
        if (headers_sent()) {
740
            echo 'plotted ' . ($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']) . ' pixels in ' . (time() - $starttime) . ' seconds<BR>';
741
            imagedestroy($im);
0 ignored issues
show
It seems like $im can also be of type false; however, parameter $image of imagedestroy() does only seem to accept GdImage|resource, 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

741
            imagedestroy(/** @scrutinizer ignore-type */ $im);
Loading history...
742
            exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
743
        }
744
        header('Content-Type: image/png');
745
        imagepng($im);
0 ignored issues
show
It seems like $im can also be of type false; however, parameter $image of imagepng() does only seem to accept GdImage|resource, 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

745
        imagepng(/** @scrutinizer ignore-type */ $im);
Loading history...
746
        imagedestroy($im);
747
        return true;
748
    }
749
750
    public function BMPcompressionWindowsLookup($compressionid)
751
    {
752
        static $BMPcompressionWindowsLookup = [
753
            0 => 'BI_RGB',
754
            1 => 'BI_RLE8',
755
            2 => 'BI_RLE4',
756
            3 => 'BI_BITFIELDS',
757
            4 => 'BI_JPEG',
758
            5 => 'BI_PNG',
759
        ];
760
        return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid');
761
    }
762
763
    public function BMPcompressionOS2Lookup($compressionid)
764
    {
765
        static $BMPcompressionOS2Lookup = [
766
            0 => 'BI_RGB',
767
            1 => 'BI_RLE8',
768
            2 => 'BI_RLE4',
769
            3 => 'Huffman 1D',
770
            4 => 'BI_RLE24',
771
        ];
772
        return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid');
773
    }
774
775
    // from getid3.lib.php
776
777
    public function trunc($floatnumber)
778
    {
779
        // truncates a floating-point number at the decimal point
780
        // returns int (if possible, otherwise float)
781
        if ($floatnumber >= 1) {
782
            $truncatednumber = floor($floatnumber);
783
        } elseif ($floatnumber <= -1) {
784
            $truncatednumber = ceil($floatnumber);
785
        } else {
786
            $truncatednumber = 0;
787
        }
788
        if ($truncatednumber <= 1073741824) { // 2^30
789
            $truncatednumber = (int)$truncatednumber;
790
        }
791
        return $truncatednumber;
792
    }
793
794
    public function LittleEndian2Int($byteword)
795
    {
796
        $intvalue    = 0;
797
        $byteword    = strrev($byteword);
798
        $bytewordlen = strlen($byteword);
799
        for ($i = 0; $i < $bytewordlen; $i++) {
800
            $intvalue += ord($byteword[$i]) * pow(256, $bytewordlen - 1 - $i);
801
        }
802
        return $intvalue;
803
    }
804
805
    public function BigEndian2Int($byteword)
806
    {
807
        return $this->LittleEndian2Int(strrev($byteword));
808
    }
809
810
    public function BigEndian2Bin($byteword)
811
    {
812
        $binvalue    = '';
813
        $bytewordlen = strlen($byteword);
814
        for ($i = 0; $i < $bytewordlen; $i++) {
815
            $binvalue .= str_pad(decbin(ord($byteword[$i])), 8, '0', STR_PAD_LEFT);
816
        }
817
        return $binvalue;
818
    }
819
820
    public function FixedPoint2_30($rawdata)
821
    {
822
        $binarystring = $this->BigEndian2Bin($rawdata);
823
        return $this->Bin2Dec(substr($binarystring, 0, 2)) + (float)($this->Bin2Dec(substr($binarystring, 2, 30)) / 1073741824);
824
    }
825
826
    public function Bin2Dec($binstring, $signed = false)
827
    {
828
        $signmult = 1;
829
        if ($signed) {
830
            if ($binstring[0] == '1') {
831
                $signmult = -1;
832
            }
833
            $binstring = substr($binstring, 1);
834
        }
835
        $decvalue = 0;
836
        for ($i = 0, $iMax = strlen($binstring); $i < $iMax; $i++) {
837
            $decvalue += ((int)$binstring[strlen($binstring) - $i - 1]) * pow(2, $i);
838
        }
839
        return $this->CastAsInt($decvalue * $signmult);
840
    }
841
842
    public function CastAsInt($floatnum)
843
    {
844
        // convert to float if not already
845
        $floatnum = (float)$floatnum;
846
847
        // convert a float to type int, only if possible
848
        if ($this->trunc($floatnum) == $floatnum) {
849
            // it's not floating point
850
            if ($floatnum <= 1073741824) { // 2^30
851
                // it's within int range
852
                $floatnum = (int)$floatnum;
853
            }
854
        }
855
        return $floatnum;
856
    }
857
}
858