Explorar o código

Updated tinyexr.

Branimir Karadžić %!s(int64=7) %!d(string=hai) anos
pai
achega
3d3d9d3273
Modificáronse 1 ficheiros con 163 adicións e 65 borrados
  1. 163 65
      3rdparty/tinyexr/tinyexr.h

+ 163 - 65
3rdparty/tinyexr/tinyexr.h

@@ -306,12 +306,14 @@ extern int ParseEXRVersionFromMemory(EXRVersion *version,
                                      const unsigned char *memory, size_t size);
 
 // Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
                                   const char *filename, const char **err);
 
 // Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int ParseEXRHeaderFromMemory(EXRHeader *header,
                                     const EXRVersion *version,
                                     const unsigned char *memory, size_t size,
@@ -319,7 +321,8 @@ extern int ParseEXRHeaderFromMemory(EXRHeader *header,
 
 // Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
 // array.
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
                                            int *num_headers,
                                            const EXRVersion *version,
@@ -328,7 +331,8 @@ extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
 
 // Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
 // array
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
                                              int *num_headers,
                                              const EXRVersion *version,
@@ -340,7 +344,8 @@ extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
 // Application can free EXRImage using `FreeEXRImage`
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
                                 const char *filename, const char **err);
 
@@ -350,7 +355,8 @@ extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
 // Application can free EXRImage using `FreeEXRImage`
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
                                   const unsigned char *memory,
                                   const size_t size, const char **err);
@@ -361,7 +367,8 @@ extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
 // Application can free EXRImage using `FreeEXRImage`
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int LoadEXRMultipartImageFromFile(EXRImage *images,
                                          const EXRHeader **headers,
                                          unsigned int num_parts,
@@ -374,7 +381,8 @@ extern int LoadEXRMultipartImageFromFile(EXRImage *images,
 // Application can free EXRImage using `FreeEXRImage`
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
                                            const EXRHeader **headers,
                                            unsigned int num_parts,
@@ -384,7 +392,8 @@ extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
 // Saves multi-channel, single-frame OpenEXR image to a file.
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int SaveEXRImageToFile(const EXRImage *image,
                               const EXRHeader *exr_header, const char *filename,
                               const char **err);
@@ -394,7 +403,8 @@ extern int SaveEXRImageToFile(const EXRImage *image,
 // Return the number of bytes if succes.
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern size_t SaveEXRImageToMemory(const EXRImage *image,
                                    const EXRHeader *exr_header,
                                    unsigned char **memory, const char **err);
@@ -403,7 +413,8 @@ extern size_t SaveEXRImageToMemory(const EXRImage *image,
 // Application must free memory of variables in DeepImage(image, offset_table)
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
                        const char **err);
 
@@ -426,7 +437,8 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
 // RGB(A) channels.
 // Returns negative value and may set error string in `err` when there's an
 // error
-// When there was an error message, Application must free `err` with FreeEXRErrorMessage()
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
 extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
                              const unsigned char *memory, size_t size,
                              const char **err);
@@ -2520,10 +2532,10 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r,
   tinfl_status status = TINFL_STATUS_FAILED;
   mz_uint32 num_bits, dist, counter, num_extra;
   tinfl_bit_buf_t bit_buf;
-  const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
-                                                  pIn_buf_next + *pIn_buf_size;
-  mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
-                                              pOut_buf_next + *pOut_buf_size;
+  const mz_uint8 *pIn_buf_cur = pIn_buf_next,
+                 *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+  mz_uint8 *pOut_buf_cur = pOut_buf_next,
+           *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
   size_t out_buf_size_mask =
              (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
                  ? (size_t)-1
@@ -2940,9 +2952,8 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
     tinfl_status status = tinfl_decompress(
         &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
         (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
-        &dst_buf_size,
-        (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
-            TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+        &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
+                           TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
     if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
       MZ_FREE(pBuf);
       *pOut_len = 0;
@@ -2995,8 +3006,9 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
     tinfl_status status =
         tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
                          &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
-                         (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
-                                    TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
+                         (flags &
+                          ~(TINFL_FLAG_HAS_MORE_INPUT |
+                            TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
     in_buf_ofs += in_buf_size;
     if ((dst_buf_size) &&
         (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
@@ -3121,9 +3133,7 @@ static const mz_uint8 s_tdefl_large_dist_extra[128] = {
 
 // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
 // values.
-typedef struct {
-  mz_uint16 m_key, m_sym_index;
-} tdefl_sym_freq;
+typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
 static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
                                              tdefl_sym_freq *pSyms0,
                                              tdefl_sym_freq *pSyms1) {
@@ -5267,10 +5277,9 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
   n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
   n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
   pStat->m_comment_size = n;
-  memcpy(pStat->m_comment,
-         p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
-             MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
-             MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
+  memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
+                               MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
+                               MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
          n);
   pStat->m_comment[n] = '\0';
 
@@ -6957,13 +6966,12 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
 //  return bint.c[0] == 1;
 //}
 
-static void SetErrorMessage(const std::string &msg, const char **err)
-{
+static void SetErrorMessage(const std::string &msg, const char **err) {
   if (err) {
 #ifdef _WIN32
-      (*err) = _strdup(msg.c_str());
+    (*err) = _strdup(msg.c_str());
 #else
-      (*err) = strdup(msg.c_str());
+    (*err) = strdup(msg.c_str());
 #endif
   }
 }
@@ -10095,6 +10103,12 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
             outLine += (height - 1 - y) * x_stride;
           }
 
+          if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
+              (data_ptr + data_len)) {
+            // Insufficient data size
+            return false;
+          }
+
           for (int u = 0; u < width; u++) {
             tinyexr::FP16 hf;
 
@@ -10123,6 +10137,12 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
           outLine += (height - 1 - y) * x_stride;
         }
 
+        if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
+            (data_ptr + data_len)) {
+          // Insufficient data size
+          return false;
+        }
+
         for (int u = 0; u < width; u++) {
           float val;
           tinyexr::cpy4(&val, line_ptr + u);
@@ -10143,6 +10163,12 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
         }
 
         for (int u = 0; u < width; u++) {
+          if (reinterpret_cast<const unsigned char *>(line_ptr + u) >=
+              (data_ptr + data_len)) {
+            // Corrupsed data?
+            return false;
+          }
+
           unsigned int val;
           tinyexr::cpy4(&val, line_ptr + u);
 
@@ -10325,6 +10351,9 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
   size_t orig_size = size;
   for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) {
     if (0 == size) {
+      if (err) {
+        (*err) += "Insufficient data size for attributes.\n";
+      }
       return TINYEXR_ERROR_INVALID_DATA;
     } else if (marker[0] == '\0') {
       size--;
@@ -10337,6 +10366,9 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
     size_t marker_size;
     if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
                                 marker, size)) {
+      if (err) {
+        (*err) += "Failed to read attribute.\n";
+      }
       return TINYEXR_ERROR_INVALID_DATA;
     }
     marker += marker_size;
@@ -10407,14 +10439,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
 
       if (!ReadChannelInfo(info->channels, data)) {
         if (err) {
-          (*err) = "Failed to parse channel info.";
+          (*err) += "Failed to parse channel info.\n";
         }
         return TINYEXR_ERROR_INVALID_DATA;
       }
 
       if (info->channels.size() < 1) {
         if (err) {
-          (*err) = "# of channels is zero.";
+          (*err) += "# of channels is zero.\n";
         }
         return TINYEXR_ERROR_INVALID_DATA;
       }
@@ -10648,7 +10680,7 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
 
 static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
                        const std::vector<tinyexr::tinyexr_uint64> &offsets,
-                       const unsigned char *head, const size_t size) {
+                       const unsigned char *head, const size_t size, std::string *err) {
   int num_channels = exr_header->num_channels;
 
   int num_scanline_blocks = 1;
@@ -10669,8 +10701,11 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
   int pixel_data_size = 0;
   size_t channel_offset = 0;
   if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
-                                &channel_offset, num_channels,
-                                exr_header->channels)) {
+                                     &channel_offset, num_channels,
+                                     exr_header->channels)) {
+    if (err) {
+      (*err) += "Failed to compute channel layout.\n";
+    }
     return TINYEXR_ERROR_INVALID_DATA;
   }
 
@@ -10692,6 +10727,9 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
       // 4 byte : data size
       // ~      : data(uncompressed or compressed)
       if (offsets[tile_idx] + sizeof(int) * 5 > size) {
+        if (err) {
+          (*err) += "Insufficient data size.\n";
+        }
         return TINYEXR_ERROR_INVALID_DATA;
       }
 
@@ -10720,6 +10758,9 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
       tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
 
       if (data_len < 4 || size_t(data_len) > data_size) {
+        if (err) {
+          (*err) += "Insufficient data length.\n";
+        }
         return TINYEXR_ERROR_INVALID_DATA;
       }
 
@@ -10977,13 +11018,38 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
         // OK
         break;
       } else {
-        tinyexr::SetErrorMessage("Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
+        tinyexr::SetErrorMessage(
+            "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
         return TINYEXR_ERROR_INVALID_DATA;
       }
     }
   }
 
-  return DecodeChunk(exr_image, exr_header, offsets, head, size);
+  {
+    std::string e;
+    int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
+
+    if (ret != TINYEXR_SUCCESS) {
+      if (!e.empty()) {
+        tinyexr::SetErrorMessage(e, err);
+      }
+
+      // release memory(if exists)
+      if ((exr_header->num_channels > 0) && exr_image && exr_image->images) {
+        for (size_t c = 0; c < size_t(exr_header->num_channels); c++) {
+          if (exr_image->images[c]) {
+            free(exr_image->images[c]);
+            exr_image->images[c] = NULL;
+          }
+        }
+        free(exr_image->images);
+        exr_image->images = NULL;
+      }
+
+    }
+
+    return ret;
+  }
 }
 
 }  // namespace tinyexr
@@ -11004,11 +11070,14 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
   {
     int ret = ParseEXRVersionFromFile(&exr_version, filename);
     if (ret != TINYEXR_SUCCESS) {
+      tinyexr::SetErrorMessage("Invalid EXR header.", err);
       return ret;
     }
 
     if (exr_version.multipart || exr_version.non_image) {
-      tinyexr::SetErrorMessage("Loading multipart or DeepImage is not supported  in LoadEXR() API", err);
+      tinyexr::SetErrorMessage(
+          "Loading multipart or DeepImage is not supported  in LoadEXR() API",
+          err);
       return TINYEXR_ERROR_INVALID_DATA;  // @fixme.
     }
   }
@@ -11161,13 +11230,19 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
                              const unsigned char *memory, size_t size,
                              const char **err) {
   if (memory == NULL || exr_header == NULL) {
-    tinyexr::SetErrorMessage("Invalid argument. `memory` or `exr_header` argument is null in ParseEXRHeaderFromMemory()", err);
+    tinyexr::SetErrorMessage(
+        "Invalid argument. `memory` or `exr_header` argument is null in "
+        "ParseEXRHeaderFromMemory()",
+        err);
 
     // Invalid argument
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }
 
   if (size < tinyexr::kEXRVersionSize) {
+    tinyexr::SetErrorMessage(
+        "Insufficient header/data size.\n",
+        err);
     return TINYEXR_ERROR_INVALID_DATA;
   }
 
@@ -11321,6 +11396,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
   fseek(fp, 0, SEEK_SET);
 
   if (filesize < 16) {
+    tinyexr::SetErrorMessage("File size too short " + std::string(filename), err);
     return TINYEXR_ERROR_INVALID_FILE;
   }
 
@@ -11342,7 +11418,8 @@ int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
                            const char **err) {
   if (exr_image == NULL || memory == NULL ||
       (size < tinyexr::kEXRVersionSize)) {
-    tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory", err);
+    tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory",
+                             err);
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }
 
@@ -11370,14 +11447,16 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
 
 #if !TINYEXR_USE_PIZ
   if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
-    tinyexr::SetErrorMessage("PIZ compression is not supported in this build", err);
+    tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
+                             err);
     return 0;
   }
 #endif
 
 #if !TINYEXR_USE_ZFP
   if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
-    tinyexr::SetErrorMessage("ZFP compression is not supported in this build", err);
+    tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
+                             err);
     return 0;
   }
 #endif
@@ -11385,7 +11464,8 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
 #if TINYEXR_USE_ZFP
   for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
     if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
-      tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression", err);
+      tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
+                               err);
       return 0;
     }
   }
@@ -11595,7 +11675,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
       if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
         if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
           for (int y = 0; y < h; y++) {
-              // Assume increasing Y
+            // Assume increasing Y
             float *line_ptr = reinterpret_cast<float *>(&buf.at(
                 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
                 channel_offset_list[c] *
@@ -11616,7 +11696,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
         } else if (exr_header->requested_pixel_types[c] ==
                    TINYEXR_PIXELTYPE_HALF) {
           for (int y = 0; y < h; y++) {
-              // Assume increasing Y
+            // Assume increasing Y
             unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
                 &buf.at(static_cast<size_t>(pixel_data_size * y *
                                             exr_image->width) +
@@ -11685,8 +11765,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
           // Assume increasing Y
           unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
               static_cast<size_t>(pixel_data_size * y * exr_image->width) +
-              channel_offset_list[c] *
-                  static_cast<size_t>(exr_image->width)));
+              channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
           for (int x = 0; x < exr_image->width; x++) {
             unsigned int val = reinterpret_cast<unsigned int **>(
                 exr_image->images)[c][(y + start_y) * exr_image->width + x];
@@ -11869,14 +11948,16 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
 
 #if !TINYEXR_USE_PIZ
   if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
-    tinyexr::SetErrorMessage("PIZ compression is not supported in this build", err);
+    tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
+                             err);
     return 0;
   }
 #endif
 
 #if !TINYEXR_USE_ZFP
   if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
-    tinyexr::SetErrorMessage("ZFP compression is not supported in this build", err);
+    tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
+                             err);
     return 0;
   }
 #endif
@@ -11915,13 +11996,15 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
   FILE *fp = NULL;
   errno_t errcode = fopen_s(&fp, filename, "rb");
   if ((0 != errcode) || (!fp)) {
-    tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), err);
+    tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
+                             err);
     return TINYEXR_ERROR_CANT_OPEN_FILE;
   }
 #else
   FILE *fp = fopen(filename, "rb");
   if (!fp) {
-    tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), err);
+    tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
+                             err);
     return TINYEXR_ERROR_CANT_OPEN_FILE;
   }
 #endif
@@ -11934,7 +12017,8 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
 
   if (filesize == 0) {
     fclose(fp);
-    tinyexr::SetErrorMessage("File size is zero : " + std::string(filename), err);
+    tinyexr::SetErrorMessage("File size is zero : " + std::string(filename),
+                             err);
     return TINYEXR_ERROR_INVALID_FILE;
   }
 
@@ -12377,7 +12461,8 @@ int FreeEXRImage(EXRImage *exr_image) {
 int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
                            const char *filename, const char **err) {
   if (exr_header == NULL || exr_version == NULL || filename == NULL) {
-    tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile", err);
+    tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
+                             err);
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }
 
@@ -12406,7 +12491,8 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
     fclose(fp);
 
     if (ret != filesize) {
-      tinyexr::SetErrorMessage("fread() error on " + std::string(filename), err);
+      tinyexr::SetErrorMessage("fread() error on " + std::string(filename),
+                               err);
       return TINYEXR_ERROR_INVALID_FILE;
     }
   }
@@ -12423,11 +12509,14 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
   if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
       exr_version == NULL) {
     // Invalid argument
-    tinyexr::SetErrorMessage("Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
+    tinyexr::SetErrorMessage(
+        "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }
 
   if (size < tinyexr::kEXRVersionSize) {
+    tinyexr::SetErrorMessage(
+        "Data size too short", err);
     return TINYEXR_ERROR_INVALID_DATA;
   }
 
@@ -12457,7 +12546,8 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
 
     // `chunkCount` must exist in the header.
     if (info.chunk_count == 0) {
-      tinyexr::SetErrorMessage("`chunkCount' attribute is not found in the header.", err);
+      tinyexr::SetErrorMessage(
+          "`chunkCount' attribute is not found in the header.", err);
       return TINYEXR_ERROR_INVALID_DATA;
     }
 
@@ -12492,7 +12582,8 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
                                     const char *filename, const char **err) {
   if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
       filename == NULL) {
-    tinyexr::SetErrorMessage("Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
+    tinyexr::SetErrorMessage(
+        "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }
 
@@ -12630,7 +12721,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
                                     const size_t size, const char **err) {
   if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
       memory == NULL || (size <= tinyexr::kEXRVersionSize)) {
-    tinyexr::SetErrorMessage("Invalid argument for LoadEXRMultipartImageFromMemory()", err);
+    tinyexr::SetErrorMessage(
+        "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }
 
@@ -12673,7 +12765,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
       tinyexr::swap8(&offset);
 
       if (offset >= size) {
-        tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", err);
+        tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
+                                 err);
         return TINYEXR_ERROR_INVALID_DATA;
       }
 
@@ -12698,15 +12791,19 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
       tinyexr::swap4(&part_no);
 
       if (part_no != i) {
-        tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.", err);
+        tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
+                                 err);
         return TINYEXR_ERROR_INVALID_DATA;
       }
     }
 
+    std::string e;
     int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
-                                   memory, size);
+                                   memory, size, &e);
     if (ret != TINYEXR_SUCCESS) {
-      tinyexr::SetErrorMessage("Error in DecodeChunk()", err);
+      if (!e.empty()) {
+        tinyexr::SetErrorMessage(e, err);
+      }
       return ret;
     }
   }
@@ -12719,7 +12816,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
                                   unsigned int num_parts, const char *filename,
                                   const char **err) {
   if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
-    tinyexr::SetErrorMessage("Invalid argument for LoadEXRMultipartImageFromFile", err);
+    tinyexr::SetErrorMessage(
+        "Invalid argument for LoadEXRMultipartImageFromFile", err);
     return TINYEXR_ERROR_INVALID_ARGUMENT;
   }