@@ -1284,6 +1284,18 @@ typedef struct {
1284
1284
mn_offset_mode_t offset_mode ;
1285
1285
} maker_note_type ;
1286
1286
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
+
1287
1299
/* Some maker notes (e.g. DJI info tag) require custom parsing */
1288
1300
#define REQUIRES_CUSTOM_PARSING NULL
1289
1301
@@ -4285,11 +4297,125 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
4285
4297
return result ;
4286
4298
}
4287
4299
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
+
4288
4414
/* {{{ exif_scan_FILE_header
4289
4415
* Parse the marker stream until SOS or EOI is seen; */
4290
4416
static bool exif_scan_FILE_header (image_info_type * ImageInfo )
4291
4417
{
4292
- unsigned char file_header [8 ];
4418
+ unsigned char file_header [16 ];
4293
4419
bool ret = false;
4294
4420
4295
4421
ImageInfo -> FileType = IMAGE_FILETYPE_UNKNOWN ;
@@ -4338,6 +4464,16 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
4338
4464
} else {
4339
4465
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid TIFF file ");
4340
4466
}
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
+ }
4341
4477
} else {
4342
4478
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "File not supported ");
4343
4479
return false;
0 commit comments