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