~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to ext/standard/image.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

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