@@ -1290,6 +1290,18 @@ typedef struct {
12901290 mn_offset_mode_t offset_mode ;
12911291} maker_note_type ;
12921292
1293+ #define FOURCC (id ) (((uint32_t)(id[0])<<24) | (id[1]<<16) | (id[2]<<8) | (id[3]))
1294+
1295+ typedef struct {
1296+ uint64_t size ;
1297+ uint32_t type ;
1298+ } isobmff_box_type ;
1299+
1300+ typedef struct {
1301+ uint32_t offset ;
1302+ uint32_t size ;
1303+ } isobmff_item_pos_type ;
1304+
12931305/* Some maker notes (e.g. DJI info tag) require custom parsing */
12941306#define REQUIRES_CUSTOM_PARSING NULL
12951307
@@ -4279,11 +4291,128 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
42794291 return result ;
42804292}
42814293
4294+ static int exif_isobmff_parse_box (unsigned char * buf , isobmff_box_type * box )
4295+ {
4296+ box -> size = php_ifd_get32u (buf , 1 );
4297+ buf += 4 ;
4298+ box -> type = php_ifd_get32u (buf , 1 );
4299+ if (box -> size != 1 ) {
4300+ return 8 ;
4301+ }
4302+ buf += 4 ;
4303+ box -> size = php_ifd_get64u (buf , 1 );
4304+ return 16 ;
4305+ }
4306+
4307+ static void exif_isobmff_parse_meta (unsigned char * data , unsigned char * end , isobmff_item_pos_type * pos )
4308+ {
4309+ isobmff_box_type box , item ;
4310+ unsigned char * box_offset , * p , * p2 ;
4311+ int header_size , exif_id = -1 , version , item_count , i ;
4312+
4313+ for (box_offset = data + 4 ; box_offset < end ; box_offset += box .size ) {
4314+ header_size = exif_isobmff_parse_box (box_offset , & box );
4315+ if (box .type == FOURCC ("iinf" )) {
4316+ p = box_offset + header_size ;
4317+ version = p [0 ];
4318+ p += 4 ;
4319+ if (version < 2 ) {
4320+ item_count = php_ifd_get16u (p , 1 );
4321+ p += 2 ;
4322+ } else {
4323+ item_count = php_ifd_get32u (p , 1 );
4324+ p += 4 ;
4325+ }
4326+ for (i = 0 ; i < item_count ; i ++ ) {
4327+ header_size = exif_isobmff_parse_box (p , & item );
4328+ if (!memcmp (p + header_size + 8 , "Exif" , 4 )) {
4329+ exif_id = php_ifd_get16u (p + header_size + 4 , 1 );
4330+ break ;
4331+ }
4332+ p += item .size ;
4333+ }
4334+ if (exif_id < 0 ) {
4335+ break ;
4336+ }
4337+ }
4338+ else if (box .type == FOURCC ("iloc" )) {
4339+ p = box_offset + header_size ;
4340+ version = p [0 ];
4341+ p += 6 ;
4342+ if (version < 2 ) {
4343+ item_count = php_ifd_get16u (p , 1 );
4344+ p += 2 ;
4345+ } else {
4346+ item_count = php_ifd_get32u (p , 1 );
4347+ p += 4 ;
4348+ }
4349+ for (i = 0 , p2 = p ; i < item_count ; i ++ , p2 += 16 ) {
4350+ if (php_ifd_get16u (p2 , 1 ) == exif_id ) {
4351+ pos -> offset = php_ifd_get32u (p2 + 8 , 1 );
4352+ pos -> size = php_ifd_get32u (p2 + 12 , 1 );
4353+ break ;
4354+ }
4355+ }
4356+ break ;
4357+ }
4358+ }
4359+ }
4360+
4361+ static bool exif_scan_HEIF_header (image_info_type * ImageInfo , unsigned char * buf )
4362+ {
4363+ isobmff_box_type box ;
4364+ isobmff_item_pos_type pos ;
4365+ unsigned char * data ;
4366+ off_t offset ;
4367+ uint64_t limit ;
4368+ int box_header_size , remain ;
4369+ bool ret = false;
4370+
4371+ pos .size = 0 ;
4372+ for (offset = php_ifd_get32u (buf , 1 ); ImageInfo -> FileSize > offset + 16 ; offset += box .size ) {
4373+ if ((php_stream_seek (ImageInfo -> infile , offset , SEEK_SET ) < 0 ) ||
4374+ (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )buf , 16 ) != 16 )) {
4375+ break ;
4376+ }
4377+ box_header_size = exif_isobmff_parse_box (buf , & box );
4378+ if (box .type == FOURCC ("meta" )) {
4379+ limit = box .size - box_header_size ;
4380+ data = (unsigned char * )emalloc (limit );
4381+ remain = 16 - box_header_size ;
4382+ if (remain ) {
4383+ memcpy (data , buf + box_header_size , remain );
4384+ }
4385+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(data + remain ), limit - remain ) == limit - remain ) {
4386+ exif_isobmff_parse_meta (data , data + limit , & pos );
4387+ }
4388+ if ((pos .size ) &&
4389+ (ImageInfo -> FileSize >= pos .offset + pos .size ) &&
4390+ (php_stream_seek (ImageInfo -> infile , pos .offset + 2 , SEEK_SET ) >= 0 )) {
4391+ if (limit >= pos .size - 2 ) {
4392+ limit = pos .size - 2 ;
4393+ } else {
4394+ limit = pos .size - 2 ;
4395+ efree (data );
4396+ data = (unsigned char * )emalloc (limit );
4397+ }
4398+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )data , limit ) == limit ) {
4399+ exif_process_APP1 (ImageInfo , (char * )data , limit , pos .offset + 2 );
4400+ ret = true;
4401+ }
4402+ }
4403+ efree (data );
4404+ break ;
4405+ }
4406+ }
4407+
4408+ return ret ;
4409+ }
4410+
42824411/* {{{ exif_scan_FILE_header
42834412 * Parse the marker stream until SOS or EOI is seen; */
42844413static bool exif_scan_FILE_header (image_info_type * ImageInfo )
42854414{
4286- unsigned char file_header [8 ];
4415+ unsigned char file_header [16 ];
42874416
42884417 ImageInfo -> FileType = IMAGE_FILETYPE_UNKNOWN ;
42894418
@@ -4344,6 +4473,17 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
43444473 exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid TIFF file ");
43454474 return false;
43464475 }
4476+ } else if ((ImageInfo -> FileSize > 12 ) &&
4477+ (!memcmp (file_header + 4 , "ftyp" , 4 )) &&
4478+ (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(file_header + 8 ), 4 ) == 4 ) &&
4479+ ((!memcmp (file_header + 8 , "heic" , 4 )) || (!memcmp (file_header + 8 , "heix" , 4 )) || (!memcmp (file_header + 8 , "mif1" , 4 )))) {
4480+ if (exif_scan_HEIF_header (ImageInfo , file_header )) {
4481+ ImageInfo -> FileType = IMAGE_FILETYPE_HEIF ;
4482+ return true;
4483+ } else {
4484+ exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid HEIF file ");
4485+ return false;
4486+ }
43474487 } else {
43484488 exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "File not supported ");
43494489 return false;
0 commit comments