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

getid3_gif   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 192
Duplicated Lines 3.13 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 6
loc 192
rs 10
c 0
b 0
f 0
wmc 17
lcom 1
cbo 3

2 Methods

Rating   Name   Duplication   Size   Complexity  
F Analyze() 6 169 15
A GetLSBits() 0 10 2

How to fix   Duplicated Code   

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:

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.gif.php                                      //
12
// module for analyzing GIF Image files                        //
13
// dependencies: NONE                                          //
14
//                                                            ///
15
/////////////////////////////////////////////////////////////////
16
17
/**
18
 * @link https://www.w3.org/Graphics/GIF/spec-gif89a.txt
19
 * @link http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
20
 */
21
class getid3_gif extends getid3_handler
22
{
23
	/**
24
	 * @return bool
25
	 */
26
	public function Analyze() {
27
		$info = &$this->getid3->info;
28
29
		$info['fileformat']                  = 'gif';
30
		$info['video']['dataformat']         = 'gif';
31
		$info['video']['lossless']           = true;
32
		$info['video']['pixel_aspect_ratio'] = (float) 1;
33
34
		$this->fseek($info['avdataoffset']);
35
		$GIFheader = $this->fread(13);
36
		$offset = 0;
37
38
		$info['gif']['header']['raw']['identifier']            =                              substr($GIFheader, $offset, 3);
39
		$offset += 3;
40
41
		$magic = 'GIF';
42 View Code Duplication
		if ($info['gif']['header']['raw']['identifier'] != $magic) {
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...
43
			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['gif']['header']['raw']['identifier']).'"');
44
			unset($info['fileformat']);
45
			unset($info['gif']);
46
			return false;
47
		}
48
49
		//if (!$this->getid3->option_extra_info) {
50
		//	$this->warning('GIF Extensions and Global Color Table not returned due to !getid3->option_extra_info');
51
		//}
52
53
		$info['gif']['header']['raw']['version']               =                              substr($GIFheader, $offset, 3);
54
		$offset += 3;
55
		$info['gif']['header']['raw']['width']                 = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
56
		$offset += 2;
57
		$info['gif']['header']['raw']['height']                = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
58
		$offset += 2;
59
		$info['gif']['header']['raw']['flags']                 = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
60
		$offset += 1;
61
		$info['gif']['header']['raw']['bg_color_index']        = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
62
		$offset += 1;
63
		$info['gif']['header']['raw']['aspect_ratio']          = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
64
		$offset += 1;
65
66
		$info['video']['resolution_x']                         = $info['gif']['header']['raw']['width'];
67
		$info['video']['resolution_y']                         = $info['gif']['header']['raw']['height'];
68
		$info['gif']['version']                                = $info['gif']['header']['raw']['version'];
69
		$info['gif']['header']['flags']['global_color_table']  = (bool) ($info['gif']['header']['raw']['flags'] & 0x80);
70
		if ($info['gif']['header']['raw']['flags'] & 0x80) {
71
			// Number of bits per primary color available to the original image, minus 1
72
			$info['gif']['header']['bits_per_pixel']  = 3 * ((($info['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1);
73
		} else {
74
			$info['gif']['header']['bits_per_pixel']  = 0;
75
		}
76
		$info['gif']['header']['flags']['global_color_sorted'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x40);
77
		if ($info['gif']['header']['flags']['global_color_table']) {
78
			// the number of bytes contained in the Global Color Table. To determine that
79
			// actual size of the color table, raise 2 to [the value of the field + 1]
80
			$info['gif']['header']['global_color_size'] = pow(2, ($info['gif']['header']['raw']['flags'] & 0x07) + 1);
81
			$info['video']['bits_per_sample']           = ($info['gif']['header']['raw']['flags'] & 0x07) + 1;
82
		} else {
83
			$info['gif']['header']['global_color_size'] = 0;
84
		}
85
		if ($info['gif']['header']['raw']['aspect_ratio'] != 0) {
86
			// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
87
			$info['gif']['header']['aspect_ratio'] = ($info['gif']['header']['raw']['aspect_ratio'] + 15) / 64;
88
		}
89
90
		if ($info['gif']['header']['flags']['global_color_table']) {
91
			$GIFcolorTable = $this->fread(3 * $info['gif']['header']['global_color_size']);
92
			if ($this->getid3->option_extra_info) {
93
				$offset = 0;
94
				for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) {
95
					$red   = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
96
					$green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
97
					$blue  = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
98
					$info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
99
					$info['gif']['global_color_table_rgb'][$i] = sprintf('%02X%02X%02X', $red, $green, $blue);
100
				}
101
			}
102
		}
103
104
		// Image Descriptor
105
		$info['gif']['animation']['animated'] = false;
106
		while (!feof($this->getid3->fp)) {
107
			$NextBlockTest = $this->fread(1);
108
			switch ($NextBlockTest) {
109
110
/*
111
				case ',': // ',' - Image separator character
112
					$ImageDescriptorData = $NextBlockTest.$this->fread(9);
113
					$ImageDescriptor = array();
114
					$ImageDescriptor['image_left']   = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2));
115
					$ImageDescriptor['image_top']    = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2));
116
					$ImageDescriptor['image_width']  = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2));
117
					$ImageDescriptor['image_height'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2));
118
					$ImageDescriptor['flags_raw']    = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1));
119
					$ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80);
120
					$ImageDescriptor['flags']['image_interlaced']    = (bool) ($ImageDescriptor['flags_raw'] & 0x40);
121
					$info['gif']['image_descriptor'][] = $ImageDescriptor;
122
123
					if ($ImageDescriptor['flags']['use_local_color_map']) {
124
125
						$this->warning('This version of getID3() cannot parse local color maps for GIFs');
126
						return true;
127
128
					}
129
					$RasterData = array();
130
					$RasterData['code_size']        = getid3_lib::LittleEndian2Int($this->fread(1));
131
					$RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int($this->fread(1));
132
					$info['gif']['raster_data'][count($info['gif']['image_descriptor']) - 1] = $RasterData;
133
134
					$CurrentCodeSize = $RasterData['code_size'] + 1;
135
					for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) {
136
						$DefaultDataLookupTable[$i] = chr($i);
137
					}
138
					$DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code
139
					$DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code
140
141
					$NextValue = $this->GetLSBits($CurrentCodeSize);
142
					echo 'Clear Code: '.$NextValue.'<BR>';
143
144
					$NextValue = $this->GetLSBits($CurrentCodeSize);
145
					echo 'First Color: '.$NextValue.'<BR>';
146
147
					$Prefix = $NextValue;
148
					$i = 0;
149
					while ($i++ < 20) {
150
						$NextValue = $this->GetLSBits($CurrentCodeSize);
151
						echo $NextValue.'<br>';
152
					}
153
					echo 'escaping<br>';
154
					return true;
155
					break;
156
*/
157
158
				case '!':
159
					// GIF Extension Block
160
					$ExtensionBlockData = $NextBlockTest.$this->fread(2);
161
					$ExtensionBlock = array();
162
					$ExtensionBlock['function_code']  = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1));
163
					$ExtensionBlock['byte_length']    = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1));
164
					$ExtensionBlock['data']           = (($ExtensionBlock['byte_length'] > 0) ? $this->fread($ExtensionBlock['byte_length']) : null);
0 ignored issues
show
Bug introduced by
It seems like $ExtensionBlock['byte_length'] can also be of type double or false; however, getid3_handler::fread() 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...
165
166
					if (substr($ExtensionBlock['data'], 0, 11) == 'NETSCAPE2.0') { // Netscape Application Block (NAB)
167
						$ExtensionBlock['data'] .= $this->fread(4);
168
						if (substr($ExtensionBlock['data'], 11, 2) == "\x03\x01") {
169
							$info['gif']['animation']['animated']   = true;
170
							$info['gif']['animation']['loop_count'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlock['data'], 13, 2));
171
						} else {
172
							$this->warning('Expecting 03 01 at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes(substr($ExtensionBlock['data'], 11, 2)).'"');
173
						}
174
					}
175
176
					if ($this->getid3->option_extra_info) {
177
						$info['gif']['extension_blocks'][] = $ExtensionBlock;
178
					}
179
					break;
180
181
				case ';':
182
					$info['gif']['terminator_offset'] = $this->ftell() - 1;
183
					// GIF Terminator
184
					break;
185
186
				default:
187
					break;
188
189
190
			}
191
		}
192
193
		return true;
194
	}
195
196
	/**
197
	 * @param int $bits
198
	 *
199
	 * @return float|int
200
	 */
201
	public function GetLSBits($bits) {
202
		static $bitbuffer = '';
203
		while (strlen($bitbuffer) < $bits) {
204
			$bitbuffer = str_pad(decbin(ord($this->fread(1))), 8, '0', STR_PAD_LEFT).$bitbuffer;
205
		}
206
		$value = bindec(substr($bitbuffer, 0 - $bits));
207
		$bitbuffer = substr($bitbuffer, 0, 0 - $bits);
208
209
		return $value;
210
	}
211
212
}
213