Back to index

php5  5.3.10
image.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
00016    |          Marcus Boerger <helly@php.net>                              |
00017    +----------------------------------------------------------------------+
00018  */
00019 
00020 /* $Id: image.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php.h"
00023 #include <stdio.h>
00024 #if HAVE_FCNTL_H
00025 #include <fcntl.h>
00026 #endif
00027 #include "fopen_wrappers.h"
00028 #include "ext/standard/fsock.h"
00029 #if HAVE_UNISTD_H
00030 #include <unistd.h>
00031 #endif
00032 #include "php_image.h"
00033 
00034 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
00035 #include "zlib.h"
00036 #endif
00037 
00038 /* file type markers */
00039 PHPAPI const char php_sig_gif[3] = {'G', 'I', 'F'};
00040 PHPAPI const char php_sig_psd[4] = {'8', 'B', 'P', 'S'};
00041 PHPAPI const char php_sig_bmp[2] = {'B', 'M'};
00042 PHPAPI const char php_sig_swf[3] = {'F', 'W', 'S'};
00043 PHPAPI const char php_sig_swc[3] = {'C', 'W', 'S'};
00044 PHPAPI const char php_sig_jpg[3] = {(char) 0xff, (char) 0xd8, (char) 0xff};
00045 PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
00046                                     (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
00047 PHPAPI const char php_sig_tif_ii[4] = {'I','I', (char)0x2A, (char)0x00};
00048 PHPAPI const char php_sig_tif_mm[4] = {'M','M', (char)0x00, (char)0x2A};
00049 PHPAPI const char php_sig_jpc[3]  = {(char)0xff, (char)0x4f, (char)0xff};
00050 PHPAPI const char php_sig_jp2[12] = {(char)0x00, (char)0x00, (char)0x00, (char)0x0c,
00051                                      (char)0x6a, (char)0x50, (char)0x20, (char)0x20,
00052                                      (char)0x0d, (char)0x0a, (char)0x87, (char)0x0a};
00053 PHPAPI const char php_sig_iff[4] = {'F','O','R','M'};
00054 PHPAPI const char php_sig_ico[4] = {(char)0x00, (char)0x00, (char)0x01, (char)0x00};
00055 
00056 /* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */
00057 /* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */
00058 
00059 /* return info as a struct, to make expansion easier */
00060 
00061 struct gfxinfo {
00062        unsigned int width;
00063        unsigned int height;
00064        unsigned int bits;
00065        unsigned int channels;
00066 };
00067 
00068 /* {{{ PHP_MINIT_FUNCTION(imagetypes)
00069  * Register IMAGETYPE_<xxx> constants used by GetImageSize(), image_type_to_mime_type, ext/exif */
00070 PHP_MINIT_FUNCTION(imagetypes)
00071 {
00072        REGISTER_LONG_CONSTANT("IMAGETYPE_GIF",     IMAGE_FILETYPE_GIF,     CONST_CS | CONST_PERSISTENT);
00073        REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG",    IMAGE_FILETYPE_JPEG,    CONST_CS | CONST_PERSISTENT);
00074        REGISTER_LONG_CONSTANT("IMAGETYPE_PNG",     IMAGE_FILETYPE_PNG,     CONST_CS | CONST_PERSISTENT);
00075        REGISTER_LONG_CONSTANT("IMAGETYPE_SWF",     IMAGE_FILETYPE_SWF,     CONST_CS | CONST_PERSISTENT);
00076        REGISTER_LONG_CONSTANT("IMAGETYPE_PSD",     IMAGE_FILETYPE_PSD,     CONST_CS | CONST_PERSISTENT);
00077        REGISTER_LONG_CONSTANT("IMAGETYPE_BMP",     IMAGE_FILETYPE_BMP,     CONST_CS | CONST_PERSISTENT);
00078        REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_II", IMAGE_FILETYPE_TIFF_II, CONST_CS | CONST_PERSISTENT);
00079        REGISTER_LONG_CONSTANT("IMAGETYPE_TIFF_MM", IMAGE_FILETYPE_TIFF_MM, CONST_CS | CONST_PERSISTENT);
00080        REGISTER_LONG_CONSTANT("IMAGETYPE_JPC",     IMAGE_FILETYPE_JPC,     CONST_CS | CONST_PERSISTENT);
00081        REGISTER_LONG_CONSTANT("IMAGETYPE_JP2",     IMAGE_FILETYPE_JP2,     CONST_CS | CONST_PERSISTENT);
00082        REGISTER_LONG_CONSTANT("IMAGETYPE_JPX",     IMAGE_FILETYPE_JPX,     CONST_CS | CONST_PERSISTENT);
00083        REGISTER_LONG_CONSTANT("IMAGETYPE_JB2",     IMAGE_FILETYPE_JB2,     CONST_CS | CONST_PERSISTENT);
00084 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
00085        REGISTER_LONG_CONSTANT("IMAGETYPE_SWC",     IMAGE_FILETYPE_SWC,     CONST_CS | CONST_PERSISTENT);
00086 #endif 
00087        REGISTER_LONG_CONSTANT("IMAGETYPE_IFF",     IMAGE_FILETYPE_IFF,     CONST_CS | CONST_PERSISTENT);
00088        REGISTER_LONG_CONSTANT("IMAGETYPE_WBMP",    IMAGE_FILETYPE_WBMP,    CONST_CS | CONST_PERSISTENT);
00089        REGISTER_LONG_CONSTANT("IMAGETYPE_JPEG2000",IMAGE_FILETYPE_JPC,     CONST_CS | CONST_PERSISTENT); /* keep alias */
00090        REGISTER_LONG_CONSTANT("IMAGETYPE_XBM",     IMAGE_FILETYPE_XBM,     CONST_CS | CONST_PERSISTENT);
00091        REGISTER_LONG_CONSTANT("IMAGETYPE_ICO",     IMAGE_FILETYPE_ICO,     CONST_CS | CONST_PERSISTENT);
00092        REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_CS | CONST_PERSISTENT);
00093        REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT",   IMAGE_FILETYPE_COUNT,   CONST_CS | CONST_PERSISTENT);
00094        return SUCCESS;
00095 }
00096 /* }}} */
00097 
00098 /* {{{ php_handle_gif
00099  * routine to handle GIF files. If only everything were that easy... ;} */
00100 static struct gfxinfo *php_handle_gif (php_stream * stream TSRMLS_DC)
00101 {
00102        struct gfxinfo *result = NULL;
00103        unsigned char dim[5];
00104 
00105        if (php_stream_seek(stream, 3, SEEK_CUR))
00106               return NULL;
00107 
00108        if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
00109               return NULL;
00110 
00111        result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00112        result->width    = (unsigned int)dim[0] | (((unsigned int)dim[1])<<8);
00113        result->height   = (unsigned int)dim[2] | (((unsigned int)dim[3])<<8);
00114        result->bits     = dim[4]&0x80 ? ((((unsigned int)dim[4])&0x07) + 1) : 0;
00115        result->channels = 3; /* allways */
00116 
00117        return result;
00118 }
00119 /* }}} */
00120 
00121 /* {{{ php_handle_psd
00122  */
00123 static struct gfxinfo *php_handle_psd (php_stream * stream TSRMLS_DC)
00124 {
00125        struct gfxinfo *result = NULL;
00126        unsigned char dim[8];
00127 
00128        if (php_stream_seek(stream, 11, SEEK_CUR))
00129               return NULL;
00130 
00131        if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
00132               return NULL;
00133 
00134        result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00135        result->height   =  (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
00136        result->width    =  (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
00137 
00138        return result;
00139 }
00140 /* }}} */
00141 
00142 /* {{{ php_handle_bmp
00143  */
00144 static struct gfxinfo *php_handle_bmp (php_stream * stream TSRMLS_DC)
00145 {
00146        struct gfxinfo *result = NULL;
00147        unsigned char dim[16];
00148        int size;
00149 
00150        if (php_stream_seek(stream, 11, SEEK_CUR))
00151               return NULL;
00152 
00153        if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
00154               return NULL;
00155 
00156        size   = (((unsigned int)dim[ 3]) << 24) + (((unsigned int)dim[ 2]) << 16) + (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]);
00157        if (size == 12) {
00158               result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo));
00159               result->width    =  (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);
00160               result->height   =  (((unsigned int)dim[ 7]) << 8) + ((unsigned int) dim[ 6]);
00161               result->bits     =  ((unsigned int)dim[11]);
00162        } else if (size > 12 && (size <= 64 || size == 108)) {
00163               result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo));
00164               result->width    =  (((unsigned int)dim[ 7]) << 24) + (((unsigned int)dim[ 6]) << 16) + (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);
00165               result->height   =  (((unsigned int)dim[11]) << 24) + (((unsigned int)dim[10]) << 16) + (((unsigned int)dim[ 9]) << 8) + ((unsigned int) dim[ 8]);
00166               result->bits     =  (((unsigned int)dim[15]) <<  8) +  ((unsigned int)dim[14]);
00167        } else {
00168               return NULL;
00169        }
00170 
00171        return result;
00172 }
00173 /* }}} */
00174 
00175 /* {{{ php_swf_get_bits
00176  * routines to handle SWF files. */
00177 static unsigned long int php_swf_get_bits (unsigned char* buffer, unsigned int pos, unsigned int count)
00178 {
00179        unsigned int loop;
00180        unsigned long int result = 0;
00181 
00182        for (loop = pos; loop < pos + count; loop++)
00183        {
00184               result = result +
00185                      ((((buffer[loop / 8]) >> (7 - (loop % 8))) & 0x01) << (count - (loop - pos) - 1));
00186        }
00187        return result;
00188 }
00189 /* }}} */
00190 
00191 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
00192 /* {{{ php_handle_swc
00193  */
00194 static struct gfxinfo *php_handle_swc(php_stream * stream TSRMLS_DC)
00195 {
00196        struct gfxinfo *result = NULL;
00197 
00198        long bits;
00199        unsigned char a[64];
00200        unsigned long len=64, szlength;
00201        int factor=1,maxfactor=16;
00202        int slength, status=0;
00203        char *b, *buf=NULL, *bufz=NULL;
00204 
00205        b = ecalloc (1, len + 1);
00206 
00207        if (php_stream_seek(stream, 5, SEEK_CUR))
00208               return NULL;
00209 
00210        if (php_stream_read(stream, a, sizeof(a)) != sizeof(a))
00211               return NULL;
00212 
00213        if (uncompress(b, &len, a, sizeof(a)) != Z_OK) {
00214               /* failed to decompress the file, will try reading the rest of the file */
00215               if (php_stream_seek(stream, 8, SEEK_SET))
00216                      return NULL;
00217 
00218               slength = php_stream_copy_to_mem(stream, &bufz, PHP_STREAM_COPY_ALL, 0);
00219               
00220               /*
00221                * zlib::uncompress() wants to know the output data length
00222                * if none was given as a parameter
00223                * we try from input length * 2 up to input length * 2^8
00224                * doubling it whenever it wasn't big enough
00225                * that should be eneugh for all real life cases
00226               */
00227               
00228               do {
00229                      szlength=slength*(1<<factor++);
00230                      buf = (char *) erealloc(buf,szlength);
00231                      status = uncompress(buf, &szlength, bufz, slength);
00232               } while ((status==Z_BUF_ERROR)&&(factor<maxfactor));
00233               
00234               if (bufz) {
00235                      pefree(bufz, 0);
00236               }      
00237               
00238               if (status == Z_OK) {
00239                       memcpy(b, buf, len);
00240               }
00241               
00242               if (buf) { 
00243                      efree(buf);
00244               }      
00245        }
00246        
00247        if (!status) {
00248               result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
00249               bits = php_swf_get_bits (b, 0, 5);
00250               result->width = (php_swf_get_bits (b, 5 + bits, bits) -
00251                      php_swf_get_bits (b, 5, bits)) / 20;
00252               result->height = (php_swf_get_bits (b, 5 + (3 * bits), bits) -
00253                      php_swf_get_bits (b, 5 + (2 * bits), bits)) / 20;
00254        } else {
00255               result = NULL;
00256        }      
00257               
00258        efree (b);
00259        return result;
00260 }
00261 /* }}} */
00262 #endif
00263 
00264 /* {{{ php_handle_swf
00265  */
00266 static struct gfxinfo *php_handle_swf (php_stream * stream TSRMLS_DC)
00267 {
00268        struct gfxinfo *result = NULL;
00269        long bits;
00270        unsigned char a[32];
00271 
00272        if (php_stream_seek(stream, 5, SEEK_CUR))
00273               return NULL;
00274 
00275        if (php_stream_read(stream, a, sizeof(a)) != sizeof(a))
00276               return NULL;
00277 
00278        result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo));
00279        bits = php_swf_get_bits (a, 0, 5);
00280        result->width = (php_swf_get_bits (a, 5 + bits, bits) -
00281               php_swf_get_bits (a, 5, bits)) / 20;
00282        result->height = (php_swf_get_bits (a, 5 + (3 * bits), bits) -
00283               php_swf_get_bits (a, 5 + (2 * bits), bits)) / 20;
00284        result->bits     = 0;
00285        result->channels = 0;
00286        return result;
00287 }
00288 /* }}} */
00289 
00290 /* {{{ php_handle_png
00291  * routine to handle PNG files */
00292 static struct gfxinfo *php_handle_png (php_stream * stream TSRMLS_DC)
00293 {
00294        struct gfxinfo *result = NULL;
00295        unsigned char dim[9];
00296 /* Width:              4 bytes
00297  * Height:             4 bytes
00298  * Bit depth:          1 byte
00299  * Color type:         1 byte
00300  * Compression method: 1 byte
00301  * Filter method:      1 byte
00302  * Interlace method:   1 byte
00303  */
00304 
00305        if (php_stream_seek(stream, 8, SEEK_CUR))
00306               return NULL;
00307 
00308        if((php_stream_read(stream, dim, sizeof(dim))) < sizeof(dim))
00309               return NULL;
00310 
00311        result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00312        result->width  = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]);
00313        result->height = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]);
00314        result->bits   = (unsigned int)dim[8];
00315        return result;
00316 }
00317 /* }}} */
00318 
00319 /* routines to handle JPEG data */
00320 
00321 /* some defines for the different JPEG block types */
00322 #define M_SOF0  0xC0               /* Start Of Frame N */
00323 #define M_SOF1  0xC1               /* N indicates which compression process */
00324 #define M_SOF2  0xC2               /* Only SOF0-SOF2 are now in common use */
00325 #define M_SOF3  0xC3
00326 #define M_SOF5  0xC5               /* NB: codes C4 and CC are NOT SOF markers */
00327 #define M_SOF6  0xC6
00328 #define M_SOF7  0xC7
00329 #define M_SOF9  0xC9
00330 #define M_SOF10 0xCA
00331 #define M_SOF11 0xCB
00332 #define M_SOF13 0xCD
00333 #define M_SOF14 0xCE
00334 #define M_SOF15 0xCF
00335 #define M_SOI   0xD8
00336 #define M_EOI   0xD9               /* End Of Image (end of datastream) */
00337 #define M_SOS   0xDA               /* Start Of Scan (begins compressed data) */
00338 #define M_APP0  0xe0
00339 #define M_APP1  0xe1
00340 #define M_APP2  0xe2
00341 #define M_APP3  0xe3
00342 #define M_APP4  0xe4
00343 #define M_APP5  0xe5
00344 #define M_APP6  0xe6
00345 #define M_APP7  0xe7
00346 #define M_APP8  0xe8
00347 #define M_APP9  0xe9
00348 #define M_APP10 0xea
00349 #define M_APP11 0xeb
00350 #define M_APP12 0xec
00351 #define M_APP13 0xed
00352 #define M_APP14 0xee
00353 #define M_APP15 0xef
00354 #define M_COM   0xFE            /* COMment                                  */
00355 
00356 #define M_PSEUDO 0xFFD8                   /* pseudo marker for start of image(byte 0) */
00357 
00358 /* {{{ php_read2
00359  */
00360 static unsigned short php_read2(php_stream * stream TSRMLS_DC)
00361 {
00362        unsigned char a[2];
00363 
00364        /* just return 0 if we hit the end-of-file */
00365        if((php_stream_read(stream, a, sizeof(a))) <= 0) return 0;
00366 
00367        return (((unsigned short)a[0]) << 8) + ((unsigned short)a[1]);
00368 }
00369 /* }}} */
00370 
00371 /* {{{ php_next_marker
00372  * get next marker byte from file */
00373 static unsigned int php_next_marker(php_stream * stream, int last_marker, int comment_correction, int ff_read TSRMLS_DC)
00374 {
00375        int a=0, marker;
00376 
00377        /* get marker byte, swallowing possible padding                           */
00378        if (last_marker==M_COM && comment_correction) {
00379               /* some software does not count the length bytes of COM section           */
00380               /* one company doing so is very much envolved in JPEG... so we accept too */
00381               /* by the way: some of those companies changed their code now...          */
00382               comment_correction = 2;
00383        } else {
00384               last_marker = 0;
00385               comment_correction = 0;
00386        }
00387        if (ff_read) {
00388               a = 1; /* already read 0xff in filetype detection */
00389        }
00390        do {
00391               if ((marker = php_stream_getc(stream)) == EOF)
00392               {
00393                      return M_EOI;/* we hit EOF */
00394               }
00395               if (last_marker==M_COM && comment_correction>0)
00396               {
00397                      if (marker != 0xFF)
00398                      {
00399                             marker = 0xff;
00400                             comment_correction--;
00401                      } else {
00402                             last_marker = M_PSEUDO; /* stop skipping non 0xff for M_COM */
00403                      }
00404               }
00405               a++;
00406        } while (marker == 0xff);
00407        if (a < 2)
00408        {
00409               return M_EOI; /* at least one 0xff is needed before marker code */
00410        }
00411        if ( last_marker==M_COM && comment_correction)
00412        {
00413               return M_EOI; /* ah illegal: char after COM section not 0xFF */
00414        }
00415        return (unsigned int)marker;
00416 }
00417 /* }}} */
00418 
00419 /* {{{ php_skip_variable
00420  * skip over a variable-length block; assumes proper length marker */
00421 static int php_skip_variable(php_stream * stream TSRMLS_DC)
00422 {
00423        off_t length = ((unsigned int)php_read2(stream TSRMLS_CC));
00424 
00425        if (length < 2)      {
00426               return 0;
00427        }
00428        length = length - 2;
00429        php_stream_seek(stream, (long)length, SEEK_CUR);
00430        return 1;
00431 }
00432 /* }}} */
00433 
00434 /* {{{ php_read_APP
00435  */
00436 static int php_read_APP(php_stream * stream, unsigned int marker, zval *info TSRMLS_DC)
00437 {
00438        unsigned short length;
00439        unsigned char *buffer;
00440        unsigned char markername[16];
00441        zval *tmp;
00442 
00443        length = php_read2(stream TSRMLS_CC);
00444        if (length < 2)      {
00445               return 0;
00446        }
00447        length -= 2;                       /* length includes itself */
00448 
00449        buffer = emalloc(length);
00450 
00451        if (php_stream_read(stream, buffer, (long) length) <= 0) {
00452               efree(buffer);
00453               return 0;
00454        }
00455 
00456        snprintf(markername, sizeof(markername), "APP%d", marker - M_APP0);
00457 
00458        if (zend_hash_find(Z_ARRVAL_P(info), markername, strlen(markername)+1, (void **) &tmp) == FAILURE) {
00459               /* XXX we onyl catch the 1st tag of it's kind! */
00460               add_assoc_stringl(info, markername, buffer, length, 1);
00461        }
00462 
00463        efree(buffer);
00464        return 1;
00465 }
00466 /* }}} */
00467 
00468 /* {{{ php_handle_jpeg
00469    main loop to parse JPEG structure */
00470 static struct gfxinfo *php_handle_jpeg (php_stream * stream, zval *info TSRMLS_DC) 
00471 {
00472        struct gfxinfo *result = NULL;
00473        unsigned int marker = M_PSEUDO;
00474        unsigned short length, ff_read=1;
00475 
00476        for (;;) {
00477               marker = php_next_marker(stream, marker, 1, ff_read TSRMLS_CC);
00478               ff_read = 0;
00479               switch (marker) {
00480                      case M_SOF0:
00481                      case M_SOF1:
00482                      case M_SOF2:
00483                      case M_SOF3:
00484                      case M_SOF5:
00485                      case M_SOF6:
00486                      case M_SOF7:
00487                      case M_SOF9:
00488                      case M_SOF10:
00489                      case M_SOF11:
00490                      case M_SOF13:
00491                      case M_SOF14:
00492                      case M_SOF15:
00493                             if (result == NULL) {
00494                                    /* handle SOFn block */
00495                                    result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00496                                    length = php_read2(stream TSRMLS_CC);
00497                                    result->bits     = php_stream_getc(stream);
00498                                    result->height   = php_read2(stream TSRMLS_CC);
00499                                    result->width    = php_read2(stream TSRMLS_CC);
00500                                    result->channels = php_stream_getc(stream);
00501                                    if (!info || length < 8) { /* if we don't want an extanded info -> return */
00502                                           return result;
00503                                    }
00504                                    if (php_stream_seek(stream, length - 8, SEEK_CUR)) { /* file error after info */
00505                                           return result;
00506                                    }
00507                             } else {
00508                                    if (!php_skip_variable(stream TSRMLS_CC)) {
00509                                           return result;
00510                                    }
00511                             }
00512                             break;
00513 
00514                      case M_APP0:
00515                      case M_APP1:
00516                      case M_APP2:
00517                      case M_APP3:
00518                      case M_APP4:
00519                      case M_APP5:
00520                      case M_APP6:
00521                      case M_APP7:
00522                      case M_APP8:
00523                      case M_APP9:
00524                      case M_APP10:
00525                      case M_APP11:
00526                      case M_APP12:
00527                      case M_APP13:
00528                      case M_APP14:
00529                      case M_APP15:
00530                             if (info) {
00531                                    if (!php_read_APP(stream, marker, info TSRMLS_CC)) { /* read all the app markes... */
00532                                           return result;
00533                                    }
00534                             } else {
00535                                    if (!php_skip_variable(stream TSRMLS_CC)) {
00536                                           return result;
00537                                    }
00538                             }
00539                             break;
00540 
00541                      case M_SOS:
00542                      case M_EOI:
00543                             return result;       /* we're about to hit image data, or are at EOF. stop processing. */
00544                      
00545                      default:
00546                             if (!php_skip_variable(stream TSRMLS_CC)) { /* anything else isn't interesting */
00547                                    return result;
00548                             }
00549                             break;
00550               }
00551        }
00552 
00553        return result; /* perhaps image broken -> no info but size */
00554 }
00555 /* }}} */
00556 
00557 /* {{{ php_read4
00558  */
00559 static unsigned int php_read4(php_stream * stream TSRMLS_DC)
00560 {
00561        unsigned char a[4];
00562 
00563        /* just return 0 if we hit the end-of-file */
00564        if ((php_stream_read(stream, a, sizeof(a))) != sizeof(a)) return 0;
00565 
00566        return (((unsigned int)a[0]) << 24)
00567             + (((unsigned int)a[1]) << 16)
00568             + (((unsigned int)a[2]) <<  8)
00569             + (((unsigned int)a[3]));
00570 }
00571 /* }}} */
00572 
00573 /* {{{ JPEG 2000 Marker Codes */
00574 #define JPEG2000_MARKER_PREFIX 0xFF /* All marker codes start with this */
00575 #define JPEG2000_MARKER_SOC 0x4F /* Start of Codestream */
00576 #define JPEG2000_MARKER_SOT 0x90 /* Start of Tile part */
00577 #define JPEG2000_MARKER_SOD 0x93 /* Start of Data */
00578 #define JPEG2000_MARKER_EOC 0xD9 /* End of Codestream */
00579 #define JPEG2000_MARKER_SIZ 0x51 /* Image and tile size */
00580 #define JPEG2000_MARKER_COD 0x52 /* Coding style default */ 
00581 #define JPEG2000_MARKER_COC 0x53 /* Coding style component */
00582 #define JPEG2000_MARKER_RGN 0x5E /* Region of interest */
00583 #define JPEG2000_MARKER_QCD 0x5C /* Quantization default */
00584 #define JPEG2000_MARKER_QCC 0x5D /* Quantization component */
00585 #define JPEG2000_MARKER_POC 0x5F /* Progression order change */
00586 #define JPEG2000_MARKER_TLM 0x55 /* Tile-part lengths */
00587 #define JPEG2000_MARKER_PLM 0x57 /* Packet length, main header */
00588 #define JPEG2000_MARKER_PLT 0x58 /* Packet length, tile-part header */
00589 #define JPEG2000_MARKER_PPM 0x60 /* Packed packet headers, main header */
00590 #define JPEG2000_MARKER_PPT 0x61 /* Packed packet headers, tile part header */
00591 #define JPEG2000_MARKER_SOP 0x91 /* Start of packet */
00592 #define JPEG2000_MARKER_EPH 0x92 /* End of packet header */
00593 #define JPEG2000_MARKER_CRG 0x63 /* Component registration */
00594 #define JPEG2000_MARKER_COM 0x64 /* Comment */
00595 /* }}} */
00596 
00597 /* {{{ php_handle_jpc
00598    Main loop to parse JPEG2000 raw codestream structure */
00599 static struct gfxinfo *php_handle_jpc(php_stream * stream TSRMLS_DC)
00600 {
00601        struct gfxinfo *result = NULL;
00602        unsigned short dummy_short;
00603        int highest_bit_depth, bit_depth;
00604        unsigned char first_marker_id;
00605        unsigned int i;
00606 
00607        /* JPEG 2000 components can be vastly different from one another.
00608           Each component can be sampled at a different resolution, use
00609           a different colour space, have a seperate colour depth, and
00610           be compressed totally differently! This makes giving a single
00611           "bit depth" answer somewhat problematic. For this implementation
00612           we'll use the highest depth encountered. */
00613 
00614        /* Get the single byte that remains after the file type indentification */
00615        first_marker_id = php_stream_getc(stream);
00616 
00617        /* Ensure that this marker is SIZ (as is mandated by the standard) */
00618        if (first_marker_id != JPEG2000_MARKER_SIZ) {
00619               php_error_docref(NULL TSRMLS_CC, E_WARNING, "JPEG2000 codestream corrupt(Expected SIZ marker not found after SOC)");
00620               return NULL;
00621        }
00622 
00623        result = (struct gfxinfo *)ecalloc(1, sizeof(struct gfxinfo));
00624 
00625        dummy_short = php_read2(stream TSRMLS_CC); /* Lsiz */
00626        dummy_short = php_read2(stream TSRMLS_CC); /* Rsiz */
00627        result->width = php_read4(stream TSRMLS_CC); /* Xsiz */
00628        result->height = php_read4(stream TSRMLS_CC); /* Ysiz */
00629 
00630 #if MBO_0
00631        php_read4(stream TSRMLS_CC); /* XOsiz */
00632        php_read4(stream TSRMLS_CC); /* YOsiz */
00633        php_read4(stream TSRMLS_CC); /* XTsiz */
00634        php_read4(stream TSRMLS_CC); /* YTsiz */
00635        php_read4(stream TSRMLS_CC); /* XTOsiz */
00636        php_read4(stream TSRMLS_CC); /* YTOsiz */
00637 #else
00638        if (php_stream_seek(stream, 24, SEEK_CUR)) {
00639               efree(result);
00640               return NULL;
00641        }
00642 #endif
00643 
00644        result->channels = php_read2(stream TSRMLS_CC); /* Csiz */
00645        if (result->channels < 0 || result->channels > 256) {
00646               efree(result);
00647               return NULL;
00648        }
00649 
00650        /* Collect bit depth info */
00651        highest_bit_depth = 0;
00652        for (i = 0; i < result->channels; i++) {
00653               bit_depth = php_stream_getc(stream); /* Ssiz[i] */
00654               bit_depth++;
00655               if (bit_depth > highest_bit_depth) {
00656                      highest_bit_depth = bit_depth;
00657               }
00658 
00659               php_stream_getc(stream); /* XRsiz[i] */
00660               php_stream_getc(stream); /* YRsiz[i] */
00661        }
00662 
00663        result->bits = highest_bit_depth;
00664 
00665        return result;
00666 }
00667 /* }}} */
00668 
00669 /* {{{ php_handle_jp2
00670    main loop to parse JPEG 2000 JP2 wrapper format structure */
00671 static struct gfxinfo *php_handle_jp2(php_stream *stream TSRMLS_DC)
00672 {
00673        struct gfxinfo *result = NULL;
00674        unsigned int box_length;
00675        unsigned int box_type;
00676        char jp2c_box_id[] = {(char)0x6a, (char)0x70, (char)0x32, (char)0x63};
00677 
00678        /* JP2 is a wrapper format for JPEG 2000. Data is contained within "boxes".
00679           Boxes themselves can be contained within "super-boxes". Super-Boxes can
00680           contain super-boxes which provides us with a hierarchical storage system.
00681 
00682           It is valid for a JP2 file to contain multiple individual codestreams.
00683           We'll just look for the first codestream at the root of the box structure
00684           and handle that.
00685        */
00686 
00687        for (;;)
00688        {
00689               box_length = php_read4(stream TSRMLS_CC); /* LBox */
00690               /* TBox */
00691               if (php_stream_read(stream, (void *)&box_type, sizeof(box_type)) != sizeof(box_type)) {
00692                      /* Use this as a general "out of stream" error */
00693                      break;
00694               }
00695 
00696               if (box_length == 1) {
00697                      /* We won't handle XLBoxes */
00698                      return NULL;
00699               }
00700 
00701               if (!memcmp(&box_type, jp2c_box_id, 4))
00702               {
00703                      /* Skip the first 3 bytes to emulate the file type examination */
00704                      php_stream_seek(stream, 3, SEEK_CUR);
00705 
00706                      result = php_handle_jpc(stream TSRMLS_CC);
00707                      break;
00708               }
00709 
00710               /* Stop if this was the last box */
00711               if ((int)box_length <= 0) {
00712                      break;
00713               }
00714 
00715               /* Skip over LBox (Which includes both TBox and LBox itself */
00716               if (php_stream_seek(stream, box_length - 8, SEEK_CUR)) {
00717                      break;
00718               }
00719        }
00720 
00721        if (result == NULL) {
00722               php_error_docref(NULL TSRMLS_CC, E_WARNING, "JP2 file has no codestreams at root level");
00723        }
00724 
00725        return result;
00726 }
00727 /* }}} */
00728 
00729 /* {{{ tiff constants
00730  */
00731 PHPAPI const int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
00732 
00733 /* uncompressed only */
00734 #define TAG_IMAGEWIDTH              0x0100
00735 #define TAG_IMAGEHEIGHT             0x0101
00736 /* compressed images only */
00737 #define TAG_COMP_IMAGEWIDTH         0xA002
00738 #define TAG_COMP_IMAGEHEIGHT        0xA003
00739 
00740 #define TAG_FMT_BYTE       1
00741 #define TAG_FMT_STRING     2
00742 #define TAG_FMT_USHORT     3
00743 #define TAG_FMT_ULONG      4
00744 #define TAG_FMT_URATIONAL  5
00745 #define TAG_FMT_SBYTE      6
00746 #define TAG_FMT_UNDEFINED  7
00747 #define TAG_FMT_SSHORT     8
00748 #define TAG_FMT_SLONG      9
00749 #define TAG_FMT_SRATIONAL 10
00750 #define TAG_FMT_SINGLE    11
00751 #define TAG_FMT_DOUBLE    12
00752 /* }}} */
00753 
00754 /* {{{ php_ifd_get16u
00755  * Convert a 16 bit unsigned value from file's native byte order */
00756 static int php_ifd_get16u(void *Short, int motorola_intel)
00757 {
00758        if (motorola_intel) {
00759               return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
00760        } else {
00761               return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
00762        }
00763 }
00764 /* }}} */
00765 
00766 /* {{{ php_ifd_get16s
00767  * Convert a 16 bit signed value from file's native byte order */
00768 static signed short php_ifd_get16s(void *Short, int motorola_intel)
00769 {
00770        return (signed short)php_ifd_get16u(Short, motorola_intel);
00771 }
00772 /* }}} */
00773 
00774 /* {{{ php_ifd_get32s
00775  * Convert a 32 bit signed value from file's native byte order */
00776 static int php_ifd_get32s(void *Long, int motorola_intel)
00777 {
00778        if (motorola_intel) {
00779               return  ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
00780                     | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
00781        } else {
00782               return  ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
00783                     | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
00784        }
00785 }
00786 /* }}} */
00787 
00788 /* {{{ php_ifd_get32u
00789  * Convert a 32 bit unsigned value from file's native byte order */
00790 static unsigned php_ifd_get32u(void *Long, int motorola_intel)
00791 {
00792        return (unsigned)php_ifd_get32s(Long, motorola_intel) & 0xffffffff;
00793 }
00794 /* }}} */
00795 
00796 /* {{{ php_handle_tiff
00797    main loop to parse TIFF structure */
00798 static struct gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int motorola_intel TSRMLS_DC)
00799 {
00800        struct gfxinfo *result = NULL;
00801        int i, num_entries;
00802        unsigned char *dir_entry;
00803        size_t ifd_size, dir_size, entry_value, width=0, height=0, ifd_addr;
00804        int entry_tag , entry_type;
00805        char *ifd_data, ifd_ptr[4];
00806 
00807        if (php_stream_read(stream, ifd_ptr, 4) != 4)
00808               return NULL;
00809        ifd_addr = php_ifd_get32u(ifd_ptr, motorola_intel);
00810        if (php_stream_seek(stream, ifd_addr-8, SEEK_CUR))
00811               return NULL;
00812        ifd_size = 2;
00813        ifd_data = emalloc(ifd_size);
00814        if (php_stream_read(stream, ifd_data, 2) != 2) {
00815               efree(ifd_data);
00816               return NULL;
00817        }
00818        num_entries = php_ifd_get16u(ifd_data, motorola_intel);
00819        dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/;
00820        ifd_size = dir_size;
00821        ifd_data = erealloc(ifd_data,ifd_size);
00822        if (php_stream_read(stream, ifd_data+2, dir_size-2) != dir_size-2) {
00823               efree(ifd_data);
00824               return NULL;
00825        }
00826        /* now we have the directory we can look how long it should be */
00827        ifd_size = dir_size;
00828        for(i=0;i<num_entries;i++) {
00829               dir_entry      = ifd_data+2+i*12;
00830               entry_tag    = php_ifd_get16u(dir_entry+0, motorola_intel);
00831               entry_type   = php_ifd_get16u(dir_entry+2, motorola_intel);
00832               switch(entry_type) {
00833                      case TAG_FMT_BYTE:
00834                      case TAG_FMT_SBYTE:
00835                             entry_value  = (size_t)(dir_entry[8]);
00836                             break;
00837                      case TAG_FMT_USHORT:
00838                             entry_value  = php_ifd_get16u(dir_entry+8, motorola_intel);
00839                             break;
00840                      case TAG_FMT_SSHORT:
00841                             entry_value  = php_ifd_get16s(dir_entry+8, motorola_intel);
00842                             break;
00843                      case TAG_FMT_ULONG:
00844                             entry_value  = php_ifd_get32u(dir_entry+8, motorola_intel);
00845                             break;
00846                      case TAG_FMT_SLONG:
00847                             entry_value  = php_ifd_get32s(dir_entry+8, motorola_intel);
00848                             break;
00849                      default:
00850                             continue;
00851               }
00852               switch(entry_tag) {
00853                      case TAG_IMAGEWIDTH:
00854                      case TAG_COMP_IMAGEWIDTH:
00855                             width  = entry_value;
00856                             break;
00857                      case TAG_IMAGEHEIGHT:
00858                      case TAG_COMP_IMAGEHEIGHT:
00859                             height = entry_value;
00860                             break;
00861               }
00862        }
00863        efree(ifd_data);
00864        if ( width && height) {
00865               /* not the same when in for-loop */
00866               result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00867               result->height   = height;
00868               result->width    = width;
00869               result->bits     = 0;
00870               result->channels = 0;
00871               return result;
00872        }
00873        return NULL;
00874 }
00875 /* }}} */
00876 
00877 /* {{{ php_handle_psd
00878  */
00879 static struct gfxinfo *php_handle_iff(php_stream * stream TSRMLS_DC)
00880 {
00881        struct gfxinfo * result;
00882        unsigned char a[10];
00883        int chunkId;
00884        int size;
00885        short width, height, bits;
00886 
00887        if (php_stream_read(stream, a, 8) != 8) {
00888               return NULL;
00889        }
00890        if (strncmp(a+4, "ILBM", 4) && strncmp(a+4, "PBM ", 4)) {
00891               return NULL;
00892        }
00893 
00894        /* loop chunks to find BMHD chunk */
00895        do {
00896               if (php_stream_read(stream, a, 8) != 8) {
00897                      return NULL;
00898               }
00899               chunkId = php_ifd_get32s(a+0, 1);
00900               size    = php_ifd_get32s(a+4, 1);
00901               if (size < 0) {
00902                      return NULL;
00903               }
00904               if ((size & 1) == 1) {
00905                      size++;
00906               }
00907               if (chunkId == 0x424d4844) { /* BMHD chunk */
00908                      if (size < 9 || php_stream_read(stream, a, 9) != 9) {
00909                             return NULL;
00910                      }
00911                      width  = php_ifd_get16s(a+0, 1);
00912                      height = php_ifd_get16s(a+2, 1);
00913                      bits   = a[8] & 0xff;
00914                      if (width > 0 && height > 0 && bits > 0 && bits < 33) {
00915                             result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00916                             result->width    = width;
00917                             result->height   = height;
00918                             result->bits     = bits;
00919                             result->channels = 0;
00920                             return result;
00921                      }
00922               } else {
00923                      if (php_stream_seek(stream, size, SEEK_CUR)) {
00924                             return NULL;
00925                      }
00926               }
00927        } while (1);
00928 }
00929 /* }}} */
00930 
00931 /* {{{ php_get_wbmp
00932  * int WBMP file format type
00933  * byte Header Type
00934  *     byte Extended Header
00935  *            byte Header Data (type 00 = multibyte)
00936  *            byte Header Data (type 11 = name/pairs)
00937  * int Number of columns
00938  * int Number of rows
00939  */
00940 static int php_get_wbmp(php_stream *stream, struct gfxinfo **result, int check TSRMLS_DC)
00941 {
00942        int i, width = 0, height = 0;
00943 
00944        if (php_stream_rewind(stream)) {
00945               return 0;
00946        }
00947 
00948        /* get type */
00949        if (php_stream_getc(stream) != 0) {
00950               return 0;
00951        }
00952 
00953        /* skip header */
00954        do {
00955               i = php_stream_getc(stream);
00956               if (i < 0) {
00957                      return 0;
00958               }
00959        } while (i & 0x80);
00960 
00961        /* get width */
00962        do {
00963               i = php_stream_getc(stream);
00964               if (i < 0) {
00965                      return 0;
00966               }
00967               width = (width << 7) | (i & 0x7f);
00968        } while (i & 0x80);
00969        
00970        /* get height */
00971        do {
00972               i = php_stream_getc(stream);
00973               if (i < 0) {
00974                      return 0;
00975               }
00976               height = (height << 7) | (i & 0x7f);
00977        } while (i & 0x80);
00978 
00979        /* maximum valid sizes for wbmp (although 127x127 may be a more accurate one) */
00980        if (!height || !width || height > 2048 || width > 2048) {
00981               return 0;
00982        }
00983        
00984        if (!check) {
00985               (*result)->width = width;
00986               (*result)->height = height;
00987        }
00988 
00989        return IMAGE_FILETYPE_WBMP;
00990 }
00991 /* }}} */
00992 
00993 /* {{{ php_handle_wbmp
00994 */
00995 static struct gfxinfo *php_handle_wbmp(php_stream * stream TSRMLS_DC)
00996 {
00997        struct gfxinfo *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
00998 
00999        if (!php_get_wbmp(stream, &result, 0 TSRMLS_CC)) {
01000               efree(result);
01001               return NULL;
01002        }
01003 
01004        return result;
01005 }
01006 /* }}} */
01007 
01008 /* {{{ php_get_xbm
01009  */
01010 static int php_get_xbm(php_stream *stream, struct gfxinfo **result TSRMLS_DC)
01011 {
01012     char *fline;
01013     char *iname;
01014     char *type;
01015     int value;
01016     unsigned int width = 0, height = 0;
01017 
01018        if (result) {
01019               *result = NULL;
01020        }
01021        if (php_stream_rewind(stream)) {
01022               return 0;
01023        }
01024        while ((fline=php_stream_gets(stream, NULL, 0)) != NULL) {
01025               iname = estrdup(fline); /* simple way to get necessary buffer of required size */
01026               if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
01027                      if (!(type = strrchr(iname, '_'))) {
01028                             type = iname;
01029                      } else {
01030                             type++;
01031                      }
01032        
01033                      if (!strcmp("width", type)) {
01034                             width = (unsigned int) value;
01035                             if (height) {
01036                                    efree(iname);
01037                                    break;
01038                             }
01039                      }
01040                      if (!strcmp("height", type)) {
01041                             height = (unsigned int) value;
01042                             if (width) {
01043                                    efree(iname);
01044                                    break;
01045                             }
01046                      }
01047               }
01048               efree(fline);
01049               efree(iname);
01050        }
01051        if (fline) {
01052               efree(fline);
01053        }
01054 
01055        if (width && height) {
01056               if (result) {
01057                      *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
01058                      (*result)->width = width;
01059                      (*result)->height = height;
01060               }
01061               return IMAGE_FILETYPE_XBM;
01062        }
01063 
01064        return 0;
01065 }
01066 /* }}} */
01067 
01068 /* {{{ php_handle_xbm
01069  */
01070 static struct gfxinfo *php_handle_xbm(php_stream * stream TSRMLS_DC)
01071 {
01072        struct gfxinfo *result;
01073        php_get_xbm(stream, &result TSRMLS_CC);
01074        return result;
01075 }
01076 /* }}} */
01077 
01078 /* {{{ php_handle_ico
01079  */
01080 static struct gfxinfo *php_handle_ico(php_stream * stream TSRMLS_DC)
01081 {
01082        struct gfxinfo *result = NULL;
01083        unsigned char dim[16];
01084        int num_icons = 0;
01085 
01086        if (php_stream_read(stream, dim, 2) != 2)
01087               return NULL;
01088 
01089        num_icons = (((unsigned int)dim[1]) << 8) + ((unsigned int) dim[0]);
01090 
01091        if (num_icons < 1 || num_icons > 255)
01092               return NULL;
01093 
01094        result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo));
01095 
01096        while (num_icons > 0)
01097        {
01098               if (php_stream_read(stream, dim, sizeof(dim)) != sizeof(dim))
01099                      break;
01100 
01101               if ((((unsigned int)dim[7]) <<  8) +  ((unsigned int)dim[6]) >= result->bits)
01102               {
01103                      result->width    =  (unsigned int)dim[0];
01104                      result->height   =  (unsigned int)dim[1];
01105                      result->bits     =  (((unsigned int)dim[7]) <<  8) +  ((unsigned int)dim[6]);
01106               }
01107               num_icons--;
01108        }
01109 
01110        return result;
01111 }
01112 /* }}} */
01113 
01114 /* {{{ php_image_type_to_mime_type
01115  * Convert internal image_type to mime type */
01116 PHPAPI char * php_image_type_to_mime_type(int image_type)
01117 {
01118        switch( image_type) {
01119               case IMAGE_FILETYPE_GIF:
01120                      return "image/gif";
01121               case IMAGE_FILETYPE_JPEG:
01122                      return "image/jpeg";
01123               case IMAGE_FILETYPE_PNG:
01124                      return "image/png";
01125               case IMAGE_FILETYPE_SWF:
01126               case IMAGE_FILETYPE_SWC:
01127                      return "application/x-shockwave-flash";
01128               case IMAGE_FILETYPE_PSD:
01129                      return "image/psd";
01130               case IMAGE_FILETYPE_BMP:
01131                      return "image/x-ms-bmp";
01132               case IMAGE_FILETYPE_TIFF_II:
01133               case IMAGE_FILETYPE_TIFF_MM:
01134                      return "image/tiff";
01135               case IMAGE_FILETYPE_IFF:
01136                      return "image/iff";
01137               case IMAGE_FILETYPE_WBMP:
01138                      return "image/vnd.wap.wbmp";
01139               case IMAGE_FILETYPE_JPC:
01140                      return "application/octet-stream";
01141               case IMAGE_FILETYPE_JP2:
01142                      return "image/jp2";
01143               case IMAGE_FILETYPE_XBM:
01144                      return "image/xbm";
01145               case IMAGE_FILETYPE_ICO:
01146                      return "image/vnd.microsoft.icon";
01147               default:
01148               case IMAGE_FILETYPE_UNKNOWN:
01149                      return "application/octet-stream"; /* suppose binary format */
01150        }
01151 }
01152 /* }}} */
01153 
01154 /* {{{ proto string image_type_to_mime_type(int imagetype)
01155    Get Mime-Type for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
01156 PHP_FUNCTION(image_type_to_mime_type)
01157 {
01158        long p_image_type;
01159 
01160        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &p_image_type) == FAILURE) {
01161               return;
01162        }
01163 
01164        ZVAL_STRING(return_value, (char*)php_image_type_to_mime_type(p_image_type), 1);
01165 }
01166 /* }}} */
01167 
01168 /* {{{ proto string image_type_to_extension(int imagetype [, bool include_dot])
01169    Get file extension for image-type returned by getimagesize, exif_read_data, exif_thumbnail, exif_imagetype */
01170 PHP_FUNCTION(image_type_to_extension)
01171 {
01172        long image_type;
01173        zend_bool inc_dot=1;
01174 
01175        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &image_type, &inc_dot) == FAILURE) {
01176               RETURN_FALSE;
01177        }
01178 
01179        switch (image_type) {
01180               case IMAGE_FILETYPE_GIF:
01181                      RETURN_STRING(".gif" + !inc_dot, 1);
01182               case IMAGE_FILETYPE_JPEG:
01183                      RETURN_STRING(".jpeg" + !inc_dot, 1);
01184               case IMAGE_FILETYPE_PNG:
01185                      RETURN_STRING(".png" + !inc_dot, 1);
01186               case IMAGE_FILETYPE_SWF:
01187               case IMAGE_FILETYPE_SWC:
01188                      RETURN_STRING(".swf" + !inc_dot, 1);
01189               case IMAGE_FILETYPE_PSD:
01190                      RETURN_STRING(".psd" + !inc_dot, 1);
01191               case IMAGE_FILETYPE_BMP:
01192               case IMAGE_FILETYPE_WBMP:
01193                      RETURN_STRING(".bmp" + !inc_dot, 1);
01194               case IMAGE_FILETYPE_TIFF_II:
01195               case IMAGE_FILETYPE_TIFF_MM:
01196                      RETURN_STRING(".tiff" + !inc_dot, 1);
01197               case IMAGE_FILETYPE_IFF:
01198                      RETURN_STRING(".iff" + !inc_dot, 1);
01199               case IMAGE_FILETYPE_JPC:
01200                      RETURN_STRING(".jpc" + !inc_dot, 1);
01201               case IMAGE_FILETYPE_JP2:
01202                      RETURN_STRING(".jp2" + !inc_dot, 1);
01203               case IMAGE_FILETYPE_JPX:
01204                      RETURN_STRING(".jpx" + !inc_dot, 1);
01205               case IMAGE_FILETYPE_JB2:
01206                      RETURN_STRING(".jb2" + !inc_dot, 1);
01207               case IMAGE_FILETYPE_XBM:
01208                      RETURN_STRING(".xbm" + !inc_dot, 1);
01209               case IMAGE_FILETYPE_ICO:
01210                      RETURN_STRING(".ico" + !inc_dot, 1);
01211        }
01212 
01213        RETURN_FALSE;
01214 }
01215 /* }}} */
01216 
01217 /* {{{ php_imagetype
01218    detect filetype from first bytes */
01219 PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
01220 {
01221        char tmp[12];
01222 
01223        if ( !filetype) filetype = tmp;
01224        if((php_stream_read(stream, filetype, 3)) != 3) {
01225               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
01226               return IMAGE_FILETYPE_UNKNOWN;
01227        }
01228 
01229 /* BYTES READ: 3 */
01230        if (!memcmp(filetype, php_sig_gif, 3)) {
01231               return IMAGE_FILETYPE_GIF;
01232        } else if (!memcmp(filetype, php_sig_jpg, 3)) {
01233               return IMAGE_FILETYPE_JPEG;
01234        } else if (!memcmp(filetype, php_sig_png, 3)) {
01235               if (php_stream_read(stream, filetype+3, 5) != 5) {
01236                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
01237                      return IMAGE_FILETYPE_UNKNOWN;
01238               }
01239               if (!memcmp(filetype, php_sig_png, 8)) {
01240                      return IMAGE_FILETYPE_PNG;
01241               } else {
01242                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "PNG file corrupted by ASCII conversion");
01243                      return IMAGE_FILETYPE_UNKNOWN;
01244               }
01245        } else if (!memcmp(filetype, php_sig_swf, 3)) {
01246               return IMAGE_FILETYPE_SWF;
01247        } else if (!memcmp(filetype, php_sig_swc, 3)) {
01248               return IMAGE_FILETYPE_SWC;
01249        } else if (!memcmp(filetype, php_sig_psd, 3)) {
01250               return IMAGE_FILETYPE_PSD;
01251        } else if (!memcmp(filetype, php_sig_bmp, 2)) {
01252               return IMAGE_FILETYPE_BMP;
01253        } else if (!memcmp(filetype, php_sig_jpc, 3)) {
01254               return IMAGE_FILETYPE_JPC;
01255        }
01256 
01257        if (php_stream_read(stream, filetype+3, 1) != 1) {
01258               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
01259               return IMAGE_FILETYPE_UNKNOWN;
01260        }
01261 /* BYTES READ: 4 */
01262        if (!memcmp(filetype, php_sig_tif_ii, 4)) {
01263               return IMAGE_FILETYPE_TIFF_II;
01264        } else if (!memcmp(filetype, php_sig_tif_mm, 4)) {
01265               return IMAGE_FILETYPE_TIFF_MM;
01266        } else if (!memcmp(filetype, php_sig_iff, 4)) {
01267               return IMAGE_FILETYPE_IFF;
01268        } else if (!memcmp(filetype, php_sig_ico, 4)) {
01269               return IMAGE_FILETYPE_ICO;
01270        }
01271 
01272        if (php_stream_read(stream, filetype+4, 8) != 8) {
01273               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
01274               return IMAGE_FILETYPE_UNKNOWN;
01275        }
01276 /* BYTES READ: 12 */
01277        if (!memcmp(filetype, php_sig_jp2, 12)) {
01278               return IMAGE_FILETYPE_JP2;
01279        }
01280 
01281 /* AFTER ALL ABOVE FAILED */
01282        if (php_get_wbmp(stream, NULL, 1 TSRMLS_CC)) {
01283               return IMAGE_FILETYPE_WBMP;
01284        }
01285        if (php_get_xbm(stream, NULL TSRMLS_CC)) {
01286               return IMAGE_FILETYPE_XBM;
01287        }
01288        return IMAGE_FILETYPE_UNKNOWN;
01289 }
01290 /* }}} */
01291 
01292 /* {{{ proto array getimagesize(string imagefile [, array info])
01293    Get the size of an image as 4-element array */
01294 PHP_FUNCTION(getimagesize)
01295 {
01296        zval **info = NULL;
01297        char *arg1, *temp;
01298        int arg1_len, itype = 0, argc = ZEND_NUM_ARGS();
01299        struct gfxinfo *result = NULL;
01300        php_stream * stream = NULL;
01301 
01302        if (zend_parse_parameters(argc TSRMLS_CC, "s|Z", &arg1, &arg1_len, &info) == FAILURE) {
01303               return;
01304        }
01305        
01306        if (argc == 2) {
01307               zval_dtor(*info);
01308               array_init(*info);
01309        }
01310 
01311        stream = php_stream_open_wrapper(arg1, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL);
01312 
01313        if (!stream) {
01314               RETURN_FALSE;
01315        }
01316 
01317        itype = php_getimagetype(stream, NULL TSRMLS_CC);
01318        switch( itype) {
01319               case IMAGE_FILETYPE_GIF:
01320                      result = php_handle_gif(stream TSRMLS_CC);
01321                      break;
01322               case IMAGE_FILETYPE_JPEG:
01323                      if (info) {
01324                             result = php_handle_jpeg(stream, *info TSRMLS_CC);
01325                      } else {
01326                             result = php_handle_jpeg(stream, NULL TSRMLS_CC);
01327                      }
01328                      break;
01329               case IMAGE_FILETYPE_PNG:
01330                      result = php_handle_png(stream TSRMLS_CC);
01331                      break;
01332               case IMAGE_FILETYPE_SWF:
01333                      result = php_handle_swf(stream TSRMLS_CC);
01334                      break;
01335               case IMAGE_FILETYPE_SWC:
01336 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
01337                      result = php_handle_swc(stream TSRMLS_CC);
01338 #else
01339                      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");
01340 #endif
01341                      break;
01342               case IMAGE_FILETYPE_PSD:
01343                      result = php_handle_psd(stream TSRMLS_CC);
01344                      break;
01345               case IMAGE_FILETYPE_BMP:
01346                      result = php_handle_bmp(stream TSRMLS_CC);
01347                      break;
01348               case IMAGE_FILETYPE_TIFF_II:
01349                      result = php_handle_tiff(stream, NULL, 0 TSRMLS_CC);
01350                      break;
01351               case IMAGE_FILETYPE_TIFF_MM:
01352                      result = php_handle_tiff(stream, NULL, 1 TSRMLS_CC);
01353                      break;
01354               case IMAGE_FILETYPE_JPC:
01355                      result = php_handle_jpc(stream TSRMLS_CC);
01356                      break;
01357               case IMAGE_FILETYPE_JP2:
01358                      result = php_handle_jp2(stream TSRMLS_CC);
01359                      break;
01360               case IMAGE_FILETYPE_IFF:
01361                      result = php_handle_iff(stream TSRMLS_CC);
01362                      break;
01363               case IMAGE_FILETYPE_WBMP:
01364                      result = php_handle_wbmp(stream TSRMLS_CC);
01365                      break;
01366               case IMAGE_FILETYPE_XBM:
01367                      result = php_handle_xbm(stream TSRMLS_CC);
01368                      break;
01369               case IMAGE_FILETYPE_ICO:
01370                      result = php_handle_ico(stream TSRMLS_CC);
01371                      break;
01372               default:
01373               case IMAGE_FILETYPE_UNKNOWN:
01374                      break;
01375        }
01376 
01377        php_stream_close(stream);
01378 
01379        if (result) {
01380               array_init(return_value);
01381               add_index_long(return_value, 0, result->width);
01382               add_index_long(return_value, 1, result->height);
01383               add_index_long(return_value, 2, itype);
01384               spprintf(&temp, 0, "width=\"%d\" height=\"%d\"", result->width, result->height);
01385               add_index_string(return_value, 3, temp, 0);
01386 
01387               if (result->bits != 0) {
01388                      add_assoc_long(return_value, "bits", result->bits);
01389               }
01390               if (result->channels != 0) {
01391                      add_assoc_long(return_value, "channels", result->channels);
01392               }
01393               add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype), 1);
01394               efree(result);
01395        } else {
01396               RETURN_FALSE;
01397        }
01398 }
01399 /* }}} */
01400 
01401 /*
01402  * Local variables:
01403  * tab-width: 4
01404  * c-basic-offset: 4
01405  * End:
01406  * vim600: sw=4 ts=4 fdm=marker
01407  * vim<600: sw=4 ts=4
01408  */