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