59 self::$gifFrameSep = pack(
"C", ord(
"," ) );
60 self::$gifExtensionSep = pack(
"C", ord(
"!" ) );
61 self::$gifTerm = pack(
"C", ord(
";" ) );
70 throw new InvalidArgumentException(
'No file name specified' );
72 if ( !file_exists( $filename ) || is_dir( $filename ) ) {
73 throw new InvalidArgumentException(
"File $filename does not exist" );
76 $fh = fopen( $filename,
'rb' );
79 throw new InvalidArgumentException(
"Unable to open file $filename" );
83 $buf = fread( $fh, 6 );
84 if ( !( $buf ===
'GIF87a' || $buf ===
'GIF89a' ) ) {
85 throw new InvalidArgumentException(
"Not a valid GIF file; header: $buf" );
89 $buf = fread( $fh, 2 );
90 if ( strlen( $buf ) < 2 ) {
91 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read width." );
93 $width = unpack(
'v', $buf )[1];
94 $buf = fread( $fh, 2 );
95 if ( strlen( $buf ) < 2 ) {
96 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read height." );
98 $height = unpack(
'v', $buf )[1];
101 $buf = fread( $fh, 1 );
102 [ $bpp, $have_map ] = self::decodeBPP( $buf );
110 self::readGCT( $fh, $bpp );
113 while ( !feof( $fh ) ) {
114 $buf = fread( $fh, 1 );
116 if ( $buf === self::$gifFrameSep ) {
120 # # Skip bounding box
125 $buf = fread( $fh, 1 );
126 [ $bpp, $have_map ] = self::decodeBPP( $buf );
130 self::readGCT( $fh, $bpp );
134 self::skipBlock( $fh );
135 } elseif ( $buf === self::$gifExtensionSep ) {
136 $buf = fread( $fh, 1 );
137 if ( strlen( $buf ) < 1 ) {
138 throw new InvalidArgumentException(
139 "Not a valid GIF file; Unable to read graphics control extension."
142 $extension_code = unpack(
'C', $buf )[1];
144 if ( $extension_code === 0xF9 ) {
153 $buf = fread( $fh, 2 );
154 if ( strlen( $buf ) < 2 ) {
155 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read delay" );
157 $delay = unpack(
'v', $buf )[1];
158 $duration += $delay * 0.01;
163 $term = fread( $fh, 1 );
164 if ( strlen( $term ) < 1 ) {
165 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read terminator byte" );
167 $term = unpack(
'C', $term )[1];
169 throw new InvalidArgumentException(
"Malformed Graphics Control Extension block" );
171 } elseif ( $extension_code === 0xFE ) {
173 $data = self::readBlock( $fh );
174 if ( $data ===
"" ) {
175 throw new InvalidArgumentException(
'Read error, zero-length comment block' );
183 UtfNormal\Validator::quickIsNFCVerify( $dataCopy );
185 if ( $dataCopy !== $data ) {
186 AtEase::suppressWarnings();
187 $data = iconv(
'windows-1252',
'UTF-8', $data );
188 AtEase::restoreWarnings();
191 $commentCount = count( $comment );
192 if ( $commentCount === 0
194 || $comment[$commentCount - 1] !== $data
201 } elseif ( $extension_code === 0xFF ) {
204 $blockLength = fread( $fh, 1 );
205 if ( strlen( $blockLength ) < 1 ) {
206 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read block length" );
208 $blockLength = unpack(
'C', $blockLength )[1];
209 $data = fread( $fh, $blockLength );
211 if ( $blockLength !== 11 ) {
212 wfDebug( __METHOD__ .
" GIF application block with wrong length" );
213 fseek( $fh, -( $blockLength + 1 ), SEEK_CUR );
214 self::skipBlock( $fh );
219 if ( $data ===
'NETSCAPE2.0' ) {
220 $data = fread( $fh, 2 );
222 if ( $data !==
"\x03\x01" ) {
223 throw new InvalidArgumentException(
"Expected \x03\x01, got $data" );
227 $loopData = fread( $fh, 2 );
228 if ( strlen( $loopData ) < 2 ) {
229 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read loop count" );
231 $loopCount = unpack(
'v', $loopData )[1];
233 if ( $loopCount !== 1 ) {
240 } elseif ( $data ===
'XMP DataXMP' ) {
244 $xmp = self::readBlock( $fh,
true );
246 if ( substr( $xmp, -257, 3 ) !==
"\x01\xFF\xFE"
247 || substr( $xmp, -4 ) !==
"\x03\x02\x01\x00"
249 throw new InvalidArgumentException(
"XMP does not have magic trailer!" );
253 $xmp = substr( $xmp, 0, -257 );
256 fseek( $fh, -( $blockLength + 1 ), SEEK_CUR );
257 self::skipBlock( $fh );
260 self::skipBlock( $fh );
262 } elseif ( $buf === self::$gifTerm ) {
265 if ( strlen( $buf ) < 1 ) {
266 throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read unknown byte." );
268 $byte = unpack(
'C', $buf )[1];
269 throw new InvalidArgumentException(
"At position: " . ftell( $fh ) .
", Unknown byte " . $byte );
274 'frameCount' => $frameCount,
275 'looped' => $isLooped,
276 'duration' => $duration,
278 'comment' => $comment,