Annotation of embedaddon/php/ext/standard/image.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>