heif_extractor.c (48697B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2026 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/heif_extractor.c 22 * @brief plugin to support HEIF/HEIC and AVIF still images 23 * @author Christian Grothoff 24 * 25 * HEIC (the default camera format on recent iPhones) and AVIF (now 26 * common on the web) are both ISO base media file format containers 27 * carrying a still image instead of a movie. We parse the container 28 * only: no HEVC or AV1 bitstream is decoded, and no external decoder 29 * library is linked, because this is a fast identification pass. 30 * 31 * Structure, per ISO/IEC 14496-12 (box structure), ISO/IEC 23008-12 32 * (HEIF item structures) and the AV1 Image File Format (AVIF brands): 33 * 34 * ftyp major brand + compatible brands 35 * meta (FullBox) 36 * hdlr 'pict' for a still image collection 37 * pitm which item is the displayed image 38 * iinf / infe the items and their types 39 * iref thumbnail / auxiliary relationships 40 * iprp 41 * ipco the properties, addressed by 1-based index 42 * ispe pixi irot imir colr av1C hvcC ... 43 * ipma item -> property index associations 44 * mdat the coded data (never read here) 45 * moov only for image sequences (bursts, Live Photos) 46 * 47 * Every box walk below is bounded by the extent of its parent box, never 48 * by the size of the file, and the whole parse shares one box budget and 49 * one byte budget so that a crafted file cannot make us loop or read the 50 * whole volume. There is no recursion: the nesting we care about is 51 * fixed and spelled out as nested calls. 52 */ 53 #include "platform.h" 54 #include "extractor.h" 55 #include "forensics.h" 56 57 58 /** 59 * Total number of boxes we are willing to look at in one file. 60 */ 61 #define HEIF_MAX_BOXES 4096 62 63 /** 64 * Total number of bytes we are willing to read from one file. Header 65 * parsing needs a few kilobytes; anything beyond this is a file trying 66 * to make us do work. 67 */ 68 #define HEIF_READ_BUDGET (256 * 1024) 69 70 /** 71 * Maximum number of compatible brands we report. 72 */ 73 #define HEIF_MAX_BRANDS 32 74 75 /** 76 * Maximum number of property boxes we index out of 'ipco'. 77 */ 78 #define HEIF_MAX_PROPS 64 79 80 /** 81 * Maximum number of properties we follow for the primary item. 82 */ 83 #define HEIF_MAX_ASSOC 32 84 85 /** 86 * Maximum number of 'infe' entries we classify. The reported item 87 * count still comes from the 'iinf' header, so a truncated walk does 88 * not falsify #EXTRACTOR_METATYPE_ENTRY_COUNT. 89 */ 90 #define HEIF_MAX_INFE 512 91 92 /** 93 * Maximum number of item references we follow. 94 */ 95 #define HEIF_MAX_IREF 512 96 97 /** 98 * Largest 'ipma' box we pull into memory. 99 */ 100 #define HEIF_IPMA_MAX 8192 101 102 /** 103 * Seconds between 1904-01-01 (the ISO-BMFF epoch) and 1970-01-01. 104 */ 105 #define HEIF_EPOCH_OFFSET 2082844800LL 106 107 108 /** 109 * One box, as located by #heif_next_box(). 110 */ 111 struct HeifBox 112 { 113 /** 114 * Four character box type. Not NUL terminated. 115 */ 116 unsigned char type[4]; 117 118 /** 119 * Absolute offset of the first payload byte. 120 */ 121 uint64_t payload; 122 123 /** 124 * Absolute offset one past the last payload byte. 125 */ 126 uint64_t end; 127 }; 128 129 130 /** 131 * One entry of the 'ipco' property container, addressed by its 1-based 132 * index from 'ipma'. 133 */ 134 struct HeifProp 135 { 136 /** 137 * Four character property box type. 138 */ 139 unsigned char type[4]; 140 141 /** 142 * Absolute offset of the first payload byte. 143 */ 144 uint64_t payload; 145 146 /** 147 * Absolute offset one past the last payload byte. 148 */ 149 uint64_t end; 150 }; 151 152 153 /** 154 * Everything we carry through the parse. 155 */ 156 struct HeifState 157 { 158 /** 159 * Extraction context we were handed. 160 */ 161 struct EXTRACTOR_ExtractContext *ec; 162 163 /** 164 * Properties found in 'ipco', in file order. 165 */ 166 struct HeifProp props[HEIF_MAX_PROPS]; 167 168 /** 169 * Property indices (1-based) associated with the primary item. 170 */ 171 unsigned int assoc[HEIF_MAX_ASSOC]; 172 173 /** 174 * Bytes we may still read. 175 */ 176 uint64_t budget; 177 178 /** 179 * Boxes we may still visit. 180 */ 181 unsigned int boxes; 182 183 /** 184 * Number of entries used in @e props. 185 */ 186 unsigned int num_props; 187 188 /** 189 * Number of entries used in @e assoc. 190 */ 191 unsigned int num_assoc; 192 193 /** 194 * Item ID of the primary item, from 'pitm'. 195 */ 196 uint32_t primary_item; 197 198 /** 199 * Number of items declared by 'iinf'. 200 */ 201 uint32_t num_items; 202 203 /** 204 * Number of coded image items seen. 205 */ 206 unsigned int num_image_items; 207 208 /** 209 * Number of items that are the source of a 'thmb' reference. 210 */ 211 unsigned int num_thumbnails; 212 213 /** 214 * Number of items that are the source of an 'auxl' reference 215 * (alpha and depth planes). 216 */ 217 unsigned int num_auxiliary; 218 219 /** 220 * Number of 'Exif' items. 221 */ 222 unsigned int num_exif; 223 224 /** 225 * Number of 'mime' (XMP and friends) items. 226 */ 227 unsigned int num_mime; 228 229 /** 230 * Item type of the primary item, if we saw its 'infe'. 231 */ 232 unsigned char primary_type[4]; 233 234 /** 235 * True if @e primary_item is valid. 236 */ 237 int have_pitm; 238 239 /** 240 * True if @e primary_type is valid. 241 */ 242 int have_primary_type; 243 244 /** 245 * True if a 'moov' box was found, which makes this a sequence. 246 */ 247 int have_moov; 248 249 /** 250 * Set once #EXTRACTOR_ExtractContext::proc asked us to stop. 251 */ 252 int stop; 253 }; 254 255 256 /** 257 * Read @a len bytes at @a offset, charged against the read budget. 258 * 259 * @param hs parser state 260 * @param offset absolute offset to read from 261 * @param buf where to put the data 262 * @param len number of bytes to read 263 * @return 1 on success, 0 on a short file or an exhausted budget 264 */ 265 static int 266 heif_read (struct HeifState *hs, 267 uint64_t offset, 268 void *buf, 269 size_t len) 270 { 271 if ( (len > hs->budget) || 272 (offset > INT64_MAX) ) 273 return 0; 274 hs->budget -= len; 275 return EXTRACTOR_forensic_read_ (hs->ec, 276 (int64_t) offset, 277 buf, 278 len); 279 } 280 281 282 /** 283 * Test whether @a box has the given four character type. 284 * 285 * @param box the box 286 * @param type four characters to compare against 287 * @return 1 on a match, 0 otherwise 288 */ 289 static int 290 heif_is (const struct HeifBox *box, 291 const char *type) 292 { 293 return 0 == memcmp (box->type, 294 type, 295 4); 296 } 297 298 299 /** 300 * Locate the box that starts at @a pos inside a parent that ends at 301 * @a limit. 302 * 303 * Handles all three ISO-BMFF size encodings: a 32-bit size, size 1 304 * meaning a 64-bit largesize follows the type, and size 0 meaning "up 305 * to the end of the enclosing box". A size that does not cover its own 306 * header, or that runs past the parent, terminates the walk rather than 307 * being clamped: a box that lies about its size is not one we want to 308 * keep reading past. 309 * 310 * @param hs parser state 311 * @param pos absolute offset of the box header 312 * @param limit absolute offset one past the end of the parent 313 * @param[out] box the box that was found 314 * @return 1 on success, 0 if there is no further box here 315 */ 316 static int 317 heif_next_box (struct HeifState *hs, 318 uint64_t pos, 319 uint64_t limit, 320 struct HeifBox *box) 321 { 322 unsigned char hdr[8]; 323 uint64_t size; 324 unsigned int hlen = 8; 325 326 if (0 == hs->boxes) 327 return 0; 328 hs->boxes--; 329 if ( (pos >= limit) || 330 (limit - pos < 8) ) 331 return 0; 332 if (! heif_read (hs, 333 pos, 334 hdr, 335 sizeof (hdr))) 336 return 0; 337 size = EXTRACTOR_forensic_be32_ (hdr); 338 memcpy (box->type, 339 &hdr[4], 340 4); 341 if (1 == size) 342 { 343 unsigned char large[8]; 344 345 if (limit - pos < 16) 346 return 0; 347 if (! heif_read (hs, 348 pos + 8, 349 large, 350 sizeof (large))) 351 return 0; 352 size = EXTRACTOR_forensic_be64_ (large); 353 hlen = 16; 354 if (size < 16) 355 return 0; 356 } 357 else if (0 == size) 358 { 359 size = limit - pos; /* extends to the end of the parent */ 360 } 361 else if (size < 8) 362 { 363 return 0; /* smaller than its own header */ 364 } 365 if (size > limit - pos) 366 return 0; 367 box->payload = pos + hlen; 368 box->end = pos + size; 369 if (box->payload > box->end) 370 return 0; 371 return 1; 372 } 373 374 375 /** 376 * Number of payload bytes in @a box. 377 * 378 * @param box the box 379 * @return payload length 380 */ 381 static uint64_t 382 heif_payload_len (const struct HeifBox *box) 383 { 384 return box->end - box->payload; 385 } 386 387 388 /** 389 * Read the version byte of a FullBox. 390 * 391 * @param hs parser state 392 * @param box the box, which must be a FullBox 393 * @param[out] version the version byte 394 * @param[out] flags the 24-bit flags field 395 * @return 1 on success, 0 if the box is too short 396 */ 397 static int 398 heif_full_header (struct HeifState *hs, 399 const struct HeifBox *box, 400 unsigned int *version, 401 uint32_t *flags) 402 { 403 unsigned char vf[4]; 404 405 if (heif_payload_len (box) < 4) 406 return 0; 407 if (! heif_read (hs, 408 box->payload, 409 vf, 410 sizeof (vf))) 411 return 0; 412 *version = vf[0]; 413 *flags = EXTRACTOR_forensic_be32_ (vf) & 0xFFFFFF; 414 return 1; 415 } 416 417 418 /** 419 * A brand we recognise, and what it says about the file. 420 */ 421 struct HeifBrand 422 { 423 /** 424 * The four character brand. 425 */ 426 const char *brand; 427 428 /** 429 * MIME type family, without the "-sequence" suffix. 430 */ 431 const char *family; 432 433 /** 434 * Coding format the brand implies, NULL if the brand is generic. 435 */ 436 const char *codec; 437 438 /** 439 * True if the brand denotes an image sequence rather than a still. 440 */ 441 int sequence; 442 }; 443 444 445 /** 446 * Brands that make a file ours. 'mif1'/'msf1' are the generic HEIF 447 * brands and say nothing about the codec, which is why the compatible 448 * brand list has to be consulted as well: "mif1" as major brand with 449 * "avif" among the compatible brands is what several AVIF encoders 450 * produce. 451 */ 452 static const struct HeifBrand heif_brands[] = { 453 { "heic", "image/heic", "HEVC", 0 }, 454 { "heix", "image/heic", "HEVC", 0 }, 455 { "heim", "image/heic", "HEVC", 0 }, 456 { "heis", "image/heic", "HEVC", 0 }, 457 { "hevc", "image/heic", "HEVC", 1 }, 458 { "hevx", "image/heic", "HEVC", 1 }, 459 { "hevm", "image/heic", "HEVC", 1 }, 460 { "hevs", "image/heic", "HEVC", 1 }, 461 { "avif", "image/avif", "AV1", 0 }, 462 { "avis", "image/avif", "AV1", 1 }, 463 { "mif1", "image/heif", NULL, 0 }, 464 { "mif2", "image/heif", NULL, 0 }, 465 { "msf1", "image/heif", NULL, 1 }, 466 { NULL, NULL, NULL, 0 } 467 }; 468 469 470 /** 471 * Look @a brand up in #heif_brands. 472 * 473 * @param brand four bytes from the file 474 * @return the entry, or NULL if we do not know the brand 475 */ 476 static const struct HeifBrand * 477 heif_lookup_brand (const unsigned char *brand) 478 { 479 for (unsigned int i = 0; NULL != heif_brands[i].brand; i++) 480 if (0 == memcmp (brand, 481 heif_brands[i].brand, 482 4)) 483 return &heif_brands[i]; 484 return NULL; 485 } 486 487 488 /** 489 * Human readable name for an item type as it appears in 'infe'. 490 * 491 * @param type four bytes from the file 492 * @return the name, or NULL if we do not know the type 493 */ 494 static const char * 495 heif_item_type_name (const unsigned char *type) 496 { 497 static const struct 498 { 499 const char *type; 500 const char *name; 501 } names[] = { 502 { "hvc1", "HEVC" }, 503 { "hev1", "HEVC" }, 504 { "av01", "AV1" }, 505 { "avc1", "AVC" }, 506 { "vvc1", "VVC" }, 507 { "jpeg", "JPEG" }, 508 { "j2k1", "JPEG 2000" }, 509 { "grid", "tiled grid" }, 510 { "iovl", "overlay" }, 511 { "iden", "identity" }, 512 { "mask", "mask" }, 513 { NULL, NULL } 514 }; 515 516 for (unsigned int i = 0; NULL != names[i].type; i++) 517 if (0 == memcmp (type, 518 names[i].type, 519 4)) 520 return names[i].name; 521 return NULL; 522 } 523 524 525 /** 526 * True if @a type names a coded or derived image item, as opposed to a 527 * metadata item such as 'Exif' or 'mime'. 528 * 529 * @param type four bytes from the file 530 * @return 1 if this is an image item 531 */ 532 static int 533 heif_is_image_item (const unsigned char *type) 534 { 535 return NULL != heif_item_type_name (type); 536 } 537 538 539 /** 540 * Parse the 'pitm' box, which names the item that a viewer displays. 541 * 542 * @param hs parser state 543 * @param box the 'pitm' box 544 */ 545 static void 546 heif_parse_pitm (struct HeifState *hs, 547 const struct HeifBox *box) 548 { 549 unsigned char buf[4]; 550 unsigned int version; 551 uint32_t flags; 552 553 if (! heif_full_header (hs, 554 box, 555 &version, 556 &flags)) 557 return; 558 if (0 == version) 559 { 560 if (heif_payload_len (box) < 6) 561 return; 562 if (! heif_read (hs, 563 box->payload + 4, 564 buf, 565 2)) 566 return; 567 hs->primary_item = EXTRACTOR_forensic_be16_ (buf); 568 } 569 else 570 { 571 if (heif_payload_len (box) < 8) 572 return; 573 if (! heif_read (hs, 574 box->payload + 4, 575 buf, 576 4)) 577 return; 578 hs->primary_item = EXTRACTOR_forensic_be32_ (buf); 579 } 580 hs->have_pitm = 1; 581 } 582 583 584 /** 585 * Parse the 'iinf' box and its 'infe' children: how many items there 586 * are, what kinds they are, and what the primary item is made of. 587 * 588 * @param hs parser state 589 * @param box the 'iinf' box 590 */ 591 static void 592 heif_parse_iinf (struct HeifState *hs, 593 const struct HeifBox *box) 594 { 595 unsigned char buf[16]; 596 unsigned int version; 597 uint32_t flags; 598 uint64_t pos; 599 unsigned int n; 600 601 if (! heif_full_header (hs, 602 box, 603 &version, 604 &flags)) 605 return; 606 if (0 == version) 607 { 608 if (heif_payload_len (box) < 6) 609 return; 610 if (! heif_read (hs, 611 box->payload + 4, 612 buf, 613 2)) 614 return; 615 hs->num_items = EXTRACTOR_forensic_be16_ (buf); 616 pos = box->payload + 6; 617 } 618 else 619 { 620 if (heif_payload_len (box) < 8) 621 return; 622 if (! heif_read (hs, 623 box->payload + 4, 624 buf, 625 4)) 626 return; 627 hs->num_items = EXTRACTOR_forensic_be32_ (buf); 628 pos = box->payload + 8; 629 } 630 n = 0; 631 while ( (pos < box->end) && 632 (n < HEIF_MAX_INFE) ) 633 { 634 struct HeifBox infe; 635 unsigned int iversion; 636 uint32_t item_id; 637 const unsigned char *item_type; 638 size_t need; 639 640 if (! heif_next_box (hs, 641 pos, 642 box->end, 643 &infe)) 644 break; 645 if (infe.end <= pos) 646 break; /* no forward progress */ 647 pos = infe.end; 648 n++; 649 if (! heif_is (&infe, 650 "infe")) 651 continue; 652 /* ItemInfoEntry: version 2 uses a 16-bit item_ID, version 3 and up 653 a 32-bit one; both are followed by a 16-bit protection index and 654 then the four character item_type. Versions 0 and 1 predate 655 item_type and carry a file name instead, which tells us nothing 656 about the coding format. */ 657 need = 14; 658 if (heif_payload_len (&infe) < 4) 659 continue; 660 if (heif_payload_len (&infe) < need) 661 need = (size_t) heif_payload_len (&infe); 662 if (need > sizeof (buf)) 663 need = sizeof (buf); 664 if (! heif_read (hs, 665 infe.payload, 666 buf, 667 need)) 668 continue; 669 iversion = buf[0]; 670 if (2 == iversion) 671 { 672 if (need < 12) 673 continue; 674 item_id = EXTRACTOR_forensic_be16_ (&buf[4]); 675 item_type = &buf[8]; 676 } 677 else if (iversion >= 3) 678 { 679 if (need < 14) 680 continue; 681 item_id = EXTRACTOR_forensic_be32_ (&buf[4]); 682 item_type = &buf[10]; 683 } 684 else 685 { 686 continue; /* no item_type in this version */ 687 } 688 if (heif_is_image_item (item_type)) 689 hs->num_image_items++; 690 else if (0 == memcmp (item_type, 691 "Exif", 692 4)) 693 hs->num_exif++; 694 else if (0 == memcmp (item_type, 695 "mime", 696 4)) 697 hs->num_mime++; 698 if ( (hs->have_pitm) && 699 (item_id == hs->primary_item) ) 700 { 701 memcpy (hs->primary_type, 702 item_type, 703 4); 704 hs->have_primary_type = 1; 705 } 706 } 707 } 708 709 710 /** 711 * Parse the 'iref' box: which items are thumbnails of, or auxiliary 712 * planes for, another item. 713 * 714 * @param hs parser state 715 * @param box the 'iref' box 716 */ 717 static void 718 heif_parse_iref (struct HeifState *hs, 719 const struct HeifBox *box) 720 { 721 unsigned int version; 722 uint32_t flags; 723 uint64_t pos; 724 unsigned int n; 725 726 if (! heif_full_header (hs, 727 box, 728 &version, 729 &flags)) 730 return; 731 pos = box->payload + 4; 732 n = 0; 733 while ( (pos < box->end) && 734 (n < HEIF_MAX_IREF) ) 735 { 736 struct HeifBox ref; 737 738 if (! heif_next_box (hs, 739 pos, 740 box->end, 741 &ref)) 742 break; 743 if (ref.end <= pos) 744 break; /* no forward progress */ 745 pos = ref.end; 746 n++; 747 /* Each child is one reference: its type is the relationship and its 748 from_item_ID is the item that plays the subordinate role. */ 749 if (heif_is (&ref, 750 "thmb")) 751 hs->num_thumbnails++; 752 else if (heif_is (&ref, 753 "auxl")) 754 hs->num_auxiliary++; 755 } 756 } 757 758 759 /** 760 * Parse the 'ipco' box, indexing its children so that 'ipma' can refer 761 * to them by their 1-based position. 762 * 763 * @param hs parser state 764 * @param box the 'ipco' box 765 */ 766 static void 767 heif_parse_ipco (struct HeifState *hs, 768 const struct HeifBox *box) 769 { 770 uint64_t pos = box->payload; 771 772 while ( (pos < box->end) && 773 (hs->num_props < HEIF_MAX_PROPS) ) 774 { 775 struct HeifBox prop; 776 777 if (! heif_next_box (hs, 778 pos, 779 box->end, 780 &prop)) 781 break; 782 if (prop.end <= pos) 783 break; /* no forward progress */ 784 pos = prop.end; 785 memcpy (hs->props[hs->num_props].type, 786 prop.type, 787 4); 788 hs->props[hs->num_props].payload = prop.payload; 789 hs->props[hs->num_props].end = prop.end; 790 hs->num_props++; 791 } 792 } 793 794 795 /** 796 * Parse the 'ipma' box and collect the property indices associated with 797 * the primary item. 798 * 799 * @param hs parser state 800 * @param box the 'ipma' box 801 */ 802 static void 803 heif_parse_ipma (struct HeifState *hs, 804 const struct HeifBox *box) 805 { 806 unsigned char *buf; 807 size_t len; 808 size_t off; 809 unsigned int version; 810 uint32_t flags; 811 uint32_t entries; 812 int wide_index; 813 814 if (! hs->have_pitm) 815 return; 816 if (0 != hs->num_assoc) 817 return; /* a previous 'ipma' already answered the question */ 818 len = (size_t) heif_payload_len (box); 819 if (len < 8) 820 return; 821 if (len > HEIF_IPMA_MAX) 822 len = HEIF_IPMA_MAX; 823 buf = malloc (len); 824 if (NULL == buf) 825 return; 826 if (! heif_read (hs, 827 box->payload, 828 buf, 829 len)) 830 { 831 free (buf); 832 return; 833 } 834 version = buf[0]; 835 flags = EXTRACTOR_forensic_be32_ (buf) & 0xFFFFFF; 836 wide_index = (0 != (flags & 1)); 837 entries = EXTRACTOR_forensic_be32_ (&buf[4]); 838 off = 8; 839 /* The entry count is a 32-bit field out of the file, so it is not a 840 loop bound we can trust; the buffer running out is what actually 841 ends the walk, and `truncated' carries that out of the inner 842 loop without ever incrementing `e' past its own maximum. */ 843 for (uint32_t e = 0; e < entries; e++) 844 { 845 uint32_t item_id; 846 unsigned int count; 847 int mine; 848 int truncated = 0; 849 850 if (version < 1) 851 { 852 if (off + 2 > len) 853 break; 854 item_id = EXTRACTOR_forensic_be16_ (&buf[off]); 855 off += 2; 856 } 857 else 858 { 859 if (off + 4 > len) 860 break; 861 item_id = EXTRACTOR_forensic_be32_ (&buf[off]); 862 off += 4; 863 } 864 if (off >= len) 865 break; 866 count = buf[off]; 867 off++; 868 mine = (item_id == hs->primary_item); 869 for (unsigned int a = 0; a < count; a++) 870 { 871 unsigned int index; 872 873 if (wide_index) 874 { 875 if (off + 2 > len) 876 { 877 truncated = 1; 878 break; 879 } 880 index = EXTRACTOR_forensic_be16_ (&buf[off]) & 0x7FFF; 881 off += 2; 882 } 883 else 884 { 885 if (off + 1 > len) 886 { 887 truncated = 1; 888 break; 889 } 890 index = buf[off] & 0x7F; 891 off++; 892 } 893 if ( (mine) && 894 (0 != index) && 895 (hs->num_assoc < HEIF_MAX_ASSOC) ) 896 hs->assoc[hs->num_assoc++] = index; 897 } 898 if (truncated) 899 break; 900 } 901 free (buf); 902 } 903 904 905 /** 906 * Emit the image dimensions from an 'ispe' property. 907 * 908 * @param hs parser state 909 * @param prop the property 910 */ 911 static void 912 heif_emit_ispe (struct HeifState *hs, 913 const struct HeifProp *prop) 914 { 915 unsigned char buf[12]; 916 917 if (prop->end - prop->payload < 12) 918 return; 919 if (! heif_read (hs, 920 prop->payload, 921 buf, 922 sizeof (buf))) 923 return; 924 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 925 "heif", 926 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS, 927 "%ux%u", 928 (unsigned int) EXTRACTOR_forensic_be32_ ( 929 &buf[4]), 930 (unsigned int) EXTRACTOR_forensic_be32_ ( 931 &buf[8]))) 932 hs->stop = 1; 933 } 934 935 936 /** 937 * Emit the bit depth from a 'pixi' property. A 10-bit still is the 938 * usual signal that the file carries HDR content. 939 * 940 * @param hs parser state 941 * @param prop the property 942 */ 943 static void 944 heif_emit_pixi (struct HeifState *hs, 945 const struct HeifProp *prop) 946 { 947 unsigned char buf[8]; 948 unsigned int channels; 949 uint64_t len = prop->end - prop->payload; 950 951 if (len < 5) 952 return; 953 if (! heif_read (hs, 954 prop->payload, 955 buf, 956 5)) 957 return; 958 channels = buf[4]; 959 if ( (0 == channels) || 960 (channels > 4) || 961 (len < 5 + channels) ) 962 return; 963 if (! heif_read (hs, 964 prop->payload + 5, 965 buf, 966 channels)) 967 return; 968 /* All channels normally share a depth; report the first and say how 969 many planes there are, which distinguishes monochrome from YUV. */ 970 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 971 "heif", 972 EXTRACTOR_METATYPE_COLOR_DEPTH, 973 "%u", 974 (unsigned int) buf[0])) 975 hs->stop = 1; 976 } 977 978 979 /** 980 * Emit the rotation recorded in an 'irot' property. 981 * 982 * @param hs parser state 983 * @param prop the property 984 */ 985 static void 986 heif_emit_irot (struct HeifState *hs, 987 const struct HeifProp *prop) 988 { 989 unsigned char buf[1]; 990 991 if (prop->end - prop->payload < 1) 992 return; 993 if (! heif_read (hs, 994 prop->payload, 995 buf, 996 1)) 997 return; 998 /* The low two bits count anti-clockwise quarter turns to apply when 999 displaying the image. */ 1000 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1001 "heif", 1002 EXTRACTOR_METATYPE_ORIENTATION, 1003 "rotate %u degrees counter-clockwise", 1004 (unsigned int) (buf[0] & 0x03) * 90)) 1005 hs->stop = 1; 1006 } 1007 1008 1009 /** 1010 * Emit the mirroring recorded in an 'imir' property. 1011 * 1012 * @param hs parser state 1013 * @param prop the property 1014 */ 1015 static void 1016 heif_emit_imir (struct HeifState *hs, 1017 const struct HeifProp *prop) 1018 { 1019 unsigned char buf[1]; 1020 1021 if (prop->end - prop->payload < 1) 1022 return; 1023 if (! heif_read (hs, 1024 prop->payload, 1025 buf, 1026 1)) 1027 return; 1028 /* axis == 0 mirrors about a vertical axis, i.e. left and right are 1029 swapped; axis == 1 mirrors about a horizontal axis. */ 1030 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1031 "heif", 1032 EXTRACTOR_METATYPE_ORIENTATION, 1033 "mirrored %s", 1034 (0 == (buf[0] & 0x01)) 1035 ? "horizontally" 1036 : "vertically")) 1037 hs->stop = 1; 1038 } 1039 1040 1041 /** 1042 * Emit the colour information from a 'colr' property. 1043 * 1044 * @param hs parser state 1045 * @param prop the property 1046 */ 1047 static void 1048 heif_emit_colr (struct HeifState *hs, 1049 const struct HeifProp *prop) 1050 { 1051 unsigned char buf[12]; 1052 uint64_t len = prop->end - prop->payload; 1053 1054 if (len < 4) 1055 return; 1056 if (! heif_read (hs, 1057 prop->payload, 1058 buf, 1059 (len < sizeof (buf)) ? (size_t) len : sizeof (buf))) 1060 return; 1061 if (0 == memcmp (buf, 1062 "nclx", 1063 4)) 1064 { 1065 unsigned int primaries; 1066 unsigned int transfer; 1067 unsigned int matrix; 1068 const char *hdr = NULL; 1069 1070 if (len < 11) 1071 return; 1072 primaries = EXTRACTOR_forensic_be16_ (&buf[4]); 1073 transfer = EXTRACTOR_forensic_be16_ (&buf[6]); 1074 matrix = EXTRACTOR_forensic_be16_ (&buf[8]); 1075 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1076 "heif", 1077 EXTRACTOR_METATYPE_COLOR_PROFILE, 1078 "nclx: primaries %u, transfer %u, " 1079 "matrix %u, %s range", 1080 primaries, 1081 transfer, 1082 matrix, 1083 (0 != (buf[10] & 0x80)) 1084 ? "full" 1085 : "limited")) 1086 { 1087 hs->stop = 1; 1088 return; 1089 } 1090 /* Transfer characteristics 16 and 18 are the two HDR curves; they 1091 are worth spelling out because they are what distinguishes an HDR 1092 capture from an ordinary one. */ 1093 if (16 == transfer) 1094 hdr = "HDR: PQ transfer function (SMPTE ST 2084)"; 1095 else if (18 == transfer) 1096 hdr = "HDR: HLG transfer function (ARIB STD-B67)"; 1097 if (NULL != hdr) 1098 { 1099 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1100 "heif", 1101 EXTRACTOR_METATYPE_COMMENT, 1102 "%s", 1103 hdr)) 1104 hs->stop = 1; 1105 } 1106 return; 1107 } 1108 if ( (0 == memcmp (buf, 1109 "prof", 1110 4)) || 1111 (0 == memcmp (buf, 1112 "rICC", 1113 4)) ) 1114 { 1115 /* We deliberately do not parse the ICC payload: exiv2 and the 1116 colour management stack do that far better than we could. */ 1117 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1118 "heif", 1119 EXTRACTOR_METATYPE_COLOR_PROFILE, 1120 "ICC profile (%.4s), %llu bytes", 1121 (const char *) buf, 1122 (unsigned long long) (len - 4))) 1123 hs->stop = 1; 1124 } 1125 } 1126 1127 1128 /** 1129 * Emit what an 'av1C' configuration record says about the bit depth, 1130 * which is the fallback when the file carries no 'pixi'. 1131 * 1132 * @param hs parser state 1133 * @param prop the property 1134 * @param have_pixi true if a 'pixi' property will report the depth 1135 */ 1136 static void 1137 heif_emit_av1c (struct HeifState *hs, 1138 const struct HeifProp *prop, 1139 int have_pixi) 1140 { 1141 unsigned char buf[4]; 1142 unsigned int depth; 1143 1144 if (have_pixi) 1145 return; 1146 if (prop->end - prop->payload < 4) 1147 return; 1148 if (! heif_read (hs, 1149 prop->payload, 1150 buf, 1151 sizeof (buf))) 1152 return; 1153 if (0x81 != buf[0]) 1154 return; /* marker bit plus version 1 */ 1155 /* byte 2: seq_tier_0(1) high_bitdepth(1) twelve_bit(1) monochrome(1) 1156 chroma_subsampling_x(1) chroma_subsampling_y(1) 1157 chroma_sample_position(2) */ 1158 if (0 != (buf[2] & 0x40)) 1159 depth = (0 != (buf[2] & 0x20)) ? 12 : 10; 1160 else 1161 depth = 8; 1162 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1163 "heif", 1164 EXTRACTOR_METATYPE_COLOR_DEPTH, 1165 "%u", 1166 depth)) 1167 hs->stop = 1; 1168 } 1169 1170 1171 /** 1172 * Walk the properties selected for the primary item and emit what they 1173 * say. Only the first property of each kind is reported: a file may 1174 * legally associate several, but the extra ones describe alternative 1175 * renderings rather than the image a user would see. 1176 * 1177 * @param hs parser state 1178 */ 1179 static void 1180 heif_emit_properties (struct HeifState *hs) 1181 { 1182 unsigned int order[HEIF_MAX_PROPS]; 1183 unsigned int n = 0; 1184 int did_ispe = 0; 1185 int did_pixi = 0; 1186 int did_irot = 0; 1187 int did_imir = 0; 1188 int did_colr = 0; 1189 int did_av1c = 0; 1190 int have_pixi = 0; 1191 1192 if (0 != hs->num_assoc) 1193 { 1194 for (unsigned int i = 0; i < hs->num_assoc; i++) 1195 if (hs->assoc[i] <= hs->num_props) 1196 order[n++] = hs->assoc[i] - 1; 1197 } 1198 else 1199 { 1200 /* No usable association: fall back to file order. The first 'ispe' 1201 in 'ipco' belongs to a thumbnail often enough that this is worth 1202 flagging, but it is still better than reporting nothing. */ 1203 for (unsigned int i = 0; i < hs->num_props; i++) 1204 order[n++] = i; 1205 } 1206 /* 'pixi' wins over 'av1C' for the bit depth, so find out whether one 1207 is coming before deciding to use the configuration record. */ 1208 for (unsigned int i = 0; i < n; i++) 1209 if (0 == memcmp (hs->props[order[i]].type, 1210 "pixi", 1211 4)) 1212 have_pixi = 1; 1213 for (unsigned int i = 0; i < n; i++) 1214 { 1215 const struct HeifProp *prop = &hs->props[order[i]]; 1216 1217 if (hs->stop) 1218 return; 1219 if ( (0 == memcmp (prop->type, "ispe", 4)) && 1220 (! did_ispe) ) 1221 { 1222 did_ispe = 1; 1223 heif_emit_ispe (hs, 1224 prop); 1225 } 1226 else if ( (0 == memcmp (prop->type, "pixi", 4)) && 1227 (! did_pixi) ) 1228 { 1229 did_pixi = 1; 1230 heif_emit_pixi (hs, 1231 prop); 1232 } 1233 else if ( (0 == memcmp (prop->type, "irot", 4)) && 1234 (! did_irot) ) 1235 { 1236 did_irot = 1; 1237 heif_emit_irot (hs, 1238 prop); 1239 } 1240 else if ( (0 == memcmp (prop->type, "imir", 4)) && 1241 (! did_imir) ) 1242 { 1243 did_imir = 1; 1244 heif_emit_imir (hs, 1245 prop); 1246 } 1247 else if ( (0 == memcmp (prop->type, "colr", 4)) && 1248 (! did_colr) ) 1249 { 1250 did_colr = 1; 1251 heif_emit_colr (hs, 1252 prop); 1253 } 1254 else if ( (0 == memcmp (prop->type, "av1C", 4)) && 1255 (! did_av1c) ) 1256 { 1257 did_av1c = 1; 1258 heif_emit_av1c (hs, 1259 prop, 1260 have_pixi); 1261 } 1262 } 1263 } 1264 1265 1266 /** 1267 * Parse the 'iprp' box: the property container and the associations. 1268 * 1269 * @param hs parser state 1270 * @param box the 'iprp' box 1271 */ 1272 static void 1273 heif_parse_iprp (struct HeifState *hs, 1274 const struct HeifBox *box) 1275 { 1276 uint64_t pos = box->payload; 1277 1278 /* 'ipco' always precedes 'ipma' in practice, but do not rely on it: 1279 index the container first in one pass, then read the associations. */ 1280 while (pos < box->end) 1281 { 1282 struct HeifBox child; 1283 1284 if (! heif_next_box (hs, 1285 pos, 1286 box->end, 1287 &child)) 1288 break; 1289 if (child.end <= pos) 1290 break; /* no forward progress */ 1291 pos = child.end; 1292 if (heif_is (&child, 1293 "ipco")) 1294 heif_parse_ipco (hs, 1295 &child); 1296 } 1297 pos = box->payload; 1298 while (pos < box->end) 1299 { 1300 struct HeifBox child; 1301 1302 if (! heif_next_box (hs, 1303 pos, 1304 box->end, 1305 &child)) 1306 break; 1307 if (child.end <= pos) 1308 break; 1309 pos = child.end; 1310 if (heif_is (&child, 1311 "ipma")) 1312 heif_parse_ipma (hs, 1313 &child); 1314 } 1315 } 1316 1317 1318 /** 1319 * Find where the children of a 'meta' box start. 1320 * 1321 * In ISO/IEC 14496-12 'meta' is a FullBox, so its children begin four 1322 * bytes into the payload. QuickTime writes the same box without the 1323 * version and flags word, and such files do turn up; probe for a 1324 * plausible child box at both offsets rather than guessing. 1325 * 1326 * @param hs parser state 1327 * @param box the 'meta' box 1328 * @param[out] start where the children begin 1329 * @return 1 if a starting offset was found 1330 */ 1331 static int 1332 heif_meta_children (struct HeifState *hs, 1333 const struct HeifBox *box, 1334 uint64_t *start) 1335 { 1336 struct HeifBox probe; 1337 1338 if ( (heif_payload_len (box) > 4) && 1339 (heif_next_box (hs, 1340 box->payload + 4, 1341 box->end, 1342 &probe)) ) 1343 { 1344 *start = box->payload + 4; 1345 return 1; 1346 } 1347 if (heif_next_box (hs, 1348 box->payload, 1349 box->end, 1350 &probe)) 1351 { 1352 *start = box->payload; 1353 return 1; 1354 } 1355 return 0; 1356 } 1357 1358 1359 /** 1360 * Parse the 'meta' box: the items, their properties and their 1361 * relationships. 1362 * 1363 * @param hs parser state 1364 * @param box the 'meta' box 1365 * @param brand_codec coding format implied by the brand, may be NULL 1366 */ 1367 static void 1368 heif_parse_meta (struct HeifState *hs, 1369 const struct HeifBox *box, 1370 const char *brand_codec) 1371 { 1372 struct HeifBox pitm; 1373 struct HeifBox iinf; 1374 struct HeifBox iref; 1375 struct HeifBox iprp; 1376 int have_pitm_box = 0; 1377 int have_iinf = 0; 1378 int have_iref = 0; 1379 int have_iprp = 0; 1380 uint64_t pos; 1381 1382 memset (&pitm, 0, sizeof (pitm)); 1383 memset (&iinf, 0, sizeof (iinf)); 1384 memset (&iref, 0, sizeof (iref)); 1385 memset (&iprp, 0, sizeof (iprp)); 1386 if (! heif_meta_children (hs, 1387 box, 1388 &pos)) 1389 return; 1390 while (pos < box->end) 1391 { 1392 struct HeifBox child; 1393 1394 if (! heif_next_box (hs, 1395 pos, 1396 box->end, 1397 &child)) 1398 break; 1399 if (child.end <= pos) 1400 break; /* no forward progress */ 1401 pos = child.end; 1402 if ( (heif_is (&child, "pitm")) && 1403 (! have_pitm_box) ) 1404 { 1405 pitm = child; 1406 have_pitm_box = 1; 1407 } 1408 else if ( (heif_is (&child, "iinf")) && 1409 (! have_iinf) ) 1410 { 1411 iinf = child; 1412 have_iinf = 1; 1413 } 1414 else if ( (heif_is (&child, "iref")) && 1415 (! have_iref) ) 1416 { 1417 iref = child; 1418 have_iref = 1; 1419 } 1420 else if ( (heif_is (&child, "iprp")) && 1421 (! have_iprp) ) 1422 { 1423 iprp = child; 1424 have_iprp = 1; 1425 } 1426 } 1427 /* The order below is ours, not the file's: the primary item ID has to 1428 be known before 'iinf' and 'ipma' can be interpreted. */ 1429 if (have_pitm_box) 1430 heif_parse_pitm (hs, 1431 &pitm); 1432 if (have_iinf) 1433 heif_parse_iinf (hs, 1434 &iinf); 1435 if (have_iref) 1436 heif_parse_iref (hs, 1437 &iref); 1438 1439 /* CODEC: the item type of the primary item is more specific than the 1440 brand, so prefer it and fall back to the brand. */ 1441 if (hs->have_primary_type) 1442 { 1443 const char *name = heif_item_type_name (hs->primary_type); 1444 1445 if (NULL != name) 1446 { 1447 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1448 "heif", 1449 EXTRACTOR_METATYPE_CODEC, 1450 "%s (%.4s)", 1451 name, 1452 (const char *) hs->primary_type)) 1453 { 1454 hs->stop = 1; 1455 return; 1456 } 1457 if ( (0 == memcmp (hs->primary_type, "grid", 4)) || 1458 (0 == memcmp (hs->primary_type, "iovl", 4)) || 1459 (0 == memcmp (hs->primary_type, "iden", 4)) ) 1460 { 1461 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1462 "heif", 1463 EXTRACTOR_METATYPE_RESOURCE_TYPE, 1464 "derived image (%.4s)", 1465 (const char *) hs->primary_type)) 1466 { 1467 hs->stop = 1; 1468 return; 1469 } 1470 } 1471 } 1472 } 1473 else if (NULL != brand_codec) 1474 { 1475 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1476 "heif", 1477 EXTRACTOR_METATYPE_CODEC, 1478 "%s", 1479 brand_codec)) 1480 { 1481 hs->stop = 1; 1482 return; 1483 } 1484 } 1485 1486 if (have_iprp) 1487 { 1488 heif_parse_iprp (hs, 1489 &iprp); 1490 heif_emit_properties (hs); 1491 if (hs->stop) 1492 return; 1493 } 1494 1495 if (0 != hs->num_items) 1496 { 1497 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1498 "heif", 1499 EXTRACTOR_METATYPE_ENTRY_COUNT, 1500 "%u", 1501 (unsigned int) hs->num_items)) 1502 { 1503 hs->stop = 1; 1504 return; 1505 } 1506 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1507 "heif", 1508 EXTRACTOR_METATYPE_COMMENT, 1509 "%u image item%s, %u thumbnail%s, " 1510 "%u auxiliary, %u metadata item%s", 1511 hs->num_image_items, 1512 (1 == hs->num_image_items) ? "" : "s", 1513 hs->num_thumbnails, 1514 (1 == hs->num_thumbnails) ? "" : "s", 1515 hs->num_auxiliary, 1516 hs->num_exif + hs->num_mime, 1517 (1 == hs->num_exif + hs->num_mime) 1518 ? "" : "s")) 1519 { 1520 hs->stop = 1; 1521 return; 1522 } 1523 } 1524 /* We do not touch the payload of these items: parsing EXIF and XMP is 1525 the exiv2 plugin's job. Saying that they are there is what lets a 1526 downstream tool decide to run it. */ 1527 if (0 != hs->num_exif) 1528 { 1529 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1530 "heif", 1531 EXTRACTOR_METATYPE_COMMENT, 1532 "contains an Exif metadata item")) 1533 { 1534 hs->stop = 1; 1535 return; 1536 } 1537 } 1538 if (0 != hs->num_mime) 1539 { 1540 if (0 != EXTRACTOR_forensic_emit_ (hs->ec, 1541 "heif", 1542 EXTRACTOR_METATYPE_COMMENT, 1543 "contains an XMP or MIME metadata item")) 1544 { 1545 hs->stop = 1; 1546 return; 1547 } 1548 } 1549 } 1550 1551 1552 /** 1553 * Parse 'moov' and its 'mvhd', which only a sequence file has. 1554 * 1555 * @param hs parser state 1556 * @param box the 'moov' box 1557 */ 1558 static void 1559 heif_parse_moov (struct HeifState *hs, 1560 const struct HeifBox *box) 1561 { 1562 uint64_t pos = box->payload; 1563 1564 while (pos < box->end) 1565 { 1566 struct HeifBox child; 1567 unsigned char buf[28]; 1568 int64_t created; 1569 int64_t modified; 1570 1571 if (! heif_next_box (hs, 1572 pos, 1573 box->end, 1574 &child)) 1575 break; 1576 if (child.end <= pos) 1577 break; /* no forward progress */ 1578 pos = child.end; 1579 if (! heif_is (&child, 1580 "mvhd")) 1581 continue; 1582 if (heif_payload_len (&child) < 5) 1583 return; 1584 if (! heif_read (hs, 1585 child.payload, 1586 buf, 1587 5)) 1588 return; 1589 /* The ISO-BMFF epoch is 1904-01-01; these fields are also famously 1590 written as local time labelled as UTC by most muxers, so treat 1591 the result as an approximate wall clock reading, not as UTC. */ 1592 if (0 == buf[0]) 1593 { 1594 if (heif_payload_len (&child) < 20) 1595 return; 1596 if (! heif_read (hs, 1597 child.payload + 4, 1598 buf, 1599 16)) 1600 return; 1601 created = (int64_t) EXTRACTOR_forensic_be32_ (&buf[0]); 1602 modified = (int64_t) EXTRACTOR_forensic_be32_ (&buf[4]); 1603 } 1604 else 1605 { 1606 if (heif_payload_len (&child) < 32) 1607 return; 1608 if (! heif_read (hs, 1609 child.payload + 4, 1610 buf, 1611 28)) 1612 return; 1613 created = (int64_t) (EXTRACTOR_forensic_be64_ (&buf[0]) 1614 & INT64_MAX); 1615 modified = (int64_t) (EXTRACTOR_forensic_be64_ (&buf[8]) 1616 & INT64_MAX); 1617 } 1618 if (0 != created) 1619 { 1620 if (0 != EXTRACTOR_forensic_emit_unix_time_ (hs->ec, 1621 "heif", 1622 EXTRACTOR_METATYPE_CREATION_DATE, 1623 created - HEIF_EPOCH_OFFSET)) 1624 { 1625 hs->stop = 1; 1626 return; 1627 } 1628 } 1629 if (0 != modified) 1630 { 1631 if (0 != EXTRACTOR_forensic_emit_unix_time_ (hs->ec, 1632 "heif", 1633 EXTRACTOR_METATYPE_MODIFICATION_DATE, 1634 modified 1635 - HEIF_EPOCH_OFFSET)) 1636 hs->stop = 1; 1637 } 1638 return; 1639 } 1640 } 1641 1642 1643 /** 1644 * Main entry method for the HEIF/HEIC/AVIF extraction plugin. 1645 * 1646 * @param ec extraction context provided to the plugin 1647 */ 1648 void 1649 EXTRACTOR_heif_extract_method (struct EXTRACTOR_ExtractContext *ec); 1650 1651 void 1652 EXTRACTOR_heif_extract_method (struct EXTRACTOR_ExtractContext *ec) 1653 { 1654 struct HeifState hs; 1655 struct HeifBox meta; 1656 struct HeifBox moov; 1657 unsigned char head[16]; 1658 unsigned char brands[HEIF_MAX_BRANDS * 4]; 1659 const struct HeifBrand *major; 1660 const char *family; 1661 const char *codec; 1662 char mime[64]; 1663 char compat[HEIF_MAX_BRANDS * 5 + 1]; 1664 uint64_t fsize; 1665 uint64_t ftyp_size; 1666 unsigned int num_brands; 1667 unsigned int sequence; 1668 uint64_t pos; 1669 int have_meta = 0; 1670 1671 fsize = ec->get_size (ec->cls); 1672 if ( (UINT64_MAX == fsize) || 1673 (fsize < 16) ) 1674 return; 1675 memset (&hs, 1676 0, 1677 sizeof (hs)); 1678 memset (&meta, 0, sizeof (meta)); 1679 memset (&moov, 0, sizeof (moov)); 1680 hs.ec = ec; 1681 hs.boxes = HEIF_MAX_BOXES; 1682 hs.budget = HEIF_READ_BUDGET; 1683 1684 /* Bail out on the first 16 bytes: almost every file we are handed is 1685 not ours, and this is the only read those files should cost. */ 1686 if (! heif_read (&hs, 1687 0, 1688 head, 1689 sizeof (head))) 1690 return; 1691 if (0 != memcmp (&head[4], 1692 "ftyp", 1693 4)) 1694 return; 1695 ftyp_size = EXTRACTOR_forensic_be32_ (head); 1696 if ( (ftyp_size < 16) || 1697 (ftyp_size > fsize) ) 1698 return; /* 'ftyp' never uses the 64-bit or to-end-of-file forms */ 1699 major = heif_lookup_brand (&head[8]); 1700 1701 num_brands = (unsigned int) ((ftyp_size - 16) / 4); 1702 if (num_brands > HEIF_MAX_BRANDS) 1703 num_brands = HEIF_MAX_BRANDS; 1704 if ( (0 != num_brands) && 1705 (! heif_read (&hs, 1706 16, 1707 brands, 1708 num_brands * 4)) ) 1709 num_brands = 0; 1710 1711 family = (NULL != major) ? major->family : NULL; 1712 codec = (NULL != major) ? major->codec : NULL; 1713 sequence = (NULL != major) ? (unsigned int) major->sequence : 0; 1714 if (NULL == codec) 1715 { 1716 /* Either the major brand is generic ('mif1'/'msf1') or we do not 1717 know it at all; the compatible brands decide. */ 1718 for (unsigned int i = 0; i < num_brands; i++) 1719 { 1720 const struct HeifBrand *b = heif_lookup_brand (&brands[i * 4]); 1721 1722 if (NULL == b) 1723 continue; 1724 if (NULL == family) 1725 { 1726 family = b->family; 1727 sequence = (unsigned int) b->sequence; 1728 } 1729 if (NULL != b->codec) 1730 { 1731 codec = b->codec; 1732 family = b->family; 1733 sequence |= (unsigned int) b->sequence; 1734 break; 1735 } 1736 } 1737 } 1738 if (NULL == family) 1739 return; /* neither the major nor any compatible brand is ours */ 1740 1741 snprintf (mime, 1742 sizeof (mime), 1743 "%s%s", 1744 family, 1745 (0 != sequence) ? "-sequence" : ""); 1746 if (0 != ec->proc (ec->cls, 1747 "heif", 1748 EXTRACTOR_METATYPE_MIMETYPE, 1749 EXTRACTOR_METAFORMAT_UTF8, 1750 "text/plain", 1751 mime, 1752 strlen (mime) + 1)) 1753 return; 1754 if (0 != EXTRACTOR_forensic_emit_text_ (ec, 1755 "heif", 1756 EXTRACTOR_METATYPE_FORMAT, 1757 (const char *) &head[8], 1758 4)) 1759 return; 1760 if (0 != num_brands) 1761 { 1762 size_t off = 0; 1763 1764 for (unsigned int i = 0; i < num_brands; i++) 1765 { 1766 /* Skip the padding brands some encoders write. */ 1767 if (0 == memcmp (&brands[i * 4], 1768 "\0\0\0\0", 1769 4)) 1770 continue; 1771 if (off + 5 >= sizeof (compat)) 1772 break; 1773 if (0 != off) 1774 compat[off++] = ','; 1775 memcpy (&compat[off], 1776 &brands[i * 4], 1777 4); 1778 off += 4; 1779 } 1780 if (0 != off) 1781 { 1782 if (0 != EXTRACTOR_forensic_emit_text_ (ec, 1783 "heif", 1784 EXTRACTOR_METATYPE_COMPATIBLE_BRANDS, 1785 compat, 1786 off)) 1787 return; 1788 } 1789 } 1790 1791 /* Top level walk: we only care about 'meta' and 'moov'. 'mdat' is 1792 stepped over by its size and never read. One pass records where 1793 they are; the emission order below is ours, not the file's. */ 1794 pos = ftyp_size; 1795 while (pos < fsize) 1796 { 1797 struct HeifBox box; 1798 1799 if (! heif_next_box (&hs, 1800 pos, 1801 fsize, 1802 &box)) 1803 break; 1804 if (box.end <= pos) 1805 break; /* no forward progress */ 1806 pos = box.end; 1807 if ( (heif_is (&box, "meta")) && 1808 (! have_meta) ) 1809 { 1810 meta = box; 1811 have_meta = 1; 1812 } 1813 else if ( (heif_is (&box, "moov")) && 1814 (! hs.have_moov) ) 1815 { 1816 moov = box; 1817 hs.have_moov = 1; 1818 } 1819 } 1820 if (have_meta) 1821 { 1822 heif_parse_meta (&hs, 1823 &meta, 1824 codec); 1825 if (hs.stop) 1826 return; 1827 } 1828 if ( (0 != sequence) || 1829 (hs.have_moov) ) 1830 { 1831 /* A burst, a Live Photo or an animated AVIF: several coded images 1832 that belong together, which is worth calling out because it means 1833 there is more here than the one frame a viewer shows. */ 1834 if (0 != EXTRACTOR_forensic_emit_ (ec, 1835 "heif", 1836 EXTRACTOR_METATYPE_RESOURCE_TYPE, 1837 "image sequence")) 1838 return; 1839 if (0 != EXTRACTOR_forensic_emit_ (ec, 1840 "heif", 1841 EXTRACTOR_METATYPE_COMMENT, 1842 "image sequence (burst, animation or " 1843 "Live Photo)")) 1844 return; 1845 } 1846 if (hs.have_moov) 1847 heif_parse_moov (&hs, 1848 &moov); 1849 } 1850 1851 1852 /* end of heif_extractor.c */