@@ -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,152 @@ 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 + 16 < 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+ if (p >= end ) {
4318+ return ;
4319+ }
4320+ version = p [0 ];
4321+ p += 4 ;
4322+ if (version < 2 ) {
4323+ if (p + 2 >= end ) {
4324+ return ;
4325+ }
4326+ item_count = php_ifd_get16u (p , 1 );
4327+ p += 2 ;
4328+ } else {
4329+ if (p + 4 >= end ) {
4330+ return ;
4331+ }
4332+ item_count = php_ifd_get32u (p , 1 );
4333+ p += 4 ;
4334+ }
4335+ for (i = 0 ; i < item_count && p + 20 < end ; i ++ ) {
4336+ header_size = exif_isobmff_parse_box (p , & item );
4337+ if (p + header_size + 12 >= end ) {
4338+ return ;
4339+ }
4340+ if (!memcmp (p + header_size + 8 , "Exif" , 4 )) {
4341+ exif_id = php_ifd_get16u (p + header_size + 4 , 1 );
4342+ break ;
4343+ }
4344+ p += item .size ;
4345+ }
4346+ if (exif_id < 0 ) {
4347+ break ;
4348+ }
4349+ }
4350+ else if (box .type == FOURCC ("iloc" )) {
4351+ p = box_offset + header_size ;
4352+ if (p >= end ) {
4353+ return ;
4354+ }
4355+ version = p [0 ];
4356+ p += 6 ;
4357+ if (version < 2 ) {
4358+ if (p + 2 >= end ) {
4359+ return ;
4360+ }
4361+ item_count = php_ifd_get16u (p , 1 );
4362+ p += 2 ;
4363+ } else {
4364+ if (p + 4 >= end ) {
4365+ return ;
4366+ }
4367+ item_count = php_ifd_get32u (p , 1 );
4368+ p += 4 ;
4369+ }
4370+ for (i = 0 , p2 = p ; i < item_count && p + 16 < end ; i ++ , p2 += 16 ) {
4371+ if (php_ifd_get16u (p2 , 1 ) == exif_id ) {
4372+ pos -> offset = php_ifd_get32u (p2 + 8 , 1 );
4373+ pos -> size = php_ifd_get32u (p2 + 12 , 1 );
4374+ break ;
4375+ }
4376+ }
4377+ break ;
4378+ }
4379+ }
4380+ }
4381+
4382+ static bool exif_scan_HEIF_header (image_info_type * ImageInfo , unsigned char * buf )
4383+ {
4384+ isobmff_box_type box ;
4385+ isobmff_item_pos_type pos ;
4386+ unsigned char * data ;
4387+ off_t offset ;
4388+ uint64_t limit ;
4389+ int box_header_size , remain ;
4390+ bool ret = false;
4391+
4392+ pos .size = 0 ;
4393+ for (offset = php_ifd_get32u (buf , 1 ); ImageInfo -> FileSize > offset + 16 ; offset += box .size ) {
4394+ if ((php_stream_seek (ImageInfo -> infile , offset , SEEK_SET ) < 0 ) ||
4395+ (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )buf , 16 ) != 16 )) {
4396+ break ;
4397+ }
4398+ box_header_size = exif_isobmff_parse_box (buf , & box );
4399+ if (box .type == FOURCC ("meta" )) {
4400+ limit = box .size - box_header_size ;
4401+ if (limit < 36 ) {
4402+ break ;
4403+ }
4404+ data = (unsigned char * )emalloc (limit );
4405+ remain = 16 - box_header_size ;
4406+ if (remain ) {
4407+ memcpy (data , buf + box_header_size , remain );
4408+ }
4409+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(data + remain ), limit - remain ) == limit - remain ) {
4410+ exif_isobmff_parse_meta (data , data + limit , & pos );
4411+ }
4412+ if ((pos .size ) &&
4413+ (ImageInfo -> FileSize >= pos .offset + pos .size ) &&
4414+ (php_stream_seek (ImageInfo -> infile , pos .offset + 2 , SEEK_SET ) >= 0 )) {
4415+ if (limit >= pos .size - 2 ) {
4416+ limit = pos .size - 2 ;
4417+ } else {
4418+ limit = pos .size - 2 ;
4419+ efree (data );
4420+ data = (unsigned char * )emalloc (limit );
4421+ }
4422+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )data , limit ) == limit ) {
4423+ exif_process_APP1 (ImageInfo , (char * )data , limit , pos .offset + 2 );
4424+ ret = true;
4425+ }
4426+ }
4427+ efree (data );
4428+ break ;
4429+ }
4430+ }
4431+
4432+ return ret ;
4433+ }
4434+
42824435/* {{{ exif_scan_FILE_header
42834436 * Parse the marker stream until SOS or EOI is seen; */
42844437static bool exif_scan_FILE_header (image_info_type * ImageInfo )
42854438{
4286- unsigned char file_header [8 ];
4439+ unsigned char file_header [16 ];
42874440
42884441 ImageInfo -> FileType = IMAGE_FILETYPE_UNKNOWN ;
42894442
@@ -4344,6 +4497,17 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
43444497 exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid TIFF file ");
43454498 return false;
43464499 }
4500+ } else if ((ImageInfo -> FileSize > 12 ) &&
4501+ (!memcmp (file_header + 4 , "ftyp" , 4 )) &&
4502+ (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(file_header + 8 ), 4 ) == 4 ) &&
4503+ ((!memcmp (file_header + 8 , "heic" , 4 )) || (!memcmp (file_header + 8 , "heix" , 4 )) || (!memcmp (file_header + 8 , "mif1" , 4 )))) {
4504+ if (exif_scan_HEIF_header (ImageInfo , file_header )) {
4505+ ImageInfo -> FileType = IMAGE_FILETYPE_HEIF ;
4506+ return true;
4507+ } else {
4508+ exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid HEIF file ");
4509+ return false;
4510+ }
43474511 } else {
43484512 exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "File not supported ");
43494513 return false;
0 commit comments