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