Commit 2d0dfa0c for libheif

commit 2d0dfa0cbb8a37ad9e13c60c70e2800552a4d487
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Fri Dec 26 12:51:53 2025 +0100

    function for safe 4x uint8_t to uint32_t conversion

diff --git a/examples/common.cc b/examples/common.cc
index 1f3a8d62..04408a1f 100644
--- a/examples/common.cc
+++ b/examples/common.cc
@@ -32,6 +32,8 @@
 #include <vector>
 #include <algorithm>

+#include "common_utils.h"
+
 namespace heif_examples {
   void show_version()
   {
@@ -121,7 +123,7 @@ namespace heif_examples {

     std::array<uint8_t, 4> length{};
     istr.read((char*) length.data(), length.size());
-    uint32_t box_size = (length[0] << 24) + (length[1] << 16) + (length[2] << 8) + (length[3]);
+    uint32_t box_size = four_bytes_to_uint32(length[0], length[1], length[2], length[3]);
     if ((box_size < 16) || (box_size > 512)) {
       fprintf(stderr, "Input file does not appear to start with a valid box length.");
       if ((box_size & 0xFFFFFFF0) == 0xFFD8FFE0) {
diff --git a/examples/heif_dec.cc b/examples/heif_dec.cc
index a621d9ff..14cbaa3c 100644
--- a/examples/heif_dec.cc
+++ b/examples/heif_dec.cc
@@ -68,6 +68,7 @@

 #include "../heifio/encoder_y4m.h"
 #include "common.h"
+#include "common_utils.h"

 #if defined(_MSC_VER)
 #include "getopt.h"
@@ -458,7 +459,7 @@ int decode_single_image(heif_image_handle* handle,
                 return 1;
               }

-              offset = (exif[0] << 24) | (exif[1] << 16) | (exif[2] << 8) | exif[3];
+              offset = four_bytes_to_uint32(exif[0], exif[1], exif[2], exif[3]);
               offset += 4;

               if (offset >= exifSize) {
diff --git a/heifio/encoder_jpeg.cc b/heifio/encoder_jpeg.cc
index 040fe37d..c38d4cb4 100644
--- a/heifio/encoder_jpeg.cc
+++ b/heifio/encoder_jpeg.cc
@@ -35,6 +35,8 @@

 #include <jpeglib.h>

+#include "common_utils.h"
+
 #define JPEG_XMP_MARKER  (JPEG_APP0+1)  /* JPEG marker code for XMP */
 #define JPEG_XMP_MARKER_ID "http://ns.adobe.com/xap/1.0/"

@@ -182,7 +184,7 @@ bool JpegEncoder::Encode(const struct heif_image_handle* handle,
       if (exifsize > 4) {
         static const uint8_t kExifMarker = JPEG_APP0 + 1;

-        uint32_t skip = (exifdata[0] << 24) | (exifdata[1] << 16) | (exifdata[2] << 8) | exifdata[3];
+        uint32_t skip = four_bytes_to_uint32(exifdata[0], exifdata[1], exifdata[2], exifdata[3]);
         if (skip > (exifsize - 4)) {
           fprintf(stderr, "Invalid EXIF data (offset too large)\n");
           free(exifdata);
diff --git a/heifio/encoder_png.cc b/heifio/encoder_png.cc
index dc2d1adb..9f82466e 100644
--- a/heifio/encoder_png.cc
+++ b/heifio/encoder_png.cc
@@ -30,6 +30,8 @@
 #include <vector>

 #include "encoder_png.h"
+
+#include "common_utils.h"
 #include "exif.h"

 PngEncoder::PngEncoder() = default;
@@ -44,10 +46,10 @@ bool fix_icc_profile(uint8_t* profile_data, uint32_t& profile_size)

   // --- check that profile size specified in header matches the real size

-  uint32_t size_in_header = ((profile_data[0] << 24) |
-                             (profile_data[1] << 16) |
-                             (profile_data[2] << 8) |
-                             (profile_data[3] << 0));
+  uint32_t size_in_header = four_bytes_to_uint32(profile_data[0],
+                                                 profile_data[1],
+                                                 profile_data[2],
+                                                 profile_data[3]);

   if (size_in_header != profile_size) {

@@ -157,7 +159,7 @@ bool PngEncoder::Encode(const heif_image_handle* handle,
     uint8_t* exifdata = GetExifMetaData(handle, &exifsize);
     if (exifdata) {
       if (exifsize > 4) {
-        uint32_t skip = (exifdata[0] << 24) | (exifdata[1] << 16) | (exifdata[2] << 8) | exifdata[3];
+        uint32_t skip = four_bytes_to_uint32(exifdata[0], exifdata[1], exifdata[2], exifdata[3]);
         if (skip < (exifsize - 4)) {
           skip += 4;
           uint8_t* ptr = exifdata + skip;
diff --git a/heifio/exif.cc b/heifio/exif.cc
index 33d55f2c..e0ffd889 100644
--- a/heifio/exif.cc
+++ b/heifio/exif.cc
@@ -21,6 +21,8 @@
 #include <cassert>
 #include "exif.h"

+#include "common_utils.h"
+
 #define EXIF_TYPE_SHORT 3
 #define EXIF_TYPE_LONG 4
 #define DEFAULT_EXIF_ORIENTATION 1
@@ -41,10 +43,10 @@ static uint32_t read32(const uint8_t* data, uint32_t size, uint32_t pos, bool li
   const uint8_t* p = data + pos;

   if (littleEndian) {
-    return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
+    return four_bytes_to_uint32(p[3], p[2], p[1], p[0]);
   }
   else {
-    return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+    return four_bytes_to_uint32(p[0], p[1], p[2], p[3]);
   }
 }

@@ -56,10 +58,10 @@ static uint16_t read16(const uint8_t* data, uint32_t size, uint32_t pos, bool li
   const uint8_t* p = data + pos;

   if (littleEndian) {
-    return static_cast<uint16_t>((p[1] << 8) | p[0]);
+    return two_bytes_to_uint16(p[1], p[0]);
   }
   else {
-    return static_cast<uint16_t>((p[0] << 8) | p[1]);
+    return two_bytes_to_uint16(p[0], p[1]);
   }
 }

diff --git a/libheif/bitstream.cc b/libheif/bitstream.cc
index 79c60c6d..4ac2805d 100644
--- a/libheif/bitstream.cc
+++ b/libheif/bitstream.cc
@@ -24,6 +24,8 @@
 #include <cstring>
 #include <cassert>

+#include "common_utils.h"
+
 #if !defined(HAVE_BIT)
 #include <type_traits>
 #else
@@ -268,10 +270,7 @@ uint32_t BitstreamRange::read32()
     return 0;
   }

-  return (uint32_t) ((buf[0] << 24) |
-                     (buf[1] << 16) |
-                     (buf[2] << 8) |
-                     (buf[3]));
+  return four_bytes_to_uint32(buf[0], buf[1], buf[2], buf[3]);
 }


diff --git a/libheif/common_utils.h b/libheif/common_utils.h
index 00e2ef91..88ac12f3 100644
--- a/libheif/common_utils.h
+++ b/libheif/common_utils.h
@@ -35,12 +35,23 @@
 #endif


-constexpr inline uint32_t fourcc(const char* id)
+constexpr uint32_t four_bytes_to_uint32(uint8_t msb, uint8_t b, uint8_t c, uint8_t lsb)
 {
-  return (((((uint32_t) id[0])&0xFF) << 24) |
-          ((((uint32_t) id[1])&0xFF) << 16) |
-          ((((uint32_t) id[2])&0xFF) << 8) |
-          ((((uint32_t) id[3])&0xFF) << 0));
+  return (static_cast<uint32_t>(msb << 24) |
+          static_cast<uint32_t>(b << 16) |
+          static_cast<uint32_t>(c << 8) |
+          static_cast<uint32_t>(lsb));
+}
+
+constexpr uint16_t two_bytes_to_uint16(uint8_t msb, uint8_t lsb)
+{
+  return (static_cast<uint16_t>(msb << 8) |
+          static_cast<uint16_t>(lsb));
+}
+
+constexpr uint32_t fourcc(const char* id)
+{
+  return four_bytes_to_uint32(id[0], id[1], id[2], id[3]);
 }

 std::string fourcc_to_string(uint32_t code);
diff --git a/libheif/context.cc b/libheif/context.cc
index 6a960453..aa263887 100644
--- a/libheif/context.cc
+++ b/libheif/context.cc
@@ -1033,7 +1033,7 @@ Error HeifContext::interpret_heif_file_images()
     if (!regionDataResult) {
       return regionDataResult.error();
     }
-    region_item->parse(*regionDataResult);
+    region_item->parse(*regionDataResult, get_security_limits());

     if (iref_box) {
       std::vector<Box_iref::Reference> references = iref_box->get_references_from(id);
diff --git a/libheif/image-items/grid.cc b/libheif/image-items/grid.cc
index 3bda1d52..a4251557 100644
--- a/libheif/image-items/grid.cc
+++ b/libheif/image-items/grid.cc
@@ -60,22 +60,12 @@ Error ImageGrid::parse(const std::vector<uint8_t>& data)
               "Grid image data incomplete"};
     }

-    m_output_width = ((static_cast<uint32_t>(data[4]) << 24) |
-                      (static_cast<uint32_t>(data[5]) << 16) |
-                      (static_cast<uint32_t>(data[6]) << 8) |
-                      (static_cast<uint32_t>(data[7])));
-
-    m_output_height = ((static_cast<uint32_t>(data[8]) << 24) |
-                       (static_cast<uint32_t>(data[9]) << 16) |
-                       (static_cast<uint32_t>(data[10]) << 8) |
-                       (static_cast<uint32_t>(data[11])));
+    m_output_width = four_bytes_to_uint32(data[4], data[5], data[6], data[7]);
+    m_output_height = four_bytes_to_uint32(data[8], data[9], data[10], data[11]);
   }
   else {
-    m_output_width = ((static_cast<uint32_t>(data[4]) << 8) |
-                      (static_cast<uint32_t>(data[5])));
-
-    m_output_height = ((static_cast<uint32_t>(data[6]) << 8) |
-                       (static_cast<uint32_t>(data[7])));
+    m_output_width = two_bytes_to_uint16(data[4], data[5]);
+    m_output_height = two_bytes_to_uint16(data[6], data[7]);
   }

   return Error::Ok;
diff --git a/libheif/plugins/decoder_ffmpeg.cc b/libheif/plugins/decoder_ffmpeg.cc
index 532d3c02..22e1bb33 100644
--- a/libheif/plugins/decoder_ffmpeg.cc
+++ b/libheif/plugins/decoder_ffmpeg.cc
@@ -237,10 +237,10 @@ static heif_error ffmpeg_push_data2(void *decoder_raw, const void *data, size_t
       };
     }

-    uint32_t nal_size = ((static_cast<uint32_t>(cdata[ptr + 0]) << 24) |
-                         (static_cast<uint32_t>(cdata[ptr + 1]) << 16) |
-                         (static_cast<uint32_t>(cdata[ptr + 2]) << 8) |
-                         (static_cast<uint32_t>(cdata[ptr + 3])));
+    uint32_t nal_size = four_bytes_to_uint32(cdata[ptr + 0],
+                                             cdata[ptr + 1],
+                                             cdata[ptr + 2],
+                                             cdata[ptr + 3]);
     ptr += 4;

     if (nal_size > size - ptr) {
diff --git a/libheif/plugins/decoder_vvdec.cc b/libheif/plugins/decoder_vvdec.cc
index 301ff225..09515720 100644
--- a/libheif/plugins/decoder_vvdec.cc
+++ b/libheif/plugins/decoder_vvdec.cc
@@ -180,10 +180,7 @@ heif_error vvdec_push_data2(void* decoder_raw, const void* frame_data, size_t fr
   const auto* data = (const uint8_t*) frame_data;

   for (;;) {
-    uint32_t size = ((((uint32_t) data[0]) << 24) |
-                     (((uint32_t) data[1]) << 16) |
-                     (((uint32_t) data[2]) << 8) |
-                     (data[3]));
+    uint32_t size = four_bytes_to_uint32(data[0], data[1], data[2], data[3]);

     data += 4;