Commit 61c7fd01 for libheif

commit 61c7fd0199abfaab2e674047d2f71b6c6032bb8c
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sun May 17 20:44:21 2026 +0200

    mini: various fixes

diff --git a/libheif/mini.cc b/libheif/mini.cc
index 3864b059..4f1af79e 100644
--- a/libheif/mini.cc
+++ b/libheif/mini.cc
@@ -27,6 +27,7 @@
 #include "codecs/hevc_boxes.h"

 #include <algorithm>
+#include <cassert>
 #include <cmath>
 #include <cstddef>
 #include <memory>
@@ -87,6 +88,11 @@ Error Box_mini::parse(BitstreamRange &range, const heif_security_limits *limits)
   if (m_float_flag)
   {
     uint8_t bit_depth_log2 = bits.get_bits8(2) + 4; // [4;6] (7 is reserved)
+    if (bit_depth_log2 > 6) {
+      return {heif_error_Invalid_input,
+              heif_suberror_Invalid_mini_box,
+              "Reserved float bit_depth_log2 value 7 in MinimizedImageBox"};
+    }
     m_bit_depth = (uint8_t)powl(2, (bit_depth_log2)); // [16,32,64]
   }
   else
@@ -159,6 +165,11 @@ Error Box_mini::parse(BitstreamRange &range, const heif_security_limits *limits)
       if (m_gainmap_float_flag)
       {
         uint8_t bit_depth_log2 = bits.get_bits8(2) + 4;
+        if (bit_depth_log2 > 6) {
+          return {heif_error_Invalid_input,
+                  heif_suberror_Invalid_mini_box,
+                  "Reserved float gainmap bit_depth_log2 value 7 in MinimizedImageBox"};
+        }
         m_gainmap_bit_depth = (uint8_t)powl(2, (bit_depth_log2));
       }
       else
@@ -889,6 +900,7 @@ Error Box_mini::write(StreamWriter& writer) const
   bits.write_flag(m_exif_flag);
   bits.write_flag(m_xmp_flag);
   bits.write_bits8(m_chroma_subsampling, 2);
+  assert(m_orientation >= 1 && m_orientation <= 8);
   bits.write_bits8(m_orientation - 1, 3);

   // Dimensions
@@ -1272,6 +1284,38 @@ static uint32_t get_item_type_for_brand(const heif_brand2 brand)
 }


+// Parse a codec config blob (raw av1C/hvcC payload, no box header) by wrapping
+// it in a synthetic box header so Box::read can dispatch and m_size is set
+// properly (av1C/hvcC parse refuses to run with unspecified box size).
+static Error parse_codec_config_box(const std::vector<uint8_t>& config_bytes,
+                                    uint32_t type_4cc,
+                                    std::shared_ptr<Box>* out_box)
+{
+  const size_t header_size = 8;
+  const size_t total_size = header_size + config_bytes.size();
+  if (total_size > 0x7FFFFFFFu) {
+    return {heif_error_Invalid_input,
+            heif_suberror_Invalid_mini_box,
+            "Codec config in MinimizedImageBox is too large"};
+  }
+
+  std::vector<uint8_t> framed(total_size);
+  framed[0] = (uint8_t)((total_size >> 24) & 0xff);
+  framed[1] = (uint8_t)((total_size >> 16) & 0xff);
+  framed[2] = (uint8_t)((total_size >> 8) & 0xff);
+  framed[3] = (uint8_t)(total_size & 0xff);
+  framed[4] = (uint8_t)((type_4cc >> 24) & 0xff);
+  framed[5] = (uint8_t)((type_4cc >> 16) & 0xff);
+  framed[6] = (uint8_t)((type_4cc >> 8) & 0xff);
+  framed[7] = (uint8_t)(type_4cc & 0xff);
+  std::copy(config_bytes.begin(), config_bytes.end(), framed.begin() + header_size);
+
+  auto istr = std::make_shared<StreamReader_memory>(framed.data(), framed.size(), false);
+  BitstreamRange range(istr, framed.size(), nullptr);
+  return Box::read(range, out_box, heif_get_global_security_limits());
+}
+
+
 Error Box_mini::create_expanded_boxes(class HeifFile* file)
 {
   file->init_meta_box();
@@ -1287,7 +1331,13 @@ Error Box_mini::create_expanded_boxes(class HeifFile* file)
   primary_infe_box->set_item_ID(1);

   // TODO: check explicit codec flag
-  uint32_t minor_version = file->get_ftyp_box()->get_minor_version();
+  auto ftyp_box = file->get_ftyp_box();
+  if (!ftyp_box) {
+    return {heif_error_Invalid_input,
+            heif_suberror_No_ftyp_box,
+            "MinimizedImageBox requires an ftyp box to identify the codec brand"};
+  }
+  uint32_t minor_version = ftyp_box->get_minor_version();
   heif_brand2 mini_brand = minor_version;
   uint32_t infe_type = get_item_type_for_brand(mini_brand);
   if (infe_type == 0) {
@@ -1339,30 +1389,22 @@ Error Box_mini::create_expanded_boxes(class HeifFile* file)
   file->set_ipco_box(ipco_box);

   if (get_main_item_codec_config().size() != 0) {
-    std::shared_ptr<StreamReader> istr = std::make_shared<StreamReader_memory>(
-        get_main_item_codec_config().data(),
-        get_main_item_codec_config().size(),
-        false
-    );
-    BitstreamRange codec_range(istr, get_main_item_codec_config().size(), nullptr);
-
-    std::shared_ptr<Box> main_item_codec_prop;
+    uint32_t config_type;
     if (infe_type == fourcc("av01")) {
-      std::shared_ptr<Box_av1C> codec_prop = std::make_shared<Box_av1C>();
-      codec_prop->parse(codec_range, heif_get_global_security_limits());
-      main_item_codec_prop = std::move(codec_prop);
+      config_type = fourcc("av1C");
     } else if (infe_type == fourcc("hvc1")) {
-      std::shared_ptr<Box_hvcC> codec_prop = std::make_shared<Box_hvcC>();
-      codec_prop->parse(codec_range, heif_get_global_security_limits());
-      main_item_codec_prop = std::move(codec_prop);
+      config_type = fourcc("hvcC");
     } else {
-      // not found
       std::stringstream sstr;
       sstr << "Minimised file requires infe support for " << fourcc_to_string(infe_type) << " but this is not yet supported.";
       return Error(heif_error_Unsupported_filetype,
                    heif_suberror_Unspecified,
                    sstr.str());
     }
+    std::shared_ptr<Box> main_item_codec_prop;
+    if (auto err = parse_codec_config_box(get_main_item_codec_config(), config_type, &main_item_codec_prop)) {
+      return err;
+    }
     ipco_box->append_child_box(main_item_codec_prop); // entry 1
   } else {
     ipco_box->append_child_box(std::make_shared<Box_free>()); // placeholder for entry 1
@@ -1401,29 +1443,22 @@ Error Box_mini::create_expanded_boxes(class HeifFile* file)
   }

   if (get_alpha_item_codec_config().size() != 0) {
-    std::shared_ptr<StreamReader> istr = std::make_shared<StreamReader_memory>(
-        get_alpha_item_codec_config().data(),
-        get_alpha_item_codec_config().size(),
-        false
-    );
-    BitstreamRange alpha_codec_range(istr, get_alpha_item_codec_config().size(), nullptr);
-    std::shared_ptr<Box> alpha_item_codec_prop;
+    uint32_t config_type;
     if (infe_type == fourcc("av01")) {
-      std::shared_ptr<Box_av1C> codec_prop = std::make_shared<Box_av1C>();
-      codec_prop->parse(alpha_codec_range, heif_get_global_security_limits());
-      alpha_item_codec_prop = std::move(codec_prop);
+      config_type = fourcc("av1C");
     } else if (infe_type == fourcc("hvc1")) {
-      std::shared_ptr<Box_hvcC> codec_prop = std::make_shared<Box_hvcC>();
-      codec_prop->parse(alpha_codec_range, heif_get_global_security_limits());
-      alpha_item_codec_prop = std::move(codec_prop);
+      config_type = fourcc("hvcC");
     } else {
-      // not found
       std::stringstream sstr;
       sstr << "Minimised file requires infe support for " << fourcc_to_string(infe_type) << " but this is not yet supported.";
       return Error(heif_error_Unsupported_filetype,
                    heif_suberror_Unspecified,
                    sstr.str());
     }
+    std::shared_ptr<Box> alpha_item_codec_prop;
+    if (auto err = parse_codec_config_box(get_alpha_item_codec_config(), config_type, &alpha_item_codec_prop)) {
+      return err;
+    }
     ipco_box->append_child_box(alpha_item_codec_prop); // entry 6
   } else {
     ipco_box->append_child_box(std::make_shared<Box_free>()); // placeholder for entry 6