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

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 3.01 of the PHP license,      |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.php.net/license/3_01.txt                                  |
        !            11:    | If you did not receive a copy of the PHP license and are unable to   |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@php.net so we can mail you a copy immediately.               |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
        !            16:    |          Marcus Boerger <helly@php.net>                              |
        !            17:    +----------------------------------------------------------------------+
        !            18:  */
        !            19: 
        !            20: /* $Id: 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>