~ubuntu-branches/ubuntu/breezy/php5/breezy-security

« back to all changes in this revision

Viewing changes to ext/exif/exif.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: exif.c,v 1.162.2.9 2005/08/05 14:00:47 hyanantha Exp $ */
 
21
 
 
22
/*  ToDos
 
23
 *
 
24
 *      See if example images from http://www.exif.org have illegal
 
25
 *              thumbnail sizes or if code is corrupt.
 
26
 *      Create/Update exif headers.
 
27
 *      Create/Remove/Update image thumbnails.
 
28
 */
 
29
 
 
30
/*  Security
 
31
 *
 
32
 *  At current time i do not see any security problems but a potential
 
33
 *  attacker could generate an image with recursive ifd pointers...(Marcus)
 
34
 */
 
35
 
 
36
#ifdef HAVE_CONFIG_H
 
37
#include "config.h"
 
38
#endif
 
39
 
 
40
#include "php.h"
 
41
#include "ext/standard/file.h"
 
42
 
 
43
#if HAVE_EXIF
 
44
 
 
45
/* When EXIF_DEBUG is defined the module generates a lot of debug messages
 
46
 * that help understanding what is going on. This can and should be used
 
47
 * while extending the module as it shows if you are at the right position.
 
48
 * You are always considered to have a copy of TIFF6.0 and EXIF2.10 standard.
 
49
 */
 
50
#undef EXIF_DEBUG
 
51
 
 
52
#ifdef EXIF_DEBUG
 
53
#define EXIFERR_DC , const char *_file, size_t _line TSRMLS_DC
 
54
#define EXIFERR_CC , __FILE__, __LINE__ TSRMLS_CC
 
55
#else
 
56
#define EXIFERR_DC TSRMLS_DC
 
57
#define EXIFERR_CC TSRMLS_CC
 
58
#endif
 
59
 
 
60
#undef EXIF_JPEG2000
 
61
 
 
62
#include "php_exif.h"
 
63
#include <math.h>
 
64
#include "php_ini.h"
 
65
#include "ext/standard/php_string.h"
 
66
#include "ext/standard/php_image.h"
 
67
#include "ext/standard/info.h" 
 
68
 
 
69
#if defined(PHP_WIN32) || (HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING))
 
70
#define EXIF_USE_MBSTRING 1
 
71
#else
 
72
#define EXIF_USE_MBSTRING 0
 
73
#endif
 
74
 
 
75
#if EXIF_USE_MBSTRING
 
76
#include "ext/mbstring/mbstring.h"
 
77
#endif
 
78
 
 
79
/* needed for ssize_t definition */
 
80
#include <sys/types.h>
 
81
 
 
82
typedef unsigned char uchar;
 
83
 
 
84
#ifndef safe_emalloc
 
85
# define safe_emalloc(a,b,c) emalloc((a)*(b)+(c))
 
86
#endif
 
87
 
 
88
#ifndef TRUE
 
89
#       define TRUE 1
 
90
#       define FALSE 0
 
91
#endif
 
92
 
 
93
#ifndef max
 
94
#       define max(a,b) ((a)>(b) ? (a) : (b))
 
95
#endif
 
96
 
 
97
#define EFREE_IF(ptr)   if (ptr) efree(ptr)
 
98
 
 
99
#define MAX_IFD_NESTING_LEVEL 100
 
100
 
 
101
static
 
102
ZEND_BEGIN_ARG_INFO(exif_thumbnail_force_ref, 1)
 
103
        ZEND_ARG_PASS_INFO(0)
 
104
ZEND_END_ARG_INFO();
 
105
 
 
106
/* {{{ exif_functions[]
 
107
 */
 
108
function_entry exif_functions[] = {
 
109
        PHP_FE(exif_read_data, NULL)
 
110
        PHP_FALIAS(read_exif_data, exif_read_data, NULL)
 
111
        PHP_FE(exif_tagname, NULL)
 
112
        PHP_FE(exif_thumbnail, exif_thumbnail_force_ref)
 
113
        PHP_FE(exif_imagetype, NULL)
 
114
        {NULL, NULL, NULL}
 
115
};
 
116
/* }}} */
 
117
 
 
118
#define EXIF_VERSION "1.4 $Id: exif.c,v 1.162.2.9 2005/08/05 14:00:47 hyanantha Exp $"
 
119
 
 
120
/* {{{ PHP_MINFO_FUNCTION
 
121
 */
 
122
PHP_MINFO_FUNCTION(exif)
 
123
{
 
124
        php_info_print_table_start();
 
125
        php_info_print_table_row(2, "EXIF Support", "enabled");
 
126
        php_info_print_table_row(2, "EXIF Version", EXIF_VERSION);
 
127
        php_info_print_table_row(2, "Supported EXIF Version", "0220");
 
128
        php_info_print_table_row(2, "Supported filetypes", "JPEG,TIFF");
 
129
        php_info_print_table_end();
 
130
}
 
131
/* }}} */
 
132
 
 
133
ZEND_BEGIN_MODULE_GLOBALS(exif)
 
134
        char * encode_unicode;
 
135
        char * decode_unicode_be;
 
136
        char * decode_unicode_le;
 
137
        char * encode_jis;
 
138
        char * decode_jis_be;
 
139
        char * decode_jis_le;
 
140
ZEND_END_MODULE_GLOBALS(exif) 
 
141
 
 
142
ZEND_DECLARE_MODULE_GLOBALS(exif)
 
143
 
 
144
#ifdef ZTS
 
145
#define EXIF_G(v) TSRMG(exif_globals_id, zend_exif_globals *, v)
 
146
#else
 
147
#define EXIF_G(v) (exif_globals.v)
 
148
#endif
 
149
 
 
150
/* {{{ PHP_INI
 
151
 */
 
152
 
 
153
ZEND_INI_MH(OnUpdateEncode)
 
154
{
 
155
#if EXIF_USE_MBSTRING
 
156
        if (new_value && strlen(new_value) && !php_mb_check_encoding_list(new_value TSRMLS_CC)) {
 
157
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal encoding ignored: '%s'", new_value);
 
158
                return FAILURE;
 
159
        }
 
160
#endif
 
161
        return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
 
162
}
 
163
 
 
164
ZEND_INI_MH(OnUpdateDecode)
 
165
{
 
166
#if EXIF_USE_MBSTRING
 
167
        if (!php_mb_check_encoding_list(new_value TSRMLS_CC)) {
 
168
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal encoding ignored: '%s'", new_value);
 
169
                return FAILURE;
 
170
        }
 
171
#endif
 
172
        return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
 
173
}
 
174
 
 
175
PHP_INI_BEGIN()
 
176
    STD_PHP_INI_ENTRY("exif.encode_unicode",          "ISO-8859-15", PHP_INI_ALL, OnUpdateEncode, encode_unicode,    zend_exif_globals, exif_globals)
 
177
    STD_PHP_INI_ENTRY("exif.decode_unicode_motorola", "UCS-2BE",     PHP_INI_ALL, OnUpdateDecode, decode_unicode_be, zend_exif_globals, exif_globals)
 
178
    STD_PHP_INI_ENTRY("exif.decode_unicode_intel",    "UCS-2LE",     PHP_INI_ALL, OnUpdateDecode, decode_unicode_le, zend_exif_globals, exif_globals)
 
179
    STD_PHP_INI_ENTRY("exif.encode_jis",              "",            PHP_INI_ALL, OnUpdateEncode, encode_jis,        zend_exif_globals, exif_globals)
 
180
    STD_PHP_INI_ENTRY("exif.decode_jis_motorola",     "JIS",         PHP_INI_ALL, OnUpdateDecode, decode_jis_be,     zend_exif_globals, exif_globals)
 
181
    STD_PHP_INI_ENTRY("exif.decode_jis_intel",        "JIS",         PHP_INI_ALL, OnUpdateDecode, decode_jis_le,     zend_exif_globals, exif_globals)
 
182
PHP_INI_END()
 
183
/* }}} */
 
184
 
 
185
/* {{{ php_extname_init_globals
 
186
 */
 
187
static void php_exif_init_globals(zend_exif_globals *exif_globals)
 
188
{
 
189
        exif_globals->encode_unicode    = NULL;
 
190
        exif_globals->decode_unicode_be = NULL;
 
191
        exif_globals->decode_unicode_le = NULL;
 
192
        exif_globals->encode_jis        = NULL;
 
193
        exif_globals->decode_jis_be     = NULL;
 
194
        exif_globals->decode_jis_le     = NULL;
 
195
}
 
196
/* }}} */
 
197
 
 
198
/* {{{ PHP_MINIT_FUNCTION(exif)
 
199
   Get the size of an image as 4-element array */
 
200
PHP_MINIT_FUNCTION(exif)
 
201
{
 
202
        ZEND_INIT_MODULE_GLOBALS(exif, php_exif_init_globals, NULL);
 
203
        REGISTER_INI_ENTRIES();
 
204
        REGISTER_LONG_CONSTANT("EXIF_USE_MBSTRING", EXIF_USE_MBSTRING, CONST_CS | CONST_PERSISTENT); 
 
205
        return SUCCESS;
 
206
}
 
207
/* }}} */
 
208
 
 
209
/* {{{ PHP_MSHUTDOWN_FUNCTION
 
210
 */
 
211
PHP_MSHUTDOWN_FUNCTION(exif)
 
212
{
 
213
        UNREGISTER_INI_ENTRIES();
 
214
        return SUCCESS;
 
215
}
 
216
/* }}} */
 
217
 
 
218
/* {{{ exif_module_entry
 
219
 */
 
220
zend_module_entry exif_module_entry = {
 
221
#if ZEND_MODULE_API_NO >= 20010901
 
222
        STANDARD_MODULE_HEADER,
 
223
#endif
 
224
        "exif",
 
225
        exif_functions,
 
226
        PHP_MINIT(exif), 
 
227
        PHP_MSHUTDOWN(exif),
 
228
        NULL, NULL,
 
229
        PHP_MINFO(exif),
 
230
#if ZEND_MODULE_API_NO >= 20010901
 
231
        EXIF_VERSION,
 
232
#endif
 
233
        STANDARD_MODULE_PROPERTIES
 
234
};
 
235
/* }}} */
 
236
 
 
237
#ifdef COMPILE_DL_EXIF
 
238
ZEND_GET_MODULE(exif)
 
239
#endif
 
240
 
 
241
/* {{{ php_strnlen
 
242
 * get length of string if buffer if less than buffer size or buffer size */
 
243
static size_t php_strnlen(char* str, size_t maxlen) {
 
244
        size_t len = 0;
 
245
 
 
246
        if (str && maxlen && *str) {
 
247
                do {
 
248
                        len++;
 
249
                } while (--maxlen && *(++str));
 
250
        }
 
251
        return len;
 
252
}
 
253
/* }}} */
 
254
 
 
255
/* {{{ error messages
 
256
*/
 
257
static const char * EXIF_ERROR_FILEEOF   = "Unexpected end of file reached";
 
258
static const char * EXIF_ERROR_CORRUPT   = "File structure corrupted";
 
259
static const char * EXIF_ERROR_THUMBEOF  = "Thumbnail goes IFD boundary or end of file reached";
 
260
static const char * EXIF_ERROR_FSREALLOC = "Illegal reallocating of undefined file section";
 
261
 
 
262
#define EXIF_ERRLOG_FILEEOF(ImageInfo)    exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "%s", EXIF_ERROR_FILEEOF);
 
263
#define EXIF_ERRLOG_CORRUPT(ImageInfo)    exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "%s", EXIF_ERROR_CORRUPT);
 
264
#define EXIF_ERRLOG_THUMBEOF(ImageInfo)   exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "%s", EXIF_ERROR_THUMBEOF);
 
265
#define EXIF_ERRLOG_FSREALLOC(ImageInfo)  exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "%s", EXIF_ERROR_FSREALLOC);
 
266
/* }}} */
 
267
 
 
268
/* {{{ format description defines
 
269
   Describes format descriptor
 
270
*/
 
271
static int php_tiff_bytes_per_format[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 1};
 
272
#define NUM_FORMATS 13
 
273
 
 
274
#define TAG_FMT_BYTE       1
 
275
#define TAG_FMT_STRING     2
 
276
#define TAG_FMT_USHORT     3
 
277
#define TAG_FMT_ULONG      4
 
278
#define TAG_FMT_URATIONAL  5
 
279
#define TAG_FMT_SBYTE      6
 
280
#define TAG_FMT_UNDEFINED  7
 
281
#define TAG_FMT_SSHORT     8
 
282
#define TAG_FMT_SLONG      9
 
283
#define TAG_FMT_SRATIONAL 10
 
284
#define TAG_FMT_SINGLE    11
 
285
#define TAG_FMT_DOUBLE    12
 
286
#define TAG_FMT_IFD       13
 
287
 
 
288
#ifdef EXIF_DEBUG
 
289
static char *exif_get_tagformat(int format)
 
290
{
 
291
        switch(format) {
 
292
                case TAG_FMT_BYTE:      return "BYTE";
 
293
                case TAG_FMT_STRING:    return "STRING";
 
294
                case TAG_FMT_USHORT:    return "USHORT";
 
295
                case TAG_FMT_ULONG:     return "ULONG";
 
296
                case TAG_FMT_URATIONAL: return "URATIONAL";
 
297
                case TAG_FMT_SBYTE:     return "SBYTE";
 
298
                case TAG_FMT_UNDEFINED: return "UNDEFINED";
 
299
                case TAG_FMT_SSHORT:    return "SSHORT";
 
300
                case TAG_FMT_SLONG:     return "SLONG";
 
301
                case TAG_FMT_SRATIONAL: return "SRATIONAL";
 
302
                case TAG_FMT_SINGLE:    return "SINGLE";
 
303
                case TAG_FMT_DOUBLE:    return "DOUBLE";
 
304
                case TAG_FMT_IFD:       return "IFD";
 
305
        }
 
306
        return "*Illegal";
 
307
}
 
308
#endif
 
309
 
 
310
/* Describes tag values */
 
311
#define TAG_GPS_VERSION_ID              0x0000
 
312
#define TAG_GPS_LATITUDE_REF            0x0001
 
313
#define TAG_GPS_LATITUDE                0x0002
 
314
#define TAG_GPS_LONGITUDE_REF           0x0003
 
315
#define TAG_GPS_LONGITUDE               0x0004
 
316
#define TAG_GPS_ALTITUDE_REF            0x0005
 
317
#define TAG_GPS_ALTITUDE                0x0006
 
318
#define TAG_GPS_TIME_STAMP              0x0007
 
319
#define TAG_GPS_SATELLITES              0x0008
 
320
#define TAG_GPS_STATUS                  0x0009
 
321
#define TAG_GPS_MEASURE_MODE            0x000A
 
322
#define TAG_GPS_DOP                     0x000B
 
323
#define TAG_GPS_SPEED_REF               0x000C
 
324
#define TAG_GPS_SPEED                   0x000D
 
325
#define TAG_GPS_TRACK_REF               0x000E
 
326
#define TAG_GPS_TRACK                   0x000F
 
327
#define TAG_GPS_IMG_DIRECTION_REF       0x0010
 
328
#define TAG_GPS_IMG_DIRECTION           0x0011
 
329
#define TAG_GPS_MAP_DATUM               0x0012
 
330
#define TAG_GPS_DEST_LATITUDE_REF       0x0013
 
331
#define TAG_GPS_DEST_LATITUDE           0x0014
 
332
#define TAG_GPS_DEST_LONGITUDE_REF      0x0015
 
333
#define TAG_GPS_DEST_LONGITUDE          0x0016
 
334
#define TAG_GPS_DEST_BEARING_REF        0x0017
 
335
#define TAG_GPS_DEST_BEARING            0x0018
 
336
#define TAG_GPS_DEST_DISTANCE_REF       0x0019
 
337
#define TAG_GPS_DEST_DISTANCE           0x001A
 
338
#define TAG_GPS_PROCESSING_METHOD       0x001B
 
339
#define TAG_GPS_AREA_INFORMATION        0x001C
 
340
#define TAG_GPS_DATE_STAMP              0x001D
 
341
#define TAG_GPS_DIFFERENTIAL            0x001E
 
342
#define TAG_TIFF_COMMENT                0x00FE /* SHOUDLNT HAPPEN */
 
343
#define TAG_NEW_SUBFILE                 0x00FE /* New version of subfile tag */
 
344
#define TAG_SUBFILE_TYPE                0x00FF /* Old version of subfile tag */
 
345
#define TAG_IMAGEWIDTH                  0x0100
 
346
#define TAG_IMAGEHEIGHT                 0x0101
 
347
#define TAG_BITS_PER_SAMPLE             0x0102
 
348
#define TAG_COMPRESSION                 0x0103
 
349
#define TAG_PHOTOMETRIC_INTERPRETATION  0x0106
 
350
#define TAG_TRESHHOLDING                0x0107
 
351
#define TAG_CELL_WIDTH                  0x0108
 
352
#define TAG_CELL_HEIGHT                 0x0109
 
353
#define TAG_FILL_ORDER                  0x010A
 
354
#define TAG_DOCUMENT_NAME               0x010D
 
355
#define TAG_IMAGE_DESCRIPTION           0x010E
 
356
#define TAG_MAKE                        0x010F
 
357
#define TAG_MODEL                       0x0110
 
358
#define TAG_STRIP_OFFSETS               0x0111
 
359
#define TAG_ORIENTATION                 0x0112
 
360
#define TAG_SAMPLES_PER_PIXEL           0x0115
 
361
#define TAG_ROWS_PER_STRIP              0x0116
 
362
#define TAG_STRIP_BYTE_COUNTS           0x0117
 
363
#define TAG_MIN_SAMPPLE_VALUE           0x0118
 
364
#define TAG_MAX_SAMPLE_VALUE            0x0119
 
365
#define TAG_X_RESOLUTION                0x011A
 
366
#define TAG_Y_RESOLUTION                0x011B
 
367
#define TAG_PLANAR_CONFIGURATION        0x011C
 
368
#define TAG_PAGE_NAME                   0x011D
 
369
#define TAG_X_POSITION                  0x011E
 
370
#define TAG_Y_POSITION                  0x011F
 
371
#define TAG_FREE_OFFSETS                0x0120
 
372
#define TAG_FREE_BYTE_COUNTS            0x0121
 
373
#define TAG_GRAY_RESPONSE_UNIT          0x0122
 
374
#define TAG_GRAY_RESPONSE_CURVE         0x0123
 
375
#define TAG_RESOLUTION_UNIT             0x0128
 
376
#define TAG_PAGE_NUMBER                 0x0129
 
377
#define TAG_TRANSFER_FUNCTION           0x012D
 
378
#define TAG_SOFTWARE                    0x0131
 
379
#define TAG_DATETIME                    0x0132
 
380
#define TAG_ARTIST                      0x013B
 
381
#define TAG_HOST_COMPUTER               0x013C
 
382
#define TAG_PREDICTOR                   0x013D
 
383
#define TAG_WHITE_POINT                 0x013E
 
384
#define TAG_PRIMARY_CHROMATICITIES      0x013F
 
385
#define TAG_COLOR_MAP                   0x0140
 
386
#define TAG_HALFTONE_HINTS              0x0141
 
387
#define TAG_TILE_WIDTH                  0x0142
 
388
#define TAG_TILE_LENGTH                 0x0143
 
389
#define TAG_TILE_OFFSETS                0x0144
 
390
#define TAG_TILE_BYTE_COUNTS            0x0145
 
391
#define TAG_SUB_IFD                     0x014A
 
392
#define TAG_INK_SETMPUTER               0x014C
 
393
#define TAG_INK_NAMES                   0x014D
 
394
#define TAG_NUMBER_OF_INKS              0x014E
 
395
#define TAG_DOT_RANGE                   0x0150
 
396
#define TAG_TARGET_PRINTER              0x0151
 
397
#define TAG_EXTRA_SAMPLE                0x0152
 
398
#define TAG_SAMPLE_FORMAT               0x0153
 
399
#define TAG_S_MIN_SAMPLE_VALUE          0x0154
 
400
#define TAG_S_MAX_SAMPLE_VALUE          0x0155
 
401
#define TAG_TRANSFER_RANGE              0x0156
 
402
#define TAG_JPEG_TABLES                 0x015B
 
403
#define TAG_JPEG_PROC                   0x0200
 
404
#define TAG_JPEG_INTERCHANGE_FORMAT     0x0201
 
405
#define TAG_JPEG_INTERCHANGE_FORMAT_LEN 0x0202
 
406
#define TAG_JPEG_RESTART_INTERVAL       0x0203
 
407
#define TAG_JPEG_LOSSLESS_PREDICTOR     0x0205
 
408
#define TAG_JPEG_POINT_TRANSFORMS       0x0206
 
409
#define TAG_JPEG_Q_TABLES               0x0207
 
410
#define TAG_JPEG_DC_TABLES              0x0208
 
411
#define TAG_JPEG_AC_TABLES              0x0209
 
412
#define TAG_YCC_COEFFICIENTS            0x0211
 
413
#define TAG_YCC_SUB_SAMPLING            0x0212
 
414
#define TAG_YCC_POSITIONING             0x0213
 
415
#define TAG_REFERENCE_BLACK_WHITE       0x0214
 
416
/* 0x0301 - 0x0302 */
 
417
/* 0x0320 */
 
418
/* 0x0343 */
 
419
/* 0x5001 - 0x501B */
 
420
/* 0x5021 - 0x503B */
 
421
/* 0x5090 - 0x5091 */
 
422
/* 0x5100 - 0x5101 */
 
423
/* 0x5110 - 0x5113 */
 
424
/* 0x80E3 - 0x80E6 */
 
425
/* 0x828d - 0x828F */
 
426
#define TAG_COPYRIGHT                   0x8298
 
427
#define TAG_EXPOSURETIME                0x829A
 
428
#define TAG_FNUMBER                     0x829D
 
429
#define TAG_EXIF_IFD_POINTER            0x8769
 
430
#define TAG_ICC_PROFILE                 0x8773
 
431
#define TAG_EXPOSURE_PROGRAM            0x8822
 
432
#define TAG_SPECTRAL_SENSITY            0x8824
 
433
#define TAG_GPS_IFD_POINTER             0x8825
 
434
#define TAG_ISOSPEED                    0x8827
 
435
#define TAG_OPTOELECTRIC_CONVERSION_F   0x8828
 
436
/* 0x8829 - 0x882b */
 
437
#define TAG_EXIFVERSION                 0x9000
 
438
#define TAG_DATE_TIME_ORIGINAL          0x9003
 
439
#define TAG_DATE_TIME_DIGITIZED         0x9004
 
440
#define TAG_COMPONENT_CONFIG            0x9101
 
441
#define TAG_COMPRESSED_BITS_PER_PIXEL   0x9102
 
442
#define TAG_SHUTTERSPEED                0x9201
 
443
#define TAG_APERTURE                    0x9202
 
444
#define TAG_BRIGHTNESS_VALUE            0x9203
 
445
#define TAG_EXPOSURE_BIAS_VALUE         0x9204
 
446
#define TAG_MAX_APERTURE                0x9205
 
447
#define TAG_SUBJECT_DISTANCE            0x9206
 
448
#define TAG_METRIC_MODULE               0x9207
 
449
#define TAG_LIGHT_SOURCE                0x9208
 
450
#define TAG_FLASH                       0x9209
 
451
#define TAG_FOCAL_LENGTH                0x920A
 
452
/* 0x920B - 0x920D */
 
453
/* 0x9211 - 0x9216 */
 
454
#define TAG_SUBJECT_AREA                0x9214
 
455
#define TAG_MAKER_NOTE                  0x927C
 
456
#define TAG_USERCOMMENT                 0x9286
 
457
#define TAG_SUB_SEC_TIME                0x9290
 
458
#define TAG_SUB_SEC_TIME_ORIGINAL       0x9291
 
459
#define TAG_SUB_SEC_TIME_DIGITIZED      0x9292
 
460
/* 0x923F */
 
461
/* 0x935C */
 
462
#define TAG_XP_TITLE                    0x9C9B
 
463
#define TAG_XP_COMMENTS                 0x9C9C
 
464
#define TAG_XP_AUTHOR                   0x9C9D
 
465
#define TAG_XP_KEYWORDS                 0x9C9E
 
466
#define TAG_XP_SUBJECT                  0x9C9F
 
467
#define TAG_FLASH_PIX_VERSION           0xA000
 
468
#define TAG_COLOR_SPACE                 0xA001
 
469
#define TAG_COMP_IMAGE_WIDTH            0xA002 /* compressed images only */
 
470
#define TAG_COMP_IMAGE_HEIGHT           0xA003
 
471
#define TAG_RELATED_SOUND_FILE          0xA004
 
472
#define TAG_INTEROP_IFD_POINTER         0xA005 /* IFD pointer */
 
473
#define TAG_FLASH_ENERGY                0xA20B
 
474
#define TAG_SPATIAL_FREQUENCY_RESPONSE  0xA20C
 
475
#define TAG_FOCALPLANE_X_RES            0xA20E
 
476
#define TAG_FOCALPLANE_Y_RES            0xA20F
 
477
#define TAG_FOCALPLANE_RESOLUTION_UNIT  0xA210
 
478
#define TAG_SUBJECT_LOCATION            0xA214
 
479
#define TAG_EXPOSURE_INDEX              0xA215
 
480
#define TAG_SENSING_METHOD              0xA217
 
481
#define TAG_FILE_SOURCE                 0xA300
 
482
#define TAG_SCENE_TYPE                  0xA301
 
483
#define TAG_CFA_PATTERN                 0xA302
 
484
#define TAG_CUSTOM_RENDERED             0xA401
 
485
#define TAG_EXPOSURE_MODE               0xA402
 
486
#define TAG_WHITE_BALANCE               0xA403
 
487
#define TAG_DIGITAL_ZOOM_RATIO          0xA404
 
488
#define TAG_FOCAL_LENGTH_IN_35_MM_FILM  0xA405
 
489
#define TAG_SCENE_CAPTURE_TYPE          0xA406
 
490
#define TAG_GAIN_CONTROL                0xA407
 
491
#define TAG_CONTRAST                    0xA408
 
492
#define TAG_SATURATION                  0xA409
 
493
#define TAG_SHARPNESS                   0xA40A
 
494
#define TAG_DEVICE_SETTING_DESCRIPTION  0xA40B
 
495
#define TAG_SUBJECT_DISTANCE_RANGE      0xA40C
 
496
#define TAG_IMAGE_UNIQUE_ID             0xA420
 
497
 
 
498
/* Olympus specific tags */
 
499
#define TAG_OLYMPUS_SPECIALMODE         0x0200
 
500
#define TAG_OLYMPUS_JPEGQUAL            0x0201
 
501
#define TAG_OLYMPUS_MACRO               0x0202
 
502
#define TAG_OLYMPUS_DIGIZOOM            0x0204
 
503
#define TAG_OLYMPUS_SOFTWARERELEASE     0x0207
 
504
#define TAG_OLYMPUS_PICTINFO            0x0208
 
505
#define TAG_OLYMPUS_CAMERAID            0x0209
 
506
/* end Olympus specific tags */
 
507
 
 
508
/* Internal */
 
509
#define TAG_NONE                                -1 /* note that -1 <> 0xFFFF */
 
510
#define TAG_COMPUTED_VALUE                      -2
 
511
#define TAG_END_OF_LIST                 0xFFFD
 
512
 
 
513
/* Values for TAG_PHOTOMETRIC_INTERPRETATION */
 
514
#define PMI_BLACK_IS_ZERO       0
 
515
#define PMI_WHITE_IS_ZERO       1
 
516
#define PMI_RGB                     2
 
517
#define PMI_PALETTE_COLOR       3
 
518
#define PMI_TRANSPARENCY_MASK   4
 
519
#define PMI_SEPARATED           5
 
520
#define PMI_YCBCR               6
 
521
#define PMI_CIELAB              8
 
522
 
 
523
/* }}} */
 
524
 
 
525
/* {{{ TabTable[]
 
526
 */
 
527
typedef const struct {
 
528
        unsigned short Tag;
 
529
        char *Desc;
 
530
} tag_info_type;
 
531
 
 
532
typedef tag_info_type  tag_info_array[];
 
533
typedef tag_info_type  *tag_table_type;
 
534
 
 
535
#define TAG_TABLE_END \
 
536
  {TAG_NONE,           "No tag value"},\
 
537
  {TAG_COMPUTED_VALUE, "Computed value"},\
 
538
  {TAG_END_OF_LIST,    ""}  /* Important for exif_get_tagname() IF value != "" functionresult is != false */
 
539
 
 
540
static tag_info_array tag_table_IFD = {
 
541
  { 0x000B, "ACDComment"},
 
542
  { 0x00FE, "NewSubFile"}, /* better name it 'ImageType' ? */
 
543
  { 0x00FF, "SubFile"},
 
544
  { 0x0100, "ImageWidth"},
 
545
  { 0x0101, "ImageLength"},
 
546
  { 0x0102, "BitsPerSample"},
 
547
  { 0x0103, "Compression"},
 
548
  { 0x0106, "PhotometricInterpretation"},
 
549
  { 0x010A, "FillOrder"},
 
550
  { 0x010D, "DocumentName"},
 
551
  { 0x010E, "ImageDescription"},
 
552
  { 0x010F, "Make"},
 
553
  { 0x0110, "Model"},
 
554
  { 0x0111, "StripOffsets"},
 
555
  { 0x0112, "Orientation"},
 
556
  { 0x0115, "SamplesPerPixel"},
 
557
  { 0x0116, "RowsPerStrip"},
 
558
  { 0x0117, "StripByteCounts"},
 
559
  { 0x0118, "MinSampleValue"},
 
560
  { 0x0119, "MaxSampleValue"},
 
561
  { 0x011A, "XResolution"},
 
562
  { 0x011B, "YResolution"},
 
563
  { 0x011C, "PlanarConfiguration"},
 
564
  { 0x011D, "PageName"},
 
565
  { 0x011E, "XPosition"},
 
566
  { 0x011F, "YPosition"},
 
567
  { 0x0120, "FreeOffsets"},
 
568
  { 0x0121, "FreeByteCounts"},
 
569
  { 0x0122, "GrayResponseUnit"},
 
570
  { 0x0123, "GrayResponseCurve"},
 
571
  { 0x0124, "T4Options"},
 
572
  { 0x0125, "T6Options"},
 
573
  { 0x0128, "ResolutionUnit"},
 
574
  { 0x0129, "PageNumber"},
 
575
  { 0x012D, "TransferFunction"},
 
576
  { 0x0131, "Software"},
 
577
  { 0x0132, "DateTime"},
 
578
  { 0x013B, "Artist"},
 
579
  { 0x013C, "HostComputer"},
 
580
  { 0x013D, "Predictor"},
 
581
  { 0x013E, "WhitePoint"},
 
582
  { 0x013F, "PrimaryChromaticities"},
 
583
  { 0x0140, "ColorMap"},
 
584
  { 0x0141, "HalfToneHints"},
 
585
  { 0x0142, "TileWidth"},
 
586
  { 0x0143, "TileLength"},
 
587
  { 0x0144, "TileOffsets"},
 
588
  { 0x0145, "TileByteCounts"},
 
589
  { 0x014A, "SubIFD"},
 
590
  { 0x014C, "InkSet"},
 
591
  { 0x014D, "InkNames"},
 
592
  { 0x014E, "NumberOfInks"},
 
593
  { 0x0150, "DotRange"},
 
594
  { 0x0151, "TargetPrinter"},
 
595
  { 0x0152, "ExtraSample"},
 
596
  { 0x0153, "SampleFormat"},
 
597
  { 0x0154, "SMinSampleValue"},
 
598
  { 0x0155, "SMaxSampleValue"},
 
599
  { 0x0156, "TransferRange"},
 
600
  { 0x0157, "ClipPath"},
 
601
  { 0x0158, "XClipPathUnits"},
 
602
  { 0x0159, "YClipPathUnits"},
 
603
  { 0x015A, "Indexed"},
 
604
  { 0x015B, "JPEGTables"},
 
605
  { 0x015F, "OPIProxy"},
 
606
  { 0x0200, "JPEGProc"},
 
607
  { 0x0201, "JPEGInterchangeFormat"},
 
608
  { 0x0202, "JPEGInterchangeFormatLength"},
 
609
  { 0x0203, "JPEGRestartInterval"},
 
610
  { 0x0205, "JPEGLosslessPredictors"},
 
611
  { 0x0206, "JPEGPointTransforms"},
 
612
  { 0x0207, "JPEGQTables"},
 
613
  { 0x0208, "JPEGDCTables"},
 
614
  { 0x0209, "JPEGACTables"},
 
615
  { 0x0211, "YCbCrCoefficients"},
 
616
  { 0x0212, "YCbCrSubSampling"},
 
617
  { 0x0213, "YCbCrPositioning"},
 
618
  { 0x0214, "ReferenceBlackWhite"},
 
619
  { 0x02BC, "ExtensibleMetadataPlatform"}, /* XAP: Extensible Authoring Publishing, obsoleted by XMP: Extensible Metadata Platform */
 
620
  { 0x0301, "Gamma"}, 
 
621
  { 0x0302, "ICCProfileDescriptor"}, 
 
622
  { 0x0303, "SRGBRenderingIntent"}, 
 
623
  { 0x0320, "ImageTitle"}, 
 
624
  { 0x5001, "ResolutionXUnit"}, 
 
625
  { 0x5002, "ResolutionYUnit"}, 
 
626
  { 0x5003, "ResolutionXLengthUnit"}, 
 
627
  { 0x5004, "ResolutionYLengthUnit"}, 
 
628
  { 0x5005, "PrintFlags"}, 
 
629
  { 0x5006, "PrintFlagsVersion"}, 
 
630
  { 0x5007, "PrintFlagsCrop"}, 
 
631
  { 0x5008, "PrintFlagsBleedWidth"}, 
 
632
  { 0x5009, "PrintFlagsBleedWidthScale"}, 
 
633
  { 0x500A, "HalftoneLPI"}, 
 
634
  { 0x500B, "HalftoneLPIUnit"}, 
 
635
  { 0x500C, "HalftoneDegree"}, 
 
636
  { 0x500D, "HalftoneShape"}, 
 
637
  { 0x500E, "HalftoneMisc"}, 
 
638
  { 0x500F, "HalftoneScreen"}, 
 
639
  { 0x5010, "JPEGQuality"}, 
 
640
  { 0x5011, "GridSize"}, 
 
641
  { 0x5012, "ThumbnailFormat"}, 
 
642
  { 0x5013, "ThumbnailWidth"}, 
 
643
  { 0x5014, "ThumbnailHeight"}, 
 
644
  { 0x5015, "ThumbnailColorDepth"}, 
 
645
  { 0x5016, "ThumbnailPlanes"}, 
 
646
  { 0x5017, "ThumbnailRawBytes"}, 
 
647
  { 0x5018, "ThumbnailSize"}, 
 
648
  { 0x5019, "ThumbnailCompressedSize"}, 
 
649
  { 0x501A, "ColorTransferFunction"}, 
 
650
  { 0x501B, "ThumbnailData"}, 
 
651
  { 0x5020, "ThumbnailImageWidth"}, 
 
652
  { 0x5021, "ThumbnailImageHeight"}, 
 
653
  { 0x5022, "ThumbnailBitsPerSample"}, 
 
654
  { 0x5023, "ThumbnailCompression"}, 
 
655
  { 0x5024, "ThumbnailPhotometricInterp"}, 
 
656
  { 0x5025, "ThumbnailImageDescription"}, 
 
657
  { 0x5026, "ThumbnailEquipMake"}, 
 
658
  { 0x5027, "ThumbnailEquipModel"}, 
 
659
  { 0x5028, "ThumbnailStripOffsets"}, 
 
660
  { 0x5029, "ThumbnailOrientation"}, 
 
661
  { 0x502A, "ThumbnailSamplesPerPixel"}, 
 
662
  { 0x502B, "ThumbnailRowsPerStrip"}, 
 
663
  { 0x502C, "ThumbnailStripBytesCount"}, 
 
664
  { 0x502D, "ThumbnailResolutionX"}, 
 
665
  { 0x502E, "ThumbnailResolutionY"}, 
 
666
  { 0x502F, "ThumbnailPlanarConfig"}, 
 
667
  { 0x5030, "ThumbnailResolutionUnit"}, 
 
668
  { 0x5031, "ThumbnailTransferFunction"}, 
 
669
  { 0x5032, "ThumbnailSoftwareUsed"}, 
 
670
  { 0x5033, "ThumbnailDateTime"}, 
 
671
  { 0x5034, "ThumbnailArtist"}, 
 
672
  { 0x5035, "ThumbnailWhitePoint"}, 
 
673
  { 0x5036, "ThumbnailPrimaryChromaticities"}, 
 
674
  { 0x5037, "ThumbnailYCbCrCoefficients"}, 
 
675
  { 0x5038, "ThumbnailYCbCrSubsampling"}, 
 
676
  { 0x5039, "ThumbnailYCbCrPositioning"}, 
 
677
  { 0x503A, "ThumbnailRefBlackWhite"}, 
 
678
  { 0x503B, "ThumbnailCopyRight"}, 
 
679
  { 0x5090, "LuminanceTable"}, 
 
680
  { 0x5091, "ChrominanceTable"}, 
 
681
  { 0x5100, "FrameDelay"}, 
 
682
  { 0x5101, "LoopCount"}, 
 
683
  { 0x5110, "PixelUnit"}, 
 
684
  { 0x5111, "PixelPerUnitX"}, 
 
685
  { 0x5112, "PixelPerUnitY"}, 
 
686
  { 0x5113, "PaletteHistogram"}, 
 
687
  { 0x1000, "RelatedImageFileFormat"},
 
688
  { 0x800D, "ImageID"},
 
689
  { 0x80E3, "Matteing"},   /* obsoleted by ExtraSamples */
 
690
  { 0x80E4, "DataType"},   /* obsoleted by SampleFormat */
 
691
  { 0x80E5, "ImageDepth"},
 
692
  { 0x80E6, "TileDepth"},
 
693
  { 0x828D, "CFARepeatPatternDim"},
 
694
  { 0x828E, "CFAPattern"},
 
695
  { 0x828F, "BatteryLevel"},
 
696
  { 0x8298, "Copyright"},
 
697
  { 0x829A, "ExposureTime"},
 
698
  { 0x829D, "FNumber"},
 
699
  { 0x83BB, "IPTC/NAA"},
 
700
  { 0x84E3, "IT8RasterPadding"},
 
701
  { 0x84E5, "IT8ColorTable"},
 
702
  { 0x8649, "ImageResourceInformation"}, /* PhotoShop */
 
703
  { 0x8769, "Exif_IFD_Pointer"},
 
704
  { 0x8773, "ICC_Profile"},
 
705
  { 0x8822, "ExposureProgram"},
 
706
  { 0x8824, "SpectralSensity"},
 
707
  { 0x8828, "OECF"},
 
708
  { 0x8825, "GPS_IFD_Pointer"},
 
709
  { 0x8827, "ISOSpeedRatings"},
 
710
  { 0x8828, "OECF"},
 
711
  { 0x9000, "ExifVersion"},
 
712
  { 0x9003, "DateTimeOriginal"},
 
713
  { 0x9004, "DateTimeDigitized"},
 
714
  { 0x9101, "ComponentsConfiguration"},
 
715
  { 0x9102, "CompressedBitsPerPixel"},
 
716
  { 0x9201, "ShutterSpeedValue"},
 
717
  { 0x9202, "ApertureValue"},
 
718
  { 0x9203, "BrightnessValue"},
 
719
  { 0x9204, "ExposureBiasValue"},
 
720
  { 0x9205, "MaxApertureValue"},
 
721
  { 0x9206, "SubjectDistance"},
 
722
  { 0x9207, "MeteringMode"},
 
723
  { 0x9208, "LightSource"},
 
724
  { 0x9209, "Flash"},
 
725
  { 0x920A, "FocalLength"},
 
726
  { 0x920B, "FlashEnergy"},                 /* 0xA20B  in JPEG   */
 
727
  { 0x920C, "SpatialFrequencyResponse"},    /* 0xA20C    -  -    */
 
728
  { 0x920D, "Noise"},
 
729
  { 0x920E, "FocalPlaneXResolution"},       /* 0xA20E    -  -    */
 
730
  { 0x920F, "FocalPlaneYResolution"},       /* 0xA20F    -  -    */
 
731
  { 0x9210, "FocalPlaneResolutionUnit"},    /* 0xA210    -  -    */
 
732
  { 0x9211, "ImageNumber"},
 
733
  { 0x9212, "SecurityClassification"},
 
734
  { 0x9213, "ImageHistory"},
 
735
  { 0x9214, "SubjectLocation"},             /* 0xA214    -  -    */
 
736
  { 0x9215, "ExposureIndex"},               /* 0xA215    -  -    */
 
737
  { 0x9216, "TIFF/EPStandardID"},
 
738
  { 0x9217, "SensingMethod"},               /* 0xA217    -  -    */
 
739
  { 0x923F, "StoNits"},
 
740
  { 0x927C, "MakerNote"},
 
741
  { 0x9286, "UserComment"},
 
742
  { 0x9290, "SubSecTime"},
 
743
  { 0x9291, "SubSecTimeOriginal"},
 
744
  { 0x9292, "SubSecTimeDigitized"},
 
745
  { 0x935C, "ImageSourceData"},             /* "Adobe Photoshop Document Data Block": 8BIM... */
 
746
  { 0x9c9b, "Title" },                      /* Win XP specific, Unicode  */
 
747
  { 0x9c9c, "Comments" },                   /* Win XP specific, Unicode  */
 
748
  { 0x9c9d, "Author" },                     /* Win XP specific, Unicode  */
 
749
  { 0x9c9e, "Keywords" },                   /* Win XP specific, Unicode  */
 
750
  { 0x9c9f, "Subject" },                    /* Win XP specific, Unicode, not to be confused with SubjectDistance and SubjectLocation */
 
751
  { 0xA000, "FlashPixVersion"},
 
752
  { 0xA001, "ColorSpace"},
 
753
  { 0xA002, "ExifImageWidth"},
 
754
  { 0xA003, "ExifImageLength"},
 
755
  { 0xA004, "RelatedSoundFile"},
 
756
  { 0xA005, "InteroperabilityOffset"},
 
757
  { 0xA20B, "FlashEnergy"},                 /* 0x920B in TIFF/EP */
 
758
  { 0xA20C, "SpatialFrequencyResponse"},    /* 0x920C    -  -    */
 
759
  { 0xA20D, "Noise"},
 
760
  { 0xA20E, "FocalPlaneXResolution"},           /* 0x920E    -  -    */
 
761
  { 0xA20F, "FocalPlaneYResolution"},       /* 0x920F    -  -    */
 
762
  { 0xA210, "FocalPlaneResolutionUnit"},    /* 0x9210    -  -    */
 
763
  { 0xA211, "ImageNumber"},
 
764
  { 0xA212, "SecurityClassification"},
 
765
  { 0xA213, "ImageHistory"},
 
766
  { 0xA214, "SubjectLocation"},             /* 0x9214    -  -    */
 
767
  { 0xA215, "ExposureIndex"},               /* 0x9215    -  -    */
 
768
  { 0xA216, "TIFF/EPStandardID"},
 
769
  { 0xA217, "SensingMethod"},               /* 0x9217    -  -    */
 
770
  { 0xA300, "FileSource"},
 
771
  { 0xA301, "SceneType"},
 
772
  { 0xA302, "CFAPattern"},
 
773
  { 0xA401, "CustomRendered"},
 
774
  { 0xA402, "ExposureMode"},
 
775
  { 0xA403, "WhiteBalance"},
 
776
  { 0xA404, "DigitalZoomRatio"},
 
777
  { 0xA405, "FocalLengthIn35mmFilm"},
 
778
  { 0xA406, "SceneCaptureType"},
 
779
  { 0xA407, "GainControl"},
 
780
  { 0xA408, "Contrast"},
 
781
  { 0xA409, "Saturation"},
 
782
  { 0xA40A, "Sharpness"},
 
783
  { 0xA40B, "DeviceSettingDescription"},
 
784
  { 0xA40C, "SubjectDistanceRange"},
 
785
  { 0xA420, "ImageUniqueID"},
 
786
  TAG_TABLE_END
 
787
} ;
 
788
 
 
789
static tag_info_array tag_table_GPS = {
 
790
  { 0x0000, "GPSVersion"},
 
791
  { 0x0001, "GPSLatitudeRef"},
 
792
  { 0x0002, "GPSLatitude"},
 
793
  { 0x0003, "GPSLongitudeRef"},
 
794
  { 0x0004, "GPSLongitude"},
 
795
  { 0x0005, "GPSAltitudeRef"},
 
796
  { 0x0006, "GPSAltitude"},
 
797
  { 0x0007, "GPSTimeStamp"},
 
798
  { 0x0008, "GPSSatellites"},
 
799
  { 0x0009, "GPSStatus"},
 
800
  { 0x000A, "GPSMeasureMode"},
 
801
  { 0x000B, "GPSDOP"},
 
802
  { 0x000C, "GPSSpeedRef"},
 
803
  { 0x000D, "GPSSpeed"},
 
804
  { 0x000E, "GPSTrackRef"},
 
805
  { 0x000F, "GPSTrack"},
 
806
  { 0x0010, "GPSImgDirectionRef"},
 
807
  { 0x0011, "GPSImgDirection"},
 
808
  { 0x0012, "GPSMapDatum"},
 
809
  { 0x0013, "GPSDestLatitudeRef"},
 
810
  { 0x0014, "GPSDestLatitude"},
 
811
  { 0x0015, "GPSDestLongitudeRef"},
 
812
  { 0x0016, "GPSDestLongitude"},
 
813
  { 0x0017, "GPSDestBearingRef"},
 
814
  { 0x0018, "GPSDestBearing"},
 
815
  { 0x0019, "GPSDestDistanceRef"},
 
816
  { 0x001A, "GPSDestDistance"},
 
817
  { 0x001B, "GPSProcessingMode"},
 
818
  { 0x001C, "GPSAreaInformation"},
 
819
  { 0x001D, "GPSDateStamp"},
 
820
  { 0x001E, "GPSDifferential"},
 
821
  TAG_TABLE_END
 
822
};
 
823
 
 
824
static tag_info_array tag_table_IOP = {
 
825
  { 0x0001, "InterOperabilityIndex"}, /* should be 'R98' or 'THM' */
 
826
  { 0x0002, "InterOperabilityVersion"},
 
827
  { 0x1000, "RelatedFileFormat"},
 
828
  { 0x1001, "RelatedImageWidth"},
 
829
  { 0x1002, "RelatedImageHeight"},
 
830
  TAG_TABLE_END
 
831
};
 
832
 
 
833
static tag_info_array tag_table_VND_CANON = {
 
834
  { 0x0001, "ModeArray"}, /* guess */
 
835
  { 0x0004, "ImageInfo"}, /* guess */
 
836
  { 0x0006, "ImageType"},
 
837
  { 0x0007, "FirmwareVersion"},
 
838
  { 0x0008, "ImageNumber"},
 
839
  { 0x0009, "OwnerName"},
 
840
  { 0x000C, "Camera"},
 
841
  { 0x000F, "CustomFunctions"},
 
842
  TAG_TABLE_END
 
843
};
 
844
 
 
845
static tag_info_array tag_table_VND_CASIO = {
 
846
  { 0x0001, "RecordingMode"},
 
847
  { 0x0002, "Quality"},
 
848
  { 0x0003, "FocusingMode"},
 
849
  { 0x0004, "FlashMode"},
 
850
  { 0x0005, "FlashIntensity"},
 
851
  { 0x0006, "ObjectDistance"},
 
852
  { 0x0007, "WhiteBalance"},
 
853
  { 0x000A, "DigitalZoom"},
 
854
  { 0x000B, "Sharpness"},
 
855
  { 0x000C, "Contrast"},
 
856
  { 0x000D, "Saturation"},
 
857
  { 0x0014, "CCDSensitivity"},
 
858
  TAG_TABLE_END
 
859
};
 
860
 
 
861
static tag_info_array tag_table_VND_FUJI = {
 
862
  { 0x0000, "Version"},
 
863
  { 0x1000, "Quality"},
 
864
  { 0x1001, "Sharpness"},
 
865
  { 0x1002, "WhiteBalance"},
 
866
  { 0x1003, "Color"},
 
867
  { 0x1004, "Tone"},
 
868
  { 0x1010, "FlashMode"},
 
869
  { 0x1011, "FlashStrength"},
 
870
  { 0x1020, "Macro"},
 
871
  { 0x1021, "FocusMode"},
 
872
  { 0x1030, "SlowSync"},
 
873
  { 0x1031, "PictureMode"},
 
874
  { 0x1100, "ContTake"},
 
875
  { 0x1300, "BlurWarning"},
 
876
  { 0x1301, "FocusWarning"},
 
877
  { 0x1302, "AEWarning "},
 
878
  TAG_TABLE_END
 
879
};
 
880
 
 
881
static tag_info_array tag_table_VND_NIKON = {
 
882
  { 0x0003, "Quality"},
 
883
  { 0x0004, "ColorMode"},
 
884
  { 0x0005, "ImageAdjustment"},
 
885
  { 0x0006, "CCDSensitivity"},
 
886
  { 0x0007, "WhiteBalance"},
 
887
  { 0x0008, "Focus"},
 
888
  { 0x000a, "DigitalZoom"},
 
889
  { 0x000b, "Converter"},
 
890
  TAG_TABLE_END
 
891
};
 
892
  
 
893
static tag_info_array tag_table_VND_NIKON_990 = {
 
894
  { 0x0001, "Version"},
 
895
  { 0x0002, "ISOSetting"},
 
896
  { 0x0003, "ColorMode"},
 
897
  { 0x0004, "Quality"},
 
898
  { 0x0005, "WhiteBalance"},
 
899
  { 0x0006, "ImageSharpening"},
 
900
  { 0x0007, "FocusMode"},
 
901
  { 0x0008, "FlashSetting"},
 
902
  { 0x000F, "ISOSelection"},
 
903
  { 0x0080, "ImageAdjustment"},
 
904
  { 0x0082, "AuxiliaryLens"},
 
905
  { 0x0085, "ManualFocusDistance"},
 
906
  { 0x0086, "DigitalZoom"},
 
907
  { 0x0088, "AFFocusPosition"},
 
908
  { 0x0010, "DataDump"},
 
909
  TAG_TABLE_END
 
910
};
 
911
  
 
912
static tag_info_array tag_table_VND_OLYMPUS = {
 
913
  { 0x0200, "SpecialMode"},
 
914
  { 0x0201, "JPEGQuality"},
 
915
  { 0x0202, "Macro"},
 
916
  { 0x0204, "DigitalZoom"},
 
917
  { 0x0207, "SoftwareRelease"},
 
918
  { 0x0208, "PictureInfo"},
 
919
  { 0x0209, "CameraId"},
 
920
  { 0x0F00, "DataDump"},
 
921
  TAG_TABLE_END
 
922
};
 
923
 
 
924
typedef enum mn_byte_order_t {
 
925
        MN_ORDER_INTEL    = 0,
 
926
        MN_ORDER_MOTOROLA = 1,
 
927
        MN_ORDER_NORMAL
 
928
} mn_byte_order_t;
 
929
 
 
930
typedef enum mn_offset_mode_t {
 
931
        MN_OFFSET_NORMAL,
 
932
        MN_OFFSET_MAKER,
 
933
        MN_OFFSET_GUESS
 
934
} mn_offset_mode_t;
 
935
 
 
936
typedef struct {
 
937
        tag_table_type   tag_table;
 
938
        char *           make;
 
939
        char *           model;
 
940
        char *           id_string;
 
941
        int              id_string_len;
 
942
        int              offset;
 
943
        mn_byte_order_t  byte_order;
 
944
        mn_offset_mode_t offset_mode;
 
945
} maker_note_type;
 
946
 
 
947
static const maker_note_type maker_note_array[] = {
 
948
  { tag_table_VND_CANON,     "Canon",                   NULL,  NULL,                       0,  0,  MN_ORDER_INTEL,    MN_OFFSET_GUESS},
 
949
/*  { tag_table_VND_CANON,     "Canon",                   NULL,  NULL,                       0,  0,  MN_ORDER_NORMAL,   MN_OFFSET_NORMAL},*/
 
950
  { tag_table_VND_CASIO,     "CASIO",                   NULL,  NULL,                       0,  0,  MN_ORDER_MOTOROLA, MN_OFFSET_NORMAL},
 
951
  { tag_table_VND_FUJI,      "FUJIFILM",                NULL,  "FUJIFILM\x0C\x00\x00\x00", 12, 12, MN_ORDER_INTEL,    MN_OFFSET_MAKER},
 
952
  { tag_table_VND_NIKON,     "NIKON",                   NULL,  "Nikon\x00\x01\x00",        8,  8,  MN_ORDER_NORMAL,   MN_OFFSET_NORMAL},
 
953
  { tag_table_VND_NIKON_990, "NIKON",                   NULL,  NULL,                       0,  0,  MN_ORDER_NORMAL,   MN_OFFSET_NORMAL},
 
954
  { tag_table_VND_OLYMPUS,   "OLYMPUS OPTICAL CO.,LTD", NULL,  "OLYMP\x00\x01\x00",        8,  8,  MN_ORDER_NORMAL,   MN_OFFSET_NORMAL},
 
955
};
 
956
/* }}} */
 
957
 
 
958
/* {{{ exif_get_tagname
 
959
        Get headername for tag_num or NULL if not defined */
 
960
static char * exif_get_tagname(int tag_num, char *ret, int len, tag_table_type tag_table TSRMLS_DC)
 
961
{
 
962
        int i, t;
 
963
        char tmp[32];
 
964
 
 
965
        for (i=0;;i++) {
 
966
                if ((t=tag_table[i].Tag) == tag_num || t==TAG_END_OF_LIST) {
 
967
                        if (t==TAG_END_OF_LIST) {
 
968
                                break;
 
969
                        }
 
970
                        if (ret && len)  {
 
971
                                strncpy(ret, tag_table[i].Desc, abs(len));
 
972
                                if (len<0) {
 
973
                                        len = -len;
 
974
                                        ret[len-1]='\0';
 
975
                                        for(i=strlen(ret);i<len;i++)ret[i]=' ';
 
976
                                }
 
977
                                ret[len-1]='\0';
 
978
                                return ret;
 
979
                        }
 
980
                        return tag_table[i].Desc;
 
981
                }
 
982
        }
 
983
        if (ret && len) {
 
984
                snprintf(tmp, sizeof(tmp), "UndefinedTag:0x%04X", tag_num);
 
985
                strncpy(ret, tmp, abs(len));
 
986
                if (len<0) {
 
987
                        len = -len;
 
988
                        ret[len-1]='\0';
 
989
                        for(i=strlen(ret);i<len;i++)ret[i]=' ';
 
990
                }
 
991
                ret[len-1]='\0';
 
992
                return ret;
 
993
        }
 
994
        return "";
 
995
}
 
996
/* }}} */
 
997
 
 
998
/* {{{ exif_char_dump
 
999
 * Do not use! This is a debug function... */
 
1000
#ifdef EXIF_DEBUG
 
1001
static unsigned char* exif_char_dump(unsigned char * addr, int len, int offset)
 
1002
{
 
1003
        static unsigned char buf[4096+1];
 
1004
        static unsigned char tmp[20];
 
1005
        int c, i, p=0, n = 5+31;
 
1006
 
 
1007
        p += sprintf(buf+p, "\nDump Len: %08X (%d)", len, len);
 
1008
        if (len) {
 
1009
                for(i=0; i<len+15 && p+n<=sizeof(buf); i++) {
 
1010
                        if (i%16==0) {
 
1011
                                p += sprintf(buf+p, "\n%08X: ", i+offset);
 
1012
                        }
 
1013
                        if (i<len) {
 
1014
                                c = *addr++;
 
1015
                                p += sprintf(buf+p, "%02X ", c);
 
1016
                                tmp[i%16] = c>=32 ? c : '.';
 
1017
                                tmp[(i%16)+1] = '\0';
 
1018
                        } else {
 
1019
                                p += sprintf(buf+p, "   ");
 
1020
                        }
 
1021
                        if (i%16==15) {
 
1022
                                p += sprintf(buf+p, "    %s", tmp);
 
1023
                                if (i>=len) {
 
1024
                                        break;
 
1025
                                }
 
1026
                        }
 
1027
                }
 
1028
        }
 
1029
        buf[sizeof(buf)-1] = '\0';
 
1030
        return buf;
 
1031
}
 
1032
#endif
 
1033
/* }}} */
 
1034
 
 
1035
/* {{{ php_jpg_get16
 
1036
   Get 16 bits motorola order (always) for jpeg header stuff.
 
1037
*/
 
1038
static int php_jpg_get16(void *value)
 
1039
{
 
1040
        return (((uchar *)value)[0] << 8) | ((uchar *)value)[1];
 
1041
}
 
1042
/* }}} */
 
1043
 
 
1044
/* {{{ php_ifd_get16u
 
1045
 * Convert a 16 bit unsigned value from file's native byte order */
 
1046
static int php_ifd_get16u(void *value, int motorola_intel)
 
1047
{
 
1048
        if (motorola_intel) {
 
1049
                return (((uchar *)value)[0] << 8) | ((uchar *)value)[1];
 
1050
        } else {
 
1051
                return (((uchar *)value)[1] << 8) | ((uchar *)value)[0];
 
1052
        }
 
1053
}
 
1054
/* }}} */
 
1055
 
 
1056
/* {{{ php_ifd_get16s
 
1057
 * Convert a 16 bit signed value from file's native byte order */
 
1058
static signed short php_ifd_get16s(void *value, int motorola_intel)
 
1059
{
 
1060
        return (signed short)php_ifd_get16u(value, motorola_intel);
 
1061
}
 
1062
/* }}} */
 
1063
 
 
1064
/* {{{ php_ifd_get32s
 
1065
 * Convert a 32 bit signed value from file's native byte order */
 
1066
static int php_ifd_get32s(void *value, int motorola_intel)
 
1067
{
 
1068
        if (motorola_intel) {
 
1069
                return  (((char  *)value)[0] << 24)
 
1070
                          | (((uchar *)value)[1] << 16)
 
1071
                          | (((uchar *)value)[2] << 8 )
 
1072
                          | (((uchar *)value)[3]      );
 
1073
        } else {
 
1074
                return  (((char  *)value)[3] << 24)
 
1075
                          | (((uchar *)value)[2] << 16)
 
1076
                          | (((uchar *)value)[1] << 8 )
 
1077
                          | (((uchar *)value)[0]      );
 
1078
        }
 
1079
}
 
1080
/* }}} */
 
1081
 
 
1082
/* {{{ php_ifd_get32u
 
1083
 * Write 32 bit unsigned value to data */
 
1084
static unsigned php_ifd_get32u(void *value, int motorola_intel)
 
1085
{
 
1086
        return (unsigned)php_ifd_get32s(value, motorola_intel) & 0xffffffff;
 
1087
}
 
1088
/* }}} */
 
1089
 
 
1090
/* {{{ php_ifd_set16u
 
1091
 * Write 16 bit unsigned value to data */
 
1092
static void php_ifd_set16u(char *data, unsigned int value, int motorola_intel)
 
1093
{
 
1094
        if (motorola_intel) {
 
1095
                data[0] = (value & 0xFF00) >> 8;
 
1096
                data[1] = (value & 0x00FF);
 
1097
        } else {
 
1098
                data[1] = (value & 0xFF00) >> 8;
 
1099
                data[0] = (value & 0x00FF);
 
1100
        }
 
1101
}
 
1102
/* }}} */
 
1103
 
 
1104
/* {{{ php_ifd_set32u
 
1105
 * Convert a 32 bit unsigned value from file's native byte order */
 
1106
static void php_ifd_set32u(char *data, size_t value, int motorola_intel)
 
1107
{
 
1108
        if (motorola_intel) {
 
1109
                data[0] = (value & 0xFF000000) >> 24;
 
1110
                data[1] = (value & 0x00FF0000) >> 16;
 
1111
                data[2] = (value & 0x0000FF00) >>  8;
 
1112
                data[3] = (value & 0x000000FF);
 
1113
        } else {
 
1114
                data[3] = (value & 0xFF000000) >> 24;
 
1115
                data[2] = (value & 0x00FF0000) >> 16;
 
1116
                data[1] = (value & 0x0000FF00) >>  8;
 
1117
                data[0] = (value & 0x000000FF);
 
1118
        }
 
1119
}
 
1120
/* }}} */
 
1121
 
 
1122
/* {{{ exif_convert_any_format
 
1123
 * Evaluate number, be it int, rational, or float from directory. */
 
1124
static double exif_convert_any_format(void *value, int format, int motorola_intel TSRMLS_DC)
 
1125
{
 
1126
        int             s_den;
 
1127
        unsigned        u_den;
 
1128
 
 
1129
        switch(format) {
 
1130
                case TAG_FMT_SBYTE:     return *(signed char *)value;
 
1131
                case TAG_FMT_BYTE:      return *(uchar *)value;
 
1132
 
 
1133
                case TAG_FMT_USHORT:    return php_ifd_get16u(value, motorola_intel);
 
1134
                case TAG_FMT_ULONG:     return php_ifd_get32u(value, motorola_intel);
 
1135
 
 
1136
                case TAG_FMT_URATIONAL:
 
1137
                        u_den = php_ifd_get32u(4+(char *)value, motorola_intel);
 
1138
                        if (u_den == 0) {
 
1139
                                return 0;
 
1140
                        } else {
 
1141
                                return (double)php_ifd_get32u(value, motorola_intel) / u_den;
 
1142
                        }
 
1143
 
 
1144
                case TAG_FMT_SRATIONAL:
 
1145
                        s_den = php_ifd_get32s(4+(char *)value, motorola_intel);
 
1146
                        if (s_den == 0) {
 
1147
                                return 0;
 
1148
                        } else {
 
1149
                                return (double)php_ifd_get32s(value, motorola_intel) / s_den;
 
1150
                        }
 
1151
 
 
1152
                case TAG_FMT_SSHORT:    return (signed short)php_ifd_get16u(value, motorola_intel);
 
1153
                case TAG_FMT_SLONG:     return php_ifd_get32s(value, motorola_intel);
 
1154
 
 
1155
                /* Not sure if this is correct (never seen float used in Exif format) */
 
1156
                case TAG_FMT_SINGLE:
 
1157
#ifdef EXIF_DEBUG
 
1158
                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found value of type single");
 
1159
#endif
 
1160
                        return (double)*(float *)value;
 
1161
                case TAG_FMT_DOUBLE:
 
1162
#ifdef EXIF_DEBUG
 
1163
                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found value of type double");
 
1164
#endif
 
1165
                        return *(double *)value;
 
1166
        }
 
1167
        return 0;
 
1168
}
 
1169
/* }}} */
 
1170
 
 
1171
/* {{{ exif_convert_any_to_int
 
1172
 * Evaluate number, be it int, rational, or float from directory. */
 
1173
static size_t exif_convert_any_to_int(void *value, int format, int motorola_intel TSRMLS_DC)
 
1174
{
 
1175
        int             s_den;
 
1176
        unsigned        u_den;
 
1177
 
 
1178
        switch(format) {
 
1179
                case TAG_FMT_SBYTE:     return *(signed char *)value;
 
1180
                case TAG_FMT_BYTE:      return *(uchar *)value;
 
1181
 
 
1182
                case TAG_FMT_USHORT:    return php_ifd_get16u(value, motorola_intel);
 
1183
                case TAG_FMT_ULONG:     return php_ifd_get32u(value, motorola_intel);
 
1184
 
 
1185
                case TAG_FMT_URATIONAL:
 
1186
                        u_den = php_ifd_get32u(4+(char *)value, motorola_intel);
 
1187
                        if (u_den == 0) {
 
1188
                                return 0;
 
1189
                        } else {
 
1190
                                return php_ifd_get32u(value, motorola_intel) / u_den;
 
1191
                        }
 
1192
 
 
1193
                case TAG_FMT_SRATIONAL:
 
1194
                        s_den = php_ifd_get32s(4+(char *)value, motorola_intel);
 
1195
                        if (s_den == 0) {
 
1196
                                return 0;
 
1197
                        } else {
 
1198
                                return php_ifd_get32s(value, motorola_intel) / s_den;
 
1199
                        }
 
1200
 
 
1201
                case TAG_FMT_SSHORT:    return php_ifd_get16u(value, motorola_intel);
 
1202
                case TAG_FMT_SLONG:     return php_ifd_get32s(value, motorola_intel);
 
1203
 
 
1204
                /* Not sure if this is correct (never seen float used in Exif format) */
 
1205
                case TAG_FMT_SINGLE:
 
1206
#ifdef EXIF_DEBUG
 
1207
                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found value of type single");
 
1208
#endif
 
1209
                        return (size_t)*(float *)value;
 
1210
                case TAG_FMT_DOUBLE:
 
1211
#ifdef EXIF_DEBUG
 
1212
                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found value of type double");
 
1213
#endif
 
1214
                        return (size_t)*(double *)value;
 
1215
        }
 
1216
        return 0;
 
1217
}
 
1218
/* }}} */
 
1219
 
 
1220
/* {{{ struct image_info_value, image_info_list
 
1221
*/
 
1222
#ifndef WORD
 
1223
#define WORD unsigned short
 
1224
#endif
 
1225
#ifndef DWORD
 
1226
#define DWORD unsigned int
 
1227
#endif
 
1228
 
 
1229
typedef struct {
 
1230
        int             num;
 
1231
        int             den;
 
1232
} signed_rational;
 
1233
 
 
1234
typedef struct {
 
1235
        unsigned int    num;
 
1236
        unsigned int    den;
 
1237
} unsigned_rational;
 
1238
 
 
1239
typedef union _image_info_value {
 
1240
        char                            *s;
 
1241
        unsigned            u;
 
1242
        int                             i;
 
1243
        float               f;
 
1244
        double              d;
 
1245
        signed_rational         sr;
 
1246
        unsigned_rational       ur;
 
1247
        union _image_info_value   *list;
 
1248
} image_info_value;
 
1249
 
 
1250
typedef struct {
 
1251
        WORD                tag;
 
1252
        WORD                format;
 
1253
        DWORD               length;
 
1254
        DWORD               dummy;  /* value ptr of tiff directory entry */
 
1255
        char                            *name;
 
1256
        image_info_value    value;
 
1257
} image_info_data;
 
1258
 
 
1259
typedef struct {
 
1260
        int                 count;
 
1261
        image_info_data         *list;
 
1262
} image_info_list;
 
1263
/* }}} */
 
1264
 
 
1265
/* {{{ exif_get_sectionname
 
1266
 Returns the name of a section
 
1267
*/
 
1268
#define SECTION_FILE        0
 
1269
#define SECTION_COMPUTED    1
 
1270
#define SECTION_ANY_TAG     2
 
1271
#define SECTION_IFD0        3
 
1272
#define SECTION_THUMBNAIL   4
 
1273
#define SECTION_COMMENT     5
 
1274
#define SECTION_APP0        6
 
1275
#define SECTION_EXIF        7
 
1276
#define SECTION_FPIX        8
 
1277
#define SECTION_GPS         9
 
1278
#define SECTION_INTEROP     10
 
1279
#define SECTION_APP12       11
 
1280
#define SECTION_WINXP       12
 
1281
#define SECTION_MAKERNOTE   13
 
1282
#define SECTION_COUNT       14
 
1283
 
 
1284
#define FOUND_FILE          (1<<SECTION_FILE)
 
1285
#define FOUND_COMPUTED      (1<<SECTION_COMPUTED)
 
1286
#define FOUND_ANY_TAG       (1<<SECTION_ANY_TAG)
 
1287
#define FOUND_IFD0          (1<<SECTION_IFD0)
 
1288
#define FOUND_THUMBNAIL     (1<<SECTION_THUMBNAIL)
 
1289
#define FOUND_COMMENT       (1<<SECTION_COMMENT)
 
1290
#define FOUND_APP0          (1<<SECTION_APP0)
 
1291
#define FOUND_EXIF          (1<<SECTION_EXIF)
 
1292
#define FOUND_FPIX          (1<<SECTION_FPIX)
 
1293
#define FOUND_GPS           (1<<SECTION_GPS)
 
1294
#define FOUND_INTEROP       (1<<SECTION_INTEROP)
 
1295
#define FOUND_APP12         (1<<SECTION_APP12)
 
1296
#define FOUND_WINXP         (1<<SECTION_WINXP)
 
1297
#define FOUND_MAKERNOTE     (1<<SECTION_MAKERNOTE)
 
1298
 
 
1299
static char *exif_get_sectionname(int section)
 
1300
{
 
1301
        switch(section) {
 
1302
                case SECTION_FILE:      return "FILE";
 
1303
                case SECTION_COMPUTED:  return "COMPUTED";
 
1304
                case SECTION_ANY_TAG:   return "ANY_TAG";
 
1305
                case SECTION_IFD0:      return "IFD0";
 
1306
                case SECTION_THUMBNAIL: return "THUMBNAIL";
 
1307
                case SECTION_COMMENT:   return "COMMENT";
 
1308
                case SECTION_APP0:      return "APP0";
 
1309
                case SECTION_EXIF:      return "EXIF";
 
1310
                case SECTION_FPIX:      return "FPIX";
 
1311
                case SECTION_GPS:       return "GPS";
 
1312
                case SECTION_INTEROP:   return "INTEROP";
 
1313
                case SECTION_APP12:     return "APP12";
 
1314
                case SECTION_WINXP:     return "WINXP";
 
1315
                case SECTION_MAKERNOTE: return "MAKERNOTE";
 
1316
        }
 
1317
        return "";
 
1318
}
 
1319
 
 
1320
static tag_table_type exif_get_tag_table(int section)
 
1321
{
 
1322
        switch(section) {
 
1323
                case SECTION_FILE:      return &tag_table_IFD[0];
 
1324
                case SECTION_COMPUTED:  return &tag_table_IFD[0];
 
1325
                case SECTION_ANY_TAG:   return &tag_table_IFD[0];
 
1326
                case SECTION_IFD0:      return &tag_table_IFD[0];
 
1327
                case SECTION_THUMBNAIL: return &tag_table_IFD[0];
 
1328
                case SECTION_COMMENT:   return &tag_table_IFD[0];
 
1329
                case SECTION_APP0:      return &tag_table_IFD[0];
 
1330
                case SECTION_EXIF:      return &tag_table_IFD[0];
 
1331
                case SECTION_FPIX:      return &tag_table_IFD[0];
 
1332
                case SECTION_GPS:       return &tag_table_GPS[0];
 
1333
                case SECTION_INTEROP:   return &tag_table_IOP[0];
 
1334
                case SECTION_APP12:     return &tag_table_IFD[0];
 
1335
                case SECTION_WINXP:     return &tag_table_IFD[0];
 
1336
        }
 
1337
        return &tag_table_IFD[0];
 
1338
}
 
1339
/* }}} */
 
1340
 
 
1341
/* {{{ exif_get_sectionlist
 
1342
   Return list of sectionnames specified by sectionlist. Return value must be freed
 
1343
*/
 
1344
static char *exif_get_sectionlist(int sectionlist TSRMLS_DC)
 
1345
{
 
1346
        int i, len=0;
 
1347
        char *sections;
 
1348
 
 
1349
        for(i=0; i<SECTION_COUNT; i++) {
 
1350
                len += strlen(exif_get_sectionname(i))+2;
 
1351
        }
 
1352
        sections = safe_emalloc(len, 1, 1);
 
1353
        sections[0] = '\0';
 
1354
        len = 0;
 
1355
        for(i=0; i<SECTION_COUNT; i++) {
 
1356
                if (sectionlist&(1<<i)) {
 
1357
                        sprintf(sections+len, "%s, ", exif_get_sectionname(i));
 
1358
                        len = strlen(sections);
 
1359
                }
 
1360
        }
 
1361
        if (len>2)
 
1362
                sections[len-2] = '\0';
 
1363
        return sections;
 
1364
}
 
1365
/* }}} */
 
1366
 
 
1367
/* {{{ struct image_info_type
 
1368
   This structure stores Exif header image elements in a simple manner
 
1369
   Used to store camera data as extracted from the various ways that it can be
 
1370
   stored in a nexif header
 
1371
*/
 
1372
 
 
1373
typedef struct {
 
1374
        int     type;
 
1375
        size_t  size;
 
1376
        uchar   *data;
 
1377
} file_section;
 
1378
 
 
1379
typedef struct {
 
1380
        int             count;
 
1381
        file_section    *list;
 
1382
} file_section_list;
 
1383
 
 
1384
typedef struct {
 
1385
        image_filetype  filetype;
 
1386
        size_t          width, height;
 
1387
        size_t          size;
 
1388
        size_t          offset;
 
1389
        char            *data;
 
1390
} thumbnail_data;
 
1391
 
 
1392
typedef struct {
 
1393
        char                    *value;
 
1394
        size_t                  size;
 
1395
        int                             tag;
 
1396
} xp_field_type;
 
1397
 
 
1398
typedef struct {
 
1399
        int             count;
 
1400
        xp_field_type   *list;
 
1401
} xp_field_list;
 
1402
 
 
1403
/* This structure is used to store a section of a Jpeg file. */
 
1404
typedef struct {
 
1405
        php_stream      *infile;
 
1406
        char            *FileName;
 
1407
        time_t          FileDateTime;
 
1408
        size_t          FileSize;
 
1409
        image_filetype  FileType;
 
1410
        int             Height, Width;
 
1411
        int             IsColor;
 
1412
 
 
1413
        char            *make;
 
1414
        char            *model;
 
1415
 
 
1416
        float           ApertureFNumber;
 
1417
        float           ExposureTime;
 
1418
        double          FocalplaneUnits;
 
1419
        float           CCDWidth;
 
1420
        double          FocalplaneXRes;
 
1421
        size_t          ExifImageWidth;
 
1422
        float           FocalLength;
 
1423
        float           Distance;
 
1424
 
 
1425
        int             motorola_intel; /* 1 Motorola; 0 Intel */
 
1426
 
 
1427
        char            *UserComment;
 
1428
        int             UserCommentLength;
 
1429
        char            *UserCommentEncoding;
 
1430
        char            *encode_unicode;
 
1431
        char            *decode_unicode_be;
 
1432
        char            *decode_unicode_le;
 
1433
        char            *encode_jis;
 
1434
        char            *decode_jis_be;
 
1435
        char            *decode_jis_le;
 
1436
        char            *Copyright;/* EXIF standard defines Copyright as "<Photographer> [ '\0' <Editor> ] ['\0']" */
 
1437
        char            *CopyrightPhotographer;
 
1438
        char            *CopyrightEditor;
 
1439
 
 
1440
        xp_field_list   xp_fields;
 
1441
 
 
1442
        thumbnail_data  Thumbnail;
 
1443
        /* other */
 
1444
        int             sections_found; /* FOUND_<marker> */
 
1445
        image_info_list info_list[SECTION_COUNT];
 
1446
        /* for parsing */
 
1447
        int             read_thumbnail;
 
1448
        int             read_all;
 
1449
        int             ifd_nesting_level;
 
1450
        /* internal */
 
1451
        file_section_list       file;
 
1452
} image_info_type;
 
1453
/* }}} */
 
1454
 
 
1455
/* {{{ exif_error_docref */
 
1456
static void exif_error_docref(const char *docref EXIFERR_DC, const image_info_type *ImageInfo, int type, const char *format, ...)
 
1457
{
 
1458
        va_list args;
 
1459
        
 
1460
        va_start(args, format);
 
1461
#ifdef EXIF_DEBUG
 
1462
        {
 
1463
                char *buf;
 
1464
 
 
1465
                spprintf(&buf, 0, "%s(%d): %s", _file, _line, format);
 
1466
                php_verror(docref, ImageInfo->FileName?ImageInfo->FileName:"", type, buf, args TSRMLS_CC);
 
1467
                efree(buf);
 
1468
        }
 
1469
#else
 
1470
        php_verror(docref, ImageInfo->FileName?ImageInfo->FileName:"", type, format, args TSRMLS_CC);
 
1471
#endif
 
1472
        va_end(args);
 
1473
}
 
1474
/* }}} */
 
1475
 
 
1476
/* {{{ jpeg_sof_info
 
1477
 */
 
1478
typedef struct {
 
1479
        int     bits_per_sample;
 
1480
        size_t  width;
 
1481
        size_t  height;
 
1482
        int     num_components;
 
1483
} jpeg_sof_info;
 
1484
/* }}} */
 
1485
 
 
1486
/* {{{ exif_file_sections_add
 
1487
 Add a file_section to image_info
 
1488
 returns the used block or -1. if size>0 and data == NULL buffer of size is allocated
 
1489
*/
 
1490
static int exif_file_sections_add(image_info_type *ImageInfo, int type, size_t size, uchar *data)
 
1491
{
 
1492
        file_section    *tmp;
 
1493
        int             count = ImageInfo->file.count;
 
1494
 
 
1495
        tmp = erealloc(ImageInfo->file.list, (count+1)*sizeof(file_section));
 
1496
        ImageInfo->file.list = tmp;
 
1497
        ImageInfo->file.list[count].type = 0xFFFF;
 
1498
        ImageInfo->file.list[count].data = NULL;
 
1499
        ImageInfo->file.list[count].size = 0;
 
1500
        ImageInfo->file.count = count+1;
 
1501
        if (!size) {
 
1502
                data = NULL;
 
1503
        } else if (data == NULL) {
 
1504
                data = emalloc(size);
 
1505
        }
 
1506
        ImageInfo->file.list[count].type = type;
 
1507
        ImageInfo->file.list[count].data = data;
 
1508
        ImageInfo->file.list[count].size = size;
 
1509
        return count;
 
1510
}
 
1511
/* }}} */
 
1512
 
 
1513
/* {{{ exif_file_sections_realloc
 
1514
 Reallocate a file section returns 0 on success and -1 on failure
 
1515
*/
 
1516
static int exif_file_sections_realloc(image_info_type *ImageInfo, int section_index, size_t size TSRMLS_DC)
 
1517
{
 
1518
        void *tmp;
 
1519
 
 
1520
        /* This is not a malloc/realloc check. It is a plausibility check for the
 
1521
         * function parameters (requirements engineering).
 
1522
         */
 
1523
        if (section_index >= ImageInfo->file.count) {
 
1524
                EXIF_ERRLOG_FSREALLOC(ImageInfo)
 
1525
                return -1;
 
1526
        }
 
1527
        tmp = erealloc(ImageInfo->file.list[section_index].data, size);
 
1528
        ImageInfo->file.list[section_index].data = tmp;
 
1529
        ImageInfo->file.list[section_index].size = size;
 
1530
        return 0;
 
1531
}
 
1532
/* }}} */
 
1533
 
 
1534
/* {{{ exif_file_section_free
 
1535
   Discard all file_sections in ImageInfo
 
1536
*/
 
1537
static int exif_file_sections_free(image_info_type *ImageInfo)
 
1538
{
 
1539
        int i;
 
1540
 
 
1541
        if (ImageInfo->file.count) {
 
1542
                for (i=0; i<ImageInfo->file.count; i++) {
 
1543
                        EFREE_IF(ImageInfo->file.list[i].data);
 
1544
                }
 
1545
        }
 
1546
        EFREE_IF(ImageInfo->file.list);
 
1547
        ImageInfo->file.count = 0;
 
1548
        return TRUE;
 
1549
}
 
1550
/* }}} */
 
1551
 
 
1552
/* {{{ exif_iif_add_value
 
1553
 Add a value to image_info
 
1554
*/
 
1555
static void exif_iif_add_value(image_info_type *image_info, int section_index, char *name, int tag, int format, int length, void* value, int motorola_intel TSRMLS_DC)
 
1556
{
 
1557
        size_t idex;
 
1558
        void *vptr;
 
1559
        image_info_value *info_value;
 
1560
        image_info_data  *info_data;
 
1561
        image_info_data  *list;
 
1562
 
 
1563
        if (length >= LONG_MAX) {
 
1564
                return;
 
1565
        }
 
1566
 
 
1567
        list = erealloc(image_info->info_list[section_index].list, (image_info->info_list[section_index].count+1)*sizeof(image_info_data));
 
1568
        image_info->info_list[section_index].list = list;
 
1569
 
 
1570
        info_data  = &image_info->info_list[section_index].list[image_info->info_list[section_index].count];
 
1571
        info_data->tag    = tag;
 
1572
        info_data->format = format;
 
1573
        info_data->length = length;
 
1574
        info_data->name   = estrdup(name);
 
1575
        info_value        = &info_data->value;
 
1576
 
 
1577
        switch (format) {
 
1578
                case TAG_FMT_STRING:
 
1579
                        if (value) {
 
1580
                                length = php_strnlen(value, length);
 
1581
                                if (PG(magic_quotes_runtime)) {
 
1582
                                        info_value->s = php_addslashes(value, length, &length, 0 TSRMLS_CC);
 
1583
                                } else {
 
1584
                                        info_value->s = estrndup(value, length);
 
1585
                                }
 
1586
                                info_data->length = length;
 
1587
                        } else {
 
1588
                                info_data->length = 0;
 
1589
                                info_value->s = estrdup("");
 
1590
                        }
 
1591
                        break;
 
1592
 
 
1593
                default:
 
1594
                        /* Standard says more types possible but skip them...
 
1595
                         * but allow users to handle data if they know how to
 
1596
                         * So not return but use type UNDEFINED
 
1597
                         * return;
 
1598
                         */
 
1599
                        info_data->tag = TAG_FMT_UNDEFINED;/* otherwise not freed from memory */
 
1600
                case TAG_FMT_SBYTE:
 
1601
                case TAG_FMT_BYTE:
 
1602
                /* in contrast to strings bytes do not need to allocate buffer for NULL if length==0 */
 
1603
                        if (!length)
 
1604
                                break;
 
1605
                case TAG_FMT_UNDEFINED:
 
1606
                        if (value) {
 
1607
                                /* do not recompute length here */
 
1608
                                if (PG(magic_quotes_runtime)) {
 
1609
                                        info_value->s = php_addslashes(value, length, &length, 0 TSRMLS_CC);
 
1610
                                } else {
 
1611
                                        info_value->s = estrndup(value, length);
 
1612
                                }
 
1613
                                info_data->length = length;
 
1614
                        } else {
 
1615
                                info_data->length = 0;
 
1616
                                info_value->s = estrdup("");
 
1617
                        }
 
1618
                        break;
 
1619
 
 
1620
                case TAG_FMT_USHORT:
 
1621
                case TAG_FMT_ULONG:
 
1622
                case TAG_FMT_URATIONAL:
 
1623
                case TAG_FMT_SSHORT:
 
1624
                case TAG_FMT_SLONG:
 
1625
                case TAG_FMT_SRATIONAL:
 
1626
                case TAG_FMT_SINGLE:
 
1627
                case TAG_FMT_DOUBLE:
 
1628
                        if (length==0) {
 
1629
                                break;
 
1630
                        } else
 
1631
                        if (length>1) {
 
1632
                                info_value->list = safe_emalloc(length, sizeof(image_info_value), 0);
 
1633
                        } else {
 
1634
                                info_value = &info_data->value;
 
1635
                        }
 
1636
                        for (idex=0,vptr=value; idex<(size_t)length; idex++,vptr=(char *) vptr + php_tiff_bytes_per_format[format]) {
 
1637
                                if (length>1) {
 
1638
                                        info_value = &info_data->value.list[idex];
 
1639
                                }
 
1640
                                switch (format) {
 
1641
                                        case TAG_FMT_USHORT:
 
1642
                                                info_value->u = php_ifd_get16u(vptr, motorola_intel);
 
1643
                                                break;
 
1644
 
 
1645
                                        case TAG_FMT_ULONG:
 
1646
                                                info_value->u = php_ifd_get32u(vptr, motorola_intel);
 
1647
                                                break;
 
1648
 
 
1649
                                        case TAG_FMT_URATIONAL:
 
1650
                                                info_value->ur.num = php_ifd_get32u(vptr, motorola_intel);
 
1651
                                                info_value->ur.den = php_ifd_get32u(4+(char *)vptr, motorola_intel);
 
1652
                                                break;
 
1653
 
 
1654
                                        case TAG_FMT_SSHORT:
 
1655
                                                info_value->i = php_ifd_get16s(vptr, motorola_intel);
 
1656
                                                break;
 
1657
 
 
1658
                                        case TAG_FMT_SLONG:
 
1659
                                                info_value->i = php_ifd_get32s(vptr, motorola_intel);
 
1660
                                                break;
 
1661
 
 
1662
                                        case TAG_FMT_SRATIONAL:
 
1663
                                                info_value->sr.num = php_ifd_get32u(vptr, motorola_intel);
 
1664
                                                info_value->sr.den = php_ifd_get32u(4+(char *)vptr, motorola_intel);
 
1665
                                                break;
 
1666
 
 
1667
                                        case TAG_FMT_SINGLE:
 
1668
#ifdef EXIF_DEBUG
 
1669
                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Found value of type single");
 
1670
#endif
 
1671
                                                info_value->f = *(float *)value;
 
1672
 
 
1673
                                        case TAG_FMT_DOUBLE:
 
1674
#ifdef EXIF_DEBUG
 
1675
                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Found value of type double");
 
1676
#endif
 
1677
                                                info_value->d = *(double *)value;
 
1678
                                                break;
 
1679
                                }
 
1680
                        }
 
1681
        }
 
1682
        image_info->sections_found |= 1<<section_index;
 
1683
        image_info->info_list[section_index].count++;
 
1684
}
 
1685
/* }}} */
 
1686
 
 
1687
/* {{{ exif_iif_add_tag
 
1688
 Add a tag from IFD to image_info
 
1689
*/
 
1690
static void exif_iif_add_tag(image_info_type *image_info, int section_index, char *name, int tag, int format, size_t length, void* value TSRMLS_DC)
 
1691
{
 
1692
        exif_iif_add_value(image_info, section_index, name, tag, format, (int)length, value, image_info->motorola_intel TSRMLS_CC);
 
1693
}
 
1694
/* }}} */
 
1695
 
 
1696
/* {{{ exif_iif_add_int
 
1697
 Add an int value to image_info
 
1698
*/
 
1699
static void exif_iif_add_int(image_info_type *image_info, int section_index, char *name, int value TSRMLS_DC)
 
1700
{
 
1701
        image_info_data  *info_data;
 
1702
        image_info_data  *list;
 
1703
 
 
1704
        list = erealloc(image_info->info_list[section_index].list, (image_info->info_list[section_index].count+1)*sizeof(image_info_data));
 
1705
        image_info->info_list[section_index].list = list;
 
1706
 
 
1707
        info_data  = &image_info->info_list[section_index].list[image_info->info_list[section_index].count];
 
1708
        info_data->tag    = TAG_NONE;
 
1709
        info_data->format = TAG_FMT_SLONG;
 
1710
        info_data->length = 1;
 
1711
        info_data->name   = estrdup(name);
 
1712
        info_data->value.i = value;
 
1713
        image_info->sections_found |= 1<<section_index;
 
1714
        image_info->info_list[section_index].count++;
 
1715
}
 
1716
/* }}} */
 
1717
 
 
1718
/* {{{ exif_iif_add_str
 
1719
 Add a string value to image_info MUST BE NUL TERMINATED
 
1720
*/
 
1721
static void exif_iif_add_str(image_info_type *image_info, int section_index, char *name, char *value TSRMLS_DC)
 
1722
{
 
1723
        image_info_data  *info_data;
 
1724
        image_info_data  *list;
 
1725
 
 
1726
        if (value) {
 
1727
                list = erealloc(image_info->info_list[section_index].list, (image_info->info_list[section_index].count+1)*sizeof(image_info_data));
 
1728
                image_info->info_list[section_index].list = list;
 
1729
                info_data  = &image_info->info_list[section_index].list[image_info->info_list[section_index].count];
 
1730
                info_data->tag    = TAG_NONE;
 
1731
                info_data->format = TAG_FMT_STRING;
 
1732
                info_data->length = 1;
 
1733
                info_data->name   = estrdup(name);
 
1734
                if (PG(magic_quotes_runtime)) {
 
1735
                        info_data->value.s = php_addslashes(value, strlen(value), NULL, 0 TSRMLS_CC);
 
1736
                } else {
 
1737
                        info_data->value.s = estrdup(value);
 
1738
                }
 
1739
                image_info->sections_found |= 1<<section_index;
 
1740
                image_info->info_list[section_index].count++;
 
1741
        }
 
1742
}
 
1743
/* }}} */
 
1744
 
 
1745
/* {{{ exif_iif_add_fmt
 
1746
 Add a format string value to image_info MUST BE NUL TERMINATED
 
1747
*/
 
1748
static void exif_iif_add_fmt(image_info_type *image_info, int section_index, char *name TSRMLS_DC, char *value, ...)
 
1749
{
 
1750
        char             *tmp;
 
1751
        va_list                  arglist;
 
1752
 
 
1753
        va_start(arglist, value);
 
1754
        if (value) {
 
1755
                vspprintf(&tmp, 0, value, arglist);
 
1756
                exif_iif_add_str(image_info, section_index, name, tmp TSRMLS_CC);
 
1757
                efree(tmp);
 
1758
        }
 
1759
        va_end(arglist);
 
1760
}
 
1761
/* }}} */
 
1762
 
 
1763
/* {{{ exif_iif_add_str
 
1764
 Add a string value to image_info MUST BE NUL TERMINATED
 
1765
*/
 
1766
static void exif_iif_add_buffer(image_info_type *image_info, int section_index, char *name, int length, char *value TSRMLS_DC)
 
1767
{
 
1768
        image_info_data  *info_data;
 
1769
        image_info_data  *list;
 
1770
 
 
1771
        if (value) {
 
1772
                list = erealloc(image_info->info_list[section_index].list, (image_info->info_list[section_index].count+1)*sizeof(image_info_data));
 
1773
                image_info->info_list[section_index].list = list;
 
1774
                info_data  = &image_info->info_list[section_index].list[image_info->info_list[section_index].count];
 
1775
                info_data->tag    = TAG_NONE;
 
1776
                info_data->format = TAG_FMT_UNDEFINED;
 
1777
                info_data->length = length;
 
1778
                info_data->name   = estrdup(name);
 
1779
                if (PG(magic_quotes_runtime)) {
 
1780
#ifdef EXIF_DEBUG
 
1781
                        exif_error_docref(NULL EXIFERR_CC, image_info, E_NOTICE, "Adding %s as buffer%s", name, exif_char_dump(value, length, 0));
 
1782
#endif
 
1783
                        info_data->value.s = php_addslashes(value, length, &length, 0 TSRMLS_CC);
 
1784
                        info_data->length = length;
 
1785
                } else {
 
1786
                        info_data->value.s = safe_emalloc(length, 1, 1);
 
1787
                        memcpy(info_data->value.s, value, length);
 
1788
                        info_data->value.s[length] = 0;
 
1789
                }
 
1790
                image_info->sections_found |= 1<<section_index;
 
1791
                image_info->info_list[section_index].count++;
 
1792
        }
 
1793
}
 
1794
/* }}} */
 
1795
 
 
1796
/* {{{ exif_iif_free
 
1797
 Free memory allocated for image_info
 
1798
*/
 
1799
static void exif_iif_free(image_info_type *image_info, int section_index) {
 
1800
        int  i;
 
1801
        void *f; /* faster */
 
1802
 
 
1803
        if (image_info->info_list[section_index].count) {
 
1804
                for (i=0; i < image_info->info_list[section_index].count; i++) {
 
1805
                        if ((f=image_info->info_list[section_index].list[i].name) != NULL) {
 
1806
                                efree(f);
 
1807
                        }
 
1808
                        switch(image_info->info_list[section_index].list[i].format) {
 
1809
                                case TAG_FMT_SBYTE:
 
1810
                                case TAG_FMT_BYTE:
 
1811
                                        /* in contrast to strings bytes do not need to allocate buffer for NULL if length==0 */
 
1812
                                        if (image_info->info_list[section_index].list[i].length<1)
 
1813
                                                break;
 
1814
                                default:
 
1815
                                case TAG_FMT_UNDEFINED:
 
1816
                                case TAG_FMT_STRING:
 
1817
                                        if ((f=image_info->info_list[section_index].list[i].value.s) != NULL) {
 
1818
                                                efree(f);
 
1819
                                        }
 
1820
                                        break;
 
1821
 
 
1822
                                case TAG_FMT_USHORT:
 
1823
                                case TAG_FMT_ULONG:
 
1824
                                case TAG_FMT_URATIONAL:
 
1825
                                case TAG_FMT_SSHORT:
 
1826
                                case TAG_FMT_SLONG:
 
1827
                                case TAG_FMT_SRATIONAL:
 
1828
                                case TAG_FMT_SINGLE:
 
1829
                                case TAG_FMT_DOUBLE:
 
1830
                                        /* nothing to do here */
 
1831
                                        if (image_info->info_list[section_index].list[i].length > 1) {
 
1832
                                                if ((f=image_info->info_list[section_index].list[i].value.list) != NULL) {
 
1833
                                                        efree(f);
 
1834
                                                }
 
1835
                                        }
 
1836
                                        break;
 
1837
                        }
 
1838
                }
 
1839
        }
 
1840
        EFREE_IF(image_info->info_list[section_index].list);
 
1841
}
 
1842
/* }}} */
 
1843
 
 
1844
/* {{{ add_assoc_image_info
 
1845
 * Add image_info to associative array value. */
 
1846
static void add_assoc_image_info(pval *value, int sub_array, image_info_type *image_info, int section_index TSRMLS_DC)
 
1847
{
 
1848
        char    buffer[64], *val, *name, uname[64];
 
1849
        int     i, ap, l, b, idx=0, unknown=0;
 
1850
#ifdef EXIF_DEBUG
 
1851
        int     info_tag;
 
1852
#endif
 
1853
        image_info_value *info_value;
 
1854
        image_info_data  *info_data;
 
1855
        pval                     *tmpi, *array = NULL;
 
1856
 
 
1857
#ifdef EXIF_DEBUG
 
1858
/*              php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Adding %d infos from section %s", image_info->info_list[section_index].count, exif_get_sectionname(section_index));*/
 
1859
#endif
 
1860
        if (image_info->info_list[section_index].count) {
 
1861
                if (sub_array) {
 
1862
                        MAKE_STD_ZVAL(tmpi);
 
1863
                        array_init(tmpi);
 
1864
                } else {
 
1865
                        tmpi = value;
 
1866
                }
 
1867
 
 
1868
                for(i=0; i<image_info->info_list[section_index].count; i++) {
 
1869
                        info_data  = &image_info->info_list[section_index].list[i];
 
1870
#ifdef EXIF_DEBUG
 
1871
                        info_tag   = info_data->tag; /* conversion */
 
1872
#endif
 
1873
                        info_value = &info_data->value;
 
1874
                        if (!(name = info_data->name)) {
 
1875
                                snprintf(uname, sizeof(uname), "%d", unknown++);
 
1876
                                name = uname;
 
1877
                        }
 
1878
#ifdef EXIF_DEBUG
 
1879
/*              php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Adding infos: tag(0x%04X,%12s,L=0x%04X): %s", info_tag, exif_get_tagname(info_tag, buffer, -12, exif_get_tag_table(section_index) TSRMLS_CC), info_data->length, info_data->format==TAG_FMT_STRING?(info_value&&info_value->s?info_value->s:"<no data>"):exif_get_tagformat(info_data->format));*/
 
1880
#endif
 
1881
                        if (info_data->length==0) {
 
1882
                                add_assoc_null(tmpi, name);
 
1883
                        } else {
 
1884
                                switch (info_data->format) {
 
1885
                                        default:
 
1886
                                                /* Standard says more types possible but skip them...
 
1887
                                                 * but allow users to handle data if they know how to
 
1888
                                                 * So not return but use type UNDEFINED
 
1889
                                                 * return;
 
1890
                                                 */
 
1891
                                        case TAG_FMT_BYTE:
 
1892
                                        case TAG_FMT_SBYTE:
 
1893
                                        case TAG_FMT_UNDEFINED:
 
1894
                                                if (!info_value->s) {
 
1895
                                                        add_assoc_stringl(tmpi, name, "", 0, 1);
 
1896
                                                } else {
 
1897
                                                        add_assoc_stringl(tmpi, name, info_value->s, info_data->length, 1);
 
1898
                                                }
 
1899
                                                break;
 
1900
 
 
1901
                                        case TAG_FMT_STRING:
 
1902
                                                if (!(val = info_value->s)) {
 
1903
                                                        val = "";
 
1904
                                                }
 
1905
                                                if (section_index==SECTION_COMMENT) {
 
1906
                                                        add_index_string(tmpi, idx++, val, 1);
 
1907
                                                } else {
 
1908
                                                        add_assoc_string(tmpi, name, val, 1);
 
1909
                                                }
 
1910
                                                break;
 
1911
 
 
1912
                                        case TAG_FMT_URATIONAL:
 
1913
                                        case TAG_FMT_SRATIONAL:
 
1914
                                        /*case TAG_FMT_BYTE:
 
1915
                                        case TAG_FMT_SBYTE:*/
 
1916
                                        case TAG_FMT_USHORT:
 
1917
                                        case TAG_FMT_SSHORT:
 
1918
                                        case TAG_FMT_SINGLE:
 
1919
                                        case TAG_FMT_DOUBLE:
 
1920
                                        case TAG_FMT_ULONG:
 
1921
                                        case TAG_FMT_SLONG:
 
1922
                                                /* now the rest, first see if it becomes an array */
 
1923
                                                if ((l = info_data->length) > 1) {
 
1924
                                                        array = NULL;
 
1925
                                                        MAKE_STD_ZVAL(array);
 
1926
                                                        array_init(array);
 
1927
                                                }
 
1928
                                                for(ap=0; ap<l; ap++) {
 
1929
                                                        if (l>1) {
 
1930
                                                                info_value = &info_data->value.list[ap];
 
1931
                                                        }
 
1932
                                                        switch (info_data->format) {
 
1933
                                                                case TAG_FMT_BYTE:
 
1934
                                                                        if (l>1) {
 
1935
                                                                                info_value = &info_data->value;
 
1936
                                                                                for (b=0;b<l;b++) {
 
1937
                                                                                        add_index_long(array, b, (int)(info_value->s[b]));
 
1938
                                                                                }
 
1939
                                                                                break;
 
1940
                                                                        }
 
1941
                                                                case TAG_FMT_USHORT:
 
1942
                                                                case TAG_FMT_ULONG:
 
1943
                                                                        if (l==1) {
 
1944
                                                                                add_assoc_long(tmpi, name, (int)info_value->u);
 
1945
                                                                        } else {
 
1946
                                                                                add_index_long(array, ap, (int)info_value->u);
 
1947
                                                                        }
 
1948
                                                                        break;
 
1949
 
 
1950
                                                                case TAG_FMT_URATIONAL:
 
1951
                                                                        snprintf(buffer, sizeof(buffer), "%i/%i", info_value->ur.num, info_value->ur.den);
 
1952
                                                                        if (l==1) {
 
1953
                                                                                add_assoc_string(tmpi, name, buffer, 1);
 
1954
                                                                        } else {
 
1955
                                                                                add_index_string(array, ap, buffer, 1);
 
1956
                                                                        }
 
1957
                                                                        break;
 
1958
 
 
1959
                                                                case TAG_FMT_SBYTE:
 
1960
                                                                        if (l>1) {
 
1961
                                                                                info_value = &info_data->value;
 
1962
                                                                                for (b=0;b<l;b++) {
 
1963
                                                                                        add_index_long(array, ap, (int)info_value->s[b]);
 
1964
                                                                                }
 
1965
                                                                                break;
 
1966
                                                                        }
 
1967
                                                                case TAG_FMT_SSHORT:
 
1968
                                                                case TAG_FMT_SLONG:
 
1969
                                                                        if (l==1) {
 
1970
                                                                                add_assoc_long(tmpi, name, info_value->i);
 
1971
                                                                        } else {
 
1972
                                                                                add_index_long(array, ap, info_value->i);
 
1973
                                                                        }
 
1974
                                                                        break;
 
1975
 
 
1976
                                                                case TAG_FMT_SRATIONAL:
 
1977
                                                                        snprintf(buffer, sizeof(buffer), "%i/%i", info_value->sr.num, info_value->sr.den);
 
1978
                                                                        if (l==1) {
 
1979
                                                                                add_assoc_string(tmpi, name, buffer, 1);
 
1980
                                                                        } else {
 
1981
                                                                                add_index_string(array, ap, buffer, 1);
 
1982
                                                                        }
 
1983
                                                                        break;
 
1984
 
 
1985
                                                                case TAG_FMT_SINGLE:
 
1986
                                                                        if (l==1) {
 
1987
                                                                                add_assoc_double(tmpi, name, info_value->f);
 
1988
                                                                        } else {
 
1989
                                                                                add_index_double(array, ap, info_value->f);
 
1990
                                                                        }
 
1991
                                                                        break;
 
1992
 
 
1993
                                                                case TAG_FMT_DOUBLE:
 
1994
                                                                        if (l==1) {
 
1995
                                                                                add_assoc_double(tmpi, name, info_value->d);
 
1996
                                                                        } else {
 
1997
                                                                                add_index_double(array, ap, info_value->d);
 
1998
                                                                        }
 
1999
                                                                        break;
 
2000
                                                        }
 
2001
                                                        info_value = &info_data->value.list[ap];
 
2002
                                                }
 
2003
                                                if (l>1) {
 
2004
                                                        add_assoc_zval(tmpi, name, array);
 
2005
                                                }
 
2006
                                                break;
 
2007
                                }
 
2008
                        }
 
2009
                }
 
2010
                if (sub_array) {
 
2011
                        add_assoc_zval(value, exif_get_sectionname(section_index), tmpi);
 
2012
                }
 
2013
        }
 
2014
}
 
2015
/* }}} */
 
2016
 
 
2017
/* {{{ Markers
 
2018
   JPEG markers consist of one or more 0xFF bytes, followed by a marker
 
2019
   code byte (which is not an FF).  Here are the marker codes of interest
 
2020
   in this program.  (See jdmarker.c for a more complete list.)
 
2021
*/
 
2022
 
 
2023
#define M_TEM   0x01    /* temp for arithmetic coding              */
 
2024
#define M_RES   0x02    /* reserved                                */
 
2025
#define M_SOF0  0xC0    /* Start Of Frame N                        */
 
2026
#define M_SOF1  0xC1    /* N indicates which compression process   */
 
2027
#define M_SOF2  0xC2    /* Only SOF0-SOF2 are now in common use    */
 
2028
#define M_SOF3  0xC3
 
2029
#define M_DHT   0xC4
 
2030
#define M_SOF5  0xC5    /* NB: codes C4 and CC are NOT SOF markers */
 
2031
#define M_SOF6  0xC6
 
2032
#define M_SOF7  0xC7
 
2033
#define M_JPEG  0x08    /* reserved for extensions                 */
 
2034
#define M_SOF9  0xC9
 
2035
#define M_SOF10 0xCA
 
2036
#define M_SOF11 0xCB
 
2037
#define M_DAC   0xCC    /* arithmetic table                         */
 
2038
#define M_SOF13 0xCD
 
2039
#define M_SOF14 0xCE
 
2040
#define M_SOF15 0xCF
 
2041
#define M_RST0  0xD0    /* restart segment                          */
 
2042
#define M_RST1  0xD1
 
2043
#define M_RST2  0xD2
 
2044
#define M_RST3  0xD3
 
2045
#define M_RST4  0xD4
 
2046
#define M_RST5  0xD5
 
2047
#define M_RST6  0xD6
 
2048
#define M_RST7  0xD7
 
2049
#define M_SOI   0xD8    /* Start Of Image (beginning of datastream) */
 
2050
#define M_EOI   0xD9    /* End Of Image (end of datastream)         */
 
2051
#define M_SOS   0xDA    /* Start Of Scan (begins compressed data)   */
 
2052
#define M_DQT   0xDB
 
2053
#define M_DNL   0xDC
 
2054
#define M_DRI   0xDD
 
2055
#define M_DHP   0xDE
 
2056
#define M_EXP   0xDF
 
2057
#define M_APP0  0xE0    /* JPEG: 'JFIFF' AND (additional 'JFXX')    */
 
2058
#define M_EXIF  0xE1    /* Exif Attribute Information               */
 
2059
#define M_APP2  0xE2    /* Flash Pix Extension Data?                */
 
2060
#define M_APP3  0xE3
 
2061
#define M_APP4  0xE4
 
2062
#define M_APP5  0xE5
 
2063
#define M_APP6  0xE6
 
2064
#define M_APP7  0xE7
 
2065
#define M_APP8  0xE8
 
2066
#define M_APP9  0xE9
 
2067
#define M_APP10 0xEA
 
2068
#define M_APP11 0xEB
 
2069
#define M_APP12 0xEC
 
2070
#define M_APP13 0xED    /* IPTC International Press Telecommunications Council */
 
2071
#define M_APP14 0xEE    /* Software, Copyright?                     */
 
2072
#define M_APP15 0xEF
 
2073
#define M_JPG0  0xF0
 
2074
#define M_JPG1  0xF1
 
2075
#define M_JPG2  0xF2
 
2076
#define M_JPG3  0xF3
 
2077
#define M_JPG4  0xF4
 
2078
#define M_JPG5  0xF5
 
2079
#define M_JPG6  0xF6
 
2080
#define M_JPG7  0xF7
 
2081
#define M_JPG8  0xF8
 
2082
#define M_JPG9  0xF9
 
2083
#define M_JPG10 0xFA
 
2084
#define M_JPG11 0xFB
 
2085
#define M_JPG12 0xFC
 
2086
#define M_JPG13 0xFD
 
2087
#define M_COM   0xFE    /* COMment                                  */
 
2088
 
 
2089
#define M_PSEUDO 0x123  /* Extra value.                             */
 
2090
 
 
2091
/* }}} */
 
2092
 
 
2093
/* {{{ jpeg2000 markers
 
2094
 */
 
2095
/* Markers x30 - x3F do not have a segment */
 
2096
/* Markers x00, x01, xFE, xC0 - xDF ISO/IEC 10918-1 -> M_<xx> */
 
2097
/* Markers xF0 - xF7 ISO/IEC 10918-3 */
 
2098
/* Markers xF7 - xF8 ISO/IEC 14495-1 */
 
2099
/* XY=Main/Tile-header:(R:required, N:not_allowed, O:optional, L:last_marker) */
 
2100
#define JC_SOC   0x4F   /* NN, Start of codestream                          */
 
2101
#define JC_SIZ   0x51   /* RN, Image and tile size                          */
 
2102
#define JC_COD   0x52   /* RO, Codeing style defaulte                       */
 
2103
#define JC_COC   0x53   /* OO, Coding style component                       */
 
2104
#define JC_TLM   0x55   /* ON, Tile part length main header                 */
 
2105
#define JC_PLM   0x57   /* ON, Packet length main header                    */
 
2106
#define JC_PLT   0x58   /* NO, Packet length tile part header               */
 
2107
#define JC_QCD   0x5C   /* RO, Quantization default                         */
 
2108
#define JC_QCC   0x5D   /* OO, Quantization component                       */
 
2109
#define JC_RGN   0x5E   /* OO, Region of interest                           */
 
2110
#define JC_POD   0x5F   /* OO, Progression order default                    */
 
2111
#define JC_PPM   0x60   /* ON, Packed packet headers main header            */
 
2112
#define JC_PPT   0x61   /* NO, Packet packet headers tile part header       */
 
2113
#define JC_CME   0x64   /* OO, Comment: "LL E <text>" E=0:binary, E=1:ascii */
 
2114
#define JC_SOT   0x90   /* NR, Start of tile                                */
 
2115
#define JC_SOP   0x91   /* NO, Start of packeter default                    */
 
2116
#define JC_EPH   0x92   /* NO, End of packet header                         */
 
2117
#define JC_SOD   0x93   /* NL, Start of data                                */
 
2118
#define JC_EOC   0xD9   /* NN, End of codestream                            */
 
2119
/* }}} */
 
2120
 
 
2121
/* {{{ exif_process_COM
 
2122
   Process a COM marker.
 
2123
   We want to print out the marker contents as legible text;
 
2124
   we must guard against random junk and varying newline representations.
 
2125
*/
 
2126
static void exif_process_COM (image_info_type *image_info, char *value, size_t length TSRMLS_DC)
 
2127
{
 
2128
        exif_iif_add_tag(image_info, SECTION_COMMENT, "Comment", TAG_COMPUTED_VALUE, TAG_FMT_STRING, length-2, value+2 TSRMLS_CC);
 
2129
}
 
2130
/* }}} */
 
2131
 
 
2132
/* {{{ exif_process_CME
 
2133
   Process a CME marker.
 
2134
   We want to print out the marker contents as legible text;
 
2135
   we must guard against random junk and varying newline representations.
 
2136
*/
 
2137
#ifdef EXIF_JPEG2000
 
2138
static void exif_process_CME (image_info_type *image_info, char *value, size_t length TSRMLS_DC)
 
2139
{
 
2140
        if (length>3) {
 
2141
                switch(value[2]) {
 
2142
                        case 0:
 
2143
                                exif_iif_add_tag(image_info, SECTION_COMMENT, "Comment", TAG_COMPUTED_VALUE, TAG_FMT_UNDEFINED, length, value TSRMLS_CC);
 
2144
                                break;
 
2145
                        case 1:
 
2146
                                exif_iif_add_tag(image_info, SECTION_COMMENT, "Comment", TAG_COMPUTED_VALUE, TAG_FMT_STRING, length, value);
 
2147
                                break;
 
2148
                        default:
 
2149
                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Undefined JPEG2000 comment encoding");
 
2150
                                break;
 
2151
                }
 
2152
        } else {
 
2153
                exif_iif_add_tag(image_info, SECTION_COMMENT, "Comment", TAG_COMPUTED_VALUE, TAG_FMT_UNDEFINED, 0, NULL);
 
2154
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "JPEG2000 comment section to small");
 
2155
        }
 
2156
}
 
2157
#endif
 
2158
/* }}} */
 
2159
 
 
2160
/* {{{ exif_process_SOFn
 
2161
 * Process a SOFn marker.  This is useful for the image dimensions */
 
2162
static void exif_process_SOFn (uchar *Data, int marker, jpeg_sof_info *result)
 
2163
{
 
2164
/* 0xFF SOSn SectLen(2) Bits(1) Height(2) Width(2) Channels(1)  3*Channels (1)  */
 
2165
        result->bits_per_sample = Data[2];
 
2166
        result->height          = php_jpg_get16(Data+3);
 
2167
        result->width           = php_jpg_get16(Data+5);
 
2168
        result->num_components  = Data[7];
 
2169
 
 
2170
/*      switch (marker) {
 
2171
                case M_SOF0:  process = "Baseline";  break;
 
2172
                case M_SOF1:  process = "Extended sequential";  break;
 
2173
                case M_SOF2:  process = "Progressive";  break;
 
2174
                case M_SOF3:  process = "Lossless";  break;
 
2175
                case M_SOF5:  process = "Differential sequential";  break;
 
2176
                case M_SOF6:  process = "Differential progressive";  break;
 
2177
                case M_SOF7:  process = "Differential lossless";  break;
 
2178
                case M_SOF9:  process = "Extended sequential, arithmetic coding";  break;
 
2179
                case M_SOF10: process = "Progressive, arithmetic coding";  break;
 
2180
                case M_SOF11: process = "Lossless, arithmetic coding";  break;
 
2181
                case M_SOF13: process = "Differential sequential, arithmetic coding";  break;
 
2182
                case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
 
2183
                case M_SOF15: process = "Differential lossless, arithmetic coding";  break;
 
2184
                default:      process = "Unknown";  break;
 
2185
        }*/
 
2186
}
 
2187
/* }}} */
 
2188
 
 
2189
/* forward declarations */
 
2190
static int exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, char *offset_base, size_t IFDlength, size_t displacement, int section_index TSRMLS_DC);
 
2191
static int exif_process_IFD_TAG(    image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table TSRMLS_DC);
 
2192
 
 
2193
/* {{{ exif_get_markername
 
2194
        Get name of marker */
 
2195
#ifdef EXIF_DEBUG
 
2196
static char * exif_get_markername(int marker)
 
2197
{
 
2198
        switch(marker) {
 
2199
                case 0xC0: return "SOF0";
 
2200
                case 0xC1: return "SOF1";
 
2201
                case 0xC2: return "SOF2";
 
2202
                case 0xC3: return "SOF3";
 
2203
                case 0xC4: return "DHT";
 
2204
                case 0xC5: return "SOF5";
 
2205
                case 0xC6: return "SOF6";
 
2206
                case 0xC7: return "SOF7";
 
2207
                case 0xC9: return "SOF9";
 
2208
                case 0xCA: return "SOF10";
 
2209
                case 0xCB: return "SOF11";
 
2210
                case 0xCD: return "SOF13";
 
2211
                case 0xCE: return "SOF14";
 
2212
                case 0xCF: return "SOF15";
 
2213
                case 0xD8: return "SOI";
 
2214
                case 0xD9: return "EOI";
 
2215
                case 0xDA: return "SOS";
 
2216
                case 0xDB: return "DQT";
 
2217
                case 0xDC: return "DNL";
 
2218
                case 0xDD: return "DRI";
 
2219
                case 0xDE: return "DHP";
 
2220
                case 0xDF: return "EXP";
 
2221
                case 0xE0: return "APP0";
 
2222
                case 0xE1: return "EXIF";
 
2223
                case 0xE2: return "FPIX";
 
2224
                case 0xE3: return "APP3";
 
2225
                case 0xE4: return "APP4";
 
2226
                case 0xE5: return "APP5";
 
2227
                case 0xE6: return "APP6";
 
2228
                case 0xE7: return "APP7";
 
2229
                case 0xE8: return "APP8";
 
2230
                case 0xE9: return "APP9";
 
2231
                case 0xEA: return "APP10";
 
2232
                case 0xEB: return "APP11";
 
2233
                case 0xEC: return "APP12";
 
2234
                case 0xED: return "APP13";
 
2235
                case 0xEE: return "APP14";
 
2236
                case 0xEF: return "APP15";
 
2237
                case 0xF0: return "JPG0";
 
2238
                case 0xFD: return "JPG13";
 
2239
                case 0xFE: return "COM";
 
2240
                case 0x01: return "TEM";
 
2241
        }
 
2242
        return "Unknown";
 
2243
}
 
2244
#endif
 
2245
/* }}} */
 
2246
 
 
2247
/* {{{ proto string exif_tagname(index)
 
2248
        Get headername for index or false if not defined */
 
2249
PHP_FUNCTION(exif_tagname)
 
2250
{
 
2251
        pval **p_num;
 
2252
        int tag, ac = ZEND_NUM_ARGS();
 
2253
        char *szTemp;
 
2254
 
 
2255
        if ((ac < 1 || ac > 1) || zend_get_parameters_ex(ac, &p_num) == FAILURE) {
 
2256
                WRONG_PARAM_COUNT;
 
2257
        }
 
2258
 
 
2259
        convert_to_long_ex(p_num);
 
2260
        tag = Z_LVAL_PP(p_num);
 
2261
        szTemp = exif_get_tagname(tag, NULL, 0, tag_table_IFD TSRMLS_CC);
 
2262
        if (tag<0 || !szTemp || !szTemp[0]) {
 
2263
                RETURN_BOOL(FALSE);
 
2264
        } else {
 
2265
                RETURN_STRING(szTemp, 1)
 
2266
        }
 
2267
}
 
2268
/* }}} */
 
2269
 
 
2270
/* {{{ exif_ifd_make_value
 
2271
 * Create a value for an ifd from an info_data pointer */
 
2272
static void* exif_ifd_make_value(image_info_data *info_data, int motorola_intel TSRMLS_DC) {
 
2273
        size_t  byte_count;
 
2274
        char    *value_ptr, *data_ptr;
 
2275
        size_t  i;
 
2276
 
 
2277
        image_info_value  *info_value;
 
2278
 
 
2279
        byte_count = php_tiff_bytes_per_format[info_data->format] * info_data->length;
 
2280
        value_ptr = emalloc(max(byte_count, 4));
 
2281
        memset(value_ptr, 0, 4);
 
2282
        if (!info_data->length) {
 
2283
                return value_ptr;
 
2284
        }
 
2285
        if (info_data->format == TAG_FMT_UNDEFINED || info_data->format == TAG_FMT_STRING
 
2286
          || (byte_count>1 && (info_data->format == TAG_FMT_BYTE || info_data->format == TAG_FMT_SBYTE))
 
2287
        ) {
 
2288
                memmove(value_ptr, info_data->value.s, byte_count);
 
2289
                return value_ptr;
 
2290
        } else if (info_data->format == TAG_FMT_BYTE) {
 
2291
                *value_ptr = info_data->value.u;
 
2292
                return value_ptr;
 
2293
        } else if (info_data->format == TAG_FMT_SBYTE) {
 
2294
                *value_ptr = info_data->value.i;
 
2295
                return value_ptr;
 
2296
        } else {
 
2297
                data_ptr = value_ptr;
 
2298
                for(i=0; i<info_data->length; i++) {
 
2299
                        if (info_data->length==1) {
 
2300
                                info_value = &info_data->value;
 
2301
                        } else {
 
2302
                                info_value = &info_data->value.list[i];
 
2303
                        }
 
2304
                        switch(info_data->format) {
 
2305
                                case TAG_FMT_USHORT:
 
2306
                                        php_ifd_set16u(data_ptr, info_value->u, motorola_intel);
 
2307
                                        data_ptr += 2;
 
2308
                                        break;
 
2309
                                case TAG_FMT_ULONG:
 
2310
                                        php_ifd_set32u(data_ptr, info_value->u, motorola_intel);
 
2311
                                        data_ptr += 4;
 
2312
                                        break;
 
2313
                                case TAG_FMT_SSHORT:
 
2314
                                        php_ifd_set16u(data_ptr, info_value->i, motorola_intel);
 
2315
                                        data_ptr += 2;
 
2316
                                        break;
 
2317
                                case TAG_FMT_SLONG:
 
2318
                                        php_ifd_set32u(data_ptr, info_value->i, motorola_intel);
 
2319
                                        data_ptr += 4;
 
2320
                                        break;
 
2321
                                case TAG_FMT_URATIONAL:
 
2322
                                        php_ifd_set32u(data_ptr,   info_value->sr.num, motorola_intel);
 
2323
                                        php_ifd_set32u(data_ptr+4, info_value->sr.den, motorola_intel);
 
2324
                                        data_ptr += 8;
 
2325
                                        break;
 
2326
                                case TAG_FMT_SRATIONAL:
 
2327
                                        php_ifd_set32u(data_ptr,   info_value->ur.num, motorola_intel);
 
2328
                                        php_ifd_set32u(data_ptr+4, info_value->ur.den, motorola_intel);
 
2329
                                        data_ptr += 8;
 
2330
                                        break;
 
2331
                                case TAG_FMT_SINGLE:
 
2332
                                        memmove(data_ptr, &info_data->value.f, byte_count);
 
2333
                                        data_ptr += 4;
 
2334
                                        break;
 
2335
                                case TAG_FMT_DOUBLE:
 
2336
                                        memmove(data_ptr, &info_data->value.d, byte_count);
 
2337
                                        data_ptr += 8;
 
2338
                                        break;
 
2339
                        }
 
2340
                }
 
2341
        }
 
2342
        return value_ptr;
 
2343
}
 
2344
/* }}} */
 
2345
 
 
2346
/* {{{ exif_thumbnail_build
 
2347
 * Check and build thumbnail */
 
2348
static void exif_thumbnail_build(image_info_type *ImageInfo TSRMLS_DC) {
 
2349
        size_t            new_size, new_move, new_value;
 
2350
        char              *new_data;
 
2351
        void              *value_ptr;
 
2352
        int               i, byte_count;
 
2353
        image_info_list   *info_list;
 
2354
        image_info_data   *info_data;
 
2355
#ifdef EXIF_DEBUG
 
2356
        char              tagname[64];
 
2357
#endif
 
2358
 
 
2359
        if (!ImageInfo->read_thumbnail || !ImageInfo->Thumbnail.offset || !ImageInfo->Thumbnail.size) {
 
2360
                return; /* ignore this call */
 
2361
        }
 
2362
#ifdef EXIF_DEBUG
 
2363
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: filetype = %d", ImageInfo->Thumbnail.filetype);
 
2364
#endif
 
2365
        switch(ImageInfo->Thumbnail.filetype) {
 
2366
                default:
 
2367
                case IMAGE_FILETYPE_JPEG:
 
2368
                        /* done */
 
2369
                        break;
 
2370
                case IMAGE_FILETYPE_TIFF_II:
 
2371
                case IMAGE_FILETYPE_TIFF_MM:
 
2372
                        info_list = &ImageInfo->info_list[SECTION_THUMBNAIL];
 
2373
                        new_size  = 8 + 2 + info_list->count * 12 + 4;
 
2374
#ifdef EXIF_DEBUG
 
2375
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: size of signature + directory(%d): 0x%02X", info_list->count, new_size);
 
2376
#endif
 
2377
                        new_value= new_size; /* offset for ifd values outside ifd directory */
 
2378
                        for (i=0; i<info_list->count; i++) {
 
2379
                                info_data  = &info_list->list[i];
 
2380
                                byte_count = php_tiff_bytes_per_format[info_data->format] * info_data->length;
 
2381
                                if (byte_count > 4) {
 
2382
                                        new_size += byte_count;
 
2383
                                }
 
2384
                        }
 
2385
                        new_move = new_size;
 
2386
                        new_data = erealloc(ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size+new_size);
 
2387
                        ImageInfo->Thumbnail.data = new_data;
 
2388
                        memmove(ImageInfo->Thumbnail.data + new_move, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size);
 
2389
                        ImageInfo->Thumbnail.size += new_size;
 
2390
                        /* fill in data */
 
2391
                        if (ImageInfo->motorola_intel) {
 
2392
                                memmove(new_data, "MM\x00\x2a\x00\x00\x00\x08", 8);
 
2393
                        } else {
 
2394
                                memmove(new_data, "II\x2a\x00\x08\x00\x00\x00", 8);
 
2395
                        }
 
2396
                        new_data += 8;
 
2397
                        php_ifd_set16u(new_data, info_list->count, ImageInfo->motorola_intel);
 
2398
                        new_data += 2;
 
2399
                        for (i=0; i<info_list->count; i++) {
 
2400
                                info_data  = &info_list->list[i];
 
2401
                                byte_count = php_tiff_bytes_per_format[info_data->format] * info_data->length;
 
2402
#ifdef EXIF_DEBUG
 
2403
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: process tag(x%04X=%s): %s%s (%d bytes)", info_data->tag, exif_get_tagname(info_data->tag, tagname, -12, tag_table_IFD TSRMLS_CC), (info_data->length>1)&&info_data->format!=TAG_FMT_UNDEFINED&&info_data->format!=TAG_FMT_STRING?"ARRAY OF ":"", exif_get_tagformat(info_data->format), byte_count);
 
2404
#endif
 
2405
                                if (info_data->tag==TAG_STRIP_OFFSETS || info_data->tag==TAG_JPEG_INTERCHANGE_FORMAT) {
 
2406
                                        php_ifd_set16u(new_data + 0, info_data->tag,    ImageInfo->motorola_intel);
 
2407
                                        php_ifd_set16u(new_data + 2, TAG_FMT_ULONG,     ImageInfo->motorola_intel);
 
2408
                                        php_ifd_set32u(new_data + 4, 1,                 ImageInfo->motorola_intel);
 
2409
                                        php_ifd_set32u(new_data + 8, new_move,          ImageInfo->motorola_intel);
 
2410
                                } else {
 
2411
                                        php_ifd_set16u(new_data + 0, info_data->tag,    ImageInfo->motorola_intel);
 
2412
                                        php_ifd_set16u(new_data + 2, info_data->format, ImageInfo->motorola_intel);
 
2413
                                        php_ifd_set32u(new_data + 4, info_data->length, ImageInfo->motorola_intel);
 
2414
                                        value_ptr  = exif_ifd_make_value(info_data, ImageInfo->motorola_intel TSRMLS_CC);
 
2415
                                        if (byte_count <= 4) {
 
2416
                                                memmove(new_data+8, value_ptr, 4);
 
2417
                                        } else {
 
2418
                                                php_ifd_set32u(new_data+8, new_value, ImageInfo->motorola_intel);
 
2419
#ifdef EXIF_DEBUG
 
2420
                                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: writing with value offset: 0x%04X + 0x%02X", new_value, byte_count);
 
2421
#endif
 
2422
                                                memmove(ImageInfo->Thumbnail.data+new_value, value_ptr, byte_count);
 
2423
                                                new_value += byte_count;
 
2424
                                        }
 
2425
                                        efree(value_ptr);
 
2426
                                }
 
2427
                                new_data += 12;
 
2428
                        }
 
2429
                        memset(new_data, 0, 4); /* next ifd pointer */
 
2430
#ifdef EXIF_DEBUG
 
2431
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: created");
 
2432
#endif
 
2433
                        break;
 
2434
        }
 
2435
}
 
2436
/* }}} */
 
2437
 
 
2438
/* {{{ exif_thumbnail_extract
 
2439
 * Grab the thumbnail, corrected */
 
2440
static void exif_thumbnail_extract(image_info_type *ImageInfo, char *offset, size_t length TSRMLS_DC) {
 
2441
        if (ImageInfo->Thumbnail.data) {
 
2442
                exif_error_docref("exif_read_data#error_mult_thumb" EXIFERR_CC, ImageInfo, E_WARNING, "Multiple possible thumbnails");
 
2443
                return; /* Should not happen */
 
2444
        }
 
2445
        if (!ImageInfo->read_thumbnail) {
 
2446
                return; /* ignore this call */
 
2447
        }
 
2448
        /* according to exif2.1, the thumbnail is not supposed to be greater than 64K */
 
2449
        if (ImageInfo->Thumbnail.size >= 65536
 
2450
         || ImageInfo->Thumbnail.size <= 0
 
2451
         || ImageInfo->Thumbnail.offset <= 0
 
2452
        ) {
 
2453
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Illegal thumbnail size/offset");
 
2454
                return;
 
2455
        }
 
2456
        /* Check to make sure we are not going to go past the ExifLength */
 
2457
        if ((ImageInfo->Thumbnail.offset + ImageInfo->Thumbnail.size) > length) {
 
2458
                EXIF_ERRLOG_THUMBEOF(ImageInfo)
 
2459
                return;
 
2460
        }
 
2461
        ImageInfo->Thumbnail.data = estrndup(offset + ImageInfo->Thumbnail.offset, ImageInfo->Thumbnail.size);
 
2462
        exif_thumbnail_build(ImageInfo TSRMLS_CC);
 
2463
}
 
2464
/* }}} */
 
2465
 
 
2466
/* {{{ exif_process_undefined
 
2467
 * Copy a string/buffer in Exif header to a character string and return length of allocated buffer if any. */
 
2468
static int exif_process_undefined(char **result, char *value, size_t byte_count TSRMLS_DC) {
 
2469
        /* we cannot use strlcpy - here the problem is that we have to copy NUL
 
2470
         * chars up to byte_count, we also have to add a single NUL character to
 
2471
         * force end of string.
 
2472
         * estrndup does not return length
 
2473
         */
 
2474
        if (byte_count) {
 
2475
                (*result) = estrndup(value, byte_count); /* NULL @ byte_count!!! */
 
2476
                return byte_count+1;
 
2477
        }
 
2478
        return 0;
 
2479
}
 
2480
/* }}} */
 
2481
 
 
2482
/* {{{ exif_process_string_raw
 
2483
 * Copy a string in Exif header to a character string returns length of allocated buffer if any. */
 
2484
#if !EXIF_USE_MBSTRING
 
2485
static int exif_process_string_raw(char **result, char *value, size_t byte_count) {
 
2486
        /* we cannot use strlcpy - here the problem is that we have to copy NUL
 
2487
         * chars up to byte_count, we also have to add a single NUL character to
 
2488
         * force end of string.
 
2489
         */
 
2490
        if (byte_count) {
 
2491
                (*result) = safe_emalloc(byte_count, 1, 1);
 
2492
                memcpy(*result, value, byte_count);
 
2493
                (*result)[byte_count] = '\0';
 
2494
                return byte_count+1;
 
2495
        }
 
2496
        return 0;
 
2497
}
 
2498
#endif
 
2499
/* }}} */
 
2500
 
 
2501
/* {{{ exif_process_string
 
2502
 * Copy a string in Exif header to a character string and return length of allocated buffer if any.
 
2503
 * In contrast to exif_process_string this function does allways return a string buffer */
 
2504
static int exif_process_string(char **result, char *value, size_t byte_count TSRMLS_DC) {
 
2505
        /* we cannot use strlcpy - here the problem is that we cannot use strlen to
 
2506
         * determin length of string and we cannot use strlcpy with len=byte_count+1
 
2507
         * because then we might get into an EXCEPTION if we exceed an allocated
 
2508
         * memory page...so we use php_strnlen in conjunction with memcpy and add the NUL
 
2509
         * char.
 
2510
         * estrdup would sometimes allocate more memory and does not return length
 
2511
         */
 
2512
        if ((byte_count=php_strnlen(value, byte_count)) > 0) {
 
2513
                return exif_process_undefined(result, value, byte_count TSRMLS_CC);
 
2514
        }
 
2515
        (*result) = estrndup("", 1); /* force empty string */
 
2516
        return byte_count+1;
 
2517
}
 
2518
/* }}} */
 
2519
 
 
2520
/* {{{ exif_process_user_comment
 
2521
 * Process UserComment in IFD. */
 
2522
static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoPtr, char **pszEncoding, char *szValuePtr, int ByteCount TSRMLS_DC)
 
2523
{
 
2524
        int   a;
 
2525
 
 
2526
#if EXIF_USE_MBSTRING
 
2527
        char  *decode;
 
2528
        size_t len;;
 
2529
#endif
 
2530
 
 
2531
        *pszEncoding = NULL;
 
2532
        /* Copy the comment */
 
2533
        if (ByteCount>=8) {
 
2534
                if (!memcmp(szValuePtr, "UNICODE\0", 8)) {
 
2535
                        *pszEncoding = estrdup((const char*)szValuePtr);
 
2536
                        szValuePtr = szValuePtr+8;
 
2537
                        ByteCount -= 8;
 
2538
#if EXIF_USE_MBSTRING
 
2539
                        /* First try to detect BOM: ZERO WIDTH NOBREAK SPACE (FEFF 16) 
 
2540
                         * since we have no encoding support for the BOM yet we skip that.
 
2541
                         */
 
2542
                        if (!memcmp(szValuePtr, "\xFE\xFF", 2)) {
 
2543
                                decode = "UCS-2BE";
 
2544
                                szValuePtr = szValuePtr+2;
 
2545
                                ByteCount -= 2;
 
2546
                        } else if (!memcmp(szValuePtr, "\xFF\xFE", 2)) {
 
2547
                                decode = "UCS-2LE";
 
2548
                                szValuePtr = szValuePtr+2;
 
2549
                                ByteCount -= 2;
 
2550
                        } else if (ImageInfo->motorola_intel) {
 
2551
                                decode = ImageInfo->decode_unicode_be;
 
2552
                        } else {
 
2553
                                decode = ImageInfo->decode_unicode_le;
 
2554
                        }
 
2555
                        *pszInfoPtr = php_mb_convert_encoding(szValuePtr, ByteCount, ImageInfo->encode_unicode, decode, &len TSRMLS_CC);
 
2556
                        return len;
 
2557
#else
 
2558
                        return exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount);
 
2559
#endif
 
2560
                } else
 
2561
                if (!memcmp(szValuePtr, "ASCII\0\0\0", 8)) {
 
2562
                        *pszEncoding = estrdup((const char*)szValuePtr);
 
2563
                        szValuePtr = szValuePtr+8;
 
2564
                        ByteCount -= 8;
 
2565
                } else
 
2566
                if (!memcmp(szValuePtr, "JIS\0\0\0\0\0", 8)) {
 
2567
                        /* JIS should be tanslated to MB or we leave it to the user - leave it to the user */
 
2568
                        *pszEncoding = estrdup((const char*)szValuePtr);
 
2569
                        szValuePtr = szValuePtr+8;
 
2570
                        ByteCount -= 8;
 
2571
#if EXIF_USE_MBSTRING
 
2572
                        if (ImageInfo->motorola_intel) {
 
2573
                                *pszInfoPtr = php_mb_convert_encoding(szValuePtr, ByteCount, ImageInfo->encode_jis, ImageInfo->decode_jis_be, &len TSRMLS_CC);
 
2574
                        } else {
 
2575
                                *pszInfoPtr = php_mb_convert_encoding(szValuePtr, ByteCount, ImageInfo->encode_jis, ImageInfo->decode_jis_le, &len TSRMLS_CC);
 
2576
                        }
 
2577
                        return len;
 
2578
#else
 
2579
                        return exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount);
 
2580
#endif
 
2581
                } else
 
2582
                if (!memcmp(szValuePtr, "\0\0\0\0\0\0\0\0", 8)) {
 
2583
                        /* 8 NULL means undefined and should be ASCII... */
 
2584
                        *pszEncoding = estrdup("UNDEFINED");
 
2585
                        szValuePtr = szValuePtr+8;
 
2586
                        ByteCount -= 8;
 
2587
                }
 
2588
        }
 
2589
 
 
2590
        /* Olympus has this padded with trailing spaces.  Remove these first. */
 
2591
        if (ByteCount>0) {
 
2592
                for (a=ByteCount-1;a && szValuePtr[a]==' ';a--) {
 
2593
                        (szValuePtr)[a] = '\0';
 
2594
                }
 
2595
        }
 
2596
 
 
2597
        /* normal text without encoding */
 
2598
        exif_process_string(pszInfoPtr, szValuePtr, ByteCount TSRMLS_CC);
 
2599
        return strlen(*pszInfoPtr);
 
2600
}
 
2601
/* }}} */
 
2602
 
 
2603
/* {{{ exif_process_unicode
 
2604
 * Process unicode field in IFD. */
 
2605
static int exif_process_unicode(image_info_type *ImageInfo, xp_field_type *xp_field, int tag, char *szValuePtr, int ByteCount TSRMLS_DC)
 
2606
{
 
2607
        xp_field->tag = tag;    
 
2608
 
 
2609
        /* Copy the comment */
 
2610
#if EXIF_USE_MBSTRING
 
2611
/*  What if MS supports big-endian with XP? */
 
2612
/*      if (ImageInfo->motorola_intel) {
 
2613
                xp_field->value = php_mb_convert_encoding(szValuePtr, ByteCount, ImageInfo->encode_unicode, ImageInfo->decode_unicode_be, &xp_field->size TSRMLS_CC);
 
2614
        } else {
 
2615
                xp_field->value = php_mb_convert_encoding(szValuePtr, ByteCount, ImageInfo->encode_unicode, ImageInfo->decode_unicode_le, &xp_field->size TSRMLS_CC);
 
2616
        }*/
 
2617
        xp_field->value = php_mb_convert_encoding(szValuePtr, ByteCount, ImageInfo->encode_unicode, ImageInfo->decode_unicode_le, &xp_field->size TSRMLS_CC);
 
2618
        return xp_field->size;
 
2619
#else
 
2620
        xp_field->size = exif_process_string_raw(&xp_field->value, szValuePtr, ByteCount);
 
2621
        return xp_field->size;
 
2622
#endif
 
2623
}
 
2624
/* }}} */
 
2625
 
 
2626
/* {{{ exif_process_IFD_in_MAKERNOTE
 
2627
 * Process nested IFDs directories in Maker Note. */
 
2628
static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * value_ptr, int value_len, char *offset_base, size_t IFDlength, size_t displacement TSRMLS_DC)
 
2629
{
 
2630
        int de, i=0, section_index = SECTION_MAKERNOTE;
 
2631
        int NumDirEntries, old_motorola_intel, offset_diff;
 
2632
        const maker_note_type *maker_note;
 
2633
        char *dir_start;
 
2634
 
 
2635
        for (i=0; i<=sizeof(maker_note_array)/sizeof(maker_note_type); i++) {
 
2636
                if (i==sizeof(maker_note_array)/sizeof(maker_note_type))
 
2637
                        return FALSE;
 
2638
                maker_note = maker_note_array+i;
 
2639
                
 
2640
                /*exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "check (%s,%s)", maker_note->make?maker_note->make:"", maker_note->model?maker_note->model:"");*/
 
2641
                if (maker_note->make && (!ImageInfo->make || strcmp(maker_note->make, ImageInfo->make)))
 
2642
                        continue;
 
2643
                if (maker_note->model && (!ImageInfo->model || strcmp(maker_note->model, ImageInfo->model)))
 
2644
                        continue;
 
2645
                if (maker_note->id_string && strncmp(maker_note->id_string, value_ptr, maker_note->id_string_len))
 
2646
                        continue;
 
2647
                break;
 
2648
        }
 
2649
 
 
2650
        dir_start = value_ptr + maker_note->offset;
 
2651
 
 
2652
#ifdef EXIF_DEBUG
 
2653
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process %s @x%04X + 0x%04X=%d: %s", exif_get_sectionname(section_index), (int)dir_start-(int)offset_base+maker_note->offset+displacement, value_len, value_len, exif_char_dump(value_ptr, value_len, (int)dir_start-(int)offset_base+maker_note->offset+displacement));
 
2654
#endif
 
2655
 
 
2656
        ImageInfo->sections_found |= FOUND_MAKERNOTE;
 
2657
 
 
2658
        old_motorola_intel = ImageInfo->motorola_intel;
 
2659
        switch (maker_note->byte_order) {
 
2660
                case MN_ORDER_INTEL:
 
2661
                        ImageInfo->motorola_intel = 0;
 
2662
                        break;
 
2663
                case MN_ORDER_MOTOROLA:
 
2664
                        ImageInfo->motorola_intel = 1;
 
2665
                        break;
 
2666
                default:
 
2667
                case MN_ORDER_NORMAL:
 
2668
                        break;
 
2669
        }
 
2670
 
 
2671
        NumDirEntries = php_ifd_get16u(dir_start, ImageInfo->motorola_intel);
 
2672
 
 
2673
        switch (maker_note->offset_mode) {
 
2674
                case MN_OFFSET_MAKER:
 
2675
                        offset_base = value_ptr;
 
2676
                        break;
 
2677
                case MN_OFFSET_GUESS:
 
2678
                        offset_diff = 2 + NumDirEntries*12 + 4 - php_ifd_get32u(dir_start+10, ImageInfo->motorola_intel);
 
2679
#ifdef EXIF_DEBUG
 
2680
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Using automatic offset correction: 0x%04X", ((int)dir_start-(int)offset_base+maker_note->offset+displacement) + offset_diff);
 
2681
#endif
 
2682
                        offset_base = value_ptr + offset_diff;
 
2683
                        break;
 
2684
                default:
 
2685
                case MN_OFFSET_NORMAL:
 
2686
                        break;
 
2687
        }
 
2688
 
 
2689
        if ((2+NumDirEntries*12) > value_len) {
 
2690
                exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size: 2 + x%04X*12 = x%04X > x%04X", NumDirEntries, 2+NumDirEntries*12, value_len);
 
2691
                return FALSE;
 
2692
        }
 
2693
 
 
2694
        for (de=0;de<NumDirEntries;de++) {
 
2695
                if (!exif_process_IFD_TAG(ImageInfo, dir_start + 2 + 12 * de,
 
2696
                                                                  offset_base, IFDlength, displacement, section_index, 0, maker_note->tag_table TSRMLS_CC)) {
 
2697
                        return FALSE;
 
2698
                }
 
2699
        }
 
2700
        ImageInfo->motorola_intel = old_motorola_intel;
 
2701
/*      NextDirOffset (must be NULL) = php_ifd_get32u(dir_start+2+12*de, ImageInfo->motorola_intel);*/
 
2702
#ifdef EXIF_DEBUG
 
2703
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Subsection %s done", exif_get_sectionname(SECTION_MAKERNOTE));
 
2704
#endif
 
2705
        return TRUE;
 
2706
}
 
2707
/* }}} */
 
2708
 
 
2709
/* {{{ exif_process_IFD_TAG
 
2710
 * Process one of the nested IFDs directories. */
 
2711
static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table TSRMLS_DC)
 
2712
{
 
2713
        size_t length;
 
2714
        int tag, format, components;
 
2715
        char *value_ptr, tagname[64], cbuf[32], *outside=NULL;
 
2716
        size_t byte_count, offset_val, fpos, fgot;
 
2717
        xp_field_type *tmp_xp;
 
2718
 
 
2719
        /* Protect against corrupt headers */
 
2720
        if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
 
2721
                exif_error_docref("exif_read_data#error_ifd" TSRMLS_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum directory nesting level reached");
 
2722
                return FALSE;
 
2723
        }
 
2724
        ImageInfo->ifd_nesting_level++;
 
2725
 
 
2726
        tag = php_ifd_get16u(dir_entry, ImageInfo->motorola_intel);
 
2727
        format = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
 
2728
        components = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel);
 
2729
 
 
2730
        if (!format || format > NUM_FORMATS) {
 
2731
                /* (-1) catches illegal zero case as unsigned underflows to positive large. */
 
2732
                exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal format code 0x%04X, suppose BYTE", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), format);
 
2733
                format = TAG_FMT_BYTE;
 
2734
                /*return TRUE;*/
 
2735
        }
 
2736
 
 
2737
        byte_count = components * php_tiff_bytes_per_format[format];
 
2738
 
 
2739
        if ((ssize_t)byte_count < 0) {
 
2740
                exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), byte_count);
 
2741
                return FALSE;
 
2742
        }
 
2743
 
 
2744
        if (byte_count > 4) {
 
2745
                offset_val = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
 
2746
                /* If its bigger than 4 bytes, the dir entry contains an offset. */
 
2747
                value_ptr = offset_base+offset_val;
 
2748
                if (offset_val+byte_count > IFDlength || value_ptr < dir_entry) {
 
2749
                        /*
 
2750
                        // It is important to check for IMAGE_FILETYPE_TIFF
 
2751
                        // JPEG does not use absolute pointers instead its pointers are relative to the start
 
2752
                        // of the TIFF header in APP1 section.
 
2753
                        */
 
2754
                        if (offset_val+byte_count>ImageInfo->FileSize || (ImageInfo->FileType!=IMAGE_FILETYPE_TIFF_II && ImageInfo->FileType!=IMAGE_FILETYPE_TIFF_MM && ImageInfo->FileType!=IMAGE_FILETYPE_JPEG)) {
 
2755
                                if (value_ptr < dir_entry) {
 
2756
                                        /* we can read this if offset_val > 0 */
 
2757
                                        /* some files have their values in other parts of the file */
 
2758
                                        exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal pointer offset(x%04X < x%04X)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), offset_val, dir_entry);
 
2759
                                } else {
 
2760
                                        /* this is for sure not allowed */
 
2761
                                        /* exception are IFD pointers */
 
2762
                                        exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal pointer offset(x%04X + x%04X = x%04X > x%04X)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), offset_val, byte_count, offset_val+byte_count, IFDlength);
 
2763
                                }
 
2764
                                return TRUE;
 
2765
                        }
 
2766
                        if (byte_count>sizeof(cbuf)) {
 
2767
                                /* mark as outside range and get buffer */
 
2768
                                value_ptr = emalloc(byte_count);
 
2769
                                outside = value_ptr;
 
2770
                        } else {
 
2771
                                /*
 
2772
                                // in most cases we only access a small range so
 
2773
                                // it is faster to use a static buffer there
 
2774
                                // BUT it offers also the possibility to have
 
2775
                                // pointers read without the need to free them
 
2776
                                // explicitley before returning.
 
2777
                                */
 
2778
                                value_ptr = cbuf;
 
2779
                        }
 
2780
 
 
2781
                        fpos = php_stream_tell(ImageInfo->infile);
 
2782
                        php_stream_seek(ImageInfo->infile, offset_val, SEEK_SET);
 
2783
                        fgot = php_stream_tell(ImageInfo->infile);
 
2784
                        if (fgot!=offset_val) {
 
2785
                                EFREE_IF(outside);
 
2786
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Wrong file pointer: 0x%08X != 0x08X", fgot, offset_val);
 
2787
                                return FALSE;
 
2788
                        }
 
2789
                        fgot = php_stream_read(ImageInfo->infile, value_ptr, byte_count);
 
2790
                        php_stream_seek(ImageInfo->infile, fpos, SEEK_SET);
 
2791
                        if (fgot<byte_count) {
 
2792
                                EFREE_IF(outside);
 
2793
                                EXIF_ERRLOG_FILEEOF(ImageInfo)
 
2794
                                return FALSE;
 
2795
                        }
 
2796
                }
 
2797
        } else {
 
2798
                /* 4 bytes or less and value is in the dir entry itself */
 
2799
                value_ptr = dir_entry+8;
 
2800
                offset_val= value_ptr-offset_base;
 
2801
        }
 
2802
 
 
2803
        ImageInfo->sections_found |= FOUND_ANY_TAG;
 
2804
#ifdef EXIF_DEBUG
 
2805
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process tag(x%04X=%s,@x%04X + x%04X(=%d)): %s%s", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), offset_val+displacement, byte_count, byte_count, (components>1)&&format!=TAG_FMT_UNDEFINED&&format!=TAG_FMT_STRING?"ARRAY OF ":"", format==TAG_FMT_STRING?(value_ptr?value_ptr:"<no data>"):exif_get_tagformat(format));
 
2806
#endif
 
2807
        if (section_index==SECTION_THUMBNAIL) {
 
2808
                if (!ImageInfo->Thumbnail.data) {
 
2809
                        switch(tag) {
 
2810
                                case TAG_IMAGEWIDTH:
 
2811
                                case TAG_COMP_IMAGE_WIDTH:
 
2812
                                        ImageInfo->Thumbnail.width = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2813
                                        break;
 
2814
        
 
2815
                                case TAG_IMAGEHEIGHT:
 
2816
                                case TAG_COMP_IMAGE_HEIGHT:
 
2817
                                        ImageInfo->Thumbnail.height = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2818
                                        break;
 
2819
        
 
2820
                                case TAG_STRIP_OFFSETS:
 
2821
                                case TAG_JPEG_INTERCHANGE_FORMAT:
 
2822
                                        /* accept both formats */
 
2823
                                        ImageInfo->Thumbnail.offset = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2824
                                        break;
 
2825
        
 
2826
                                case TAG_STRIP_BYTE_COUNTS:
 
2827
                                        if (ImageInfo->FileType == IMAGE_FILETYPE_TIFF_II || ImageInfo->FileType == IMAGE_FILETYPE_TIFF_MM) {
 
2828
                                                ImageInfo->Thumbnail.filetype = ImageInfo->FileType;
 
2829
                                        } else {
 
2830
                                                /* motorola is easier to read */
 
2831
                                                ImageInfo->Thumbnail.filetype = IMAGE_FILETYPE_TIFF_MM;
 
2832
                                        }
 
2833
                                        ImageInfo->Thumbnail.size = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2834
                                        break;
 
2835
        
 
2836
                                case TAG_JPEG_INTERCHANGE_FORMAT_LEN:
 
2837
                                        if (ImageInfo->Thumbnail.filetype == IMAGE_FILETYPE_UNKNOWN) {
 
2838
                                                ImageInfo->Thumbnail.filetype = IMAGE_FILETYPE_JPEG;
 
2839
                                                ImageInfo->Thumbnail.size = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2840
                                        }
 
2841
                                        break;
 
2842
                        }
 
2843
                }
 
2844
        } else {
 
2845
                if (section_index==SECTION_IFD0 || section_index==SECTION_EXIF)
 
2846
                switch(tag) {
 
2847
                        case TAG_COPYRIGHT:
 
2848
                                /* check for "<photographer> NUL <editor> NUL" */
 
2849
                                if (byte_count>1 && (length=php_strnlen(value_ptr, byte_count)) > 0) {
 
2850
                                        if (length<byte_count-1) {
 
2851
                                                /* When there are any characters after the first NUL */
 
2852
                                                ImageInfo->CopyrightPhotographer  = estrdup(value_ptr);
 
2853
                                                ImageInfo->CopyrightEditor        = estrdup(value_ptr+length+1);
 
2854
                                                spprintf(&ImageInfo->Copyright, 0, "%s, %s", value_ptr, value_ptr+length+1);
 
2855
                                                /* format = TAG_FMT_UNDEFINED; this musn't be ASCII         */
 
2856
                                                /* but we are not supposed to change this                   */
 
2857
                                                /* keep in mind that image_info does not store editor value */
 
2858
                                        } else {
 
2859
                                                ImageInfo->Copyright = estrdup(value_ptr);
 
2860
                                        }
 
2861
                                }
 
2862
                                break;   
 
2863
 
 
2864
                        case TAG_USERCOMMENT:
 
2865
                                ImageInfo->UserCommentLength = exif_process_user_comment(ImageInfo, &(ImageInfo->UserComment), &(ImageInfo->UserCommentEncoding), value_ptr, byte_count TSRMLS_CC);
 
2866
                                break;
 
2867
 
 
2868
                        case TAG_XP_TITLE:
 
2869
                        case TAG_XP_COMMENTS:
 
2870
                        case TAG_XP_AUTHOR:
 
2871
                        case TAG_XP_KEYWORDS:
 
2872
                        case TAG_XP_SUBJECT:
 
2873
                                tmp_xp = (xp_field_type*)erealloc(ImageInfo->xp_fields.list, sizeof(xp_field_type)*(ImageInfo->xp_fields.count+1));
 
2874
                                ImageInfo->sections_found |= FOUND_WINXP;
 
2875
                                ImageInfo->xp_fields.list = tmp_xp;
 
2876
                                ImageInfo->xp_fields.count++;
 
2877
                                exif_process_unicode(ImageInfo, &(ImageInfo->xp_fields.list[ImageInfo->xp_fields.count-1]), tag, value_ptr, byte_count TSRMLS_CC);
 
2878
                                break;
 
2879
 
 
2880
                        case TAG_FNUMBER:
 
2881
                                /* Simplest way of expressing aperture, so I trust it the most.
 
2882
                                   (overwrite previously computed value if there is one) */
 
2883
                                ImageInfo->ApertureFNumber = (float)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2884
                                break;
 
2885
 
 
2886
                        case TAG_APERTURE:
 
2887
                        case TAG_MAX_APERTURE:
 
2888
                                /* More relevant info always comes earlier, so only use this field if we don't
 
2889
                                   have appropriate aperture information yet. */
 
2890
                                if (ImageInfo->ApertureFNumber == 0) {
 
2891
                                        ImageInfo->ApertureFNumber
 
2892
                                                = (float)exp(exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC)*log(2)*0.5);
 
2893
                                }
 
2894
                                break;
 
2895
 
 
2896
                        case TAG_SHUTTERSPEED:
 
2897
                                /* More complicated way of expressing exposure time, so only use
 
2898
                                   this value if we don't already have it from somewhere else.
 
2899
                                   SHUTTERSPEED comes after EXPOSURE TIME
 
2900
                                  */
 
2901
                                if (ImageInfo->ExposureTime == 0) {
 
2902
                                        ImageInfo->ExposureTime
 
2903
                                                = (float)(1/exp(exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC)*log(2)));
 
2904
                                }
 
2905
                                break;
 
2906
                        case TAG_EXPOSURETIME:
 
2907
                                ImageInfo->ExposureTime = -1;
 
2908
                                break;
 
2909
 
 
2910
                        case TAG_COMP_IMAGE_WIDTH:
 
2911
                                ImageInfo->ExifImageWidth = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2912
                                break;
 
2913
 
 
2914
                        case TAG_FOCALPLANE_X_RES:
 
2915
                                ImageInfo->FocalplaneXRes = exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2916
                                break;
 
2917
 
 
2918
                        case TAG_SUBJECT_DISTANCE:
 
2919
                                /* Inidcates the distacne the autofocus camera is focused to.
 
2920
                                   Tends to be less accurate as distance increases. */
 
2921
                                ImageInfo->Distance = (float)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC);
 
2922
                                break;
 
2923
 
 
2924
                        case TAG_FOCALPLANE_RESOLUTION_UNIT:
 
2925
                                switch((int)exif_convert_any_format(value_ptr, format, ImageInfo->motorola_intel TSRMLS_CC)) {
 
2926
                                        case 1: ImageInfo->FocalplaneUnits = 25.4; break; /* inch */
 
2927
                                        case 2:
 
2928
                                                /* According to the information I was using, 2 measn meters.
 
2929
                                                   But looking at the Cannon powershot's files, inches is the only
 
2930
                                                   sensible value. */
 
2931
                                                ImageInfo->FocalplaneUnits = 25.4;
 
2932
                                                break;
 
2933
 
 
2934
                                        case 3: ImageInfo->FocalplaneUnits = 10;   break;  /* centimeter */
 
2935
                                        case 4: ImageInfo->FocalplaneUnits = 1;    break;  /* milimeter  */
 
2936
                                        case 5: ImageInfo->FocalplaneUnits = .001; break;  /* micrometer */
 
2937
                                }
 
2938
                                break;
 
2939
 
 
2940
                        case TAG_SUB_IFD:
 
2941
                                if (format==TAG_FMT_IFD) {
 
2942
                                        /* If this is called we are either in a TIFFs thumbnail or a JPEG where we cannot handle it */
 
2943
                                        /* TIFF thumbnail: our data structure cannot store a thumbnail of a thumbnail */
 
2944
                                        /* JPEG do we have the data area and what to do with it */
 
2945
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Skip SUB IFD");
 
2946
                                }
 
2947
                                break;
 
2948
 
 
2949
                        case TAG_MAKE:
 
2950
                                ImageInfo->make = estrdup(value_ptr);
 
2951
                                break;
 
2952
                        case TAG_MODEL:
 
2953
                                ImageInfo->model = estrdup(value_ptr);
 
2954
                                break;
 
2955
 
 
2956
                        case TAG_MAKER_NOTE:
 
2957
                                exif_process_IFD_in_MAKERNOTE(ImageInfo, value_ptr, byte_count, offset_base, IFDlength, displacement TSRMLS_CC);
 
2958
                                break;
 
2959
 
 
2960
                        case TAG_EXIF_IFD_POINTER:
 
2961
                        case TAG_GPS_IFD_POINTER:
 
2962
                        case TAG_INTEROP_IFD_POINTER:
 
2963
                                if (ReadNextIFD) {
 
2964
                                        char *Subdir_start;
 
2965
                                        int sub_section_index = 0;
 
2966
                                        switch(tag) {
 
2967
                                                case TAG_EXIF_IFD_POINTER:
 
2968
#ifdef EXIF_DEBUG
 
2969
                                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Found EXIF");
 
2970
#endif
 
2971
                                                        ImageInfo->sections_found |= FOUND_EXIF;
 
2972
                                                        sub_section_index = SECTION_EXIF;
 
2973
                                                        break;
 
2974
                                                case TAG_GPS_IFD_POINTER:
 
2975
#ifdef EXIF_DEBUG
 
2976
                                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Found GPS");
 
2977
#endif
 
2978
                                                        ImageInfo->sections_found |= FOUND_GPS;
 
2979
                                                        sub_section_index = SECTION_GPS;
 
2980
                                                        break;
 
2981
                                                case TAG_INTEROP_IFD_POINTER:
 
2982
#ifdef EXIF_DEBUG
 
2983
                                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Found INTEROPERABILITY");
 
2984
#endif
 
2985
                                                        ImageInfo->sections_found |= FOUND_INTEROP;
 
2986
                                                        sub_section_index = SECTION_INTEROP;
 
2987
                                                        break;
 
2988
                                        }
 
2989
                                        Subdir_start = offset_base + php_ifd_get32u(value_ptr, ImageInfo->motorola_intel);
 
2990
                                        if (Subdir_start < offset_base || Subdir_start > offset_base+IFDlength) {
 
2991
                                                exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD Pointer");
 
2992
                                                return FALSE;
 
2993
                                        }
 
2994
                                        exif_process_IFD_in_JPEG(ImageInfo, Subdir_start, offset_base, IFDlength, displacement, sub_section_index TSRMLS_CC);
 
2995
#ifdef EXIF_DEBUG
 
2996
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Subsection %s done", exif_get_sectionname(sub_section_index));
 
2997
#endif
 
2998
                                }
 
2999
                }
 
3000
        }
 
3001
        exif_iif_add_tag(ImageInfo, section_index, exif_get_tagname(tag, tagname, sizeof(tagname), tag_table TSRMLS_CC), tag, format, components, value_ptr TSRMLS_CC);
 
3002
        EFREE_IF(outside);
 
3003
        return TRUE;
 
3004
}
 
3005
/* }}} */
 
3006
 
 
3007
/* {{{ exif_process_IFD_in_JPEG
 
3008
 * Process one of the nested IFDs directories. */
 
3009
static int exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, char *offset_base, size_t IFDlength, size_t displacement, int section_index TSRMLS_DC)
 
3010
{
 
3011
        int de;
 
3012
        int NumDirEntries;
 
3013
        int NextDirOffset;
 
3014
 
 
3015
#ifdef EXIF_DEBUG
 
3016
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process %s (x%04X(=%d))", exif_get_sectionname(section_index), IFDlength, IFDlength);
 
3017
#endif
 
3018
 
 
3019
        ImageInfo->sections_found |= FOUND_IFD0;
 
3020
 
 
3021
        NumDirEntries = php_ifd_get16u(dir_start, ImageInfo->motorola_intel);
 
3022
 
 
3023
        if ((dir_start+2+NumDirEntries*12) > (offset_base+IFDlength)) {
 
3024
                exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size: x%04X + 2 + x%04X*12 = x%04X > x%04X", (int)((size_t)dir_start+2-(size_t)offset_base), NumDirEntries, (int)((size_t)dir_start+2+NumDirEntries*12-(size_t)offset_base), IFDlength);
 
3025
                return FALSE;
 
3026
        }
 
3027
 
 
3028
        for (de=0;de<NumDirEntries;de++) {
 
3029
                if (!exif_process_IFD_TAG(ImageInfo, dir_start + 2 + 12 * de,
 
3030
                                                                  offset_base, IFDlength, displacement, section_index, 1, exif_get_tag_table(section_index) TSRMLS_CC)) {
 
3031
                        return FALSE;
 
3032
                }
 
3033
        }
 
3034
        /*
 
3035
         * Hack to make it process IDF1 I hope
 
3036
         * There are 2 IDFs, the second one holds the keys (0x0201 and 0x0202) to the thumbnail
 
3037
         */
 
3038
        NextDirOffset = php_ifd_get32u(dir_start+2+12*de, ImageInfo->motorola_intel);
 
3039
        if (NextDirOffset) {
 
3040
                /* the next line seems false but here IFDlength means length of all IFDs */
 
3041
                if (offset_base + NextDirOffset < offset_base || offset_base + NextDirOffset > offset_base+IFDlength) {
 
3042
                        exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD offset");
 
3043
                        return FALSE;
 
3044
                }
 
3045
                /* That is the IFD for the first thumbnail */
 
3046
#ifdef EXIF_DEBUG
 
3047
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Expect next IFD to be thumbnail");
 
3048
#endif
 
3049
                if (exif_process_IFD_in_JPEG(ImageInfo, offset_base + NextDirOffset, offset_base, IFDlength, displacement, SECTION_THUMBNAIL TSRMLS_CC)) {
 
3050
#ifdef EXIF_DEBUG
 
3051
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail size: 0x%04X", ImageInfo->Thumbnail.size);
 
3052
#endif
 
3053
                        if (ImageInfo->Thumbnail.filetype != IMAGE_FILETYPE_UNKNOWN
 
3054
                        &&  ImageInfo->Thumbnail.size
 
3055
                        &&  ImageInfo->Thumbnail.offset
 
3056
                        &&  ImageInfo->read_thumbnail
 
3057
                        ) {
 
3058
                                exif_thumbnail_extract(ImageInfo, offset_base, IFDlength TSRMLS_CC);
 
3059
                        }
 
3060
                        return TRUE;
 
3061
                } else {
 
3062
                        return FALSE;
 
3063
                }
 
3064
        }
 
3065
        return TRUE;
 
3066
}
 
3067
/* }}} */
 
3068
 
 
3069
/* {{{ exif_process_TIFF_in_JPEG
 
3070
   Process a TIFF header in a JPEG file
 
3071
*/
 
3072
static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf, size_t length, size_t displacement TSRMLS_DC)
 
3073
{
 
3074
        unsigned exif_value_2a, offset_of_ifd;
 
3075
 
 
3076
        /* set the thumbnail stuff to nothing so we can test to see if they get set up */
 
3077
        if (memcmp(CharBuf, "II", 2) == 0) {
 
3078
                ImageInfo->motorola_intel = 0;
 
3079
        } else if (memcmp(CharBuf, "MM", 2) == 0) {
 
3080
                ImageInfo->motorola_intel = 1;
 
3081
        } else {
 
3082
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF alignment marker");
 
3083
                return;
 
3084
        }
 
3085
 
 
3086
        /* Check the next two values for correctness. */
 
3087
        exif_value_2a = php_ifd_get16u(CharBuf+2, ImageInfo->motorola_intel);
 
3088
        offset_of_ifd = php_ifd_get32u(CharBuf+4, ImageInfo->motorola_intel);
 
3089
        if ( exif_value_2a != 0x2a || offset_of_ifd < 0x08) {
 
3090
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF start (1)");
 
3091
                return;
 
3092
        }
 
3093
 
 
3094
        ImageInfo->sections_found |= FOUND_IFD0;
 
3095
        /* First directory starts at offset 8. Offsets starts at 0. */
 
3096
        exif_process_IFD_in_JPEG(ImageInfo, CharBuf+offset_of_ifd, CharBuf, length/*-14*/, displacement, SECTION_IFD0 TSRMLS_CC);
 
3097
 
 
3098
#ifdef EXIF_DEBUG
 
3099
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process TIFF in JPEG done");
 
3100
#endif
 
3101
 
 
3102
        /* Compute the CCD width, in milimeters. */
 
3103
        if (ImageInfo->FocalplaneXRes != 0) {
 
3104
                ImageInfo->CCDWidth = (float)(ImageInfo->ExifImageWidth * ImageInfo->FocalplaneUnits / ImageInfo->FocalplaneXRes);
 
3105
        }
 
3106
}
 
3107
/* }}} */
 
3108
 
 
3109
/* {{{ exif_process_APP1
 
3110
   Process an JPEG APP1 block marker
 
3111
   Describes all the drivel that most digital cameras include...
 
3112
*/
 
3113
static void exif_process_APP1(image_info_type *ImageInfo, char *CharBuf, size_t length, size_t displacement TSRMLS_DC)
 
3114
{
 
3115
        /* Check the APP1 for Exif Identifier Code */
 
3116
        static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
 
3117
        if (memcmp(CharBuf+2, ExifHeader, 6)) {
 
3118
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Incorrect APP1 Exif Identifier Code");
 
3119
                return;
 
3120
        }
 
3121
        exif_process_TIFF_in_JPEG(ImageInfo, CharBuf + 8, length - 8, displacement+8 TSRMLS_CC);
 
3122
#ifdef EXIF_DEBUG
 
3123
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process APP1/EXIF done");
 
3124
#endif
 
3125
}
 
3126
/* }}} */
 
3127
 
 
3128
/* {{{ exif_process_APP12
 
3129
   Process an JPEG APP12 block marker used by OLYMPUS
 
3130
*/
 
3131
static void exif_process_APP12(image_info_type *ImageInfo, char *buffer, size_t length TSRMLS_DC)
 
3132
{
 
3133
        size_t l1, l2=0;
 
3134
 
 
3135
        if ((l1 = php_strnlen(buffer+2, length-2)) > 0) {
 
3136
                exif_iif_add_tag(ImageInfo, SECTION_APP12, "Company", TAG_NONE, TAG_FMT_STRING, l1, buffer+2 TSRMLS_CC);
 
3137
                if (length > 2+l1+1) {
 
3138
                        l2 = php_strnlen(buffer+2+l1+1, length-2-l1+1);
 
3139
                        exif_iif_add_tag(ImageInfo, SECTION_APP12, "Info", TAG_NONE, TAG_FMT_STRING, l2, buffer+2+l1+1 TSRMLS_CC);
 
3140
                }
 
3141
        }
 
3142
#ifdef EXIF_DEBUG
 
3143
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process section APP12 with l1=%d, l2=%d done", l1, l2);
 
3144
#endif
 
3145
}
 
3146
/* }}} */
 
3147
 
 
3148
/* {{{ exif_scan_JPEG_header
 
3149
 * Parse the marker stream until SOS or EOI is seen; */
 
3150
static int exif_scan_JPEG_header(image_info_type *ImageInfo TSRMLS_DC)
 
3151
{
 
3152
        int section, sn;
 
3153
        int marker = 0, last_marker = M_PSEUDO, comment_correction=1;
 
3154
        unsigned int ll, lh;
 
3155
        uchar *Data;
 
3156
        size_t fpos, size, got, itemlen;
 
3157
        jpeg_sof_info  sof_info;
 
3158
 
 
3159
        for(section=0;;section++) {
 
3160
#ifdef EXIF_DEBUG
 
3161
                fpos = php_stream_tell(ImageInfo->infile);
 
3162
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Needing section %d @ 0x%08X", ImageInfo->file.count, fpos);
 
3163
#endif
 
3164
 
 
3165
                /* get marker byte, swallowing possible padding                           */
 
3166
                /* some software does not count the length bytes of COM section           */
 
3167
                /* one company doing so is very much envolved in JPEG... so we accept too */
 
3168
                if (last_marker==M_COM && comment_correction) {
 
3169
                        comment_correction = 2;
 
3170
                }
 
3171
                do {
 
3172
                        if ((marker = php_stream_getc(ImageInfo->infile)) == EOF) {
 
3173
                                EXIF_ERRLOG_CORRUPT(ImageInfo)
 
3174
                                return FALSE;
 
3175
                        }
 
3176
                        if (last_marker==M_COM && comment_correction>0) {
 
3177
                                if (marker!=0xFF) {
 
3178
                                        marker = 0xff;
 
3179
                                        comment_correction--;
 
3180
                                } else  {
 
3181
                                        last_marker = M_PSEUDO; /* stop skipping 0 for M_COM */
 
3182
                                }
 
3183
                        }
 
3184
                } while (marker == 0xff);
 
3185
                if (last_marker==M_COM && !comment_correction) {
 
3186
                        exif_error_docref("exif_read_data#error_mcom" EXIFERR_CC, ImageInfo, E_NOTICE, "Image has corrupt COM section: some software set wrong length information");
 
3187
                }
 
3188
                if (last_marker==M_COM && comment_correction)
 
3189
                        return M_EOI; /* ah illegal: char after COM section not 0xFF */
 
3190
 
 
3191
                fpos = php_stream_tell(ImageInfo->infile);
 
3192
 
 
3193
                if (marker == 0xff) {
 
3194
                        /* 0xff is legal padding, but if we get that many, something's wrong. */
 
3195
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "To many padding bytes");
 
3196
                        return FALSE;
 
3197
                }
 
3198
 
 
3199
                /* Read the length of the section. */
 
3200
                lh = php_stream_getc(ImageInfo->infile);
 
3201
                ll = php_stream_getc(ImageInfo->infile);
 
3202
 
 
3203
                itemlen = (lh << 8) | ll;
 
3204
 
 
3205
                if (itemlen < 2) {
 
3206
#ifdef EXIF_DEBUG
 
3207
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "%s, Section length: 0x%02X%02X", EXIF_ERROR_CORRUPT, lh, ll);
 
3208
#else
 
3209
                        EXIF_ERRLOG_CORRUPT(ImageInfo)
 
3210
#endif
 
3211
                        return FALSE;
 
3212
                }
 
3213
 
 
3214
                sn = exif_file_sections_add(ImageInfo, marker, itemlen+1, NULL);
 
3215
                Data = ImageInfo->file.list[sn].data;
 
3216
 
 
3217
                /* Store first two pre-read bytes. */
 
3218
                Data[0] = (uchar)lh;
 
3219
                Data[1] = (uchar)ll;
 
3220
 
 
3221
                got = php_stream_read(ImageInfo->infile, (char*)(Data+2), itemlen-2); /* Read the whole section. */
 
3222
                if (got != itemlen-2) {
 
3223
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Error reading from file: got=x%04X(=%d) != itemlen-2=x%04X(=%d)", got, got, itemlen-2, itemlen-2);
 
3224
                        return FALSE;
 
3225
                }
 
3226
 
 
3227
#ifdef EXIF_DEBUG
 
3228
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process section(x%02X=%s) @ x%04X + x%04X(=%d)", marker, exif_get_markername(marker), fpos, itemlen, itemlen);
 
3229
#endif
 
3230
                switch(marker) {
 
3231
                        case M_SOS:   /* stop before hitting compressed data  */
 
3232
                                /* If reading entire image is requested, read the rest of the data. */
 
3233
                                if (ImageInfo->read_all) {
 
3234
                                        /* Determine how much file is left. */
 
3235
                                        fpos = php_stream_tell(ImageInfo->infile);
 
3236
                                        size = ImageInfo->FileSize - fpos;
 
3237
                                        sn = exif_file_sections_add(ImageInfo, M_PSEUDO, size, NULL);
 
3238
                                        Data = ImageInfo->file.list[sn].data;
 
3239
                                        got = php_stream_read(ImageInfo->infile, (char*)Data, size);
 
3240
                                        if (got != size) {
 
3241
                                                EXIF_ERRLOG_FILEEOF(ImageInfo)
 
3242
                                                return FALSE;
 
3243
                                        }
 
3244
                                }
 
3245
                                return TRUE;
 
3246
 
 
3247
                        case M_EOI:   /* in case it's a tables-only JPEG stream */
 
3248
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "No image in jpeg!");
 
3249
                                return (ImageInfo->sections_found&(~FOUND_COMPUTED)) ? TRUE : FALSE;
 
3250
 
 
3251
                        case M_COM: /* Comment section */
 
3252
                                exif_process_COM(ImageInfo, (char *)Data, itemlen TSRMLS_CC);
 
3253
                                break;
 
3254
 
 
3255
                        case M_EXIF:
 
3256
                                if (!(ImageInfo->sections_found&FOUND_IFD0)) {
 
3257
                                        /*ImageInfo->sections_found |= FOUND_EXIF;*/
 
3258
                                        /* Seen files from some 'U-lead' software with Vivitar scanner
 
3259
                                           that uses marker 31 later in the file (no clue what for!) */
 
3260
                                        exif_process_APP1(ImageInfo, (char *)Data, itemlen, fpos TSRMLS_CC);
 
3261
                                }
 
3262
                                break;
 
3263
 
 
3264
                        case M_APP12:
 
3265
                                exif_process_APP12(ImageInfo, (char *)Data, itemlen TSRMLS_CC);
 
3266
                                break;
 
3267
 
 
3268
 
 
3269
                        case M_SOF0:
 
3270
                        case M_SOF1:
 
3271
                        case M_SOF2:
 
3272
                        case M_SOF3:
 
3273
                        case M_SOF5:
 
3274
                        case M_SOF6:
 
3275
                        case M_SOF7:
 
3276
                        case M_SOF9:
 
3277
                        case M_SOF10:
 
3278
                        case M_SOF11:
 
3279
                        case M_SOF13:
 
3280
                        case M_SOF14:
 
3281
                        case M_SOF15:
 
3282
                                exif_process_SOFn(Data, marker, &sof_info);
 
3283
                                ImageInfo->Width  = sof_info.width;
 
3284
                                ImageInfo->Height = sof_info.height;
 
3285
                                if (sof_info.num_components == 3) {
 
3286
                                        ImageInfo->IsColor = 1;
 
3287
                                } else {
 
3288
                                        ImageInfo->IsColor = 0;
 
3289
                                }
 
3290
                                break;
 
3291
                        default:
 
3292
                                /* skip any other marker silently. */
 
3293
                                break;
 
3294
                }
 
3295
 
 
3296
                /* keep track of last marker */
 
3297
                last_marker = marker;
 
3298
        }
 
3299
#ifdef EXIF_DEBUG
 
3300
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Done");
 
3301
#endif
 
3302
        return TRUE;
 
3303
}
 
3304
/* }}} */
 
3305
 
 
3306
/* {{{ exif_scan_thumbnail
 
3307
 * scan JPEG in thumbnail (memory) */
 
3308
static int exif_scan_thumbnail(image_info_type *ImageInfo TSRMLS_DC)
 
3309
{
 
3310
        uchar           c, *data = (uchar*)ImageInfo->Thumbnail.data;
 
3311
        int             n, marker;
 
3312
        size_t          length=2, pos=0;
 
3313
        jpeg_sof_info   sof_info;
 
3314
 
 
3315
        if (!data) {
 
3316
                return FALSE; /* nothing to do here */
 
3317
        }
 
3318
        if (memcmp(data, "\xFF\xD8\xFF", 3)) {
 
3319
                if (!ImageInfo->Thumbnail.width && !ImageInfo->Thumbnail.height) {
 
3320
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Thumbnail is not a JPEG image");
 
3321
                }
 
3322
                return FALSE;
 
3323
        }
 
3324
        for (;;) {
 
3325
                pos += length;
 
3326
                if (pos>=ImageInfo->Thumbnail.size) 
 
3327
                        return FALSE;
 
3328
                c = data[pos++];
 
3329
                if (pos>=ImageInfo->Thumbnail.size) 
 
3330
                        return FALSE;
 
3331
                if (c != 0xFF) {
 
3332
                        return FALSE;
 
3333
                }
 
3334
                n = 8;
 
3335
                while ((c = data[pos++]) == 0xFF && n--) {
 
3336
                        if (pos+3>=ImageInfo->Thumbnail.size) 
 
3337
                                return FALSE;
 
3338
                        /* +3 = pos++ of next check when reaching marker + 2 bytes for length */
 
3339
                }
 
3340
                if (c == 0xFF) 
 
3341
                        return FALSE;
 
3342
                marker = c;
 
3343
                length = php_jpg_get16(data+pos);
 
3344
                if (pos+length>=ImageInfo->Thumbnail.size) {
 
3345
                        return FALSE;
 
3346
                }
 
3347
#ifdef EXIF_DEBUG
 
3348
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: process section(x%02X=%s) @ x%04X + x%04X", marker, exif_get_markername(marker), pos, length);
 
3349
#endif
 
3350
                switch (marker) {
 
3351
                        case M_SOF0:
 
3352
                        case M_SOF1:
 
3353
                        case M_SOF2:
 
3354
                        case M_SOF3:
 
3355
                        case M_SOF5:
 
3356
                        case M_SOF6:
 
3357
                        case M_SOF7:
 
3358
                        case M_SOF9:
 
3359
                        case M_SOF10:
 
3360
                        case M_SOF11:
 
3361
                        case M_SOF13:
 
3362
                        case M_SOF14:
 
3363
                        case M_SOF15:
 
3364
                                /* handle SOFn block */
 
3365
                                exif_process_SOFn(data+pos, marker, &sof_info);
 
3366
                                ImageInfo->Thumbnail.height   = sof_info.height;
 
3367
                                ImageInfo->Thumbnail.width    = sof_info.width;
 
3368
#ifdef EXIF_DEBUG
 
3369
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Thumbnail: size: %d * %d", sof_info.width, sof_info.height);
 
3370
#endif
 
3371
                                return TRUE;
 
3372
 
 
3373
                        case M_SOS:
 
3374
                        case M_EOI:
 
3375
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Could not compute size of thumbnail");
 
3376
                                return FALSE;
 
3377
                                break;
 
3378
 
 
3379
                        default:
 
3380
                                /* just skip */
 
3381
                                break;
 
3382
                }
 
3383
        }
 
3384
 
 
3385
        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Could not compute size of thumbnail");
 
3386
        return FALSE;
 
3387
}
 
3388
/* }}} */
 
3389
 
 
3390
/* {{{ exif_process_IFD_in_TIFF
 
3391
 * Parse the TIFF header; */
 
3392
static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index TSRMLS_DC)
 
3393
{
 
3394
        int i, sn, num_entries, sub_section_index = 0;
 
3395
        unsigned char *dir_entry;
 
3396
        char tagname[64];
 
3397
        size_t ifd_size, dir_size, entry_offset, next_offset, entry_length, entry_value=0, fgot;
 
3398
        int entry_tag , entry_type;
 
3399
        tag_table_type tag_table = exif_get_tag_table(section_index);
 
3400
 
 
3401
        if (ImageInfo->FileSize >= dir_offset+2) {
 
3402
                sn = exif_file_sections_add(ImageInfo, M_PSEUDO, 2, NULL);
 
3403
#ifdef EXIF_DEBUG
 
3404
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF: filesize(x%04X), IFD dir(x%04X + x%04X)", ImageInfo->FileSize, dir_offset, 2);
 
3405
#endif
 
3406
                php_stream_seek(ImageInfo->infile, dir_offset, SEEK_SET); /* we do not know the order of sections */
 
3407
                php_stream_read(ImageInfo->infile, (char*)ImageInfo->file.list[sn].data, 2);
 
3408
                num_entries = php_ifd_get16u(ImageInfo->file.list[sn].data, ImageInfo->motorola_intel);
 
3409
                dir_size = 2/*num dir entries*/ +12/*length of entry*/*num_entries +4/* offset to next ifd (points to thumbnail or NULL)*/;
 
3410
                if (ImageInfo->FileSize >= dir_offset+dir_size) {
 
3411
#ifdef EXIF_DEBUG
 
3412
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF: filesize(x%04X), IFD dir(x%04X + x%04X), IFD entries(%d)", ImageInfo->FileSize, dir_offset+2, dir_size-2, num_entries);
 
3413
#endif
 
3414
                        if (exif_file_sections_realloc(ImageInfo, sn, dir_size TSRMLS_CC)) {
 
3415
                                return FALSE;
 
3416
                        }
 
3417
                        php_stream_read(ImageInfo->infile, (char*)(ImageInfo->file.list[sn].data+2), dir_size-2);
 
3418
                        /*exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Dump: %s", exif_char_dump(ImageInfo->file.list[sn].data, dir_size, 0));*/
 
3419
                        next_offset = php_ifd_get32u(ImageInfo->file.list[sn].data + dir_size - 4, ImageInfo->motorola_intel);
 
3420
#ifdef EXIF_DEBUG
 
3421
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF done, next offset x%04X", next_offset);
 
3422
#endif
 
3423
                        /* now we have the directory we can look how long it should be */
 
3424
                        ifd_size = dir_size;
 
3425
                        for(i=0;i<num_entries;i++) {
 
3426
                                dir_entry        = ImageInfo->file.list[sn].data+2+i*12;
 
3427
                                entry_tag    = php_ifd_get16u(dir_entry+0, ImageInfo->motorola_intel);
 
3428
                                entry_type   = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
 
3429
                                if (entry_type > NUM_FORMATS) {
 
3430
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF: tag(0x%04X,%12s): Illegal format code 0x%04X, switching to BYTE", entry_tag, exif_get_tagname(entry_tag, tagname, -12, tag_table TSRMLS_CC), entry_type);
 
3431
                                        /* Since this is repeated in exif_process_IFD_TAG make it a notice here */
 
3432
                                        /* and make it a warning in the exif_process_IFD_TAG which is called    */
 
3433
                                        /* elsewhere. */
 
3434
                                        entry_type = TAG_FMT_BYTE;
 
3435
                                        /*The next line would break the image on writeback: */
 
3436
                                        /* php_ifd_set16u(dir_entry+2, entry_type, ImageInfo->motorola_intel);*/
 
3437
                                }
 
3438
                                entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel) * php_tiff_bytes_per_format[entry_type];
 
3439
                                if (entry_length <= 4) {
 
3440
                                        switch(entry_type) {
 
3441
                                                case TAG_FMT_USHORT:
 
3442
                                                        entry_value  = php_ifd_get16u(dir_entry+8, ImageInfo->motorola_intel);
 
3443
                                                        break;
 
3444
                                                case TAG_FMT_SSHORT:
 
3445
                                                        entry_value  = php_ifd_get16s(dir_entry+8, ImageInfo->motorola_intel);
 
3446
                                                        break;
 
3447
                                                case TAG_FMT_ULONG:
 
3448
                                                        entry_value  = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
 
3449
                                                        break;
 
3450
                                                case TAG_FMT_SLONG:
 
3451
                                                        entry_value  = php_ifd_get32s(dir_entry+8, ImageInfo->motorola_intel);
 
3452
                                                        break;
 
3453
                                        }
 
3454
                                        switch(entry_tag) {
 
3455
                                                case TAG_IMAGEWIDTH:
 
3456
                                                case TAG_COMP_IMAGE_WIDTH:
 
3457
                                                        ImageInfo->Width  = entry_value;
 
3458
                                                        break;
 
3459
                                                case TAG_IMAGEHEIGHT:
 
3460
                                                case TAG_COMP_IMAGE_HEIGHT:
 
3461
                                                        ImageInfo->Height = entry_value;
 
3462
                                                        break;
 
3463
                                                case TAG_PHOTOMETRIC_INTERPRETATION:
 
3464
                                                        switch (entry_value) {
 
3465
                                                                case PMI_BLACK_IS_ZERO:
 
3466
                                                                case PMI_WHITE_IS_ZERO:
 
3467
                                                                case PMI_TRANSPARENCY_MASK:
 
3468
                                                                        ImageInfo->IsColor = 0;
 
3469
                                                                        break;
 
3470
                                                                case PMI_RGB:
 
3471
                                                                case PMI_PALETTE_COLOR:
 
3472
                                                                case PMI_SEPARATED:
 
3473
                                                                case PMI_YCBCR:
 
3474
                                                                case PMI_CIELAB:
 
3475
                                                                        ImageInfo->IsColor = 1;
 
3476
                                                                        break;
 
3477
                                                        }
 
3478
                                                        break;
 
3479
                                        }
 
3480
                                } else {
 
3481
                                        entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
 
3482
                                        /* if entry needs expading ifd cache and entry is at end of current ifd cache. */
 
3483
                                        /* otherwise there may be huge holes between two entries */
 
3484
                                        if (entry_offset + entry_length > dir_offset + ifd_size
 
3485
                                          && entry_offset == dir_offset + ifd_size) {
 
3486
                                                ifd_size = entry_offset + entry_length - dir_offset;
 
3487
#ifdef EXIF_DEBUG
 
3488
                                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Resize struct: x%04X + x%04X - x%04X = x%04X", entry_offset, entry_length, dir_offset, ifd_size);
 
3489
#endif
 
3490
                                        }
 
3491
                                }
 
3492
                        }
 
3493
                        if (ImageInfo->FileSize >= dir_offset + ImageInfo->file.list[sn].size) {
 
3494
                                if (ifd_size > dir_size) {
 
3495
                                        if (dir_offset + ifd_size > ImageInfo->FileSize) {
 
3496
                                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Error in TIFF: filesize(x%04X) less than size of IFD(x%04X + x%04X)", ImageInfo->FileSize, dir_offset, ifd_size);
 
3497
                                                return FALSE;
 
3498
                                        }
 
3499
                                        if (exif_file_sections_realloc(ImageInfo, sn, ifd_size TSRMLS_CC)) {
 
3500
                                                return FALSE;
 
3501
                                        }
 
3502
                                        /* read values not stored in directory itself */
 
3503
#ifdef EXIF_DEBUG
 
3504
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF: filesize(x%04X), IFD(x%04X + x%04X)", ImageInfo->FileSize, dir_offset, ifd_size);
 
3505
#endif
 
3506
                                        php_stream_read(ImageInfo->infile, (char*)(ImageInfo->file.list[sn].data+dir_size), ifd_size-dir_size);
 
3507
#ifdef EXIF_DEBUG
 
3508
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read from TIFF, done");
 
3509
#endif
 
3510
                                }
 
3511
                                /* now process the tags */
 
3512
                                for(i=0;i<num_entries;i++) {
 
3513
                                        dir_entry        = ImageInfo->file.list[sn].data+2+i*12;
 
3514
                                        entry_tag    = php_ifd_get16u(dir_entry+0, ImageInfo->motorola_intel);
 
3515
                                        entry_type   = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
 
3516
                                        /*entry_length = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel);*/
 
3517
                                        if (entry_tag == TAG_EXIF_IFD_POINTER ||
 
3518
                                                entry_tag == TAG_INTEROP_IFD_POINTER ||
 
3519
                                                entry_tag == TAG_GPS_IFD_POINTER ||
 
3520
                                                entry_tag == TAG_SUB_IFD
 
3521
                                        ) {
 
3522
                                                switch(entry_tag) {
 
3523
                                                        case TAG_EXIF_IFD_POINTER:
 
3524
                                                                ImageInfo->sections_found |= FOUND_EXIF;
 
3525
                                                                sub_section_index = SECTION_EXIF;
 
3526
                                                                break;
 
3527
                                                        case TAG_GPS_IFD_POINTER:
 
3528
                                                                ImageInfo->sections_found |= FOUND_GPS;
 
3529
                                                                sub_section_index = SECTION_GPS;
 
3530
                                                                break;
 
3531
                                                        case TAG_INTEROP_IFD_POINTER:
 
3532
                                                                ImageInfo->sections_found |= FOUND_INTEROP;
 
3533
                                                                sub_section_index = SECTION_INTEROP;
 
3534
                                                                break;
 
3535
                                                        case TAG_SUB_IFD:
 
3536
                                                                ImageInfo->sections_found |= FOUND_THUMBNAIL;
 
3537
                                                                sub_section_index = SECTION_THUMBNAIL;
 
3538
                                                                break;
 
3539
                                                }
 
3540
                                                entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel);
 
3541
#ifdef EXIF_DEBUG
 
3542
                                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @x%04X", exif_get_sectionname(sub_section_index), entry_offset);
 
3543
#endif
 
3544
                                                exif_process_IFD_in_TIFF(ImageInfo, entry_offset, sub_section_index TSRMLS_CC);
 
3545
                                                if (section_index!=SECTION_THUMBNAIL && entry_tag==TAG_SUB_IFD) {
 
3546
                                                        if (ImageInfo->Thumbnail.filetype != IMAGE_FILETYPE_UNKNOWN
 
3547
                                                        &&  ImageInfo->Thumbnail.size
 
3548
                                                        &&  ImageInfo->Thumbnail.offset
 
3549
                                                        &&  ImageInfo->read_thumbnail
 
3550
                                                        ) {
 
3551
#ifdef EXIF_DEBUG
 
3552
                                                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "%s THUMBNAIL @0x%04X + 0x%04X", ImageInfo->Thumbnail.data ? "Ignore" : "Read", ImageInfo->Thumbnail.offset, ImageInfo->Thumbnail.size);
 
3553
#endif
 
3554
                                                                if (!ImageInfo->Thumbnail.data) {
 
3555
                                                                        ImageInfo->Thumbnail.data = emalloc(ImageInfo->Thumbnail.size);
 
3556
                                                                        php_stream_seek(ImageInfo->infile, ImageInfo->Thumbnail.offset, SEEK_SET);
 
3557
                                                                        fgot = php_stream_read(ImageInfo->infile, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size);
 
3558
                                                                        if (fgot < ImageInfo->Thumbnail.size) {
 
3559
                                                                                EXIF_ERRLOG_THUMBEOF(ImageInfo)
 
3560
                                                                        }
 
3561
                                                                        exif_thumbnail_build(ImageInfo TSRMLS_CC);
 
3562
                                                                }
 
3563
                                                        }
 
3564
                                                }
 
3565
#ifdef EXIF_DEBUG
 
3566
                                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s done", exif_get_sectionname(sub_section_index));
 
3567
#endif
 
3568
                                        } else {
 
3569
                                                if (!exif_process_IFD_TAG(ImageInfo, (char*)dir_entry,
 
3570
                                                                                                  (char*)(ImageInfo->file.list[sn].data-dir_offset),
 
3571
                                                                                                  ifd_size, 0, section_index, 0, tag_table TSRMLS_CC)) {
 
3572
                                                        return FALSE;
 
3573
                                                }
 
3574
                                        }
 
3575
                                }
 
3576
                                /* If we had a thumbnail in a SUB_IFD we have ANOTHER image in NEXT IFD */
 
3577
                                if (next_offset && section_index != SECTION_THUMBNAIL) {
 
3578
                                        /* this should be a thumbnail IFD */
 
3579
                                        /* the thumbnail itself is stored at Tag=StripOffsets */
 
3580
#ifdef EXIF_DEBUG
 
3581
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read next IFD (THUMBNAIL) at x%04X", next_offset);
 
3582
#endif
 
3583
                                        exif_process_IFD_in_TIFF(ImageInfo, next_offset, SECTION_THUMBNAIL TSRMLS_CC);
 
3584
#ifdef EXIF_DEBUG
 
3585
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "%s THUMBNAIL @0x%04X + 0x%04X", ImageInfo->Thumbnail.data ? "Ignore" : "Read", ImageInfo->Thumbnail.offset, ImageInfo->Thumbnail.size);
 
3586
#endif
 
3587
                                        if (!ImageInfo->Thumbnail.data && ImageInfo->Thumbnail.offset && ImageInfo->Thumbnail.size && ImageInfo->read_thumbnail) {
 
3588
                                                ImageInfo->Thumbnail.data = emalloc(ImageInfo->Thumbnail.size);
 
3589
                                                php_stream_seek(ImageInfo->infile, ImageInfo->Thumbnail.offset, SEEK_SET);
 
3590
                                                fgot = php_stream_read(ImageInfo->infile, ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size);
 
3591
                                                if (fgot < ImageInfo->Thumbnail.size) {
 
3592
                                                        EXIF_ERRLOG_THUMBEOF(ImageInfo)
 
3593
                                                }
 
3594
                                                exif_thumbnail_build(ImageInfo TSRMLS_CC);
 
3595
                                        }
 
3596
#ifdef EXIF_DEBUG
 
3597
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read next IFD (THUMBNAIL) done");
 
3598
#endif
 
3599
                                }
 
3600
                                return TRUE;
 
3601
                        } else {
 
3602
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Error in TIFF: filesize(x%04X) less than size of IFD(x%04X)", ImageInfo->FileSize, dir_offset+ImageInfo->file.list[sn].size);
 
3603
                                return FALSE;
 
3604
                        }
 
3605
                } else {
 
3606
                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Error in TIFF: filesize(x%04X) less than size of IFD dir(x%04X)", ImageInfo->FileSize, dir_offset+dir_size);
 
3607
                        return FALSE;
 
3608
                }
 
3609
        } else {
 
3610
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Error in TIFF: filesize(x%04X) less than start of IFD dir(x%04X)", ImageInfo->FileSize, dir_offset+2);
 
3611
                return FALSE;
 
3612
        }
 
3613
}
 
3614
/* }}} */
 
3615
 
 
3616
/* {{{ exif_scan_FILE_header
 
3617
 * Parse the marker stream until SOS or EOI is seen; */
 
3618
static int exif_scan_FILE_header(image_info_type *ImageInfo TSRMLS_DC)
 
3619
{
 
3620
        unsigned char file_header[8];
 
3621
        int ret = FALSE;
 
3622
 
 
3623
        ImageInfo->FileType = IMAGE_FILETYPE_UNKNOWN;
 
3624
 
 
3625
        if (ImageInfo->FileSize >= 2) {
 
3626
                php_stream_seek(ImageInfo->infile, 0, SEEK_SET);
 
3627
                php_stream_read(ImageInfo->infile, (char*)file_header, 2);
 
3628
                if ((file_header[0]==0xff) && (file_header[1]==M_SOI)) {
 
3629
                        ImageInfo->FileType = IMAGE_FILETYPE_JPEG;
 
3630
                        if (exif_scan_JPEG_header(ImageInfo TSRMLS_CC)) {
 
3631
                                ret = TRUE;
 
3632
                        } else {
 
3633
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid JPEG file");
 
3634
                        }
 
3635
                } else if (ImageInfo->FileSize >= 8) {
 
3636
                        php_stream_read(ImageInfo->infile, (char*)(file_header+2), 6);
 
3637
                        if (!memcmp(file_header, "II\x2A\x00", 4)) {
 
3638
                                ImageInfo->FileType = IMAGE_FILETYPE_TIFF_II;
 
3639
                                ImageInfo->motorola_intel = 0;
 
3640
#ifdef EXIF_DEBUG
 
3641
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "File has TIFF/II format");
 
3642
#endif
 
3643
                                ImageInfo->sections_found |= FOUND_IFD0;
 
3644
                                if (exif_process_IFD_in_TIFF(ImageInfo, 
 
3645
                                                                                         php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel),
 
3646
                                                                                         SECTION_IFD0 TSRMLS_CC)) {
 
3647
                                        ret = TRUE;
 
3648
                                } else {
 
3649
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file");
 
3650
                                }
 
3651
                        }
 
3652
                        else
 
3653
                        if (!memcmp(file_header, "MM\x00\x2a", 4)) {
 
3654
                                ImageInfo->FileType = IMAGE_FILETYPE_TIFF_MM;
 
3655
                                ImageInfo->motorola_intel = 1;
 
3656
#ifdef EXIF_DEBUG
 
3657
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "File has TIFF/MM format");
 
3658
#endif
 
3659
                                ImageInfo->sections_found |= FOUND_IFD0;
 
3660
                                if (exif_process_IFD_in_TIFF(ImageInfo,
 
3661
                                                                                         php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel),
 
3662
                                                                                         SECTION_IFD0 TSRMLS_CC)) {
 
3663
                                        ret = TRUE;
 
3664
                                } else {
 
3665
                                        exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file");
 
3666
                                }
 
3667
                        } else {
 
3668
                                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "File not supported");
 
3669
                                return FALSE;
 
3670
                        }
 
3671
                }
 
3672
        } else {
 
3673
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "File to small (%d)", ImageInfo->FileSize);
 
3674
        }
 
3675
        return ret;
 
3676
}
 
3677
/* }}} */
 
3678
 
 
3679
/* {{{ exif_discard_imageinfo
 
3680
   Discard data scanned by exif_read_file.
 
3681
*/
 
3682
static int exif_discard_imageinfo(image_info_type *ImageInfo)
 
3683
{
 
3684
        int i;
 
3685
 
 
3686
        EFREE_IF(ImageInfo->FileName);
 
3687
        EFREE_IF(ImageInfo->UserComment);
 
3688
        EFREE_IF(ImageInfo->UserCommentEncoding);
 
3689
        EFREE_IF(ImageInfo->Copyright);
 
3690
        EFREE_IF(ImageInfo->CopyrightPhotographer);
 
3691
        EFREE_IF(ImageInfo->CopyrightEditor);
 
3692
        EFREE_IF(ImageInfo->Thumbnail.data);
 
3693
        EFREE_IF(ImageInfo->encode_unicode);
 
3694
        EFREE_IF(ImageInfo->decode_unicode_be);
 
3695
        EFREE_IF(ImageInfo->decode_unicode_le);
 
3696
        EFREE_IF(ImageInfo->encode_jis);
 
3697
        EFREE_IF(ImageInfo->decode_jis_be);
 
3698
        EFREE_IF(ImageInfo->decode_jis_le);
 
3699
        EFREE_IF(ImageInfo->make);
 
3700
        EFREE_IF(ImageInfo->model);
 
3701
        for (i=0; i<ImageInfo->xp_fields.count; i++) {
 
3702
                EFREE_IF(ImageInfo->xp_fields.list[i].value);
 
3703
        }
 
3704
        EFREE_IF(ImageInfo->xp_fields.list);
 
3705
        for (i=0; i<SECTION_COUNT; i++) {
 
3706
                exif_iif_free(ImageInfo, i);
 
3707
        }
 
3708
        exif_file_sections_free(ImageInfo);
 
3709
        memset(ImageInfo, 0, sizeof(*ImageInfo));
 
3710
        return TRUE;
 
3711
}
 
3712
/* }}} */
 
3713
 
 
3714
/* {{{ exif_read_file
 
3715
 */
 
3716
static int exif_read_file(image_info_type *ImageInfo, char *FileName, int read_thumbnail, int read_all TSRMLS_DC)
 
3717
{
 
3718
        int ret;
 
3719
        struct stat st;
 
3720
 
 
3721
        /* Start with an empty image information structure. */
 
3722
        memset(ImageInfo, 0, sizeof(*ImageInfo));
 
3723
 
 
3724
        ImageInfo->motorola_intel = -1; /* flag as unknown */
 
3725
 
 
3726
        ImageInfo->infile = php_stream_open_wrapper(FileName, "rb", STREAM_MUST_SEEK|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL);
 
3727
        if (!ImageInfo->infile) {
 
3728
                exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Unable to open file");
 
3729
                return FALSE;
 
3730
        }
 
3731
 
 
3732
        php_basename(FileName, strlen(FileName), NULL, 0, &(ImageInfo->FileName), NULL TSRMLS_CC);
 
3733
        ImageInfo->read_thumbnail = read_thumbnail;
 
3734
        ImageInfo->read_all = read_all;
 
3735
        ImageInfo->Thumbnail.filetype = IMAGE_FILETYPE_UNKNOWN;
 
3736
 
 
3737
        ImageInfo->encode_unicode    = safe_estrdup(EXIF_G(encode_unicode));
 
3738
        ImageInfo->decode_unicode_be = safe_estrdup(EXIF_G(decode_unicode_be));
 
3739
        ImageInfo->decode_unicode_le = safe_estrdup(EXIF_G(decode_unicode_le));
 
3740
        ImageInfo->encode_jis        = safe_estrdup(EXIF_G(encode_jis));
 
3741
        ImageInfo->decode_jis_be     = safe_estrdup(EXIF_G(decode_jis_be));
 
3742
        ImageInfo->decode_jis_le     = safe_estrdup(EXIF_G(decode_jis_le));
 
3743
 
 
3744
        if (php_stream_is(ImageInfo->infile, PHP_STREAM_IS_STDIO)) {
 
3745
                if (VCWD_STAT(FileName, &st) >= 0) {
 
3746
                        /* Store file date/time. */
 
3747
#ifdef NETWARE
 
3748
                        ImageInfo->FileDateTime = st.st_mtime.tv_sec;
 
3749
#else
 
3750
                        ImageInfo->FileDateTime = st.st_mtime;
 
3751
#endif
 
3752
                        ImageInfo->FileSize = st.st_size;
 
3753
                        /*exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Opened stream is file: %d", ImageInfo->FileSize);*/
 
3754
                }
 
3755
        } else {
 
3756
                if (!ImageInfo->FileSize) {
 
3757
                        php_stream_seek(ImageInfo->infile, 0, SEEK_END);
 
3758
                        ImageInfo->FileSize = php_stream_tell(ImageInfo->infile);
 
3759
                        php_stream_seek(ImageInfo->infile, 0, SEEK_SET);
 
3760
                }
 
3761
        }
 
3762
 
 
3763
        ImageInfo->ifd_nesting_level = 0;
 
3764
 
 
3765
        /* Scan the JPEG headers. */
 
3766
        ret = exif_scan_FILE_header(ImageInfo TSRMLS_CC);
 
3767
 
 
3768
        php_stream_close(ImageInfo->infile);
 
3769
        return ret;
 
3770
}
 
3771
/* }}} */
 
3772
 
 
3773
/* {{{ proto array exif_read_data(string filename [, sections_needed [, sub_arrays[, read_thumbnail]]])
 
3774
   Reads header data from the JPEG/TIFF image filename and optionally reads the internal thumbnails */
 
3775
PHP_FUNCTION(exif_read_data)
 
3776
{
 
3777
        pval **p_name, **p_sections_needed, **p_sub_arrays, **p_read_thumbnail, **p_read_all;
 
3778
        int i, ac = ZEND_NUM_ARGS(), ret, sections_needed=0, sub_arrays=0, read_thumbnail=0, read_all=0;
 
3779
        image_info_type ImageInfo;
 
3780
        char tmp[64], *sections_str, *s;
 
3781
 
 
3782
        memset(&ImageInfo, 0, sizeof(ImageInfo));
 
3783
 
 
3784
        if ((ac < 1 || ac > 4) || zend_get_parameters_ex(ac, &p_name, &p_sections_needed, &p_sub_arrays, &p_read_thumbnail, &p_read_all) == FAILURE) {
 
3785
                WRONG_PARAM_COUNT;
 
3786
        }
 
3787
 
 
3788
        convert_to_string_ex(p_name);
 
3789
 
 
3790
        if(ac >= 2) {
 
3791
                convert_to_string_ex(p_sections_needed);
 
3792
                sections_str = safe_emalloc(strlen(Z_STRVAL_PP(p_sections_needed)), 1, 3);
 
3793
                sprintf(sections_str, ",%s,", Z_STRVAL_PP(p_sections_needed));
 
3794
                /* sections_str DOES start with , and SPACES are NOT allowed in names */
 
3795
                s = sections_str;
 
3796
                while(*++s) {
 
3797
                        if(*s==' ') {
 
3798
                                *s = ',';
 
3799
                        }
 
3800
                }
 
3801
                for (i=0; i<SECTION_COUNT; i++) {
 
3802
                        snprintf(tmp, sizeof(tmp), ",%s,", exif_get_sectionname(i));
 
3803
                        if (strstr(sections_str, tmp)) {
 
3804
                                sections_needed |= 1<<i;
 
3805
                        }
 
3806
                }
 
3807
                EFREE_IF(sections_str);
 
3808
                /* now see what we need */
 
3809
#ifdef EXIF_DEBUG
 
3810
                sections_str = exif_get_sectionlist(sections_needed TSRMLS_CC);
 
3811
                if (!sections_str) {
 
3812
                        RETURN_FALSE;
 
3813
                }
 
3814
                exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Sections needed: %s", sections_str[0] ? sections_str : "None");
 
3815
                EFREE_IF(sections_str);
 
3816
#endif
 
3817
        }
 
3818
        if(ac >= 3) {
 
3819
                convert_to_long_ex(p_sub_arrays);
 
3820
                sub_arrays = Z_LVAL_PP(p_sub_arrays);
 
3821
        }
 
3822
        if(ac >= 4) {
 
3823
                convert_to_long_ex(p_read_thumbnail);
 
3824
                read_thumbnail = Z_LVAL_PP(p_read_thumbnail);
 
3825
        }
 
3826
        if(ac >= 5) {
 
3827
                convert_to_long_ex(p_read_all);
 
3828
                read_all = Z_LVAL_PP(p_read_all);
 
3829
        }
 
3830
        /* parameters 3,4 will be working in later versions.... */
 
3831
        read_all = 0;       /* just to make function work for 4.2 tree */
 
3832
 
 
3833
        ret = exif_read_file(&ImageInfo, Z_STRVAL_PP(p_name), read_thumbnail, read_all TSRMLS_CC);
 
3834
 
 
3835
        sections_str = exif_get_sectionlist(ImageInfo.sections_found TSRMLS_CC);
 
3836
 
 
3837
#ifdef EXIF_DEBUG
 
3838
        if (sections_str) 
 
3839
                exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Sections found: %s", sections_str[0] ? sections_str : "None");
 
3840
#endif
 
3841
 
 
3842
        ImageInfo.sections_found |= FOUND_COMPUTED|FOUND_FILE;/* do not inform about in debug*/
 
3843
 
 
3844
        if (ret==FALSE || (sections_needed && !(sections_needed&ImageInfo.sections_found))) {
 
3845
                /* array_init must be checked at last! otherwise the array must be freed if a later test fails. */
 
3846
                exif_discard_imageinfo(&ImageInfo);
 
3847
                EFREE_IF(sections_str);
 
3848
                RETURN_FALSE;
 
3849
        }
 
3850
 
 
3851
        array_init(return_value);
 
3852
 
 
3853
#ifdef EXIF_DEBUG
 
3854
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Generate section FILE");
 
3855
#endif
 
3856
 
 
3857
        /* now we can add our information */
 
3858
        exif_iif_add_str(&ImageInfo, SECTION_FILE, "FileName",      ImageInfo.FileName TSRMLS_CC);
 
3859
        exif_iif_add_int(&ImageInfo, SECTION_FILE, "FileDateTime",  ImageInfo.FileDateTime TSRMLS_CC);
 
3860
        exif_iif_add_int(&ImageInfo, SECTION_FILE, "FileSize",      ImageInfo.FileSize TSRMLS_CC);
 
3861
        exif_iif_add_int(&ImageInfo, SECTION_FILE, "FileType",      ImageInfo.FileType TSRMLS_CC);
 
3862
        exif_iif_add_str(&ImageInfo, SECTION_FILE, "MimeType",      (char*)php_image_type_to_mime_type(ImageInfo.FileType) TSRMLS_CC);
 
3863
        exif_iif_add_str(&ImageInfo, SECTION_FILE, "SectionsFound", sections_str ? sections_str : "NONE" TSRMLS_CC);
 
3864
 
 
3865
#ifdef EXIF_DEBUG
 
3866
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Generate section COMPUTED");
 
3867
#endif
 
3868
 
 
3869
        if (ImageInfo.Width>0 &&  ImageInfo.Height>0) {
 
3870
                exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "html"    TSRMLS_CC, "width=\"%d\" height=\"%d\"", ImageInfo.Width, ImageInfo.Height);
 
3871
                exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Height", ImageInfo.Height TSRMLS_CC);
 
3872
                exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Width",  ImageInfo.Width TSRMLS_CC);
 
3873
        }
 
3874
        exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "IsColor", ImageInfo.IsColor TSRMLS_CC);
 
3875
        if (ImageInfo.motorola_intel != -1) {
 
3876
                exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "ByteOrderMotorola", ImageInfo.motorola_intel TSRMLS_CC);
 
3877
        }
 
3878
        if (ImageInfo.FocalLength) {
 
3879
                exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "FocalLength" TSRMLS_CC, "%4.1fmm", ImageInfo.FocalLength);
 
3880
                if(ImageInfo.CCDWidth) {
 
3881
                        exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "35mmFocalLength" TSRMLS_CC, "%dmm", (int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*35+0.5));
 
3882
                }
 
3883
        }
 
3884
        if(ImageInfo.CCDWidth) {
 
3885
                exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "CCDWidth" TSRMLS_CC, "%dmm", (int)ImageInfo.CCDWidth);
 
3886
        }
 
3887
        if(ImageInfo.ExposureTime>0) {
 
3888
                if(ImageInfo.ExposureTime <= 0.5) {
 
3889
                        exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "ExposureTime" TSRMLS_CC, "%0.3f s (1/%d)", ImageInfo.ExposureTime, (int)(0.5 + 1/ImageInfo.ExposureTime));
 
3890
                } else {
 
3891
                        exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "ExposureTime" TSRMLS_CC, "%0.3f s", ImageInfo.ExposureTime);
 
3892
                }
 
3893
        }
 
3894
        if(ImageInfo.ApertureFNumber) {
 
3895
                exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "ApertureFNumber" TSRMLS_CC, "f/%.1f", ImageInfo.ApertureFNumber);
 
3896
        }
 
3897
        if(ImageInfo.Distance) {
 
3898
                if(ImageInfo.Distance<0) {
 
3899
                        exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "FocusDistance", "Infinite" TSRMLS_CC);
 
3900
                } else {
 
3901
                        exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "FocusDistance" TSRMLS_CC, "%0.2fm", ImageInfo.Distance);
 
3902
                }
 
3903
        }
 
3904
        if (ImageInfo.UserComment) {
 
3905
                exif_iif_add_buffer(&ImageInfo, SECTION_COMPUTED, "UserComment", ImageInfo.UserCommentLength, ImageInfo.UserComment TSRMLS_CC);
 
3906
                if (ImageInfo.UserCommentEncoding && strlen(ImageInfo.UserCommentEncoding)) {
 
3907
                        exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "UserCommentEncoding", ImageInfo.UserCommentEncoding TSRMLS_CC);
 
3908
                }
 
3909
        }
 
3910
 
 
3911
        exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Copyright",              ImageInfo.Copyright TSRMLS_CC);
 
3912
        exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Copyright.Photographer", ImageInfo.CopyrightPhotographer TSRMLS_CC);
 
3913
        exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Copyright.Editor",       ImageInfo.CopyrightEditor TSRMLS_CC);
 
3914
 
 
3915
        for (i=0; i<ImageInfo.xp_fields.count; i++) {
 
3916
                exif_iif_add_str(&ImageInfo, SECTION_WINXP, exif_get_tagname(ImageInfo.xp_fields.list[i].tag, NULL, 0, exif_get_tag_table(SECTION_WINXP) TSRMLS_CC), ImageInfo.xp_fields.list[i].value TSRMLS_CC);
 
3917
        }
 
3918
        if (ImageInfo.Thumbnail.size) {
 
3919
                if (read_thumbnail) {
 
3920
                        /* not exif_iif_add_str : this is a buffer */
 
3921
                        exif_iif_add_tag(&ImageInfo, SECTION_THUMBNAIL, "THUMBNAIL", TAG_NONE, TAG_FMT_UNDEFINED, ImageInfo.Thumbnail.size, ImageInfo.Thumbnail.data TSRMLS_CC);
 
3922
                }
 
3923
                if (!ImageInfo.Thumbnail.width || !ImageInfo.Thumbnail.height) {
 
3924
                        /* try to evaluate if thumbnail data is present */
 
3925
                        exif_scan_thumbnail(&ImageInfo TSRMLS_CC);
 
3926
                }
 
3927
                exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Thumbnail.FileType", ImageInfo.Thumbnail.filetype TSRMLS_CC);
 
3928
                exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Thumbnail.MimeType", (char*)php_image_type_to_mime_type(ImageInfo.Thumbnail.filetype) TSRMLS_CC);
 
3929
        }
 
3930
        if (ImageInfo.Thumbnail.width && ImageInfo.Thumbnail.height) {
 
3931
                exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Thumbnail.Height", ImageInfo.Thumbnail.height TSRMLS_CC);
 
3932
                exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Thumbnail.Width",  ImageInfo.Thumbnail.width TSRMLS_CC);
 
3933
        }
 
3934
        EFREE_IF(sections_str);
 
3935
 
 
3936
#ifdef EXIF_DEBUG
 
3937
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Adding image infos");
 
3938
#endif
 
3939
 
 
3940
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_FILE       TSRMLS_CC);
 
3941
        add_assoc_image_info(return_value, 1,          &ImageInfo, SECTION_COMPUTED   TSRMLS_CC);
 
3942
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_ANY_TAG    TSRMLS_CC);
 
3943
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_IFD0       TSRMLS_CC);
 
3944
        add_assoc_image_info(return_value, 1,          &ImageInfo, SECTION_THUMBNAIL  TSRMLS_CC);
 
3945
        add_assoc_image_info(return_value, 1,          &ImageInfo, SECTION_COMMENT    TSRMLS_CC);
 
3946
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_EXIF       TSRMLS_CC);
 
3947
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_GPS        TSRMLS_CC);
 
3948
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_INTEROP    TSRMLS_CC);
 
3949
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_FPIX       TSRMLS_CC);
 
3950
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_APP12      TSRMLS_CC);
 
3951
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_WINXP      TSRMLS_CC);
 
3952
        add_assoc_image_info(return_value, sub_arrays, &ImageInfo, SECTION_MAKERNOTE  TSRMLS_CC);
 
3953
 
 
3954
#ifdef EXIF_DEBUG
 
3955
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Discarding info");
 
3956
#endif
 
3957
 
 
3958
        exif_discard_imageinfo(&ImageInfo);
 
3959
 
 
3960
#ifdef EXIF_DEBUG
 
3961
        php_error_docref1(NULL TSRMLS_CC, Z_STRVAL_PP(p_name), E_NOTICE, "done");
 
3962
#endif
 
3963
}
 
3964
/* }}} */
 
3965
 
 
3966
/* {{{ proto string exif_thumbnail(string filename [, &width, &height [, &imagetype]])
 
3967
   Reads the embedded thumbnail */
 
3968
PHP_FUNCTION(exif_thumbnail)
 
3969
{
 
3970
        zval *p_width, *p_height, *p_imagetype;
 
3971
        char *p_name;
 
3972
        int p_name_len, ret, arg_c = ZEND_NUM_ARGS();
 
3973
        image_info_type ImageInfo;
 
3974
 
 
3975
        memset(&ImageInfo, 0, sizeof(ImageInfo));
 
3976
 
 
3977
        if (arg_c!=1 && arg_c!=3 && arg_c!=4) {
 
3978
                WRONG_PARAM_COUNT;
 
3979
        }
 
3980
 
 
3981
        if (zend_parse_parameters(arg_c TSRMLS_CC, "s|z/z/z/", &p_name, &p_name_len, &p_width, &p_height, &p_imagetype) == FAILURE) {
 
3982
                return;
 
3983
        }
 
3984
 
 
3985
        ret = exif_read_file(&ImageInfo, p_name, 1, 0 TSRMLS_CC);
 
3986
        if (ret==FALSE) {
 
3987
                RETURN_FALSE;
 
3988
        }
 
3989
 
 
3990
#ifdef EXIF_DEBUG
 
3991
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Thumbnail data %d %d %d, %d x %d", ImageInfo.Thumbnail.data, ImageInfo.Thumbnail.size, ImageInfo.Thumbnail.filetype, ImageInfo.Thumbnail.width, ImageInfo.Thumbnail.height);
 
3992
#endif
 
3993
        if (!ImageInfo.Thumbnail.data || !ImageInfo.Thumbnail.size) {
 
3994
                exif_discard_imageinfo(&ImageInfo);
 
3995
                RETURN_FALSE;
 
3996
        }
 
3997
 
 
3998
#ifdef EXIF_DEBUG
 
3999
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Returning thumbnail(%d)", ImageInfo.Thumbnail.size);
 
4000
#endif
 
4001
 
 
4002
        ZVAL_STRINGL(return_value, ImageInfo.Thumbnail.data, ImageInfo.Thumbnail.size, 1);
 
4003
        if (arg_c >= 3) {
 
4004
                if (!ImageInfo.Thumbnail.width || !ImageInfo.Thumbnail.height) {
 
4005
                        exif_scan_thumbnail(&ImageInfo TSRMLS_CC);
 
4006
                }
 
4007
                zval_dtor(p_width);
 
4008
                zval_dtor(p_height);
 
4009
                ZVAL_LONG(p_width,  ImageInfo.Thumbnail.width);
 
4010
                ZVAL_LONG(p_height, ImageInfo.Thumbnail.height);
 
4011
        }
 
4012
        if (arg_c >= 4) {
 
4013
                zval_dtor(p_imagetype);
 
4014
                ZVAL_LONG(p_imagetype, ImageInfo.Thumbnail.filetype);
 
4015
        }
 
4016
 
 
4017
#ifdef EXIF_DEBUG
 
4018
        exif_error_docref(NULL EXIFERR_CC, &ImageInfo, E_NOTICE, "Discarding info");
 
4019
#endif
 
4020
 
 
4021
        exif_discard_imageinfo(&ImageInfo);
 
4022
 
 
4023
#ifdef EXIF_DEBUG
 
4024
        php_error_docref1(NULL TSRMLS_CC, p_name, E_NOTICE, "Done");
 
4025
#endif
 
4026
}
 
4027
/* }}} */
 
4028
 
 
4029
/* {{{ proto int exif_imagetype(string imagefile)
 
4030
   Get the type of an image */
 
4031
PHP_FUNCTION(exif_imagetype)
 
4032
{
 
4033
        zval **arg1;
 
4034
        php_stream * stream;
 
4035
        int itype = 0;
 
4036
 
 
4037
        if (ZEND_NUM_ARGS() != 1)
 
4038
                WRONG_PARAM_COUNT;
 
4039
 
 
4040
        if (zend_get_parameters_ex(1, &arg1) == FAILURE)
 
4041
                WRONG_PARAM_COUNT;
 
4042
 
 
4043
        convert_to_string_ex(arg1);
 
4044
        stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), "rb", IGNORE_PATH|ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
 
4045
 
 
4046
        if (stream == NULL) {
 
4047
                RETURN_FALSE;
 
4048
        }
 
4049
 
 
4050
        itype = php_getimagetype(stream, NULL TSRMLS_CC);
 
4051
 
 
4052
        php_stream_close(stream);
 
4053
 
 
4054
        if (itype == IMAGE_FILETYPE_UNKNOWN) {
 
4055
                RETURN_FALSE;
 
4056
        } else {
 
4057
                ZVAL_LONG(return_value, itype);
 
4058
        }
 
4059
}
 
4060
/* }}} */
 
4061
 
 
4062
#endif
 
4063
 
 
4064
/*
 
4065
 * Local variables:
 
4066
 * tab-width: 4
 
4067
 * c-basic-offset: 4
 
4068
 * End:
 
4069
 * vim600: sw=4 ts=4 tw=78 fdm=marker
 
4070
 * vim<600: sw=4 ts=4 tw=78
 
4071
 */