diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp index 64ef56c8c5..08e37ec0c3 100644 --- a/modules/imgcodecs/src/grfmt_png.cpp +++ b/modules/imgcodecs/src/grfmt_png.cpp @@ -274,7 +274,7 @@ bool PngDecoder::readHeader() } // Read PNG header: 137 80 78 71 13 10 26 10 - if (!read_from_io(&sig, 8)) + if (!readFromStreamOrBuffer(&sig, 8)) return false; id = read_chunk(m_chunkIHDR); @@ -682,7 +682,7 @@ void PngDecoder::compose_frame(std::vector& rows_dst, const std::vect }); } -bool PngDecoder::read_from_io(void* buffer, size_t num_bytes) +bool PngDecoder::readFromStreamOrBuffer(void* buffer, size_t num_bytes) { if (m_f) return fread(buffer, 1, num_bytes, m_f) == num_bytes; @@ -700,7 +700,7 @@ bool PngDecoder::read_from_io(void* buffer, size_t num_bytes) uint32_t PngDecoder::read_chunk(Chunk& chunk) { unsigned char size_id[8]; - if (!read_from_io(&size_id, 8)) + if (!readFromStreamOrBuffer(&size_id, 8)) return 0; const size_t size = static_cast(png_get_uint_32(size_id)) + 12; @@ -737,7 +737,7 @@ uint32_t PngDecoder::read_chunk(Chunk& chunk) chunk.p.resize(size); memcpy(chunk.p.data(), size_id, 8); - if (read_from_io(&chunk.p[8], chunk.p.size() - 8)) + if (readFromStreamOrBuffer(&chunk.p[8], chunk.p.size() - 8)) return id; return 0; } @@ -960,15 +960,24 @@ bool PngEncoder::write( const Mat& img, const std::vector& params ) return result; } -size_t PngEncoder::write_to_io(void const* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE * _Stream) +size_t PngEncoder::writeToStreamOrBuffer(void const* buffer, size_t num_bytes, FILE* stream) { - if (_Stream) - return fwrite(_Buffer, _ElementSize, _ElementCount, _Stream); + if (!buffer || !num_bytes) + return 0; // Handle null buffer or empty writes + + if (stream) + { + size_t written = fwrite(buffer, 1, num_bytes, stream); + return written; // fwrite handles the write count + } size_t cursz = m_buf->size(); - m_buf->resize(cursz + _ElementCount); - memcpy( &(*m_buf)[cursz], _Buffer, _ElementCount ); - return _ElementCount; + if (cursz + num_bytes > m_buf->max_size()) + throw std::runtime_error("Buffer size exceeds maximum capacity"); + + m_buf->resize(cursz + num_bytes); + memcpy(&(*m_buf)[cursz], buffer, num_bytes); + return num_bytes; } void PngEncoder::writeChunk(FILE* f, const char* name, unsigned char* data, uint32_t length) @@ -977,26 +986,26 @@ void PngEncoder::writeChunk(FILE* f, const char* name, unsigned char* data, uint uint32_t crc = crc32(0, Z_NULL, 0); png_save_uint_32(buf, length); - write_to_io(buf, 1, 4, f); - write_to_io(name, 1, 4, f); + writeToStreamOrBuffer(buf, 4, f); + writeToStreamOrBuffer(name, 4, f); crc = crc32(crc, (const Bytef*)name, 4); if (memcmp(name, "fdAT", 4) == 0) { png_save_uint_32(buf, next_seq_num++); - write_to_io(buf, 1, 4, f); + writeToStreamOrBuffer(buf, 4, f); crc = crc32(crc, buf, 4); length -= 4; } if (data != NULL && length > 0) { - write_to_io(data, 1, length, f); + writeToStreamOrBuffer(data, length, f); crc = crc32(crc, data, length); } png_save_uint_32(buf, crc); - write_to_io(buf, 1, 4, f); + writeToStreamOrBuffer(buf, 4, f); } void PngEncoder::writeIDATs(FILE* f, int frame, unsigned char* data, uint32_t length, uint32_t idat_size) @@ -1521,7 +1530,7 @@ bool PngEncoder::writeanimation(const Animation& animation, const std::vector& rows_dst, const std::vector& rows_src, unsigned char bop, uint32_t x, uint32_t y, uint32_t w, uint32_t h, Mat& img); - CV_NODISCARD_STD bool read_from_io(void* buffer, size_t num_bytes); + /** + * @brief Reads data from an I/O source into the provided buffer. + * @param buffer Pointer to the buffer where the data will be stored. + * @param num_bytes Number of bytes to read into the buffer. + * @return true if the operation is successful, false otherwise. + */ + CV_NODISCARD_STD bool readFromStreamOrBuffer(void* buffer, size_t num_bytes); uint32_t read_chunk(Chunk& chunk); CV_NODISCARD_STD bool InitPngPtr(); void ClearPngPtr(); @@ -185,7 +191,24 @@ public: protected: static void writeDataToBuf(void* png_ptr, unsigned char* src, size_t size); static void flushBuf(void* png_ptr); - size_t write_to_io(void const* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE* _Stream); + /** + * @brief Writes data to an output destination, either a file stream or an in-memory buffer. + * + * This function handles two output scenarios: + * 1. If a file stream is provided, the data is written to the stream using `fwrite`. + * 2. If `stream` is null, the data is written to an in-memory buffer (`m_buf`), which is resized as needed. + * + * @param buffer Pointer to the data to be written. + * @param num_bytes The number of bytes to be written. + * @param stream Pointer to the file stream for writing. If null, the data is written to the in-memory buffer. + * @return The number of bytes successfully written. + * - For file-based writes, this is the number of bytes written to the stream. + * - For buffer-based writes, this is the total number of bytes added to the buffer. + * + * @throws std::runtime_error If the in-memory buffer (`m_buf`) exceeds its maximum capacity. + * @note If `num_bytes` is 0 or `buffer` is null, the function returns 0. + */ + size_t writeToStreamOrBuffer(void const* buffer, size_t num_bytes, FILE* stream); private: void writeChunk(FILE* f, const char* name, unsigned char* data, uint32_t length);