Annotation of embedaddon/php/ext/exif/exif.c, revision 1.1.1.1

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

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