xref: /PHP-7.2/ext/standard/image.c (revision ff577b04)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
16    |          Marcus Boerger <helly@php.net>                              |
17    +----------------------------------------------------------------------+
18  */
19 
20 /* $Id$ */
21 
22 #include "php.h"
23 #include <stdio.h>
24 #if HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27 #include "fopen_wrappers.h"
28 #include "ext/standard/fsock.h"
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include "php_image.h"
33 #ifdef PHP_WIN32
34 #include "win32/php_stdint.h"
35 #endif
36 
37 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
38 #include "zlib.h"
39 #endif
40 
41 /* file type markers */
42 PHPAPI const char php_sig_gif[3] = {'G', 'I', 'F'};
43 PHPAPI const char php_sig_psd[4] = {'8', 'B', 'P', 'S'};
44 PHPAPI const char php_sig_bmp[2] = {'B', 'M'};
45 PHPAPI const char php_sig_swf[3] = {'F', 'W', 'S'};
46 PHPAPI const char php_sig_swc[3] = {'C', 'W', 'S'};
47 PHPAPI const char php_sig_jpg[3] = {(char) 0xff, (char) 0xd8, (char) 0xff};
48 PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
49                                     (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
50 PHPAPI const char php_sig_tif_ii[4] = {'I','I', (char)0x2A, (char)0x00};
51 PHPAPI const char php_sig_tif_mm[4] = {'M','M', (char)0x00, (char)0x2A};
52 PHPAPI const char php_sig_jpc[3]  = {(char)0xff, (char)0x4f, (char)0xff};
53 PHPAPI const char php_sig_jp2[12] = {(char)0x00, (char)0x00, (char)0x00, (char)0x0c,
54                                      (char)0x6a, (char)0x50, (char)0x20, (char)0x20,
55                                      (char)0x0d, (char)0x0a, (char)0x87, (char)0x0a};
56 PHPAPI const char php_sig_iff[4] = {'F','O','R','M'};
57 PHPAPI const char php_sig_ico[4] = {(char)0x00, (char)0x00, (char)0x01, (char)0x00};
58 PHPAPI const char php_sig_riff[4] = {'R', 'I', 'F', 'F'};
59 PHPAPI const char php_sig_webp[4] = {'W', 'E', 'B', 'P'};
60 
61 /* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */
62 /* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */
63 
64 /* return info as a struct, to make expansion easier */
65 
66 struct gfxinfo {
67 	unsigned int width;
68 	unsigned int height;
69 	unsigned int bits;
70 	unsigned int channels;
71 };
72 
73 /* {{{ PHP_MINIT_FUNCTION(imagetypes)
74  * Register IMAGETYPE_<xxx> constants used by GetImageSize(), image_type_to_mime_type, ext/exif */
PHP_MINIT_FUNCTION(imagetypes)75 PHP_MINIT_FUNCTION(imagetypes)
76 {
77 	REGISTER_LONG_CONSTANT("IMAGETYPE_GIF",     IMAGE_FILETYPE_GIF,     CONST_CS | CONST_PERSISTENT);
78 	REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG",    IMAGE_FILETYPE_JPEG,    CONST_CS | CONST_PERSISTENT);
79 	REGISTER_LONG_CONSTANT("IMAGETYPE_PNG",     IMAGE_FILETYPE_PNG,     CONST_CS | CONST_PERSISTENT);
80 	REGISTER_LONG_CONSTANT("IMAGETYPE_SWF",     IMAGE_FILETYPE_SWF,     CONST_CS | CONST_PERSISTENT);
81 	REGISTER_LONG_CONSTANT("IMAGETYPE_PSD",     IMAGE_FILETYPE_PSD,     CONST_CS | CONST_PERSISTENT);
82 	REGISTER_LONG_CONSTANT("IMAGETYPE_BMP",     IMAGE_FILETYPE_BMP,     CONST_CS | CONST_PERSISTENT);
83 	REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_II", IMAGE_FILETYPE_TIFF_II, CONST_CS | CONST_PERSISTENT);
84 	REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_MM", IMAGE_FILETYPE_TIFF_MM, CONST_CS | CONST_PERSISTENT);
85 	REGISTER_LONG_CONSTANT("IMAGETYPE_JPC",     IMAGE_FILETYPE_JPC,     CONST_CS | CONST_PERSISTENT);
86 	REGISTER_LONG_CONSTANT("IMAGETYPE_JP2",     IMAGE_FILETYPE_JP2,     CONST_CS | CONST_PERSISTENT);
87 	REGISTER_LONG_CONSTANT("IMAGETYPE_JPX",     IMAGE_FILETYPE_JPX,     CONST_CS | CONST_PERSISTENT);
88 	REGISTER_LONG_CONSTANT("IMAGETYPE_JB2",     IMAGE_FILETYPE_JB2,     CONST_CS | CONST_PERSISTENT);
89 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
90 	REGISTER_LONG_CONSTANT("IMAGETYPE_SWC",     IMAGE_FILETYPE_SWC,     CONST_CS | CONST_PERSISTENT);
91 #endif
92 	REGISTER_LONG_CONSTANT("IMAGETYPE_IFF",     IMAGE_FILETYPE_IFF,     CONST_CS | CONST_PERSISTENT);
93 	REGISTER_LONG_CONSTANT("IMAGETYPE_WBMP",    IMAGE_FILETYPE_WBMP,    CONST_CS | CONST_PERSISTENT);
94 	REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG2000",IMAGE_FILETYPE_JPC,     CONST_CS | CONST_PERSISTENT); /* keep alias */
95 	REGISTER_LONG_CONSTANT("IMAGETYPE_XBM",     IMAGE_FILETYPE_XBM,     CONST_CS | CONST_PERSISTENT);
96 	REGISTER_LONG_CONSTANT("IMAGETYPE_ICO",     IMAGE_FILETYPE_ICO,     CONST_CS | CONST_PERSISTENT);
97 	REGISTER_LONG_CONSTANT("IMAGETYPE_WEBP",	IMAGE_FILETYPE_WEBP,	CONST_CS | CONST_PERSISTENT);
98 	REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT);
99 	REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT",   IMAGE_FILETYPE_COUNT,   CONST_CS | CONST_PERSISTENT);
100 	return SUCCESS;
101 }
102 /* }}} */
103 
104 /* {{{ php_handle_gif
105  * routine to handle GIF files. If only everything were that easy... ;} */
php_handle_gif(php_stream * stream)106 static struct gfxinfo *php_handle_gif (php_stream * stream)
107 {
108 	struct gfxinfo *result = NULL;
109 	unsigned char dim[5];
110 
111 	if (php_stream_seek(stream, 3, SEEK_CUR))
112 		return NULL;
113 
114 	if (php_stream_read(stream, (char*)dim, sizeof(dim)) != sizeof(dim))
115 		return NULL;
116 
117 	result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
118 	result->width    = (unsigned int)dim[0] | (((unsigned int)dim[1])<<8);
119 	result->height   = (unsigned int)dim[2] | (((unsigned int)dim[3])<<8);
120 	result->bits     = dim[4]&0x80 ? ((((unsigned int)dim[4])&0x07) + 1) : 0;
121 	result->channels = 3; /* always */
122 
123 	return result;
124 }
125 /* }}} */
126 
127 /* {{{ php_handle_psd
128  */
php_handle_psd(php_stream * stream)129 static struct gfxinfo *php_handle_psd (php_stream * stream)
130 {
131 	struct gfxinfo *result = NULL;
132 	unsigned char dim[8];
133 
134 	if (php_stream_seek(stream, 11, SEEK_CUR))
135 		return NULL;
136 
137 	if (php_stream_read(stream, (char*)dim, sizeof(dim)) != sizeof(dim))
138 		return NULL;
139 
140 	result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
141 	result->height   =  (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
142 	result->width    =  (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
143 
144 	return result;
145 }
146 /* }}} */
147 
148 /* {{{ php_handle_bmp
149  */
php_handle_bmp(php_stream * stream)150 static struct gfxinfo *php_handle_bmp (php_stream * stream)
151 {
152 	struct gfxinfo *result = NULL;
153 	unsigned char dim[16];
154 	int size;
155 
156 	if (php_stream_seek(stream, 11, SEEK_CUR))
157 		return NULL;
158 
159 	if (php_stream_read(stream, (char*)dim, sizeof(dim)) != sizeof(dim))
160 		return NULL;
161 
162 	size   = (((unsigned int)dim[ 3]) << 24) + (((unsigned int)dim[ 2]) << 16) + (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]);
163 	if (size == 12) {
164 		result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo));
165 		result->width    =  (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);
166 		result->height   =  (((unsigned int)dim[ 7]) << 8) + ((unsigned int) dim[ 6]);
167 		result->bits     =  ((unsigned int)dim[11]);
168 	} else if (size > 12 && (size <= 64 || size == 108 || size == 124)) {
169 		result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo));
170 		result->width    =  (((unsigned int)dim[ 7]) << 24) + (((unsigned int)dim[ 6]) << 16) + (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);
171 		result->height   =  (((unsigned int)dim[11]) << 24) + (((unsigned int)dim[10]) << 16) + (((unsigned int)dim[ 9]) << 8) + ((unsigned int) dim[ 8]);
172 		result->height   =  abs((int32_t)result->height);
173 		result->bits     =  (((unsigned int)dim[15]) <<  8) +  ((unsigned int)dim[14]);
174 	} else {
175 		return NULL;
176 	}
177 
178 	return result;
179 }
180 /* }}} */
181 
182 /* {{{ php_swf_get_bits
183  * routines to handle SWF files. */
php_swf_get_bits(unsigned char * buffer,unsigned int pos,unsigned int count)184 static unsigned long int php_swf_get_bits (unsigned char* buffer, unsigned int pos, unsigned int count)
185 {
186 	unsigned int loop;
187 	unsigned long int result = 0;
188 
189 	for (loop = pos; loop < pos + count; loop++)
190 	{
191 		result = result +
192 			((((buffer[loop / 8]) >> (7 - (loop % 8))) & 0x01) << (count - (loop - pos) - 1));
193 	}
194 	return result;
195 }
196 /* }}} */
197 
198 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
199 /* {{{ php_handle_swc
200  */
php_handle_swc(php_stream * stream)201 static struct gfxinfo *php_handle_swc(php_stream * stream)
202 {
203 	struct gfxinfo *result = NULL;
204 
205 	long bits;
206 	unsigned char a[64];
207 	unsigned long len=64, szlength;
208 	int factor = 1,maxfactor = 16;
209 	int status = 0;
210 	unsigned char *b, *buf = NULL;
211 	zend_string *bufz;
212 
213 	if (php_stream_seek(stream, 5, SEEK_CUR)) {
214 		return NULL;
215 	}
216 
217 	if (php_stream_read(stream, (char *) a, sizeof(a)) != sizeof(a)) {
218 		return NULL;
219 	}
220 
221 	b = ecalloc(1, len + 1);
222 
223 	if (uncompress(b, &len, a, sizeof(a)) != Z_OK) {
224 		/* failed to decompress the file, will try reading the rest of the file */
225 		if (php_stream_seek(stream, 8, SEEK_SET)) {
226 			efree(b);
227 			return NULL;
228 		}
229 
230 		bufz = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
231 
232 		if (!bufz) {
233 			efree(b);
234 			return NULL;
235 		}
236 
237 		/*
238 		 * zlib::uncompress() wants to know the output data length
239 		 * if none was given as a parameter
240 		 * we try from input length * 2 up to input length * 2^8
241 		 * doubling it whenever it wasn't big enough
242 		 * that should be eneugh for all real life cases
243 		*/
244 
245 		do {
246 			szlength = ZSTR_LEN(bufz) * (1<<factor++);
247 			buf = erealloc(buf, szlength);
248 			status = uncompress(buf, &szlength, (unsigned char *) ZSTR_VAL(bufz), ZSTR_LEN(bufz));
249 		} while ((status==Z_BUF_ERROR)&&(factor<maxfactor));
250 
251 		if (bufz) {
252 			zend_string_release(bufz);
253 		}
254 
255 		if (status == Z_OK) {
256 			 memcpy(b, buf, len);
257 		}
258 
259 		if (buf) {
260 			efree(buf);
261 		}
262 	}
263 
264 	if (!status) {
265 		result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
266 		bits = php_swf_get_bits (b, 0, 5);
267 		result->width = (php_swf_get_bits (b, 5 + bits, bits) -
268 			php_swf_get_bits (b, 5, bits)) / 20;
269 		result->height = (php_swf_get_bits (b, 5 + (3 * bits), bits) -
270 			php_swf_get_bits (b, 5 + (2 * bits), bits)) / 20;
271 	} else {
272 		result = NULL;
273 	}
274 
275 	efree (b);
276 	return result;
277 }
278 /* }}} */
279 #endif
280 
281 /* {{{ php_handle_swf
282  */
php_handle_swf(php_stream * stream)283 static struct gfxinfo *php_handle_swf (php_stream * stream)
284 {
285 	struct gfxinfo *result = NULL;
286 	long bits;
287 	unsigned char a[32];
288 
289 	if (php_stream_seek(stream, 5, SEEK_CUR))
290 		return NULL;
291 
292 	if (php_stream_read(stream, (char*)a, sizeof(a)) != sizeof(a))
293 		return NULL;
294 
295 	result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
296 	bits = php_swf_get_bits (a, 0, 5);
297 	result->width = (php_swf_get_bits (a, 5 + bits, bits) -
298 		php_swf_get_bits (a, 5, bits)) / 20;
299 	result->height = (php_swf_get_bits (a, 5 + (3 * bits), bits) -
300 		php_swf_get_bits (a, 5 + (2 * bits), bits)) / 20;
301 	result->bits     = 0;
302 	result->channels = 0;
303 	return result;
304 }
305 /* }}} */
306 
307 /* {{{ php_handle_png
308  * routine to handle PNG files */
php_handle_png(php_stream * stream)309 static struct gfxinfo *php_handle_png (php_stream * stream)
310 {
311 	struct gfxinfo *result = NULL;
312 	unsigned char dim[9];
313 /* Width:              4 bytes
314  * Height:             4 bytes
315  * Bit depth:          1 byte
316  * Color type:         1 byte
317  * Compression method: 1 byte
318  * Filter method:      1 byte
319  * Interlace method:   1 byte
320  */
321 
322 	if (php_stream_seek(stream, 8, SEEK_CUR))
323 		return NULL;
324 
325 	if((php_stream_read(stream, (char*)dim, sizeof(dim))) < sizeof(dim))
326 		return NULL;
327 
328 	result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
329 	result->width  = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
330 	result->height = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
331 	result->bits   = (unsigned int)dim[8];
332 	return result;
333 }
334 /* }}} */
335 
336 /* routines to handle JPEG data */
337 
338 /* some defines for the different JPEG block types */
339 #define M_SOF0  0xC0			/* Start Of Frame N */
340 #define M_SOF1  0xC1			/* N indicates which compression process */
341 #define M_SOF2  0xC2			/* Only SOF0-SOF2 are now in common use */
342 #define M_SOF3  0xC3
343 #define M_SOF5  0xC5			/* NB: codes C4 and CC are NOT SOF markers */
344 #define M_SOF6  0xC6
345 #define M_SOF7  0xC7
346 #define M_SOF9  0xC9
347 #define M_SOF10 0xCA
348 #define M_SOF11 0xCB
349 #define M_SOF13 0xCD
350 #define M_SOF14 0xCE
351 #define M_SOF15 0xCF
352 #define M_SOI   0xD8
353 #define M_EOI   0xD9			/* End Of Image (end of datastream) */
354 #define M_SOS   0xDA			/* Start Of Scan (begins compressed data) */
355 #define M_APP0  0xe0
356 #define M_APP1  0xe1
357 #define M_APP2  0xe2
358 #define M_APP3  0xe3
359 #define M_APP4  0xe4
360 #define M_APP5  0xe5
361 #define M_APP6  0xe6
362 #define M_APP7  0xe7
363 #define M_APP8  0xe8
364 #define M_APP9  0xe9
365 #define M_APP10 0xea
366 #define M_APP11 0xeb
367 #define M_APP12 0xec
368 #define M_APP13 0xed
369 #define M_APP14 0xee
370 #define M_APP15 0xef
371 #define M_COM   0xFE            /* COMment                                  */
372 
373 #define M_PSEUDO 0xFFD8			/* pseudo marker for start of image(byte 0) */
374 
375 /* {{{ php_read2
376  */
php_read2(php_stream * stream)377 static unsigned short php_read2(php_stream * stream)
378 {
379 	unsigned char a[2];
380 
381 	/* return 0 if we couldn't read enough data */
382 	if((php_stream_read(stream, (char *) a, sizeof(a))) < sizeof(a)) return 0;
383 
384 	return (((unsigned short)a[0]) << 8) + ((unsigned short)a[1]);
385 }
386 /* }}} */
387 
388 /* {{{ php_next_marker
389  * get next marker byte from file */
php_next_marker(php_stream * stream,int last_marker,int ff_read)390 static unsigned int php_next_marker(php_stream * stream, int last_marker, int ff_read)
391 {
392 	int a=0, marker;
393 
394 	/* get marker byte, swallowing possible padding                           */
395 	if (!ff_read) {
396 		size_t extraneous = 0;
397 
398 		while ((marker = php_stream_getc(stream)) != 0xff) {
399 			if (marker == EOF) {
400 				return M_EOI;/* we hit EOF */
401 	}
402 			extraneous++;
403 	}
404 		if (extraneous) {
405 			php_error_docref(NULL, E_WARNING, "corrupt JPEG data: %zu extraneous bytes before marker", extraneous);
406 		}
407 	}
408 	a = 1;
409 	do {
410 		if ((marker = php_stream_getc(stream)) == EOF)
411 		{
412 			return M_EOI;/* we hit EOF */
413 		}
414 		a++;
415 	} while (marker == 0xff);
416 	if (a < 2)
417 	{
418 		return M_EOI; /* at least one 0xff is needed before marker code */
419 	}
420 	return (unsigned int)marker;
421 }
422 /* }}} */
423 
424 /* {{{ php_skip_variable
425  * skip over a variable-length block; assumes proper length marker */
php_skip_variable(php_stream * stream)426 static int php_skip_variable(php_stream * stream)
427 {
428 	zend_off_t length = ((unsigned int)php_read2(stream));
429 
430 	if (length < 2)	{
431 		return 0;
432 	}
433 	length = length - 2;
434 	php_stream_seek(stream, (zend_long)length, SEEK_CUR);
435 	return 1;
436 }
437 /* }}} */
438 
439 /* {{{ php_read_APP
440  */
php_read_APP(php_stream * stream,unsigned int marker,zval * info)441 static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
442 {
443 	unsigned short length;
444 	char *buffer;
445 	char markername[16];
446 	zval *tmp;
447 
448 	length = php_read2(stream);
449 	if (length < 2)	{
450 		return 0;
451 	}
452 	length -= 2;				/* length includes itself */
453 
454 	buffer = emalloc(length);
455 
456 	if (php_stream_read(stream, buffer, (zend_long) length) != length) {
457 		efree(buffer);
458 		return 0;
459 	}
460 
461 	snprintf(markername, sizeof(markername), "APP%d", marker - M_APP0);
462 
463 	if ((tmp = zend_hash_str_find(Z_ARRVAL_P(info), markername, strlen(markername))) == NULL) {
464 		/* XXX we only catch the 1st tag of it's kind! */
465 		add_assoc_stringl(info, markername, buffer, length);
466 	}
467 
468 	efree(buffer);
469 	return 1;
470 }
471 /* }}} */
472 
473 /* {{{ php_handle_jpeg
474    main loop to parse JPEG structure */
php_handle_jpeg(php_stream * stream,zval * info)475 static struct gfxinfo *php_handle_jpeg (php_stream * stream, zval *info)
476 {
477 	struct gfxinfo *result = NULL;
478 	unsigned int marker = M_PSEUDO;
479 	unsigned short length, ff_read=1;
480 
481 	for (;;) {
482 		marker = php_next_marker(stream, marker, ff_read);
483 		ff_read = 0;
484 		switch (marker) {
485 			case M_SOF0:
486 			case M_SOF1:
487 			case M_SOF2:
488 			case M_SOF3:
489 			case M_SOF5:
490 			case M_SOF6:
491 			case M_SOF7:
492 			case M_SOF9:
493 			case M_SOF10:
494 			case M_SOF11:
495 			case M_SOF13:
496 			case M_SOF14:
497 			case M_SOF15:
498 				if (result == NULL) {
499 					/* handle SOFn block */
500 					result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
501 					length = php_read2(stream);
502 					result->bits     = php_stream_getc(stream);
503 					result->height   = php_read2(stream);
504 					result->width    = php_read2(stream);
505 					result->channels = php_stream_getc(stream);
506 					if (!info || length < 8) { /* if we don't want an extanded info -> return */
507 						return result;
508 					}
509 					if (php_stream_seek(stream, length - 8, SEEK_CUR)) { /* file error after info */
510 						return result;
511 					}
512 				} else {
513 					if (!php_skip_variable(stream)) {
514 						return result;
515 					}
516 				}
517 				break;
518 
519 			case M_APP0:
520 			case M_APP1:
521 			case M_APP2:
522 			case M_APP3:
523 			case M_APP4:
524 			case M_APP5:
525 			case M_APP6:
526 			case M_APP7:
527 			case M_APP8:
528 			case M_APP9:
529 			case M_APP10:
530 			case M_APP11:
531 			case M_APP12:
532 			case M_APP13:
533 			case M_APP14:
534 			case M_APP15:
535 				if (info) {
536 					if (!php_read_APP(stream, marker, info)) { /* read all the app marks... */
537 						return result;
538 					}
539 				} else {
540 					if (!php_skip_variable(stream)) {
541 						return result;
542 					}
543 				}
544 				break;
545 
546 			case M_SOS:
547 			case M_EOI:
548 				return result;	/* we're about to hit image data, or are at EOF. stop processing. */
549 
550 			default:
551 				if (!php_skip_variable(stream)) { /* anything else isn't interesting */
552 					return result;
553 				}
554 				break;
555 		}
556 	}
557 
558 	return result; /* perhaps image broken -> no info but size */
559 }
560 /* }}} */
561 
562 /* {{{ php_read4
563  */
php_read4(php_stream * stream)564 static unsigned int php_read4(php_stream * stream)
565 {
566 	unsigned char a[4];
567 
568 	/* just return 0 if we hit the end-of-file */
569 	if ((php_stream_read(stream, (char*)a, sizeof(a))) != sizeof(a)) return 0;
570 
571 	return (((unsigned int)a[0]) << 24)
572 	     + (((unsigned int)a[1]) << 16)
573 	     + (((unsigned int)a[2]) <<  8)
574 	     + (((unsigned int)a[3]));
575 }
576 /* }}} */
577 
578 /* {{{ JPEG 2000 Marker Codes */
579 #define JPEG2000_MARKER_PREFIX 0xFF /* All marker codes start with this */
580 #define JPEG2000_MARKER_SOC 0x4F /* Start of Codestream */
581 #define JPEG2000_MARKER_SOT 0x90 /* Start of Tile part */
582 #define JPEG2000_MARKER_SOD 0x93 /* Start of Data */
583 #define JPEG2000_MARKER_EOC 0xD9 /* End of Codestream */
584 #define JPEG2000_MARKER_SIZ 0x51 /* Image and tile size */
585 #define JPEG2000_MARKER_COD 0x52 /* Coding style default */
586 #define JPEG2000_MARKER_COC 0x53 /* Coding style component */
587 #define JPEG2000_MARKER_RGN 0x5E /* Region of interest */
588 #define JPEG2000_MARKER_QCD 0x5C /* Quantization default */
589 #define JPEG2000_MARKER_QCC 0x5D /* Quantization component */
590 #define JPEG2000_MARKER_POC 0x5F /* Progression order change */
591 #define JPEG2000_MARKER_TLM 0x55 /* Tile-part lengths */
592 #define JPEG2000_MARKER_PLM 0x57 /* Packet length, main header */
593 #define JPEG2000_MARKER_PLT 0x58 /* Packet length, tile-part header */
594 #define JPEG2000_MARKER_PPM 0x60 /* Packed packet headers, main header */
595 #define JPEG2000_MARKER_PPT 0x61 /* Packed packet headers, tile part header */
596 #define JPEG2000_MARKER_SOP 0x91 /* Start of packet */
597 #define JPEG2000_MARKER_EPH 0x92 /* End of packet header */
598 #define JPEG2000_MARKER_CRG 0x63 /* Component registration */
599 #define JPEG2000_MARKER_COM 0x64 /* Comment */
600 /* }}} */
601 
602 /* {{{ php_handle_jpc
603    Main loop to parse JPEG2000 raw codestream structure */
php_handle_jpc(php_stream * stream)604 static struct gfxinfo *php_handle_jpc(php_stream * stream)
605 {
606 	struct gfxinfo *result = NULL;
607 	int highest_bit_depth, bit_depth;
608 	unsigned char first_marker_id;
609 	unsigned int i;
610 
611 	/* JPEG 2000 components can be vastly different from one another.
612 	   Each component can be sampled at a different resolution, use
613 	   a different colour space, have a separate colour depth, and
614 	   be compressed totally differently! This makes giving a single
615 	   "bit depth" answer somewhat problematic. For this implementation
616 	   we'll use the highest depth encountered. */
617 
618 	/* Get the single byte that remains after the file type indentification */
619 	first_marker_id = php_stream_getc(stream);
620 
621 	/* Ensure that this marker is SIZ (as is mandated by the standard) */
622 	if (first_marker_id != JPEG2000_MARKER_SIZ) {
623 		php_error_docref(NULL, E_WARNING, "JPEG2000 codestream corrupt(Expected SIZ marker not found after SOC)");
624 		return NULL;
625 	}
626 
627 	result = (struct gfxinfo *)ecalloc(1, sizeof(struct gfxinfo));
628 
629 	php_read2(stream); /* Lsiz */
630 	php_read2(stream); /* Rsiz */
631 	result->width = php_read4(stream); /* Xsiz */
632 	result->height = php_read4(stream); /* Ysiz */
633 
634 #if MBO_0
635 	php_read4(stream); /* XOsiz */
636 	php_read4(stream); /* YOsiz */
637 	php_read4(stream); /* XTsiz */
638 	php_read4(stream); /* YTsiz */
639 	php_read4(stream); /* XTOsiz */
640 	php_read4(stream); /* YTOsiz */
641 #else
642 	if (php_stream_seek(stream, 24, SEEK_CUR)) {
643 		efree(result);
644 		return NULL;
645 	}
646 #endif
647 
648 	result->channels = php_read2(stream); /* Csiz */
649 	if ((result->channels == 0 && php_stream_eof(stream)) || result->channels > 256) {
650 		efree(result);
651 		return NULL;
652 	}
653 
654 	/* Collect bit depth info */
655 	highest_bit_depth = 0;
656 	for (i = 0; i < result->channels; i++) {
657 		bit_depth = php_stream_getc(stream); /* Ssiz[i] */
658 		bit_depth++;
659 		if (bit_depth > highest_bit_depth) {
660 			highest_bit_depth = bit_depth;
661 		}
662 
663 		php_stream_getc(stream); /* XRsiz[i] */
664 		php_stream_getc(stream); /* YRsiz[i] */
665 	}
666 
667 	result->bits = highest_bit_depth;
668 
669 	return result;
670 }
671 /* }}} */
672 
673 /* {{{ php_handle_jp2
674    main loop to parse JPEG 2000 JP2 wrapper format structure */
php_handle_jp2(php_stream * stream)675 static struct gfxinfo *php_handle_jp2(php_stream *stream)
676 {
677 	struct gfxinfo *result = NULL;
678 	unsigned int box_length;
679 	unsigned int box_type;
680 	char jp2c_box_id[] = {(char)0x6a, (char)0x70, (char)0x32, (char)0x63};
681 
682 	/* JP2 is a wrapper format for JPEG 2000. Data is contained within "boxes".
683 	   Boxes themselves can be contained within "super-boxes". Super-Boxes can
684 	   contain super-boxes which provides us with a hierarchical storage system.
685 
686 	   It is valid for a JP2 file to contain multiple individual codestreams.
687 	   We'll just look for the first codestream at the root of the box structure
688 	   and handle that.
689 	*/
690 
691 	for (;;)
692 	{
693 		box_length = php_read4(stream); /* LBox */
694 		/* TBox */
695 		if (php_stream_read(stream, (void *)&box_type, sizeof(box_type)) != sizeof(box_type)) {
696 			/* Use this as a general "out of stream" error */
697 			break;
698 		}
699 
700 		if (box_length == 1) {
701 			/* We won't handle XLBoxes */
702 			return NULL;
703 		}
704 
705 		if (!memcmp(&box_type, jp2c_box_id, 4))
706 		{
707 			/* Skip the first 3 bytes to emulate the file type examination */
708 			php_stream_seek(stream, 3, SEEK_CUR);
709 
710 			result = php_handle_jpc(stream);
711 			break;
712 		}
713 
714 		/* Stop if this was the last box */
715 		if ((int)box_length <= 0) {
716 			break;
717 		}
718 
719 		/* Skip over LBox (Which includes both TBox and LBox itself */
720 		if (php_stream_seek(stream, box_length - 8, SEEK_CUR)) {
721 			break;
722 		}
723 	}
724 
725 	if (result == NULL) {
726 		php_error_docref(NULL, E_WARNING, "JP2 file has no codestreams at root level");
727 	}
728 
729 	return result;
730 }
731 /* }}} */
732 
733 /* {{{ tiff constants
734  */
735 PHPAPI const int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
736 
737 /* uncompressed only */
738 #define TAG_IMAGEWIDTH              0x0100
739 #define TAG_IMAGEHEIGHT             0x0101
740 /* compressed images only */
741 #define TAG_COMP_IMAGEWIDTH         0xA002
742 #define TAG_COMP_IMAGEHEIGHT        0xA003
743 
744 #define TAG_FMT_BYTE       1
745 #define TAG_FMT_STRING     2
746 #define TAG_FMT_USHORT     3
747 #define TAG_FMT_ULONG      4
748 #define TAG_FMT_URATIONAL  5
749 #define TAG_FMT_SBYTE      6
750 #define TAG_FMT_UNDEFINED  7
751 #define TAG_FMT_SSHORT     8
752 #define TAG_FMT_SLONG      9
753 #define TAG_FMT_SRATIONAL 10
754 #define TAG_FMT_SINGLE    11
755 #define TAG_FMT_DOUBLE    12
756 /* }}} */
757 
758 /* {{{ php_ifd_get16u
759  * Convert a 16 bit unsigned value from file's native byte order */
php_ifd_get16u(void * Short,int motorola_intel)760 static int php_ifd_get16u(void *Short, int motorola_intel)
761 {
762 	if (motorola_intel) {
763 		return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
764 	} else {
765 		return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
766 	}
767 }
768 /* }}} */
769 
770 /* {{{ php_ifd_get16s
771  * Convert a 16 bit signed value from file's native byte order */
php_ifd_get16s(void * Short,int motorola_intel)772 static signed short php_ifd_get16s(void *Short, int motorola_intel)
773 {
774 	return (signed short)php_ifd_get16u(Short, motorola_intel);
775 }
776 /* }}} */
777 
778 /* {{{ php_ifd_get32s
779  * Convert a 32 bit signed value from file's native byte order */
php_ifd_get32s(void * Long,int motorola_intel)780 static int php_ifd_get32s(void *Long, int motorola_intel)
781 {
782 	if (motorola_intel) {
783 		return  ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
784 		      | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
785 	} else {
786 		return  ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
787 		      | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
788 	}
789 }
790 /* }}} */
791 
792 /* {{{ php_ifd_get32u
793  * Convert a 32 bit unsigned value from file's native byte order */
php_ifd_get32u(void * Long,int motorola_intel)794 static unsigned php_ifd_get32u(void *Long, int motorola_intel)
795 {
796 	return (unsigned)php_ifd_get32s(Long, motorola_intel) & 0xffffffff;
797 }
798 /* }}} */
799 
800 /* {{{ php_handle_tiff
801    main loop to parse TIFF structure */
php_handle_tiff(php_stream * stream,zval * info,int motorola_intel)802 static struct gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int motorola_intel)
803 {
804 	struct gfxinfo *result = NULL;
805 	int i, num_entries;
806 	unsigned char *dir_entry;
807 	size_t ifd_size, dir_size, entry_value, width=0, height=0, ifd_addr;
808 	int entry_tag , entry_type;
809 	char *ifd_data, ifd_ptr[4];
810 
811 	if (php_stream_read(stream, ifd_ptr, 4) != 4)
812 		return NULL;
813 	ifd_addr = php_ifd_get32u(ifd_ptr, motorola_intel);
814 	if (php_stream_seek(stream, ifd_addr-8, SEEK_CUR))
815 		return NULL;
816 	ifd_size = 2;
817 	ifd_data = emalloc(ifd_size);
818 	if (php_stream_read(stream, ifd_data, 2) != 2) {
819 		efree(ifd_data);
820 		return NULL;
821 	}
822 	num_entries = php_ifd_get16u(ifd_data, motorola_intel);
823 	dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/;
824 	ifd_size = dir_size;
825 	ifd_data = erealloc(ifd_data,ifd_size);
826 	if (php_stream_read(stream, ifd_data+2, dir_size-2) != dir_size-2) {
827 		efree(ifd_data);
828 		return NULL;
829 	}
830 	/* now we have the directory we can look how long it should be */
831 	ifd_size = dir_size;
832 	for(i=0;i<num_entries;i++) {
833 		dir_entry 	 = (unsigned char *) ifd_data+2+i*12;
834 		entry_tag    = php_ifd_get16u(dir_entry+0, motorola_intel);
835 		entry_type   = php_ifd_get16u(dir_entry+2, motorola_intel);
836 		switch(entry_type) {
837 			case TAG_FMT_BYTE:
838 			case TAG_FMT_SBYTE:
839 				entry_value  = (size_t)(dir_entry[8]);
840 				break;
841 			case TAG_FMT_USHORT:
842 				entry_value  = php_ifd_get16u(dir_entry+8, motorola_intel);
843 				break;
844 			case TAG_FMT_SSHORT:
845 				entry_value  = php_ifd_get16s(dir_entry+8, motorola_intel);
846 				break;
847 			case TAG_FMT_ULONG:
848 				entry_value  = php_ifd_get32u(dir_entry+8, motorola_intel);
849 				break;
850 			case TAG_FMT_SLONG:
851 				entry_value  = php_ifd_get32s(dir_entry+8, motorola_intel);
852 				break;
853 			default:
854 				continue;
855 		}
856 		switch(entry_tag) {
857 			case TAG_IMAGEWIDTH:
858 			case TAG_COMP_IMAGEWIDTH:
859 				width  = entry_value;
860 				break;
861 			case TAG_IMAGEHEIGHT:
862 			case TAG_COMP_IMAGEHEIGHT:
863 				height = entry_value;
864 				break;
865 		}
866 	}
867 	efree(ifd_data);
868 	if ( width && height) {
869 		/* not the same when in for-loop */
870 		result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
871 		result->height   = height;
872 		result->width    = width;
873 		result->bits     = 0;
874 		result->channels = 0;
875 		return result;
876 	}
877 	return NULL;
878 }
879 /* }}} */
880 
881 /* {{{ php_handle_psd
882  */
php_handle_iff(php_stream * stream)883 static struct gfxinfo *php_handle_iff(php_stream * stream)
884 {
885 	struct gfxinfo * result;
886 	unsigned char a[10];
887 	int chunkId;
888 	int size;
889 	short width, height, bits;
890 
891 	if (php_stream_read(stream, (char *) a, 8) != 8) {
892 		return NULL;
893 	}
894 	if (strncmp((char *) a+4, "ILBM", 4) && strncmp((char *) a+4, "PBM ", 4)) {
895 		return NULL;
896 	}
897 
898 	/* loop chunks to find BMHD chunk */
899 	do {
900 		if (php_stream_read(stream, (char*)a, 8) != 8) {
901 			return NULL;
902 		}
903 		chunkId = php_ifd_get32s(a+0, 1);
904 		size    = php_ifd_get32s(a+4, 1);
905 		if (size < 0) {
906 			return NULL;
907 		}
908 		if ((size & 1) == 1) {
909 			size++;
910 		}
911 		if (chunkId == 0x424d4844) { /* BMHD chunk */
912 			if (size < 9 || php_stream_read(stream, (char*)a, 9) != 9) {
913 				return NULL;
914 			}
915 			width  = php_ifd_get16s(a+0, 1);
916 			height = php_ifd_get16s(a+2, 1);
917 			bits   = a[8] & 0xff;
918 			if (width > 0 && height > 0 && bits > 0 && bits < 33) {
919 				result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
920 				result->width    = width;
921 				result->height   = height;
922 				result->bits     = bits;
923 				result->channels = 0;
924 				return result;
925 			}
926 		} else {
927 			if (php_stream_seek(stream, size, SEEK_CUR)) {
928 				return NULL;
929 			}
930 		}
931 	} while (1);
932 }
933 /* }}} */
934 
935 /* {{{ php_get_wbmp
936  * int WBMP file format type
937  * byte Header Type
938  *	byte Extended Header
939  *		byte Header Data (type 00 = multibyte)
940  *		byte Header Data (type 11 = name/pairs)
941  * int Number of columns
942  * int Number of rows
943  */
php_get_wbmp(php_stream * stream,struct gfxinfo ** result,int check)944 static int php_get_wbmp(php_stream *stream, struct gfxinfo **result, int check)
945 {
946 	int i, width = 0, height = 0;
947 
948 	if (php_stream_rewind(stream)) {
949 		return 0;
950 	}
951 
952 	/* get type */
953 	if (php_stream_getc(stream) != 0) {
954 		return 0;
955 	}
956 
957 	/* skip header */
958 	do {
959 		i = php_stream_getc(stream);
960 		if (i < 0) {
961 			return 0;
962 		}
963 	} while (i & 0x80);
964 
965 	/* get width */
966 	do {
967 		i = php_stream_getc(stream);
968 		if (i < 0) {
969 			return 0;
970 		}
971 		width = (width << 7) | (i & 0x7f);
972         /* maximum valid width for wbmp (although 127 may be a more accurate one) */
973         if (width > 2048) {
974             return 0;
975         }
976 	} while (i & 0x80);
977 
978 	/* get height */
979 	do {
980 		i = php_stream_getc(stream);
981 		if (i < 0) {
982 			return 0;
983 		}
984 		height = (height << 7) | (i & 0x7f);
985         /* maximum valid heigth for wbmp (although 127 may be a more accurate one) */
986         if (height > 2048) {
987             return 0;
988         }
989 	} while (i & 0x80);
990 
991 	if (!height || !width) {
992 		return 0;
993 	}
994 
995 	if (!check) {
996 		(*result)->width = width;
997 		(*result)->height = height;
998 	}
999 
1000 	return IMAGE_FILETYPE_WBMP;
1001 }
1002 /* }}} */
1003 
1004 /* {{{ php_handle_wbmp
1005 */
php_handle_wbmp(php_stream * stream)1006 static struct gfxinfo *php_handle_wbmp(php_stream * stream)
1007 {
1008 	struct gfxinfo *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1009 
1010 	if (!php_get_wbmp(stream, &result, 0)) {
1011 		efree(result);
1012 		return NULL;
1013 	}
1014 
1015 	return result;
1016 }
1017 /* }}} */
1018 
1019 /* {{{ php_get_xbm
1020  */
php_get_xbm(php_stream * stream,struct gfxinfo ** result)1021 static int php_get_xbm(php_stream *stream, struct gfxinfo **result)
1022 {
1023     char *fline;
1024     char *iname;
1025     char *type;
1026     int value;
1027     unsigned int width = 0, height = 0;
1028 
1029 	if (result) {
1030 		*result = NULL;
1031 	}
1032 	if (php_stream_rewind(stream)) {
1033 		return 0;
1034 	}
1035 	while ((fline=php_stream_gets(stream, NULL, 0)) != NULL) {
1036 		iname = estrdup(fline); /* simple way to get necessary buffer of required size */
1037 		if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
1038 			if (!(type = strrchr(iname, '_'))) {
1039 				type = iname;
1040 			} else {
1041 				type++;
1042 			}
1043 
1044 			if (!strcmp("width", type)) {
1045 				width = (unsigned int) value;
1046 				if (height) {
1047 					efree(iname);
1048 					break;
1049 				}
1050 			}
1051 			if (!strcmp("height", type)) {
1052 				height = (unsigned int) value;
1053 				if (width) {
1054 					efree(iname);
1055 					break;
1056 				}
1057 			}
1058 		}
1059 		efree(fline);
1060 		efree(iname);
1061 	}
1062 	if (fline) {
1063 		efree(fline);
1064 	}
1065 
1066 	if (width && height) {
1067 		if (result) {
1068 			*result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1069 			(*result)->width = width;
1070 			(*result)->height = height;
1071 		}
1072 		return IMAGE_FILETYPE_XBM;
1073 	}
1074 
1075 	return 0;
1076 }
1077 /* }}} */
1078 
1079 /* {{{ php_handle_xbm
1080  */
php_handle_xbm(php_stream * stream)1081 static struct gfxinfo *php_handle_xbm(php_stream * stream)
1082 {
1083 	struct gfxinfo *result;
1084 	php_get_xbm(stream, &result);
1085 	return result;
1086 }
1087 /* }}} */
1088 
1089 /* {{{ php_handle_ico
1090  */
php_handle_ico(php_stream * stream)1091 static struct gfxinfo *php_handle_ico(php_stream * stream)
1092 {
1093 	struct gfxinfo *result = NULL;
1094 	unsigned char dim[16];
1095 	int num_icons = 0;
1096 
1097 	if (php_stream_read(stream, (char *) dim, 2) != 2)
1098 		return NULL;
1099 
1100 	num_icons = (((unsigned int)dim[1]) << 8) + ((unsigned int) dim[0]);
1101 
1102 	if (num_icons < 1 || num_icons > 255)
1103 		return NULL;
1104 
1105 	result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1106 
1107 	while (num_icons > 0)
1108 	{
1109 		if (php_stream_read(stream, (char *) dim, sizeof(dim)) != sizeof(dim))
1110 			break;
1111 
1112 		if ((((unsigned int)dim[7]) <<  8) +  ((unsigned int)dim[6]) >= result->bits)
1113 		{
1114 			result->width    =  (unsigned int)dim[0];
1115 			result->height   =  (unsigned int)dim[1];
1116 			result->bits     =  (((unsigned int)dim[7]) <<  8) +  ((unsigned int)dim[6]);
1117 		}
1118 		num_icons--;
1119 	}
1120 
1121 	return result;
1122 }
1123 /* }}} */
1124 
1125 /* {{{ php_handle_webp
1126  */
php_handle_webp(php_stream * stream)1127 static struct gfxinfo *php_handle_webp(php_stream * stream)
1128 {
1129 	struct gfxinfo *result = NULL;
1130 	const char sig[3] = {'V', 'P', '8'};
1131 	unsigned char buf[18];
1132 	char format;
1133 
1134 	if (php_stream_read(stream, (char *) buf, 18) != 18)
1135 		return NULL;
1136 
1137 	if (memcmp(buf, sig, 3)) {
1138 		return NULL;
1139 	}
1140 	switch (buf[3]) {
1141 		case ' ':
1142 		case 'L':
1143 		case 'X':
1144 			format = buf[3];
1145 			break;
1146 		default:
1147 			return NULL;
1148 	}
1149 
1150 	result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
1151 
1152 	switch (format) {
1153 		case ' ':
1154 			result->width = buf[14] + ((buf[15] & 0x3F) << 8);
1155 			result->height = buf[16] + ((buf[17] & 0x3F) << 8);
1156 			break;
1157 		case 'L':
1158 			result->width = buf[9] + ((buf[10] & 0x3F) << 8) + 1;
1159 			result->height = (buf[10] >> 6) + (buf[11] << 2) + ((buf[12] & 0xF) << 10) + 1;
1160 			break;
1161 		case 'X':
1162 			result->width = buf[12] + (buf[13] << 8) + (buf[14] << 16) + 1;
1163 			result->height = buf[15] + (buf[16] << 8) + (buf[17] << 16) + 1;
1164 			break;
1165 	}
1166 	result->bits = 8; /* always 1 byte */
1167 
1168 	return result;
1169 }
1170 /* }}} */
1171 
1172 /* {{{ php_image_type_to_mime_type
1173  * Convert internal image_type to mime type */
php_image_type_to_mime_type(int image_type)1174 PHPAPI char * php_image_type_to_mime_type(int image_type)
1175 {
1176 	switch( image_type) {
1177 		case IMAGE_FILETYPE_GIF:
1178 			return "image/gif";
1179 		case IMAGE_FILETYPE_JPEG:
1180 			return "image/jpeg";
1181 		case IMAGE_FILETYPE_PNG:
1182 			return "image/png";
1183 		case IMAGE_FILETYPE_SWF:
1184 		case IMAGE_FILETYPE_SWC:
1185 			return "application/x-shockwave-flash";
1186 		case IMAGE_FILETYPE_PSD:
1187 			return "image/psd";
1188 		case IMAGE_FILETYPE_BMP:
1189 			return "image/x-ms-bmp";
1190 		case IMAGE_FILETYPE_TIFF_II:
1191 		case IMAGE_FILETYPE_TIFF_MM:
1192 			return "image/tiff";
1193 		case IMAGE_FILETYPE_IFF:
1194 			return "image/iff";
1195 		case IMAGE_FILETYPE_WBMP:
1196 			return "image/vnd.wap.wbmp";
1197 		case IMAGE_FILETYPE_JPC:
1198 			return "application/octet-stream";
1199 		case IMAGE_FILETYPE_JP2:
1200 			return "image/jp2";
1201 		case IMAGE_FILETYPE_XBM:
1202 			return "image/xbm";
1203 		case IMAGE_FILETYPE_ICO:
1204 			return "image/vnd.microsoft.icon";
1205 		case IMAGE_FILETYPE_WEBP:
1206 			return "image/webp";
1207 		default:
1208 		case IMAGE_FILETYPE_UNKNOWN:
1209 			return "application/octet-stream"; /* suppose binary format */
1210 	}
1211 }
1212 /* }}} */
1213 
1214 /* {{{ proto string image_type_to_mime_type(int imagetype)
1215    Get Mime-Type for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
PHP_FUNCTION(image_type_to_mime_type)1216 PHP_FUNCTION(image_type_to_mime_type)
1217 {
1218 	zend_long p_image_type;
1219 
1220 	ZEND_PARSE_PARAMETERS_START(1, 1)
1221 		Z_PARAM_LONG(p_image_type)
1222 	ZEND_PARSE_PARAMETERS_END();
1223 
1224 	ZVAL_STRING(return_value, (char*)php_image_type_to_mime_type(p_image_type));
1225 }
1226 /* }}} */
1227 
1228 /* {{{ proto string image_type_to_extension(int imagetype [, bool include_dot])
1229    Get file extension for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
PHP_FUNCTION(image_type_to_extension)1230 PHP_FUNCTION(image_type_to_extension)
1231 {
1232 	zend_long image_type;
1233 	zend_bool inc_dot=1;
1234 
1235 	ZEND_PARSE_PARAMETERS_START(1, 2)
1236 		Z_PARAM_LONG(image_type)
1237 		Z_PARAM_OPTIONAL
1238 		Z_PARAM_BOOL(inc_dot)
1239 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1240 
1241 	switch (image_type) {
1242 		case IMAGE_FILETYPE_GIF:
1243 			RETURN_STRING(".gif" + !inc_dot);
1244 		case IMAGE_FILETYPE_JPEG:
1245 			RETURN_STRING(".jpeg" + !inc_dot);
1246 		case IMAGE_FILETYPE_PNG:
1247 			RETURN_STRING(".png" + !inc_dot);
1248 		case IMAGE_FILETYPE_SWF:
1249 		case IMAGE_FILETYPE_SWC:
1250 			RETURN_STRING(".swf" + !inc_dot);
1251 		case IMAGE_FILETYPE_PSD:
1252 			RETURN_STRING(".psd" + !inc_dot);
1253 		case IMAGE_FILETYPE_BMP:
1254 		case IMAGE_FILETYPE_WBMP:
1255 			RETURN_STRING(".bmp" + !inc_dot);
1256 		case IMAGE_FILETYPE_TIFF_II:
1257 		case IMAGE_FILETYPE_TIFF_MM:
1258 			RETURN_STRING(".tiff" + !inc_dot);
1259 		case IMAGE_FILETYPE_IFF:
1260 			RETURN_STRING(".iff" + !inc_dot);
1261 		case IMAGE_FILETYPE_JPC:
1262 			RETURN_STRING(".jpc" + !inc_dot);
1263 		case IMAGE_FILETYPE_JP2:
1264 			RETURN_STRING(".jp2" + !inc_dot);
1265 		case IMAGE_FILETYPE_JPX:
1266 			RETURN_STRING(".jpx" + !inc_dot);
1267 		case IMAGE_FILETYPE_JB2:
1268 			RETURN_STRING(".jb2" + !inc_dot);
1269 		case IMAGE_FILETYPE_XBM:
1270 			RETURN_STRING(".xbm" + !inc_dot);
1271 		case IMAGE_FILETYPE_ICO:
1272 			RETURN_STRING(".ico" + !inc_dot);
1273 		case IMAGE_FILETYPE_WEBP:
1274 			RETURN_STRING(".webp" + !inc_dot);
1275 	}
1276 
1277 	RETURN_FALSE;
1278 }
1279 /* }}} */
1280 
1281 /* {{{ php_imagetype
1282    detect filetype from first bytes */
php_getimagetype(php_stream * stream,char * filetype)1283 PHPAPI int php_getimagetype(php_stream * stream, char *filetype)
1284 {
1285 	char tmp[12];
1286     int twelve_bytes_read;
1287 
1288 	if ( !filetype) filetype = tmp;
1289 	if((php_stream_read(stream, filetype, 3)) != 3) {
1290 		php_error_docref(NULL, E_NOTICE, "Read error!");
1291 		return IMAGE_FILETYPE_UNKNOWN;
1292 	}
1293 
1294 /* BYTES READ: 3 */
1295 	if (!memcmp(filetype, php_sig_gif, 3)) {
1296 		return IMAGE_FILETYPE_GIF;
1297 	} else if (!memcmp(filetype, php_sig_jpg, 3)) {
1298 		return IMAGE_FILETYPE_JPEG;
1299 	} else if (!memcmp(filetype, php_sig_png, 3)) {
1300 		if (php_stream_read(stream, filetype+3, 5) != 5) {
1301 			php_error_docref(NULL, E_NOTICE, "Read error!");
1302 			return IMAGE_FILETYPE_UNKNOWN;
1303 		}
1304 		if (!memcmp(filetype, php_sig_png, 8)) {
1305 			return IMAGE_FILETYPE_PNG;
1306 		} else {
1307 			php_error_docref(NULL, E_WARNING, "PNG file corrupted by ASCII conversion");
1308 			return IMAGE_FILETYPE_UNKNOWN;
1309 		}
1310 	} else if (!memcmp(filetype, php_sig_swf, 3)) {
1311 		return IMAGE_FILETYPE_SWF;
1312 	} else if (!memcmp(filetype, php_sig_swc, 3)) {
1313 		return IMAGE_FILETYPE_SWC;
1314 	} else if (!memcmp(filetype, php_sig_psd, 3)) {
1315 		return IMAGE_FILETYPE_PSD;
1316 	} else if (!memcmp(filetype, php_sig_bmp, 2)) {
1317 		return IMAGE_FILETYPE_BMP;
1318 	} else if (!memcmp(filetype, php_sig_jpc, 3)) {
1319 		return IMAGE_FILETYPE_JPC;
1320 	} else if (!memcmp(filetype, php_sig_riff, 3)) {
1321 		if (php_stream_read(stream, filetype+3, 9) != 9) {
1322 			php_error_docref(NULL, E_NOTICE, "Read error!");
1323 			return IMAGE_FILETYPE_UNKNOWN;
1324 		}
1325 		if (!memcmp(filetype+8, php_sig_webp, 4)) {
1326 			return IMAGE_FILETYPE_WEBP;
1327 		} else {
1328 			return IMAGE_FILETYPE_UNKNOWN;
1329 		}
1330 	}
1331 
1332 	if (php_stream_read(stream, filetype+3, 1) != 1) {
1333 		php_error_docref(NULL, E_NOTICE, "Read error!");
1334 		return IMAGE_FILETYPE_UNKNOWN;
1335 	}
1336 /* BYTES READ: 4 */
1337 	if (!memcmp(filetype, php_sig_tif_ii, 4)) {
1338 		return IMAGE_FILETYPE_TIFF_II;
1339 	} else if (!memcmp(filetype, php_sig_tif_mm, 4)) {
1340 		return IMAGE_FILETYPE_TIFF_MM;
1341 	} else if (!memcmp(filetype, php_sig_iff, 4)) {
1342 		return IMAGE_FILETYPE_IFF;
1343 	} else if (!memcmp(filetype, php_sig_ico, 4)) {
1344 		return IMAGE_FILETYPE_ICO;
1345 	}
1346 
1347     /* WBMP may be smaller than 12 bytes, so delay error */
1348 	twelve_bytes_read = (php_stream_read(stream, filetype+4, 8) == 8);
1349 
1350 /* BYTES READ: 12 */
1351    	if (twelve_bytes_read && !memcmp(filetype, php_sig_jp2, 12)) {
1352 		return IMAGE_FILETYPE_JP2;
1353 	}
1354 
1355 /* AFTER ALL ABOVE FAILED */
1356 	if (php_get_wbmp(stream, NULL, 1)) {
1357 		return IMAGE_FILETYPE_WBMP;
1358 	}
1359     if (!twelve_bytes_read) {
1360 		php_error_docref(NULL, E_NOTICE, "Read error!");
1361 		return IMAGE_FILETYPE_UNKNOWN;
1362     }
1363 	if (php_get_xbm(stream, NULL)) {
1364 		return IMAGE_FILETYPE_XBM;
1365 	}
1366 	return IMAGE_FILETYPE_UNKNOWN;
1367 }
1368 /* }}} */
1369 
php_getimagesize_from_stream(php_stream * stream,zval * info,INTERNAL_FUNCTION_PARAMETERS)1370 static void php_getimagesize_from_stream(php_stream *stream, zval *info, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
1371 {
1372 	int itype = 0;
1373 	struct gfxinfo *result = NULL;
1374 
1375 	if (!stream) {
1376 		RETURN_FALSE;
1377 	}
1378 
1379 	itype = php_getimagetype(stream, NULL);
1380 	switch( itype) {
1381 		case IMAGE_FILETYPE_GIF:
1382 			result = php_handle_gif(stream);
1383 			break;
1384 		case IMAGE_FILETYPE_JPEG:
1385 			if (info) {
1386 				result = php_handle_jpeg(stream, info);
1387 			} else {
1388 				result = php_handle_jpeg(stream, NULL);
1389 			}
1390 			break;
1391 		case IMAGE_FILETYPE_PNG:
1392 			result = php_handle_png(stream);
1393 			break;
1394 		case IMAGE_FILETYPE_SWF:
1395 			result = php_handle_swf(stream);
1396 			break;
1397 		case IMAGE_FILETYPE_SWC:
1398 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
1399 			result = php_handle_swc(stream);
1400 #else
1401 			php_error_docref(NULL, E_NOTICE, "The image is a compressed SWF file, but you do not have a static version of the zlib extension enabled");
1402 #endif
1403 			break;
1404 		case IMAGE_FILETYPE_PSD:
1405 			result = php_handle_psd(stream);
1406 			break;
1407 		case IMAGE_FILETYPE_BMP:
1408 			result = php_handle_bmp(stream);
1409 			break;
1410 		case IMAGE_FILETYPE_TIFF_II:
1411 			result = php_handle_tiff(stream, NULL, 0);
1412 			break;
1413 		case IMAGE_FILETYPE_TIFF_MM:
1414 			result = php_handle_tiff(stream, NULL, 1);
1415 			break;
1416 		case IMAGE_FILETYPE_JPC:
1417 			result = php_handle_jpc(stream);
1418 			break;
1419 		case IMAGE_FILETYPE_JP2:
1420 			result = php_handle_jp2(stream);
1421 			break;
1422 		case IMAGE_FILETYPE_IFF:
1423 			result = php_handle_iff(stream);
1424 			break;
1425 		case IMAGE_FILETYPE_WBMP:
1426 			result = php_handle_wbmp(stream);
1427 			break;
1428 		case IMAGE_FILETYPE_XBM:
1429 			result = php_handle_xbm(stream);
1430 			break;
1431 		case IMAGE_FILETYPE_ICO:
1432 			result = php_handle_ico(stream);
1433 			break;
1434 		case IMAGE_FILETYPE_WEBP:
1435 			result = php_handle_webp(stream);
1436 			break;
1437 		default:
1438 		case IMAGE_FILETYPE_UNKNOWN:
1439 			break;
1440 	}
1441 
1442 	if (result) {
1443 		char temp[MAX_LENGTH_OF_LONG * 2 + sizeof("width=\"\" height=\"\"")];
1444 		array_init(return_value);
1445 		add_index_long(return_value, 0, result->width);
1446 		add_index_long(return_value, 1, result->height);
1447 		add_index_long(return_value, 2, itype);
1448 		snprintf(temp, sizeof(temp), "width=\"%d\" height=\"%d\"", result->width, result->height);
1449 		add_index_string(return_value, 3, temp);
1450 
1451 		if (result->bits != 0) {
1452 			add_assoc_long(return_value, "bits", result->bits);
1453 		}
1454 		if (result->channels != 0) {
1455 			add_assoc_long(return_value, "channels", result->channels);
1456 		}
1457 		add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype));
1458 		efree(result);
1459 	} else {
1460 		RETURN_FALSE;
1461 	}
1462 }
1463 /* }}} */
1464 
1465 #define FROM_DATA 0
1466 #define FROM_PATH 1
1467 
php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS,int mode)1468 static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) {  /* {{{ */
1469 	zval *info = NULL;
1470 	php_stream *stream = NULL;
1471 	char *input;
1472 	size_t input_len;
1473 	const int argc = ZEND_NUM_ARGS();
1474 
1475 	ZEND_PARSE_PARAMETERS_START(1, 2)
1476 		Z_PARAM_STRING(input, input_len)
1477 		Z_PARAM_OPTIONAL
1478 		Z_PARAM_ZVAL_DEREF(info)
1479 	ZEND_PARSE_PARAMETERS_END();
1480 
1481 	if (mode == FROM_PATH && CHECK_NULL_PATH(input, input_len)) {
1482 		php_error_docref(NULL, E_WARNING, "Invalid path");
1483 		return;
1484 	}
1485 
1486 	if (argc == 2) {
1487 		zval_ptr_dtor(info);
1488 		array_init(info);
1489 	}
1490 
1491 	if (mode == FROM_PATH) {
1492 		stream = php_stream_open_wrapper(input, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH, NULL);
1493 	} else {
1494 		stream = php_stream_memory_open(TEMP_STREAM_READONLY, input, input_len);
1495 	}
1496 
1497 	if (!stream) {
1498 		   RETURN_FALSE;
1499 	}
1500 
1501 	php_getimagesize_from_stream(stream, info, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1502 	php_stream_close(stream);
1503 }
1504 /* }}} */
1505 
1506 /* {{{ proto array getimagesize(string imagefile [, array info])
1507    Get the size of an image as 4-element array */
PHP_FUNCTION(getimagesize)1508 PHP_FUNCTION(getimagesize)
1509 {
1510 	php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
1511 }
1512 /* }}} */
1513 
1514 /* {{{ proto array getimagesizefromstring(string data [, array info])
1515    Get the size of an image as 4-element array */
PHP_FUNCTION(getimagesizefromstring)1516 PHP_FUNCTION(getimagesizefromstring)
1517 {
1518 	php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_DATA);
1519 }
1520 
1521 /*
1522  * Local variables:
1523  * tab-width: 4
1524  * c-basic-offset: 4
1525  * End:
1526  * vim600: sw=4 ts=4 fdm=marker
1527  * vim<600: sw=4 ts=4
1528  */
1529