Commit ecffcfc8 for libheif

commit ecffcfc85e82735e3d7b611fc5378566eebb739d
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Thu Jul 2 12:20:53 2026 +0200

    Resolve 'mini' and 'moov' boxes with size 0 to end of file (#1857)

    Apply the same handling that was added for the 'meta' box: a top-level
    'mini' or 'moov' box with a box size of 0 extends to the end of the file
    (ISO/IEC 14496-12 clause 4.2), which is legal for the last box. Resolve
    the size via request_range() and parse normally, instead of rejecting
    the file outright.

    This removes the remaining "Cannot read <box> with unspecified size"
    TODOs in FileLayout::read(). The known-size paths are unchanged.

diff --git a/libheif/file_layout.cc b/libheif/file_layout.cc
index d66c20a6..387331c4 100644
--- a/libheif/file_layout.cc
+++ b/libheif/file_layout.cc
@@ -176,19 +176,29 @@ Error FileLayout::read(const std::shared_ptr<StreamReader>& stream, const heif_s
     // TODO: this is basically the same as the meta box case above, with different error handling.
     if (box_header.get_short_type() == fourcc("mini")) {
       const uint64_t mini_box_start = next_box_start;
-      if (box_header.get_box_size() == 0) {
-        // TODO: get file-size from stream and compute box size
-        return {heif_error_Invalid_input,
-                heif_suberror_Invalid_mini_box,
-                "Cannot read mini box with unspecified size"};
+      uint64_t end_of_mini_box;
+      if (box_header.get_box_size() == BoxHeader::size_until_end_of_file) {
+        // A box size of 0 means the box extends to the end of the file
+        // (ISO/IEC 14496-12 clause 4.2), which is legal for the last box.
+        // Resolve it to the file size.
+        end_of_mini_box = m_stream_reader->request_range(mini_box_start,
+                                                         std::numeric_limits<uint64_t>::max());
+        m_max_length = end_of_mini_box;
+        if (end_of_mini_box <= mini_box_start) {
+          return {heif_error_Invalid_input,
+                  heif_suberror_Invalid_mini_box,
+                  "Cannot read mini box with unspecified size"};
+        }
       }
-      uint64_t end_of_mini_box = box_header.get_box_size();
-      if (end_of_mini_box > std::numeric_limits<uint64_t>::max() - mini_box_start) {
-        return {heif_error_Invalid_input,
-                heif_suberror_Invalid_mini_box,
-                "Cannot read mini box with invalid size"};
+      else {
+        end_of_mini_box = box_header.get_box_size();
+        if (end_of_mini_box > std::numeric_limits<uint64_t>::max() - mini_box_start) {
+          return {heif_error_Invalid_input,
+                  heif_suberror_Invalid_mini_box,
+                  "Cannot read mini box with invalid size"};
+        }
+        end_of_mini_box += mini_box_start;
       }
-      end_of_mini_box += mini_box_start;
       if (m_max_length < end_of_mini_box) {
         m_max_length = m_stream_reader->request_range(mini_box_start, end_of_mini_box);
       }
@@ -213,20 +223,29 @@ Error FileLayout::read(const std::shared_ptr<StreamReader>& stream, const heif_s

     if (box_header.get_short_type() == fourcc("moov")) {
       const uint64_t moov_box_start = next_box_start;
-      if (box_header.get_box_size() == 0) {
-        // TODO: get file-size from stream and compute box size
-        return {heif_error_Invalid_input,
-                heif_suberror_No_moov_box,
-                "Cannot read moov box with unspecified size"};
+      uint64_t end_of_moov_box;
+      if (box_header.get_box_size() == BoxHeader::size_until_end_of_file) {
+        // A box size of 0 means the box extends to the end of the file
+        // (ISO/IEC 14496-12 clause 4.2), which is legal for the last box.
+        // Resolve it to the file size.
+        end_of_moov_box = m_stream_reader->request_range(moov_box_start,
+                                                         std::numeric_limits<uint64_t>::max());
+        m_max_length = end_of_moov_box;
+        if (end_of_moov_box <= moov_box_start) {
+          return {heif_error_Invalid_input,
+                  heif_suberror_No_moov_box,
+                  "Cannot read moov box with unspecified size"};
+        }
       }
-
-      uint64_t end_of_moov_box = box_header.get_box_size();
-      if (end_of_moov_box > std::numeric_limits<uint64_t>::max() - moov_box_start) {
-        return {heif_error_Invalid_input,
-                heif_suberror_No_moov_box,
-                "Cannot read moov box with invalid size"};
+      else {
+        end_of_moov_box = box_header.get_box_size();
+        if (end_of_moov_box > std::numeric_limits<uint64_t>::max() - moov_box_start) {
+          return {heif_error_Invalid_input,
+                  heif_suberror_No_moov_box,
+                  "Cannot read moov box with invalid size"};
+        }
+        end_of_moov_box += moov_box_start;
       }
-      end_of_moov_box += moov_box_start;
       if (m_max_length < end_of_moov_box) {
         m_max_length = m_stream_reader->request_range(moov_box_start, end_of_moov_box);
       }