root/ext/standard/image.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_MINIT_FUNCTION
  2. php_handle_gif
  3. php_handle_psd
  4. php_handle_bmp
  5. php_swf_get_bits
  6. php_handle_swc
  7. php_handle_swf
  8. php_handle_png
  9. php_read2
  10. php_next_marker
  11. php_skip_variable
  12. php_read_APP
  13. php_handle_jpeg
  14. php_read4
  15. php_handle_jpc
  16. php_handle_jp2
  17. php_ifd_get16u
  18. php_ifd_get16s
  19. php_ifd_get32s
  20. php_ifd_get32u
  21. php_handle_tiff
  22. php_handle_iff
  23. php_get_wbmp
  24. php_handle_wbmp
  25. php_get_xbm
  26. php_handle_xbm
  27. php_handle_ico
  28. php_image_type_to_mime_type
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. php_getimagetype
  32. php_getimagesize_from_stream
  33. php_getimagesize_from_any
  34. PHP_FUNCTION
  35. PHP_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */