@@ -1284,6 +1284,18 @@ typedef struct {
12841284 mn_offset_mode_t offset_mode ;
12851285} maker_note_type ;
12861286
1287+ #define FOURCC (id ) (((uint32_t)(id[0])<<24) | (id[1]<<16) | (id[2]<<8) | (id[3]))
1288+
1289+ typedef struct {
1290+ uint64_t size ;
1291+ uint32_t type ;
1292+ } isobmff_box_type ;
1293+
1294+ typedef struct {
1295+ uint32_t offset ;
1296+ uint32_t size ;
1297+ } isobmff_item_pos_type ;
1298+
12871299/* Some maker notes (e.g. DJI info tag) require custom parsing */
12881300#define REQUIRES_CUSTOM_PARSING NULL
12891301
@@ -4285,11 +4297,125 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
42854297 return result ;
42864298}
42874299
4300+ static int exif_isobmff_parse_box (unsigned char * buf , isobmff_box_type * box )
4301+ {
4302+ box -> size = php_ifd_get32u (buf , 1 );
4303+ buf += 4 ;
4304+ box -> type = php_ifd_get32u (buf , 1 );
4305+ if (box -> size != 1 ) {
4306+ return 8 ;
4307+ }
4308+ buf += 4 ;
4309+ box -> size = php_ifd_get64u (buf , 1 );
4310+ return 16 ;
4311+ }
4312+
4313+ static void exif_isobmff_parse_meta (unsigned char * data , unsigned char * end , isobmff_item_pos_type * pos )
4314+ {
4315+ isobmff_box_type box , item ;
4316+ unsigned char * box_offset , * p , * p2 ;
4317+ int header_size , exif_id = -1 , version , item_count , i ;
4318+
4319+ for (box_offset = data + 4 ; box_offset < end ; box_offset += box .size ) {
4320+ header_size = exif_isobmff_parse_box (box_offset , & box );
4321+ if (box .type == FOURCC ("iinf" )) {
4322+ p = box_offset + header_size ;
4323+ version = p [0 ];
4324+ p += 4 ;
4325+ if (version < 2 ) {
4326+ item_count = php_ifd_get16u (p , 1 );
4327+ p += 2 ;
4328+ } else {
4329+ item_count = php_ifd_get32u (p , 1 );
4330+ p += 4 ;
4331+ }
4332+ for (i = 0 ; i < item_count ; i ++ ) {
4333+ header_size = exif_isobmff_parse_box (p , & item );
4334+ if (!memcmp (p + header_size + 8 , "Exif" , 4 )) {
4335+ exif_id = php_ifd_get16u (p + header_size + 4 , 1 );
4336+ break ;
4337+ }
4338+ p += item .size ;
4339+ }
4340+ if (exif_id < 0 ) {
4341+ break ;
4342+ }
4343+ }
4344+ else if (box .type == FOURCC ("iloc" )) {
4345+ p = box_offset + header_size ;
4346+ version = p [0 ];
4347+ p += 6 ;
4348+ if (version < 2 ) {
4349+ item_count = php_ifd_get16u (p , 1 );
4350+ p += 2 ;
4351+ } else {
4352+ item_count = php_ifd_get32u (p , 1 );
4353+ p += 4 ;
4354+ }
4355+ for (i = 0 , p2 = p ; i < item_count ; i ++ , p2 += 16 ) {
4356+ fflush (stdout );
4357+ if (php_ifd_get16u (p2 , 1 ) == exif_id ) {
4358+ pos -> offset = php_ifd_get32u (p2 + 8 , 1 );
4359+ pos -> size = php_ifd_get32u (p2 + 12 , 1 );
4360+ break ;
4361+ }
4362+ }
4363+ break ;
4364+ }
4365+ }
4366+ }
4367+
4368+ static bool exif_scan_HEIF_header (image_info_type * ImageInfo , unsigned char * buf )
4369+ {
4370+ isobmff_box_type box ;
4371+ isobmff_item_pos_type pos ;
4372+ unsigned char * data ;
4373+ off_t offset ;
4374+ uint64_t limit ;
4375+ int box_header_size , remain ;
4376+ bool ret = false;
4377+
4378+ pos .size = 0 ;
4379+ for (offset = php_ifd_get32u (buf , 1 ); ImageInfo -> FileSize > offset + 16 ; offset += box .size ) {
4380+ if ((php_stream_seek (ImageInfo -> infile , offset , SEEK_SET ) < 0 ) ||
4381+ (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )buf , 16 ) != 16 )) {
4382+ break ;
4383+ }
4384+ box_header_size = exif_isobmff_parse_box (buf , & box );
4385+ if (box .type == FOURCC ("meta" )) {
4386+ limit = box .size - box_header_size ;
4387+ data = (unsigned char * )safe_emalloc (1 , limit , 0 );
4388+ remain = 16 - box_header_size ;
4389+ if (remain ) {
4390+ memcpy (data , buf + box_header_size , remain );
4391+ }
4392+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , data + remain , limit - remain ) == limit - remain ) {
4393+ exif_isobmff_parse_meta (data , data + limit , & pos );
4394+ }
4395+ efree (data );
4396+ if ((pos .size ) &&
4397+ (ImageInfo -> FileSize >= pos .offset + pos .size ) &&
4398+ (php_stream_seek (ImageInfo -> infile , pos .offset + 2 , SEEK_SET ) >= 0 )) {
4399+ limit = pos .size - 2 ;
4400+ data = (unsigned char * )safe_emalloc (1 , limit , 0 );
4401+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , data , limit ) == limit ) {
4402+ exif_process_APP1 (ImageInfo , data , limit , pos .offset + 2 );
4403+ ret = true;
4404+ }
4405+ efree (data );
4406+ }
4407+ break ;
4408+ }
4409+ }
4410+
4411+ return ret ;
4412+ }
4413+
42884414/* {{{ exif_scan_FILE_header
42894415 * Parse the marker stream until SOS or EOI is seen; */
42904416static bool exif_scan_FILE_header (image_info_type * ImageInfo )
42914417{
4292- unsigned char file_header [8 ];
4418+ unsigned char file_header [16 ];
42934419 bool ret = false;
42944420
42954421 ImageInfo -> FileType = IMAGE_FILETYPE_UNKNOWN ;
@@ -4338,6 +4464,16 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
43384464 } else {
43394465 exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid TIFF file ");
43404466 }
4467+ } else if ((ImageInfo -> FileSize > 12 ) &&
4468+ (!memcmp (file_header + 4 , "ftyp" , 4 )) &&
4469+ (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(file_header + 8 ), 4 ) == 4 ) &&
4470+ ((!memcmp (file_header + 8 , "heic" , 4 )) || (!memcmp (file_header + 8 , "heix" , 4 )) || (!memcmp (file_header + 8 , "mif1" , 4 )))) {
4471+ if (exif_scan_HEIF_header (ImageInfo , file_header )) {
4472+ ImageInfo -> FileType = IMAGE_FILETYPE_HEIF ;
4473+ ret = true;
4474+ } else {
4475+ exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid HEIF file ");
4476+ }
43414477 } else {
43424478 exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "File not supported ");
43434479 return false;
0 commit comments