@@ -1290,6 +1290,18 @@ typedef struct {
1290
1290
mn_offset_mode_t offset_mode ;
1291
1291
} maker_note_type ;
1292
1292
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
+
1293
1305
/* Some maker notes (e.g. DJI info tag) require custom parsing */
1294
1306
#define REQUIRES_CUSTOM_PARSING NULL
1295
1307
@@ -4279,11 +4291,128 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
4279
4291
return result ;
4280
4292
}
4281
4293
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
+
4282
4411
/* {{{ exif_scan_FILE_header
4283
4412
* Parse the marker stream until SOS or EOI is seen; */
4284
4413
static bool exif_scan_FILE_header (image_info_type * ImageInfo )
4285
4414
{
4286
- unsigned char file_header [8 ];
4415
+ unsigned char file_header [16 ];
4287
4416
4288
4417
ImageInfo -> FileType = IMAGE_FILETYPE_UNKNOWN ;
4289
4418
@@ -4344,6 +4473,17 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
4344
4473
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid TIFF file ");
4345
4474
return false;
4346
4475
}
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
+ }
4347
4487
} else {
4348
4488
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "File not supported ");
4349
4489
return false;
0 commit comments