Completed
Push — vendor/getid3 ( 69b815...49c253 )
by Pauli
04:26 queued 01:37
created

getid3_png   F

Complexity

Total Complexity 85

Size/Duplication

Total Lines 595
Duplicated Lines 11.09 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 66
loc 595
rs 2
c 0
b 0
f 0
wmc 85
lcom 1
cbo 3

8 Methods

Rating   Name   Duplication   Size   Complexity  
F Analyze() 66 473 67
A PNGsRGBintentLookup() 0 9 2
A PNGcompressionMethodLookup() 0 6 2
A PNGpHYsUnitLookup() 0 7 2
A PNGoFFsUnitLookup() 0 7 2
A PNGpCALequationTypeLookup() 0 9 2
A PNGsCALUnitLookup() 0 7 2
A IHDRcalculateBitsPerSample() 0 19 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like getid3_png often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use getid3_png, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/////////////////////////////////////////////////////////////////
4
/// getID3() by James Heinrich <[email protected]>               //
5
//  available at https://github.com/JamesHeinrich/getID3       //
6
//            or https://www.getid3.org                        //
7
//            or http://getid3.sourceforge.net                 //
8
//  see readme.txt for more details                            //
9
/////////////////////////////////////////////////////////////////
10
//                                                             //
11
// module.graphic.png.php                                      //
12
// module for analyzing PNG Image files                        //
13
// dependencies: NONE                                          //
14
//                                                            ///
15
/////////////////////////////////////////////////////////////////
16
17
18
class getid3_png extends getid3_handler
19
{
20
	/**
21
	 * If data chunk is larger than this do not read it completely (getID3 only needs the first
22
	 * few dozen bytes for parsing).
23
	 *
24
	 * @var int
25
	 */
26
	public $max_data_bytes = 10000000;
27
28
	/**
29
	 * @return bool
30
	 */
31
	public function Analyze() {
32
33
		$info = &$this->getid3->info;
34
35
		// shortcut
36
		$info['png'] = array();
37
		$thisfile_png = &$info['png'];
38
39
		$info['fileformat']          = 'png';
40
		$info['video']['dataformat'] = 'png';
41
		$info['video']['lossless']   = false;
42
43
		$this->fseek($info['avdataoffset']);
44
		$PNGfiledata = $this->fread($this->getid3->fread_buffer_size());
45
		$offset = 0;
46
47
		$PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A
48
		$offset += 8;
49
50
		if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") {
51
			$this->error('First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier');
52
			unset($info['fileformat']);
53
			return false;
54
		}
55
56
		while ((($this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
57
			$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
0 ignored issues
show
Coding Style Comprehensibility introduced by
$chunk was never initialized. Although not strictly required by PHP, it is generally a good practice to add $chunk = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
58
			if ($chunk['data_length'] === false) {
0 ignored issues
show
Bug introduced by
The variable $chunk does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
59
				$this->error('Failed to read data_length at offset '.$offset);
60
				return false;
61
			}
62
			$offset += 4;
63
			$truncated_data = false;
0 ignored issues
show
Unused Code introduced by
$truncated_data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
64
			while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) {
65
				if (strlen($PNGfiledata) < $this->max_data_bytes) {
66
					$PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
67
				} else {
68
					$this->warning('At offset '.$offset.' chunk "'.substr($PNGfiledata, $offset, 4).'" exceeded max_data_bytes value of '.$this->max_data_bytes.', data chunk will be truncated at '.(strlen($PNGfiledata) - 8).' bytes');
69
					break;
70
				}
71
			}
72
			$chunk['type_text']   =                           substr($PNGfiledata, $offset, 4);
73
			$offset += 4;
74
			$chunk['type_raw']    = getid3_lib::BigEndian2Int($chunk['type_text']);
75
			$chunk['data']        =                           substr($PNGfiledata, $offset, $chunk['data_length']);
76
			$offset += $chunk['data_length'];
77
			$chunk['crc']         = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
78
			$offset += 4;
79
80
			$chunk['flags']['ancilliary']   = (bool) ($chunk['type_raw'] & 0x20000000);
81
			$chunk['flags']['private']      = (bool) ($chunk['type_raw'] & 0x00200000);
82
			$chunk['flags']['reserved']     = (bool) ($chunk['type_raw'] & 0x00002000);
83
			$chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);
84
85
			// shortcut
86
			$thisfile_png[$chunk['type_text']] = array();
87
			$thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']];
88
89
			switch ($chunk['type_text']) {
90
91
				case 'IHDR': // Image Header
92
					$thisfile_png_chunk_type_text['header'] = $chunk;
93
					$thisfile_png_chunk_type_text['width']                     = getid3_lib::BigEndian2Int(substr($chunk['data'],  0, 4));
94
					$thisfile_png_chunk_type_text['height']                    = getid3_lib::BigEndian2Int(substr($chunk['data'],  4, 4));
95
					$thisfile_png_chunk_type_text['raw']['bit_depth']          = getid3_lib::BigEndian2Int(substr($chunk['data'],  8, 1));
96
					$thisfile_png_chunk_type_text['raw']['color_type']         = getid3_lib::BigEndian2Int(substr($chunk['data'],  9, 1));
97
					$thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1));
98
					$thisfile_png_chunk_type_text['raw']['filter_method']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1));
99
					$thisfile_png_chunk_type_text['raw']['interlace_method']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1));
100
101
					$thisfile_png_chunk_type_text['compression_method_text']   = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
102
					$thisfile_png_chunk_type_text['color_type']['palette']     = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01);
103
					$thisfile_png_chunk_type_text['color_type']['true_color']  = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02);
104
					$thisfile_png_chunk_type_text['color_type']['alpha']       = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04);
105
106
					$info['video']['resolution_x']    = $thisfile_png_chunk_type_text['width'];
107
					$info['video']['resolution_y']    = $thisfile_png_chunk_type_text['height'];
108
109
					$info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
110
					break;
111
112
113
				case 'PLTE': // Palette
114
					$thisfile_png_chunk_type_text['header'] = $chunk;
115
					$paletteoffset = 0;
116
					for ($i = 0; $i <= 255; $i++) {
117
						//$thisfile_png_chunk_type_text['red'][$i]   = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
118
						//$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
119
						//$thisfile_png_chunk_type_text['blue'][$i]  = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
120
						$red   = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
121
						$green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
122
						$blue  = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
123
						$thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue));
124
					}
125
					break;
126
127
128
				case 'tRNS': // Transparency
129
					$thisfile_png_chunk_type_text['header'] = $chunk;
130
					switch ($thisfile_png['IHDR']['raw']['color_type']) {
131 View Code Duplication
						case 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
							$thisfile_png_chunk_type_text['transparent_color_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
133
							break;
134
135 View Code Duplication
						case 2:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
136
							$thisfile_png_chunk_type_text['transparent_color_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
137
							$thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
138
							$thisfile_png_chunk_type_text['transparent_color_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2));
139
							break;
140
141 View Code Duplication
						case 3:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
							for ($i = 0; $i < strlen($chunk['data']); $i++) {
143
								$thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1));
144
							}
145
							break;
146
147
						case 4:
148
						case 6:
149
							$this->error('Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']);
150
							break;
151
152
						default:
153
							$this->warning('Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']);
154
							break;
155
					}
156
					break;
157
158
159
				case 'gAMA': // Image Gamma
160
					$thisfile_png_chunk_type_text['header'] = $chunk;
161
					$thisfile_png_chunk_type_text['gamma']  = getid3_lib::BigEndian2Int($chunk['data']) / 100000;
162
					break;
163
164
165
				case 'cHRM': // Primary Chromaticities
166
					$thisfile_png_chunk_type_text['header']  = $chunk;
167
					$thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  0, 4)) / 100000;
168
					$thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  4, 4)) / 100000;
169
					$thisfile_png_chunk_type_text['red_y']   = getid3_lib::BigEndian2Int(substr($chunk['data'],  8, 4)) / 100000;
170
					$thisfile_png_chunk_type_text['red_y']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000;
171
					$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000;
172
					$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000;
173
					$thisfile_png_chunk_type_text['blue_y']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000;
174
					$thisfile_png_chunk_type_text['blue_y']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000;
175
					break;
176
177
178
				case 'sRGB': // Standard RGB Color Space
179
					$thisfile_png_chunk_type_text['header']                 = $chunk;
180
					$thisfile_png_chunk_type_text['reindering_intent']      = getid3_lib::BigEndian2Int($chunk['data']);
181
					$thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
0 ignored issues
show
Bug introduced by
It seems like $thisfile_png_chunk_type...xt['reindering_intent'] can also be of type double or false; however, getid3_png::PNGsRGBintentLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
182
					break;
183
184
185 View Code Duplication
				case 'iCCP': // Embedded ICC Profile
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
					$thisfile_png_chunk_type_text['header']                  = $chunk;
187
					list($profilename, $compressiondata)                     = explode("\x00", $chunk['data'], 2);
188
					$thisfile_png_chunk_type_text['profile_name']            = $profilename;
189
					$thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1));
190
					$thisfile_png_chunk_type_text['compression_profile']     = substr($compressiondata, 1);
191
192
					$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
193
					break;
194
195
196
				case 'tEXt': // Textual Data
197
					$thisfile_png_chunk_type_text['header']  = $chunk;
198
					list($keyword, $text) = explode("\x00", $chunk['data'], 2);
199
					$thisfile_png_chunk_type_text['keyword'] = $keyword;
200
					$thisfile_png_chunk_type_text['text']    = $text;
201
202
					$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
203
					break;
204
205
206
				case 'zTXt': // Compressed Textual Data
207
					$thisfile_png_chunk_type_text['header']                  = $chunk;
208
					list($keyword, $otherdata)                               = explode("\x00", $chunk['data'], 2);
209
					$thisfile_png_chunk_type_text['keyword']                 = $keyword;
210
					$thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
211
					$thisfile_png_chunk_type_text['compressed_text']         = substr($otherdata, 1);
212
					$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
213 View Code Duplication
					switch ($thisfile_png_chunk_type_text['compression_method']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214
						case 0:
215
							$thisfile_png_chunk_type_text['text']            = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
216
							break;
217
218
						default:
219
							// unknown compression method
220
							break;
221
					}
222
223 View Code Duplication
					if (isset($thisfile_png_chunk_type_text['text'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
224
						$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
225
					}
226
					break;
227
228
229
				case 'iTXt': // International Textual Data
230
					$thisfile_png_chunk_type_text['header']                  = $chunk;
231
					list($keyword, $otherdata)                               = explode("\x00", $chunk['data'], 2);
232
					$thisfile_png_chunk_type_text['keyword']                 = $keyword;
233
					$thisfile_png_chunk_type_text['compression']             = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
234
					$thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1));
235
					$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
0 ignored issues
show
Bug introduced by
It seems like $thisfile_png_chunk_type...t['compression_method'] can also be of type double or false; however, getid3_png::PNGcompressionMethodLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
236
					list($languagetag, $translatedkeyword, $text)                        = explode("\x00", substr($otherdata, 2), 3);
237
					$thisfile_png_chunk_type_text['language_tag']            = $languagetag;
238
					$thisfile_png_chunk_type_text['translated_keyword']      = $translatedkeyword;
239
240
					if ($thisfile_png_chunk_type_text['compression']) {
241
242 View Code Duplication
						switch ($thisfile_png_chunk_type_text['compression_method']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
243
							case 0:
244
								$thisfile_png_chunk_type_text['text']        = gzuncompress($text);
245
								break;
246
247
							default:
248
								// unknown compression method
249
								break;
250
						}
251
252
					} else {
253
254
						$thisfile_png_chunk_type_text['text']                = $text;
255
256
					}
257
258 View Code Duplication
					if (isset($thisfile_png_chunk_type_text['text'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
259
						$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
260
					}
261
					break;
262
263
264
				case 'bKGD': // Background Color
265
					$thisfile_png_chunk_type_text['header']                   = $chunk;
266
					switch ($thisfile_png['IHDR']['raw']['color_type']) {
267
						case 0:
268
						case 4:
269
							$thisfile_png_chunk_type_text['background_gray']  = getid3_lib::BigEndian2Int($chunk['data']);
270
							break;
271
272
						case 2:
273
						case 6:
274
							$thisfile_png_chunk_type_text['background_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
275
							$thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
276
							$thisfile_png_chunk_type_text['background_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
277
							break;
278
279
						case 3:
280
							$thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']);
281
							break;
282
283
						default:
284
							break;
285
					}
286
					break;
287
288
289
				case 'pHYs': // Physical Pixel Dimensions
290
					$thisfile_png_chunk_type_text['header']                 = $chunk;
291
					$thisfile_png_chunk_type_text['pixels_per_unit_x']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
292
					$thisfile_png_chunk_type_text['pixels_per_unit_y']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
293
					$thisfile_png_chunk_type_text['unit_specifier']         = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
294
					$thisfile_png_chunk_type_text['unit']                   = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
0 ignored issues
show
Bug introduced by
It seems like $thisfile_png_chunk_type_text['unit_specifier'] can also be of type double or false; however, getid3_png::PNGpHYsUnitLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
295
					break;
296
297
298
				case 'sBIT': // Significant Bits
299
					$thisfile_png_chunk_type_text['header'] = $chunk;
300
					switch ($thisfile_png['IHDR']['raw']['color_type']) {
301 View Code Duplication
						case 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
302
							$thisfile_png_chunk_type_text['significant_bits_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
303
							break;
304
305
						case 2:
306 View Code Duplication
						case 3:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307
							$thisfile_png_chunk_type_text['significant_bits_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
308
							$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
309
							$thisfile_png_chunk_type_text['significant_bits_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
310
							break;
311
312 View Code Duplication
						case 4:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
313
							$thisfile_png_chunk_type_text['significant_bits_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
314
							$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
315
							break;
316
317
						case 6:
318
							$thisfile_png_chunk_type_text['significant_bits_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
319
							$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
320
							$thisfile_png_chunk_type_text['significant_bits_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
321
							$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
322
							break;
323
324
						default:
325
							break;
326
					}
327
					break;
328
329
330
				case 'sPLT': // Suggested Palette
331
					$thisfile_png_chunk_type_text['header']                           = $chunk;
332
					list($palettename, $otherdata)                                    = explode("\x00", $chunk['data'], 2);
333
					$thisfile_png_chunk_type_text['palette_name']                     = $palettename;
334
					$sPLToffset = 0;
335
					$thisfile_png_chunk_type_text['sample_depth_bits']                = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
336
					$sPLToffset += 1;
337
					$thisfile_png_chunk_type_text['sample_depth_bytes']               = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
338
					$paletteCounter = 0;
339
					while ($sPLToffset < strlen($otherdata)) {
340
						$thisfile_png_chunk_type_text['red'][$paletteCounter]       = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
341
						$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
342
						$thisfile_png_chunk_type_text['green'][$paletteCounter]     = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
343
						$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
344
						$thisfile_png_chunk_type_text['blue'][$paletteCounter]      = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
345
						$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
346
						$thisfile_png_chunk_type_text['alpha'][$paletteCounter]     = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
347
						$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
348
						$thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2));
349
						$sPLToffset += 2;
350
						$paletteCounter++;
351
					}
352
					break;
353
354
355
				case 'hIST': // Palette Histogram
356
					$thisfile_png_chunk_type_text['header'] = $chunk;
357
					$hISTcounter = 0;
358
					while ($hISTcounter < strlen($chunk['data'])) {
359
						$thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2));
360
						$hISTcounter += 2;
361
					}
362
					break;
363
364
365
				case 'tIME': // Image Last-Modification Time
366
					$thisfile_png_chunk_type_text['header'] = $chunk;
367
					$thisfile_png_chunk_type_text['year']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
368
					$thisfile_png_chunk_type_text['month']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
369
					$thisfile_png_chunk_type_text['day']    = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
370
					$thisfile_png_chunk_type_text['hour']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1));
371
					$thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1));
372
					$thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1));
373
					$thisfile_png_chunk_type_text['unix']   = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']);
374
					break;
375
376
377
				case 'oFFs': // Image Offset
378
					$thisfile_png_chunk_type_text['header']         = $chunk;
379
					$thisfile_png_chunk_type_text['position_x']     = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true);
380
					$thisfile_png_chunk_type_text['position_y']     = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true);
381
					$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
382
					$thisfile_png_chunk_type_text['unit']           = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
0 ignored issues
show
Bug introduced by
It seems like $thisfile_png_chunk_type_text['unit_specifier'] can also be of type double or false; however, getid3_png::PNGoFFsUnitLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
383
					break;
384
385
386
				case 'pCAL': // Calibration Of Pixel Values
387
					$thisfile_png_chunk_type_text['header']             = $chunk;
388
					list($calibrationname, $otherdata)                              = explode("\x00", $chunk['data'], 2);
389
					$thisfile_png_chunk_type_text['calibration_name']   = $calibrationname;
390
					$pCALoffset = 0;
391
					$thisfile_png_chunk_type_text['original_zero']      = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
392
					$pCALoffset += 4;
393
					$thisfile_png_chunk_type_text['original_max']       = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
394
					$pCALoffset += 4;
395
					$thisfile_png_chunk_type_text['equation_type']      = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
396
					$pCALoffset += 1;
397
					$thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
0 ignored issues
show
Bug introduced by
It seems like $thisfile_png_chunk_type_text['equation_type'] can also be of type double or false; however, getid3_png::PNGpCALequationTypeLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
398
					$thisfile_png_chunk_type_text['parameter_count']    = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
399
					$pCALoffset += 1;
400
					$thisfile_png_chunk_type_text['parameters']         = explode("\x00", substr($chunk['data'], $pCALoffset));
401
					break;
402
403
404 View Code Duplication
				case 'sCAL': // Physical Scale Of Image Subject
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
405
					$thisfile_png_chunk_type_text['header']         = $chunk;
406
					$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
407
					$thisfile_png_chunk_type_text['unit']           = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
0 ignored issues
show
Bug introduced by
It seems like $thisfile_png_chunk_type_text['unit_specifier'] can also be of type double or false; however, getid3_png::PNGsCALUnitLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
408
					list($pixelwidth, $pixelheight)                             = explode("\x00", substr($chunk['data'], 1));
409
					$thisfile_png_chunk_type_text['pixel_width']    = $pixelwidth;
410
					$thisfile_png_chunk_type_text['pixel_height']   = $pixelheight;
411
					break;
412
413
414
				case 'gIFg': // GIF Graphic Control Extension
415
					$gIFgCounter = 0;
416
					if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
417
						$gIFgCounter = count($thisfile_png_chunk_type_text);
418
					}
419
					$thisfile_png_chunk_type_text[$gIFgCounter]['header']          = $chunk;
420
					$thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
421
					$thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
422
					$thisfile_png_chunk_type_text[$gIFgCounter]['delay_time']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
423
					break;
424
425
426
				case 'gIFx': // GIF Application Extension
427
					$gIFxCounter = 0;
428
					if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
429
						$gIFxCounter = count($thisfile_png_chunk_type_text);
430
					}
431
					$thisfile_png_chunk_type_text[$gIFxCounter]['header']                 = $chunk;
432
					$thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'],  0, 8);
433
					$thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code']    = substr($chunk['data'],  8, 3);
434
					$thisfile_png_chunk_type_text[$gIFxCounter]['application_data']       = substr($chunk['data'], 11);
435
					break;
436
437
438
				case 'IDAT': // Image Data
439
					$idatinformationfieldindex = 0;
440
					if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
441
						$idatinformationfieldindex = count($thisfile_png['IDAT']);
442
					}
443
					unset($chunk['data']);
444
					$thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
445
					break;
446
447
				case 'IEND': // Image Trailer
448
					$thisfile_png_chunk_type_text['header'] = $chunk;
449
					break;
450
451
				case 'acTL': // Animation Control chunk
452
					// https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk
453
					$thisfile_png['animation']['num_frames'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)); // Number of frames
454
					$thisfile_png['animation']['num_plays']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)); // Number of times to loop this APNG.  0 indicates infinite looping.
455
456
					unset($chunk['data']);
457
					$thisfile_png_chunk_type_text['header'] = $chunk;
458
					break;
459
460
				case 'fcTL': // Frame Control chunk
461
					// https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
462
					$fcTL = array();
463
					$fcTL['sequence_number'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  0, 4)); // Sequence number of the animation chunk, starting from 0
464
					$fcTL['width']           = getid3_lib::BigEndian2Int(substr($chunk['data'],  4, 4)); // Width of the following frame
465
					$fcTL['height']          = getid3_lib::BigEndian2Int(substr($chunk['data'],  8, 4)); // Height of the following frame
466
					$fcTL['x_offset']        = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)); // X position at which to render the following frame
467
					$fcTL['y_offset']        = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)); // Y position at which to render the following frame
468
					$fcTL['delay_num']       = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 2)); // Frame delay fraction numerator
469
					$fcTL['delay_den']       = getid3_lib::BigEndian2Int(substr($chunk['data'], 22, 2)); // Frame delay fraction numerator
470
					$fcTL['dispose_op']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 23, 1)); // Type of frame area disposal to be done after rendering this frame
471
					$fcTL['blend_op']        = getid3_lib::BigEndian2Int(substr($chunk['data'], 23, 1)); // Type of frame area rendering for this frame
472
					if ($fcTL['delay_den']) {
473
						$fcTL['delay'] = $fcTL['delay_num'] / $fcTL['delay_den'];
474
					}
475
					$thisfile_png['animation']['fcTL'][$fcTL['sequence_number']] = $fcTL;
476
477
					unset($chunk['data']);
478
					$thisfile_png_chunk_type_text['header'] = $chunk;
479
					break;
480
481
				case 'fdAT': // Frame Data chunk
482
					// https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
483
					// "The `fdAT` chunk has the same purpose as an `IDAT` chunk. It has the same structure as an `IDAT` chunk, except preceded by a sequence number."
484
					unset($chunk['data']);
485
					$thisfile_png_chunk_type_text['header'] = $chunk;
486
					break;
487
488
				default:
489
					//unset($chunk['data']);
490
					$thisfile_png_chunk_type_text['header'] = $chunk;
491
					$this->warning('Unhandled chunk type: '.$chunk['type_text']);
492
					break;
493
			}
494
		}
495
		if (!empty($thisfile_png['animation']['num_frames']) && !empty($thisfile_png['animation']['fcTL'])) {
496
			$info['video']['dataformat'] = 'apng';
497
			$info['playtime_seconds'] = 0;
498
			foreach ($thisfile_png['animation']['fcTL'] as $seqno => $fcTL) {
499
				$info['playtime_seconds'] += $fcTL['delay'];
500
			}
501
		}
502
		return true;
503
	}
504
505
	/**
506
	 * @param int $sRGB
507
	 *
508
	 * @return string
509
	 */
510
	public function PNGsRGBintentLookup($sRGB) {
511
		static $PNGsRGBintentLookup = array(
512
			0 => 'Perceptual',
513
			1 => 'Relative colorimetric',
514
			2 => 'Saturation',
515
			3 => 'Absolute colorimetric'
516
		);
517
		return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
518
	}
519
520
	/**
521
	 * @param int $compressionmethod
522
	 *
523
	 * @return string
524
	 */
525
	public function PNGcompressionMethodLookup($compressionmethod) {
526
		static $PNGcompressionMethodLookup = array(
527
			0 => 'deflate/inflate'
528
		);
529
		return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
530
	}
531
532
	/**
533
	 * @param int $unitid
534
	 *
535
	 * @return string
536
	 */
537
	public function PNGpHYsUnitLookup($unitid) {
538
		static $PNGpHYsUnitLookup = array(
539
			0 => 'unknown',
540
			1 => 'meter'
541
		);
542
		return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
543
	}
544
545
	/**
546
	 * @param int $unitid
547
	 *
548
	 * @return string
549
	 */
550
	public function PNGoFFsUnitLookup($unitid) {
551
		static $PNGoFFsUnitLookup = array(
552
			0 => 'pixel',
553
			1 => 'micrometer'
554
		);
555
		return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
556
	}
557
558
	/**
559
	 * @param int $equationtype
560
	 *
561
	 * @return string
562
	 */
563
	public function PNGpCALequationTypeLookup($equationtype) {
564
		static $PNGpCALequationTypeLookup = array(
565
			0 => 'Linear mapping',
566
			1 => 'Base-e exponential mapping',
567
			2 => 'Arbitrary-base exponential mapping',
568
			3 => 'Hyperbolic mapping'
569
		);
570
		return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid');
571
	}
572
573
	/**
574
	 * @param int $unitid
575
	 *
576
	 * @return string
577
	 */
578
	public function PNGsCALUnitLookup($unitid) {
579
		static $PNGsCALUnitLookup = array(
580
			0 => 'meter',
581
			1 => 'radian'
582
		);
583
		return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
584
	}
585
586
	/**
587
	 * @param int $color_type
588
	 * @param int $bit_depth
589
	 *
590
	 * @return int|false
591
	 */
592
	public function IHDRcalculateBitsPerSample($color_type, $bit_depth) {
593
		switch ($color_type) {
594
			case 0: // Each pixel is a grayscale sample.
595
				return $bit_depth;
596
597
			case 2: // Each pixel is an R,G,B triple
598
				return 3 * $bit_depth;
599
600
			case 3: // Each pixel is a palette index; a PLTE chunk must appear.
601
				return $bit_depth;
602
603
			case 4: // Each pixel is a grayscale sample, followed by an alpha sample.
604
				return 2 * $bit_depth;
605
606
			case 6: // Each pixel is an R,G,B triple, followed by an alpha sample.
607
				return 4 * $bit_depth;
608
		}
609
		return false;
610
	}
611
612
}
613