summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/png.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/png.cpp')
-rw-r--r--src/lib/util/png.cpp710
1 files changed, 381 insertions, 329 deletions
diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp
index 6b13f4f9593..ce28a866604 100644
--- a/src/lib/util/png.cpp
+++ b/src/lib/util/png.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
/*********************************************************************
- png.c
+ png.cpp
PNG reading functions.
@@ -10,40 +10,24 @@
#include "png.h"
+#include "ioprocs.h"
#include "unicode.h"
+#include "osdcomm.h"
+
#include <zlib.h>
#include <algorithm>
#include <cassert>
-#include <cstdint>
-#include <cstring>
+#include <cerrno>
#include <cmath>
+#include <cstdlib>
+#include <cstring>
#include <new>
-
-#include <math.h>
-#include <stdlib.h>
-
-
-
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
-
-static const int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-static inline int compute_rowbytes(const png_info &pnginfo)
-{
- return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8;
-}
+#include <tuple>
+namespace util {
/***************************************************************************
GENERAL FUNCTIONS
@@ -54,7 +38,7 @@ static inline int compute_rowbytes(const png_info &pnginfo)
pnginfo structure
-------------------------------------------------*/
-void png_info::free_data()
+void png_info::free_data() noexcept
{
textlist.clear();
palette.reset();
@@ -66,6 +50,12 @@ void png_info::free_data()
namespace {
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+constexpr int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
+
constexpr std::uint8_t PNG_SIGNATURE[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
#define MNG_Signature "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A"
@@ -101,13 +91,51 @@ constexpr std::uint8_t PNG_PF_Average = 3;
constexpr std::uint8_t PNG_PF_Paeth = 4;
-inline uint8_t fetch_8bit(uint8_t const *v) { return *v; }
-inline uint16_t fetch_16bit(uint8_t const *v) { return big_endianize_int16(*reinterpret_cast<uint16_t const *>(v)); }
-inline uint32_t fetch_32bit(uint8_t const *v) { return big_endianize_int32(*reinterpret_cast<uint32_t const *>(v)); }
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+inline int compute_rowbytes(const png_info &pnginfo) noexcept { return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8; }
+
+inline uint8_t fetch_8bit(uint8_t const *v) noexcept { return *v; }
+inline uint16_t fetch_16bit(uint8_t const *v) noexcept { return big_endianize_int16(*reinterpret_cast<uint16_t const *>(v)); }
+inline uint32_t fetch_32bit(uint8_t const *v) noexcept { return big_endianize_int32(*reinterpret_cast<uint32_t const *>(v)); }
+
+inline void put_8bit(uint8_t *v, uint8_t data) noexcept { *v = data; }
+inline void put_16bit(uint8_t *v, uint16_t data) noexcept { *reinterpret_cast<uint16_t *>(v) = big_endianize_int16(data); }
+inline void put_32bit(uint8_t *v, uint32_t data) noexcept { *reinterpret_cast<uint32_t *>(v) = big_endianize_int32(data); }
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+class png_category_impl : public std::error_category
+{
+public:
+ virtual char const *name() const noexcept override { return "png"; }
+
+ virtual std::string message(int condition) const override
+ {
+ using namespace std::literals;
+ static std::string_view const s_messages[] = {
+ "No error"sv,
+ "Unknown filter algorithm"sv,
+ "Bad file signature"sv,
+ "Decompression error"sv,
+ "Image file truncated"sv,
+ "Image file corrupt"sv,
+ "Unknown chunk type"sv,
+ "Compression error"sv,
+ "Unsupported image format"sv };
+ if ((0 <= condition) && (std::size(s_messages) > condition))
+ return std::string(s_messages[condition]);
+ else
+ return "Unknown error"s;
+ }
+};
-inline void put_8bit(uint8_t *v, uint8_t data) { *v = data; }
-inline void put_16bit(uint8_t *v, uint16_t data) { *reinterpret_cast<uint16_t *>(v) = big_endianize_int16(data); }
-inline void put_32bit(uint8_t *v, uint32_t data) { *reinterpret_cast<uint32_t *>(v) = big_endianize_int32(data); }
+png_category_impl const f_png_category_instance;
class png_private
@@ -122,21 +150,21 @@ private:
struct image_data_chunk
{
- image_data_chunk(std::uint32_t l, std::unique_ptr<std::uint8_t []> &&d) : length(l), data(std::move(d)) { }
+ image_data_chunk(std::uint32_t l, std::unique_ptr<std::uint8_t []> &&d) noexcept : length(l), data(std::move(d)) { }
std::uint32_t length;
std::unique_ptr<std::uint8_t []> data;
};
- png_error process(std::list<image_data_chunk> const &idata)
+ std::error_condition process(std::list<image_data_chunk> const &idata) noexcept
{
// do some basic checks for unsupported images
- if (!pnginfo.bit_depth || (ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour format
+ if (!pnginfo.bit_depth || (std::size(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
+ return png_error::UNSUPPORTED_FORMAT; // unknown colour format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
if ((3 == pnginfo.color_type) && (!pnginfo.num_palette || !pnginfo.palette))
- return PNGERR_FILE_CORRUPT; // indexed colour with no palette
+ return png_error::FILE_CORRUPT; // indexed colour with no palette
// calculate the offset for each pass of the interlace
unsigned const pass_count(get_pass_count());
@@ -145,14 +173,15 @@ private:
pass_offset[pass + 1] = pass_offset[pass] + get_pass_bytes(pass);
// allocate memory for the filtered image
- try { pnginfo.image.reset(new std::uint8_t [pass_offset[pass_count]]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ pnginfo.image.reset(new (std::nothrow) std::uint8_t [pass_offset[pass_count]]);
+ if (!pnginfo.image)
+ return std::errc::not_enough_memory;
// decompress image data
- png_error error = PNGERR_NONE;
+ std::error_condition error;
error = decompress(idata, pass_offset[pass_count]);
std::uint32_t const bpp(get_bytes_per_pixel());
- for (unsigned pass = 0; (pass_count > pass) && (PNGERR_NONE == error); ++pass)
+ for (unsigned pass = 0; (pass_count > pass) && !error; ++pass)
{
// compute some basic parameters
std::pair<std::uint32_t, std::uint32_t> const dimensions(get_pass_dimensions(pass));
@@ -161,7 +190,7 @@ private:
// we de-filter in place, stripping the filter bytes off the rows
uint8_t *dst(&pnginfo.image[pass_offset[pass]]);
uint8_t const *src(dst);
- for (std::uint32_t y = 0; (dimensions.second > y) && (PNGERR_NONE == error); ++y)
+ for (std::uint32_t y = 0; (dimensions.second > y) && !error; ++y)
{
// first byte of each row is the filter type
uint8_t const filter(*src++);
@@ -172,17 +201,17 @@ private:
}
// if we errored, free the image data
- if (error != PNGERR_NONE)
+ if (error)
pnginfo.image.reset();
return error;
}
- png_error decompress(std::list<image_data_chunk> const &idata, std::uint32_t expected)
+ std::error_condition decompress(std::list<image_data_chunk> const &idata, std::uint32_t expected) noexcept
{
// only deflate is permitted
if (0 != pnginfo.compression_method)
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
// allocate zlib stream
z_stream stream;
@@ -194,14 +223,18 @@ private:
stream.avail_in = 0;
stream.next_in = Z_NULL;
zerr = inflateInit(&stream);
- if (Z_OK != zerr)
- return PNGERR_DECOMPRESS_ERROR;
+ if (Z_ERRNO == zerr)
+ return std::error_condition(errno, std::generic_category());
+ else if (Z_MEM_ERROR == zerr)
+ return std::errc::not_enough_memory;
+ else if (Z_OK != zerr)
+ return png_error::DECOMPRESS_ERROR;
// decompress IDAT blocks
stream.next_out = pnginfo.image.get();
stream.avail_out = expected;
stream.avail_in = 0;
- std::list<image_data_chunk>::const_iterator it = idata.begin();
+ auto it = idata.begin();
while ((idata.end() != it) && ((Z_OK == zerr) || (Z_BUF_ERROR == zerr)) && !stream.avail_in)
{
stream.avail_in = it->length;
@@ -217,28 +250,28 @@ private:
// it's all good if we got end-of-stream or we have with no data remaining
if ((Z_OK == inflateEnd(&stream)) && ((Z_STREAM_END == zerr) || ((Z_OK == zerr) && (idata.end() == it) && !stream.avail_in)))
- return PNGERR_NONE;
+ return std::error_condition();
else
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR; // TODO: refactor this function for more fine-grained error reporting?
}
- png_error unfilter_row(std::uint8_t type, uint8_t const *src, uint8_t *dst, uint8_t const *dstprev, int bpp, std::uint32_t rowbytes)
+ std::error_condition unfilter_row(std::uint8_t type, uint8_t const *src, uint8_t *dst, uint8_t const *dstprev, int bpp, std::uint32_t rowbytes) noexcept
{
if (0 != pnginfo.filter_method)
- return PNGERR_UNKNOWN_FILTER;
+ return png_error::UNKNOWN_FILTER;
switch (type)
{
case PNG_PF_None: // no filter, just copy
std::copy_n(src, rowbytes, dst);
- return PNGERR_NONE;
+ return std::error_condition();
case PNG_PF_Sub: // SUB = previous pixel
dst = std::copy_n(src, bpp, dst);
src += bpp;
for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst)
*dst = *src + dst[-bpp];
- return PNGERR_NONE;
+ return std::error_condition();
case PNG_PF_Up: // UP = pixel above
if (dstprev)
@@ -250,7 +283,7 @@ private:
{
std::copy_n(src, rowbytes, dst);
}
- return PNGERR_NONE;
+ return std::error_condition();
case PNG_PF_Average: // AVERAGE = average of pixel above and previous pixel
if (dstprev)
@@ -267,7 +300,7 @@ private:
for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst)
*dst = *src + (dst[-bpp] >> 1);
}
- return PNGERR_NONE;
+ return std::error_condition();
case PNG_PF_Paeth: // PAETH = special filter
for (std::uint32_t x = 0; rowbytes > x; ++x, ++src, ++dst)
@@ -281,20 +314,20 @@ private:
int32_t const dc(std::abs(prediction - pc));
*dst = ((da <= db) && (da <= dc)) ? (*src + pa) : (db <= dc) ? (*src + pb) : (*src + pc);
}
- return PNGERR_NONE;
+ return std::error_condition();
default: // unknown filter type
- return PNGERR_UNKNOWN_FILTER;
+ return png_error::UNKNOWN_FILTER;
}
}
- png_error process_chunk(std::list<image_data_chunk> &idata, std::unique_ptr<std::uint8_t []> &&data, uint32_t type, uint32_t length)
+ std::error_condition process_chunk(std::list<image_data_chunk> &idata, std::unique_ptr<std::uint8_t []> &&data, uint32_t type, uint32_t length) noexcept
{
switch (type)
{
case PNG_CN_IHDR: // image header
if (13 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.width = fetch_32bit(&data[0]);
pnginfo.height = fetch_32bit(&data[4]);
pnginfo.bit_depth = fetch_8bit(&data[8]);
@@ -307,31 +340,31 @@ private:
case PNG_CN_PLTE: // palette
pnginfo.num_palette = length / 3;
if ((length % 3) || ((3 == pnginfo.color_type) && ((1 << pnginfo.bit_depth) < pnginfo.num_palette)))
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.palette = std::move(data);
break;
case PNG_CN_tRNS: // transparency information
if (((0 == pnginfo.color_type) && (2 > length)) || ((2 == pnginfo.color_type) && (6 > length)))
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.num_trans = length;
pnginfo.trans = std::move(data);
break;
case PNG_CN_IDAT: // image data
try { idata.emplace_back(length, std::move(data)); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return std::errc::not_enough_memory; }
break;
case PNG_CN_gAMA: // gamma
if (4 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.source_gamma = fetch_32bit(data.get()) / 100000.0;
break;
case PNG_CN_pHYs: // physical information
if (9 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.xres = fetch_32bit(&data[0]);
pnginfo.yres = fetch_32bit(&data[4]);
pnginfo.resolution_unit = fetch_8bit(&data[8]);
@@ -361,25 +394,25 @@ private:
}
catch (std::bad_alloc const &)
{
- return PNGERR_OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
break;
/* anything else */
default:
if ((type & 0x20000000) == 0)
- return PNGERR_UNKNOWN_CHUNK;
+ return png_error::UNKNOWN_CHUNK;
break;
}
- return PNGERR_NONE;
+ return std::error_condition();
}
- unsigned get_pass_count() const
+ unsigned get_pass_count() const noexcept
{
return (1 == pnginfo.interlace_method) ? 7 : 1;
}
- std::pair<uint32_t, uint32_t> get_pass_dimensions(unsigned pass) const
+ std::pair<uint32_t, uint32_t> get_pass_dimensions(unsigned pass) const noexcept
{
if (0 == pnginfo.interlace_method)
return std::make_pair(pnginfo.width, pnginfo.height);
@@ -387,110 +420,130 @@ private:
return std::make_pair((pnginfo.width + ADAM7_X_BIAS[pass]) >> ADAM7_X_SHIFT[pass], (pnginfo.height + ADAM7_Y_BIAS[pass]) >> ADAM7_Y_SHIFT[pass]);
}
- std::uint32_t get_pass_bytes(unsigned pass) const
+ std::uint32_t get_pass_bytes(unsigned pass) const noexcept
{
return get_pass_bytes(pass, pnginfo.bit_depth);
}
- std::uint32_t get_pass_bytes(unsigned pass, uint8_t bit_depth) const
+ std::uint32_t get_pass_bytes(unsigned pass, uint8_t bit_depth) const noexcept
{
std::pair<std::uint32_t, std::uint32_t> const dimensions(get_pass_dimensions(pass));
return (get_row_bytes(dimensions.first, bit_depth) + 1) * dimensions.second;
}
- std::uint32_t get_row_bytes(std::uint32_t width) const
+ std::uint32_t get_row_bytes(std::uint32_t width) const noexcept
{
return get_row_bytes(width, pnginfo.bit_depth);
}
- std::uint32_t get_row_bytes(std::uint32_t width, uint8_t bit_depth) const
+ std::uint32_t get_row_bytes(std::uint32_t width, uint8_t bit_depth) const noexcept
{
return ((width * samples[pnginfo.color_type] * bit_depth) + 7) >> 3;
}
- std::uint32_t get_bytes_per_pixel() const
+ std::uint32_t get_bytes_per_pixel() const noexcept
{
return ((samples[pnginfo.color_type] * pnginfo.bit_depth) + 7) >> 3;
}
- static png_error read_chunk(util::core_file &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length)
+ static std::error_condition read_chunk(read_stream &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length) noexcept
{
+ std::error_condition err;
+ std::size_t actual;
std::uint8_t tempbuff[4];
- /* fetch the length of this chunk */
- if (fp.read(tempbuff, 4) != 4)
- return PNGERR_FILE_TRUNCATED;
+ // fetch the length of this chunk
+ std::tie(err, actual) = read(fp, tempbuff, 4);
+ if (err)
+ return err;
+ else if (4 != actual)
+ return png_error::FILE_TRUNCATED;
length = fetch_32bit(tempbuff);
- /* fetch the type of this chunk */
- if (fp.read(tempbuff, 4) != 4)
- return PNGERR_FILE_TRUNCATED;
+ // fetch the type of this chunk
+ std::tie(err, actual) = read(fp, tempbuff, 4);
+ if (err)
+ return err;
+ else if (4 != actual)
+ return png_error::FILE_TRUNCATED;
type = fetch_32bit(tempbuff);
- /* stop when we hit an IEND chunk */
+ // stop when we hit an IEND chunk
if (type == PNG_CN_IEND)
- return PNGERR_NONE;
+ return std::error_condition();
- /* start the CRC with the chunk type (but not the length) */
+ // start the CRC with the chunk type (but not the length)
std::uint32_t crc = crc32(0, tempbuff, 4);
- /* read the chunk itself into an allocated memory buffer */
+ // read the chunk itself into an allocated memory buffer
if (length)
{
- /* allocate memory for this chunk */
- try { data.reset(new std::uint8_t [length]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
-
- /* read the data from the file */
- if (fp.read(data.get(), length) != length)
+ // allocate memory and read the data from the file
+ std::tie(err, data, actual) = read(fp, length);
+ if (err)
{
data.reset();
- return PNGERR_FILE_TRUNCATED;
+ return err;
+ }
+ else if (length != actual)
+ {
+ data.reset();
+ return png_error::FILE_TRUNCATED;
}
- /* update the CRC */
+ // update the CRC
crc = crc32(crc, data.get(), length);
}
- /* read the CRC */
- if (fp.read(tempbuff, 4) != 4)
+ // read the CRC
+ std::tie(err, actual) = read(fp, tempbuff, 4);
+ if (err)
{
data.reset();
- return PNGERR_FILE_TRUNCATED;
+ return err;
+ }
+ else if (4 != actual)
+ {
+ data.reset();
+ return png_error::FILE_TRUNCATED;
}
std::uint32_t const chunk_crc = fetch_32bit(tempbuff);
- /* validate the CRC */
+ // validate the CRC
if (crc != chunk_crc)
{
data.reset();
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
}
- return PNGERR_NONE;
+ return std::error_condition();
}
png_info & pnginfo;
public:
- png_private(png_info &info) : pnginfo(info)
+ png_private(png_info &info) noexcept : pnginfo(info)
{
}
- png_error copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha) const
+ std::error_condition copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha) const noexcept
{
// do some basic checks for unsupported images
if ((8 > pnginfo.bit_depth) || (pnginfo.bit_depth % 8))
- return PNGERR_UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
- if ((ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour sample format
+ return png_error::UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
+ if ((std::size(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
+ return png_error::UNSUPPORTED_FORMAT; // unknown colour sample format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
if ((3 == pnginfo.color_type) && (8 != pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
+ return png_error::UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
- // everything looks sane, allocate the bitmap and deinterlace into it
+ // try to allocate the bitmap
bitmap.allocate(pnginfo.width, pnginfo.height);
+ if (!bitmap.valid())
+ return std::errc::not_enough_memory;
+
+ // everything looks sane, deinterlace into the bitmap
std::uint8_t accumalpha(0xff);
uint32_t const bps(pnginfo.bit_depth >> 3);
uint32_t const bpp(bps * samples[pnginfo.color_type]);
@@ -519,7 +572,7 @@ public:
accumalpha &= alpha;
std::uint16_t const paloffs(std::uint16_t(*src) * 3);
rgb_t const pix(alpha, pnginfo.palette[paloffs], pnginfo.palette[paloffs + 1], pnginfo.palette[paloffs + 2]);
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
@@ -537,7 +590,7 @@ public:
std::uint8_t const a_val((pnginfo.trans && (transpen == i_val)) ? 0x00 : 0xff);
i_val >>= samp_shift;
accumalpha &= a_val;
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, i_val, i_val, i_val);
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, i_val, i_val, i_val);
}
}
}
@@ -552,7 +605,7 @@ public:
{
accumalpha &= src[a];
rgb_t const pix(src[a], src[i], src[i], src[i]);
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
@@ -578,7 +631,7 @@ public:
g_val >>= samp_shift;
b_val >>= samp_shift;
accumalpha &= a_val;
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, r_val, g_val, b_val);
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, r_val, g_val, b_val);
}
}
}
@@ -595,7 +648,7 @@ public:
{
accumalpha &= src[a];
rgb_t const pix(src[a], src[r], src[g], src[b]);
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
@@ -603,22 +656,22 @@ public:
// set hasalpha flag and return
hasalpha = 0xffU != accumalpha;
- return PNGERR_NONE;
+ return std::error_condition();
}
- png_error expand_buffer_8bit()
+ std::error_condition expand_buffer_8bit() noexcept
{
// nothing to do if we're at 8 or greater already
if (pnginfo.bit_depth >= 8)
- return PNGERR_NONE;
+ return std::error_condition();
// do some basic checks for unsupported images
if (!pnginfo.bit_depth || (8 % pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
+ return png_error::UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
if ((0 != pnginfo.color_type) && (3 != pnginfo.color_type))
- return PNGERR_UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
+ return png_error::UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
// calculate the offset for each pass of the interlace on the input and output
unsigned const pass_count(get_pass_count());
@@ -631,9 +684,9 @@ public:
}
// allocate a new buffer at 8-bit
- std::unique_ptr<std::uint8_t []> outbuf;
- try { outbuf.reset(new std::uint8_t [outp_offset[pass_count]]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ std::unique_ptr<std::uint8_t []> outbuf(new (std::nothrow) std::uint8_t [outp_offset[pass_count]]);
+ if (!outbuf)
+ return std::errc::not_enough_memory;
// upsample bitmap
std::uint8_t const bytesamples(8 / pnginfo.bit_depth);
@@ -687,13 +740,13 @@ public:
pnginfo.image = std::move(outbuf);
pnginfo.bit_depth = 8;
- return PNGERR_NONE;
+ return std::error_condition();
}
- png_error read_file(util::core_file &fp)
+ std::error_condition read_file(read_stream &fp) noexcept
{
// initialize the data structures
- png_error error = PNGERR_NONE;
+ std::error_condition error;
pnginfo.reset();
std::list<image_data_chunk> idata;
@@ -701,13 +754,13 @@ public:
error = verify_header(fp);
// loop until we hit an IEND chunk
- while (PNGERR_NONE == error)
+ while (!error)
{
// read a chunk
std::unique_ptr<std::uint8_t []> chunk_data;
std::uint32_t chunk_type = 0, chunk_length;
error = read_chunk(fp, chunk_data, chunk_type, chunk_length);
- if (PNGERR_NONE == error)
+ if (!error)
{
if (chunk_type == PNG_CN_IEND)
break; // stop when we hit an IEND chunk
@@ -717,29 +770,32 @@ public:
}
// finish processing the image
- if (PNGERR_NONE == error)
+ if (!error)
error = process(idata);
// if we have an error, free all the output data
- if (error != PNGERR_NONE)
+ if (error)
pnginfo.reset();
return error;
}
- static png_error verify_header(util::core_file &fp)
+ static std::error_condition verify_header(read_stream &fp) noexcept
{
- EQUIVALENT_ARRAY(PNG_SIGNATURE, std::uint8_t) signature;
+ std::uint8_t signature[sizeof(PNG_SIGNATURE)];
// read 8 bytes
- if (fp.read(signature, sizeof(signature)) != sizeof(signature))
- return PNGERR_FILE_TRUNCATED;
+ auto const [err, actual] = read(fp, signature, sizeof(signature));
+ if (err)
+ return err;
+ else if (sizeof(signature) != actual)
+ return png_error::FILE_TRUNCATED;
// return an error if we don't match
if (std::memcmp(signature, PNG_SIGNATURE, sizeof(PNG_SIGNATURE)))
- return PNGERR_BAD_SIGNATURE;
+ return png_error::BAD_SIGNATURE;
- return PNGERR_NONE;
+ return std::error_condition();
}
};
@@ -760,7 +816,7 @@ constexpr unsigned png_private::ADAM7_Y_OFFS[7];
core stream
-------------------------------------------------*/
-png_error png_info::verify_header(util::core_file &fp)
+std::error_condition png_info::verify_header(read_stream &fp) noexcept
{
return png_private::verify_header(fp);
}
@@ -770,7 +826,7 @@ png_error png_info::verify_header(util::core_file &fp)
read_file - read a PNG from a core stream
-------------------------------------------------*/
-png_error png_info::read_file(util::core_file &fp)
+std::error_condition png_info::read_file(read_stream &fp) noexcept
{
return png_private(*this).read_file(fp);
}
@@ -781,20 +837,20 @@ png_error png_info::read_file(util::core_file &fp)
bitmap
-------------------------------------------------*/
-png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
+std::error_condition png_read_bitmap(read_stream &fp, bitmap_argb32 &bitmap) noexcept
{
- png_error result;
+ std::error_condition result;
png_info pnginfo;
png_private png(pnginfo);
// read the PNG data
result = png.read_file(fp);
- if (PNGERR_NONE != result)
+ if (result)
return result;
// resample to 8bpp if necessary
result = png.expand_buffer_8bit();
- if (PNGERR_NONE != result)
+ if (result)
{
pnginfo.free_data();
return result;
@@ -811,7 +867,7 @@ png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
bitmap
-------------------------------------------------*/
-png_error png_info::copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha)
+std::error_condition png_info::copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha) noexcept
{
return png_private(*this).copy_to_bitmap(bitmap, hasalpha);
}
@@ -822,7 +878,7 @@ png_error png_info::copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha)
sub 8-bit to 8-bit
-------------------------------------------------*/
-png_error png_info::expand_buffer_8bit()
+std::error_condition png_info::expand_buffer_8bit() noexcept
{
return png_private(*this).expand_buffer_8bit();
}
@@ -837,40 +893,38 @@ png_error png_info::expand_buffer_8bit()
add_text - add a text entry to the png_info
-------------------------------------------------*/
-png_error png_info::add_text(const char *keyword, const char *text)
+std::error_condition png_info::add_text(std::string_view keyword, std::string_view text) noexcept
{
// apply rules to keyword
char32_t prev(0);
std::size_t cnt(0);
- char const *const kwend(keyword + std::strlen(keyword));
- for (char const *ptr = keyword; kwend > ptr; )
+ for (std::string_view kw = keyword; !kw.empty(); )
{
char32_t ch;
- int const len(uchar_from_utf8(&ch, ptr, kwend - ptr));
- if ((0 >= len) || (32 > ch) || (255 < ch) || ((126 < ch) && (161 > ch)) || (((32 == prev) || (keyword == ptr)) && (32 == ch)))
- return PNGERR_UNSUPPORTED_FORMAT;
+ int const len(uchar_from_utf8(&ch, kw));
+ if ((0 >= len) || (32 > ch) || (255 < ch) || ((126 < ch) && (161 > ch)) || (((32 == prev) || (0 == cnt)) && (32 == ch)))
+ return png_error::UNSUPPORTED_FORMAT;
prev = ch;
++cnt;
- ptr += len;
+ kw.remove_prefix(len);
}
if ((32 == prev) || (1 > cnt) || (79 < cnt))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
// apply rules to text
- char const *const textend(text + std::strlen(text));
- for (char const *ptr = text; textend > ptr; )
+ for (std::string_view tx = text; !tx.empty(); )
{
char32_t ch;
- int const len(uchar_from_utf8(&ch, ptr, textend - ptr));
+ int const len(uchar_from_utf8(&ch, tx));
if ((0 >= len) || (1 > ch) || (255 < ch))
- return PNGERR_UNSUPPORTED_FORMAT;
- ptr += len;
+ return png_error::UNSUPPORTED_FORMAT;
+ tx.remove_prefix(len);
}
// allocate a new text element
- try { textlist.emplace_back(std::piecewise_construct, std::forward_as_tuple(keyword, kwend), std::forward_as_tuple(text, textend)); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
- return PNGERR_NONE;
+ try { textlist.emplace_back(std::piecewise_construct, std::forward_as_tuple(keyword), std::forward_as_tuple(text)); }
+ catch (std::bad_alloc const &) { return std::errc::not_enough_memory; }
+ return std::error_condition();
}
@@ -879,34 +933,38 @@ png_error png_info::add_text(const char *keyword, const char *text)
the given file
-------------------------------------------------*/
-static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t type, uint32_t length)
+static std::error_condition write_chunk(write_stream &fp, const uint8_t *data, uint32_t type, uint32_t length) noexcept
{
- uint8_t tempbuff[8];
- uint32_t crc;
+ std::error_condition err;
+ std::uint8_t tempbuff[8];
+ std::uint32_t crc;
- /* stuff the length/type into the buffer */
+ // stuff the length/type into the buffer
put_32bit(tempbuff + 0, length);
put_32bit(tempbuff + 4, type);
crc = crc32(0, tempbuff + 4, 4);
- /* write that data */
- if (fp.write(tempbuff, 8) != 8)
- return PNGERR_FILE_ERROR;
+ // write that data
+ std::tie(err, std::ignore) = write(fp, tempbuff, 8);
+ if (err)
+ return err;
- /* append the actual data */
+ // append the actual data
if (length > 0)
{
- if (fp.write(data, length) != length)
- return PNGERR_FILE_ERROR;
+ std::tie(err, std::ignore) = write(fp, data, length);
+ if (err)
+ return err;
crc = crc32(crc, data, length);
}
- /* write the CRC */
+ // write the CRC
put_32bit(tempbuff, crc);
- if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ std::tie(err, std::ignore) = write(fp, tempbuff, 4);
+ if (err)
+ return err;
- return PNGERR_NONE;
+ return std::error_condition();
}
@@ -915,33 +973,43 @@ static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t
chunk to the given file by deflating it
-------------------------------------------------*/
-static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32_t type, uint32_t length)
+static std::error_condition write_deflated_chunk(random_write &fp, uint8_t *data, uint32_t type, uint32_t length) noexcept
{
- uint64_t lengthpos = fp.tell();
- uint8_t tempbuff[8192];
- uint32_t zlength = 0;
+ std::error_condition err;
+ std::uint64_t lengthpos;
+ err = fp.tell(lengthpos);
+ if (err)
+ return err;
+
+ std::uint8_t tempbuff[8192];
+ std::uint32_t zlength = 0;
z_stream stream;
- uint32_t crc;
+ std::uint32_t crc;
int zerr;
- /* stuff the length/type into the buffer */
+ // stuff the length/type into the buffer
put_32bit(tempbuff + 0, length);
put_32bit(tempbuff + 4, type);
crc = crc32(0, tempbuff + 4, 4);
- /* write that data */
- if (fp.write(tempbuff, 8) != 8)
- return PNGERR_FILE_ERROR;
+ // write that data
+ std::tie(err, std::ignore) = write(fp, tempbuff, 8);
+ if (err)
+ return err;
- /* initialize the stream */
+ // initialize the stream
memset(&stream, 0, sizeof(stream));
stream.next_in = data;
stream.avail_in = length;
zerr = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
- if (zerr != Z_OK)
- return PNGERR_COMPRESS_ERROR;
-
- /* now loop until we run out of data */
+ if (Z_ERRNO == zerr)
+ return std::error_condition(errno, std::generic_category());
+ else if (Z_MEM_ERROR == zerr)
+ return std::errc::not_enough_memory;
+ else if (Z_OK != zerr)
+ return png_error::COMPRESS_ERROR;
+
+ // now loop until we run out of data
for ( ; ; )
{
/* compress this chunk */
@@ -949,50 +1017,63 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
stream.avail_out = sizeof(tempbuff);
zerr = deflate(&stream, Z_FINISH);
- /* if there's data to write, do it */
+ // if there's data to write, do it
if (stream.avail_out < sizeof(tempbuff))
{
int bytes = sizeof(tempbuff) - stream.avail_out;
- if (fp.write(tempbuff, bytes) != bytes)
+ std::tie(err, std::ignore) = write(fp, tempbuff, bytes);
+ if (err)
{
deflateEnd(&stream);
- return PNGERR_FILE_ERROR;
+ return err;
}
crc = crc32(crc, tempbuff, bytes);
zlength += bytes;
}
- /* stop at the end of the stream */
+ // stop at the end of the stream
if (zerr == Z_STREAM_END)
break;
- /* other errors are fatal */
+ // other errors are fatal
if (zerr != Z_OK)
{
deflateEnd(&stream);
- return PNGERR_COMPRESS_ERROR;
+ if (Z_ERRNO == zerr)
+ return std::error_condition(errno, std::generic_category());
+ else if (Z_MEM_ERROR == zerr)
+ return std::errc::not_enough_memory;
+ else
+ return png_error::COMPRESS_ERROR;
}
}
- /* clean up deflater(maus) */
+ // clean up deflater
zerr = deflateEnd(&stream);
- if (zerr != Z_OK)
- return PNGERR_COMPRESS_ERROR;
-
- /* write the CRC */
+ if (Z_ERRNO == zerr)
+ return std::error_condition(errno, std::generic_category());
+ else if (Z_MEM_ERROR == zerr)
+ return std::errc::not_enough_memory;
+ else if (Z_OK != zerr)
+ return png_error::COMPRESS_ERROR;
+
+ // write the CRC
put_32bit(tempbuff, crc);
- if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
-
- /* seek back and update the length */
- fp.seek(lengthpos, SEEK_SET);
+ std::tie(err, std::ignore) = write(fp, tempbuff, 4);
+ if (err)
+ return err;
+
+ // seek back and update the length
+ err = fp.seek(lengthpos, SEEK_SET);
+ if (err)
+ return err;
put_32bit(tempbuff + 0, zlength);
- if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ std::tie(err, std::ignore) = write(fp, tempbuff, 4);
+ if (err)
+ return err;
- /* return to the end */
- fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET);
- return PNGERR_NONE;
+ // return to the end
+ return fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET);
}
@@ -1001,26 +1082,24 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
bitmap to a palettized image
-------------------------------------------------*/
-static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+static std::error_condition convert_bitmap_to_image_palette(png_info &pnginfo, bitmap_t const &bitmap, int palette_length, const rgb_t *palette) noexcept
{
- int rowbytes;
- int x, y;
-
- /* set the common info */
+ // set the common info
pnginfo.width = bitmap.width();
pnginfo.height = bitmap.height();
pnginfo.bit_depth = 8;
pnginfo.color_type = 3;
pnginfo.num_palette = 256;
- rowbytes = pnginfo.width;
+ int const rowbytes = pnginfo.width;
- /* allocate memory for the palette */
- try { pnginfo.palette.reset(new std::uint8_t [3 * 256]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ // allocate memory for the palette
+ pnginfo.palette.reset(new (std::nothrow) std::uint8_t [3 * 256]);
+ if (!pnginfo.palette)
+ return std::errc::not_enough_memory;
- /* build the palette */
+ // build the palette
std::fill_n(pnginfo.palette.get(), 3 * 256, 0);
- for (x = 0; x < palette_length; x++)
+ for (int x = 0; x < palette_length; x++)
{
rgb_t color = palette[x];
pnginfo.palette[3 * x + 0] = color.r();
@@ -1028,30 +1107,27 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
pnginfo.palette[3 * x + 2] = color.b();
}
- /* allocate memory for the image */
- try
- {
- pnginfo.image.reset(new std::uint8_t [pnginfo.height * (rowbytes + 1)]);
- }
- catch (std::bad_alloc const &)
+ // allocate memory for the image
+ pnginfo.image.reset(new (std::nothrow) std::uint8_t [pnginfo.height * (rowbytes + 1)]);
+ if (!pnginfo.image)
{
pnginfo.palette.reset();
- return PNGERR_OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
- /* copy in the pixels, specifying a nullptr filter */
- for (y = 0; y < pnginfo.height; y++)
+ // copy in the pixels, specifying a nullptr filter
+ for (int y = 0; y < pnginfo.height; y++)
{
- uint16_t *src = reinterpret_cast<uint16_t *>(bitmap.raw_pixptr(y));
+ uint16_t const *src = reinterpret_cast<uint16_t const *>(bitmap.raw_pixptr(y));
uint8_t *dst = &pnginfo.image[y * (rowbytes + 1)];
- /* store the filter byte, then copy the data */
+ // store the filter byte, then copy the data
*dst++ = 0;
- for (x = 0; x < pnginfo.width; x++)
+ for (int x = 0; x < pnginfo.width; x++)
*dst++ = *src++;
}
- return PNGERR_NONE;
+ return std::error_condition();
}
@@ -1060,77 +1136,75 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
bitmap to an RGB image
-------------------------------------------------*/
-static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+static std::error_condition convert_bitmap_to_image_rgb(png_info &pnginfo, bitmap_t const &bitmap, int palette_length, const rgb_t *palette) noexcept
{
- int alpha = (bitmap.format() == BITMAP_FORMAT_ARGB32);
- int rowbytes;
- int x, y;
+ bool const alpha = (bitmap.format() == BITMAP_FORMAT_ARGB32);
- /* set the common info */
+ // set the common info
pnginfo.width = bitmap.width();
pnginfo.height = bitmap.height();
pnginfo.bit_depth = 8;
pnginfo.color_type = alpha ? 6 : 2;
- rowbytes = pnginfo.width * (alpha ? 4 : 3);
+ int const rowbytes = pnginfo.width * (alpha ? 4 : 3);
- /* allocate memory for the image */
- try { pnginfo.image.reset(new std::uint8_t [pnginfo.height * (rowbytes + 1)]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ // allocate memory for the image
+ pnginfo.image.reset(new (std::nothrow) std::uint8_t [pnginfo.height * (rowbytes + 1)]);
+ if (!pnginfo.image)
+ return std::errc::not_enough_memory;
- /* copy in the pixels, specifying a nullptr filter */
- for (y = 0; y < pnginfo.height; y++)
+ // copy in the pixels, specifying a nullptr filter
+ for (int y = 0; y < pnginfo.height; y++)
{
uint8_t *dst = &pnginfo.image[y * (rowbytes + 1)];
- /* store the filter byte, then copy the data */
+ // store the filter byte, then copy the data
*dst++ = 0;
- /* 16bpp palettized format */
if (bitmap.format() == BITMAP_FORMAT_IND16)
{
- uint16_t *src16 = reinterpret_cast<uint16_t *>(bitmap.raw_pixptr(y));
- for (x = 0; x < pnginfo.width; x++)
+ // 16bpp palettized format
+ uint16_t const *src16 = reinterpret_cast<uint16_t const *>(bitmap.raw_pixptr(y));
+ for (int x = 0; x < pnginfo.width; x++)
{
- rgb_t color = palette[*src16++];
+ rgb_t const color = palette[*src16++];
*dst++ = color.r();
*dst++ = color.g();
*dst++ = color.b();
}
}
-
- /* 32-bit RGB direct */
else if (bitmap.format() == BITMAP_FORMAT_RGB32)
{
- uint32_t *src32 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y));
- for (x = 0; x < pnginfo.width; x++)
+ // 32-bit RGB direct
+ uint32_t const *src32 = reinterpret_cast<uint32_t const *>(bitmap.raw_pixptr(y));
+ for (int x = 0; x < pnginfo.width; x++)
{
- rgb_t raw = *src32++;
+ rgb_t const raw = *src32++;
*dst++ = raw.r();
*dst++ = raw.g();
*dst++ = raw.b();
}
}
-
- /* 32-bit ARGB direct */
else if (bitmap.format() == BITMAP_FORMAT_ARGB32)
{
- uint32_t *src32 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y));
- for (x = 0; x < pnginfo.width; x++)
+ // 32-bit ARGB direct
+ uint32_t const *src32 = reinterpret_cast<uint32_t const *>(bitmap.raw_pixptr(y));
+ for (int x = 0; x < pnginfo.width; x++)
{
- rgb_t raw = *src32++;
+ rgb_t const raw = *src32++;
*dst++ = raw.r();
*dst++ = raw.g();
*dst++ = raw.b();
*dst++ = raw.a();
}
}
-
- /* unsupported format */
else
- return PNGERR_UNSUPPORTED_FORMAT;
+ {
+ // unsupported format
+ return png_error::UNSUPPORTED_FORMAT;
+ }
}
- return PNGERR_NONE;
+ return std::error_condition();
}
@@ -1139,17 +1213,17 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
chunks to the given file
-------------------------------------------------*/
-static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+static std::error_condition write_png_stream(random_write &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette) noexcept
{
uint8_t tempbuff[16];
- png_error error;
+ std::error_condition error;
// create an unfiltered image in either palette or RGB form
if (bitmap.format() == BITMAP_FORMAT_IND16 && palette_length <= 256)
error = convert_bitmap_to_image_palette(pnginfo, bitmap, palette_length, palette);
else
error = convert_bitmap_to_image_rgb(pnginfo, bitmap, palette_length, palette);
- if (error != PNGERR_NONE)
+ if (error)
return error;
// if we wanted to get clever and do filtering, we would do it here
@@ -1163,18 +1237,18 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
put_8bit(tempbuff + 11, pnginfo.filter_method);
put_8bit(tempbuff + 12, pnginfo.interlace_method);
error = write_chunk(fp, tempbuff, PNG_CN_IHDR, 13);
- if (error != PNGERR_NONE)
+ if (error)
return error;
// write the PLTE chunk
if (pnginfo.num_palette > 0)
error = write_chunk(fp, pnginfo.palette.get(), PNG_CN_PLTE, pnginfo.num_palette * 3);
- if (error != PNGERR_NONE)
+ if (error)
return error;
- // write a single IDAT chunk */
+ // write a single IDAT chunk
error = write_deflated_chunk(fp, pnginfo.image.get(), PNG_CN_IDAT, pnginfo.height * (compute_rowbytes(pnginfo) + 1));
- if (error != PNGERR_NONE)
+ if (error)
return error;
// write TEXT chunks
@@ -1182,38 +1256,36 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
for (png_info::png_text const &text : pnginfo.textlist)
{
try { textbuf.resize(text.first.length() + 1 + text.second.length()); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return std::errc::not_enough_memory; }
std::uint8_t *dst(&textbuf[0]);
// convert keyword to ISO-8859-1
- char const *const kwend(text.first.c_str() + text.first.length());
- for (char const *src = text.first.c_str(); kwend > src; ++dst)
+ for (std::string_view src = text.first; !src.empty(); ++dst)
{
char32_t ch;
- int const len(uchar_from_utf8(&ch, src, kwend - src));
+ int const len(uchar_from_utf8(&ch, src));
if (0 >= len)
break;
*dst = std::uint8_t(ch);
- src += len;
+ src.remove_prefix(len);
}
- // NUL separator between keword and text
+ // NUL separator between keyword and text
*dst++ = 0;
// convert text to ISO-8859-1
- char const *const textend(text.second.c_str() + text.second.length());
- for (char const *src = text.second.c_str(); textend > src; ++dst)
+ for (std::string_view src = text.second; !src.empty(); ++dst)
{
char32_t ch;
- int const len(uchar_from_utf8(&ch, src, textend - src));
+ int const len(uchar_from_utf8(&ch, src));
if (0 >= len)
break;
*dst = std::uint8_t(ch);
- src += len;
+ src.remove_prefix(len);
}
error = write_chunk(fp, &textbuf[0], PNG_CN_tEXt, dst - &textbuf[0]);
- if (error != PNGERR_NONE)
+ if (error)
return error;
}
@@ -1222,18 +1294,19 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
}
-png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
+std::error_condition png_write_bitmap(random_write &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette) noexcept
{
// use a dummy pnginfo if none passed to us
png_info pnginfo;
- if (info == nullptr)
+ if (!info)
info = &pnginfo;
// write the PNG signature
- if (fp.write(PNG_SIGNATURE, sizeof(PNG_SIGNATURE)) != sizeof(PNG_SIGNATURE))
- return PNGERR_FILE_ERROR;
+ auto const [err, written] = write(fp, PNG_SIGNATURE, sizeof(PNG_SIGNATURE));
+ if (err)
+ return err;
- /* write the rest of the PNG data */
+ // write the rest of the PNG data
return write_png_stream(fp, *info, bitmap, palette_length, palette);
}
@@ -1245,25 +1318,13 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
********************************************************************************/
-/**
- * @fn png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, double rate)
- *
- * @brief Mng capture start.
- *
- * @param [in,out] fp If non-null, the fp.
- * @param [in,out] bitmap The bitmap.
- * @param rate The rate.
- *
- * @return A png_error.
- */
-
-png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, double rate)
+std::error_condition mng_capture_start(random_write &fp, bitmap_t const &bitmap, unsigned rate) noexcept
{
- uint8_t mhdr[28];
-
- if (fp.write(MNG_Signature, 8) != 8)
- return PNGERR_FILE_ERROR;
+ auto const [err, written] = write(fp, MNG_Signature, 8);
+ if (err)
+ return err;
+ uint8_t mhdr[28];
memset(mhdr, 0, 28);
put_32bit(mhdr + 0, bitmap.width());
put_32bit(mhdr + 4, bitmap.height());
@@ -1272,36 +1333,27 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, double rate)
return write_chunk(fp, mhdr, MNG_CN_MHDR, 28);
}
-/**
- * @fn png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
- *
- * @brief Mng capture frame.
- *
- * @param [in,out] fp If non-null, the fp.
- * @param [in,out] info If non-null, the information.
- * @param [in,out] bitmap The bitmap.
- * @param palette_length Length of the palette.
- * @param palette The palette.
- *
- * @return A png_error.
- */
-
-png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
+
+std::error_condition mng_capture_frame(random_write &fp, png_info &info, bitmap_t const &bitmap, int palette_length, rgb_t const *palette) noexcept
{
return write_png_stream(fp, info, bitmap, palette_length, palette);
}
-/**
- * @fn png_error mng_capture_stop(util::core_file &fp)
- *
- * @brief Mng capture stop.
- *
- * @param [in,out] fp If non-null, the fp.
- *
- * @return A png_error.
- */
-
-png_error mng_capture_stop(util::core_file &fp)
+
+std::error_condition mng_capture_stop(random_write &fp) noexcept
{
return write_chunk(fp, nullptr, MNG_CN_MEND, 0);
}
+
+
+/*-------------------------------------------------
+ png_category - gets the PNG error category
+ instance
+-------------------------------------------------*/
+
+std::error_category const &png_category() noexcept
+{
+ return f_png_category_instance;
+}
+
+} // namespace util