diff options
Diffstat (limited to 'src/lib/util')
-rw-r--r-- | src/lib/util/avhuff.cpp | 23 | ||||
-rw-r--r-- | src/lib/util/avhuff.h | 64 | ||||
-rw-r--r-- | src/lib/util/aviio.cpp | 16 | ||||
-rw-r--r-- | src/lib/util/bitmap.cpp | 104 | ||||
-rw-r--r-- | src/lib/util/bitmap.h | 79 | ||||
-rw-r--r-- | src/lib/util/chdcodec.cpp | 2 | ||||
-rw-r--r-- | src/lib/util/corealloc.h | 40 | ||||
-rw-r--r-- | src/lib/util/coretmpl.h | 6 | ||||
-rw-r--r-- | src/lib/util/msdib.cpp | 642 | ||||
-rw-r--r-- | src/lib/util/msdib.h | 46 | ||||
-rw-r--r-- | src/lib/util/nanosvg.cpp | 6 | ||||
-rw-r--r-- | src/lib/util/nanosvg.h | 33 | ||||
-rw-r--r-- | src/lib/util/png.cpp | 271 | ||||
-rw-r--r-- | src/lib/util/png.h | 42 | ||||
-rw-r--r-- | src/lib/util/xmlfile.cpp | 9 |
15 files changed, 1017 insertions, 366 deletions
diff --git a/src/lib/util/avhuff.cpp b/src/lib/util/avhuff.cpp index 50eea9f24dc..ac5cea71526 100644 --- a/src/lib/util/avhuff.cpp +++ b/src/lib/util/avhuff.cpp @@ -691,24 +691,19 @@ avhuff_decoder::avhuff_decoder() } /** - * @fn void avhuff_decoder::configure(const avhuff_decompress_config &config) + * @fn void avhuff_decoder::configure(const config &cfg) * * @brief ------------------------------------------------- * configure - configure decompression parameters * -------------------------------------------------. * - * @param config The configuration. + * @param cfg The configuration. */ -void avhuff_decoder::configure(const avhuff_decompress_config &config) +void avhuff_decoder::configure(const config &cfg) { - m_config.video.wrap(config.video, config.video.cliprect()); - m_config.maxsamples = config.maxsamples; - m_config.actsamples = config.actsamples; - memcpy(m_config.audio, config.audio, sizeof(m_config.audio)); - m_config.maxmetalength = config.maxmetalength; - m_config.actmetalength = config.actmetalength; - m_config.metadata = config.metadata; + m_video.wrap(*cfg.video, cfg.video->cliprect()); + m_config = cfg; } /** @@ -792,9 +787,9 @@ avhuff_error avhuff_decoder::decode_data(const uint8_t *source, uint32_t complen // determine the start of each piece of data metastart = m_config.metadata; for (int chnum = 0; chnum < channels; chnum++) - audiostart[chnum] = (uint8_t *)m_config.audio[chnum]; - videostart = (m_config.video.valid()) ? reinterpret_cast<uint8_t *>(&m_config.video.pix(0)) : nullptr; - videostride = (m_config.video.valid()) ? m_config.video.rowpixels() * 2 : 0; + audiostart[chnum] = reinterpret_cast<uint8_t *>(m_config.audio[chnum]); + videostart = m_video.valid() ? reinterpret_cast<uint8_t *>(&m_video.pix(0)) : nullptr; + videostride = m_video.valid() ? m_video.rowpixels() * 2 : 0; // data is assumed to be native-endian uint16_t betest = 0; @@ -802,7 +797,7 @@ avhuff_error avhuff_decoder::decode_data(const uint8_t *source, uint32_t complen audioxor = videoxor = (betest == 1) ? 1 : 0; // verify against sizes - if (m_config.video.valid() && (m_config.video.width() < width || m_config.video.height() < height)) + if (m_video.valid() && (m_video.width() < width || m_video.height() < height)) return AVHERR_VIDEO_TOO_LARGE; for (int chnum = 0; chnum < channels; chnum++) if (m_config.audio[chnum] != nullptr && m_config.maxsamples < samples) diff --git a/src/lib/util/avhuff.h b/src/lib/util/avhuff.h index 90ef43e977f..83b46195d6b 100644 --- a/src/lib/util/avhuff.h +++ b/src/lib/util/avhuff.h @@ -19,6 +19,8 @@ #include "huffman.h" #include "flac.h" +#include <algorithm> + //************************************************************************** // CONSTANTS @@ -49,32 +51,6 @@ enum avhuff_error // TYPE DEFINITIONS //************************************************************************** -// ======================> av_codec_decompress_config - -// decompression configuration -class avhuff_decompress_config -{ -public: - avhuff_decompress_config() - : maxsamples(0), - actsamples(nullptr), - maxmetalength(0), - actmetalength(nullptr), - metadata(nullptr) - { - memset(audio, 0, sizeof(audio)); - } - - bitmap_yuy16 video; // pointer to video bitmap - uint32_t maxsamples; // maximum number of samples per channel - uint32_t * actsamples; // actual number of samples per channel - int16_t * audio[16]; // pointer to individual audio channels - uint32_t maxmetalength; // maximum length of metadata - uint32_t * actmetalength; // actual length of metadata - uint8_t * metadata; // pointer to metadata buffer -}; - - // ======================> avhuff_encoder // core state for the codec @@ -98,8 +74,7 @@ private: { public: // construction/destruction - deltarle_encoder() - : m_rlecount(0) { } + deltarle_encoder() { } // histogramming uint16_t *rle_and_histo_bitmap(const uint8_t *source, uint32_t items_per_row, uint32_t item_advance, uint32_t row_count); @@ -111,7 +86,7 @@ private: private: // internal state - int m_rlecount; + int m_rlecount = 0; huffman_encoder<256 + 16> m_encoder; std::vector<uint16_t> m_rlebuffer; }; @@ -143,11 +118,30 @@ private: class avhuff_decoder { public: + // decompression configuration + class config + { + public: + config() + { + std::fill(std::begin(audio), std::end(audio), nullptr); + } + + bitmap_yuy16 * video = nullptr; // pointer to video bitmap + uint32_t maxsamples = 0; // maximum number of samples per channel + uint32_t * actsamples = nullptr; // actual number of samples per channel + int16_t * audio[16]; // pointer to individual audio channels + uint32_t maxmetalength = 0; // maximum length of metadata + uint32_t * actmetalength = nullptr; // actual length of metadata + uint8_t * metadata = nullptr; // pointer to metadata buffer + }; + + // construction/destruction avhuff_decoder(); // configuration - void configure(const avhuff_decompress_config &config); + void configure(const config &cfg); // encode/decode avhuff_error decode_data(const uint8_t *source, uint32_t complength, uint8_t *dest); @@ -158,8 +152,7 @@ private: { public: // construction/destruction - deltarle_decoder() - : m_rlecount(0), m_prevdata(0) { } + deltarle_decoder() { } // general void reset() { m_rlecount = m_prevdata = 0; } @@ -171,8 +164,8 @@ private: private: // internal state - int m_rlecount; - uint8_t m_prevdata; + int m_rlecount = 0; + uint8_t m_prevdata = 0; huffman_decoder<256 + 16> m_decoder; }; @@ -183,7 +176,8 @@ private: avhuff_error decode_video_lossless(int width, int height, const uint8_t *source, uint32_t complength, uint8_t *dest, uint32_t dstride, uint32_t dxor); // internal state - avhuff_decompress_config m_config; + bitmap_yuy16 m_video; + config m_config; // video decoding contexts deltarle_decoder m_ycontext; diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp index 8722017d3e8..7f74920f06b 100644 --- a/src/lib/util/aviio.cpp +++ b/src/lib/util/aviio.cpp @@ -999,7 +999,7 @@ avi_file::error avi_stream::rgb32_compress_to_rgb(const bitmap_rgb32 &bitmap, st /* compressed video */ for (y = 0; y < height; y++) { - const std::uint32_t *source = &bitmap.pix32(y); + const std::uint32_t *source = &bitmap.pix(y); std::uint8_t *dest = data + (m_height - 1 - y) * m_width * 3; for (x = 0; x < width && dest < dataend; x++) @@ -1062,7 +1062,7 @@ avi_file::error avi_stream::yuv_decompress_to_yuy16(const std::uint8_t *data, st for (y = 0; y < m_height; y++) { const std::uint16_t *source = reinterpret_cast<const std::uint16_t *>(data) + y * m_width; - std::uint16_t *dest = &bitmap.pix16(y); + std::uint16_t *dest = &bitmap.pix(y); /* switch off the compression */ switch (m_format) @@ -1113,7 +1113,7 @@ avi_file::error avi_stream::yuy16_compress_to_yuy(const bitmap_yuy16 &bitmap, st /* compressed video */ for (y = 0; y < m_height; y++) { - const std::uint16_t *source = &bitmap.pix16(y); + const std::uint16_t *source = &bitmap.pix(y); std::uint16_t *dest = reinterpret_cast<std::uint16_t *>(data) + y * m_width; /* switch off the compression */ @@ -1298,7 +1298,7 @@ avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data /* compressed video */ for (y = 0; y < m_height; y++) { - std::uint16_t *dest = &bitmap.pix16(y); + std::uint16_t *dest = &bitmap.pix(y); /* handle the first four bytes independently */ x = 0; @@ -1386,8 +1386,8 @@ avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data lastprevy = lastprevcb = lastprevcr = 0; for (y = 0; y < m_height; y++) { - std::uint16_t *prevrow = &bitmap.pix16(y - prevlines); - std::uint16_t *dest = &bitmap.pix16(y); + std::uint16_t *prevrow = &bitmap.pix(y - prevlines); + std::uint16_t *dest = &bitmap.pix(y); /* handle the first four bytes independently */ x = 0; @@ -1500,7 +1500,7 @@ avi_file::error avi_stream::uncompressed_rgb24_to_argb32(const std::uint8_t *dat /* uncompressed video */ for (int y = 0; y < m_height; y++) { - std::uint32_t *dest = &bitmap.pix32(y); + std::uint32_t *dest = &bitmap.pix(y); /* loop over pixels */ for (int x = 0; x < m_width; x++) @@ -1530,7 +1530,7 @@ avi_file::error avi_stream::uncompressed_yuv420p_to_argb32(const std::uint8_t *d /* uncompressed video */ for (int y = 0; y < m_height; y++) { - std::uint32_t *dest = &bitmap.pix32(y); + std::uint32_t *dest = &bitmap.pix(y); /* loop over pixels */ for (int x = 0; x < m_width; x++) diff --git a/src/lib/util/bitmap.cpp b/src/lib/util/bitmap.cpp index ed814aae218..fc05b89f1b6 100644 --- a/src/lib/util/bitmap.cpp +++ b/src/lib/util/bitmap.cpp @@ -8,14 +8,12 @@ ***************************************************************************/ -#include <cassert> - #include "bitmap.h" +#include <cassert> #include <new> - //************************************************************************** // INLINE HELPERS //************************************************************************** @@ -361,7 +359,7 @@ void bitmap_t::wrap(void *base, int width, int height, int rowpixels) * @param subrect The subrect. */ -void bitmap_t::wrap(const bitmap_t &source, const rectangle &subrect) +void bitmap_t::wrap(bitmap_t &source, const rectangle &subrect) { assert(m_format == source.m_format); assert(m_bpp == source.m_bpp); @@ -407,7 +405,7 @@ void bitmap_t::set_palette(palette_t *palette) } /** - * @fn void bitmap_t::fill(uint32_t color, const rectangle &cliprect) + * @fn void bitmap_t::fill(uint64_t color, const rectangle &bounds) * * @brief ------------------------------------------------- * fill -- fill a bitmap with a solid color @@ -417,93 +415,45 @@ void bitmap_t::set_palette(palette_t *palette) * @param cliprect The cliprect. */ -void bitmap_t::fill(uint32_t color, const rectangle &cliprect) +void bitmap_t::fill(uint64_t color, const rectangle &bounds) { // if we have a cliprect, intersect with that - rectangle fill = cliprect; + rectangle fill(bounds); fill &= m_cliprect; - if (fill.empty()) - return; - - // based on the bpp go from there - switch (m_bpp) + if (!fill.empty()) { + // based on the bpp go from there + switch (m_bpp) + { case 8: - // 8bpp always uses memset for (int32_t y = fill.top(); y <= fill.bottom(); y++) - memset(raw_pixptr(y, fill.left()), uint8_t(color), fill.width()); + std::fill_n(&pixt<uint8_t>(y, fill.left()), fill.width(), uint8_t(color)); break; case 16: - // 16bpp can use memset if the bytes are equal - if (uint8_t(color >> 8) == uint8_t(color)) - { - for (int32_t y = fill.top(); y <= fill.bottom(); y++) - memset(raw_pixptr(y, fill.left()), uint8_t(color), fill.width() * 2); - } - else - { - // Fill the first line the hard way - uint16_t *destrow = &pixt<uint16_t>(fill.top()); - for (int32_t x = fill.left(); x <= fill.right(); x++) - destrow[x] = uint16_t(color); - - // For the other lines, just copy the first one - void *destrow0 = &pixt<uint16_t>(fill.top(), fill.left()); - for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++) - { - destrow = &pixt<uint16_t>(y, fill.left()); - memcpy(destrow, destrow0, fill.width() * 2); - } - } + for (int32_t y = fill.top(); y <= fill.bottom(); ++y) + std::fill_n(&pixt<uint16_t>(y, fill.left()), fill.width(), uint16_t(color)); break; case 32: - // 32bpp can use memset if the bytes are equal - if ((uint8_t)(color >> 8) == (uint8_t)color && (uint16_t)(color >> 16) == (uint16_t)color) - { - for (int32_t y = fill.top(); y <= fill.bottom(); y++) - memset(&pixt<uint32_t>(y, fill.left()), uint8_t(color), fill.width() * 4); - } - else - { - // Fill the first line the hard way - uint32_t *destrow = &pixt<uint32_t>(fill.top()); - for (int32_t x = fill.left(); x <= fill.right(); x++) - destrow[x] = uint32_t(color); - - // For the other lines, just copy the first one - uint32_t *destrow0 = &pixt<uint32_t>(fill.top(), fill.left()); - for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++) - { - destrow = &pixt<uint32_t>(y, fill.left()); - memcpy(destrow, destrow0, fill.width() * 4); - } - } + for (int32_t y = fill.top(); y <= fill.bottom(); ++y) + std::fill_n(&pixt<uint32_t>(y, fill.left()), fill.width(), uint32_t(color)); break; case 64: - // 64bpp can use memset if the bytes are equal - if (uint8_t(color >> 8) == uint8_t(color) && uint16_t(color >> 16) == uint16_t(color)) // FIXME: really? wat about the upper bits that would be zeroed when done the "hard way"? - { - for (int32_t y = fill.top(); y <= fill.bottom(); y++) - memset(&pixt<uint64_t>(y, fill.left()), uint8_t(color), fill.width() * 8); - } - else - { - // Fill the first line the hard way - uint64_t *destrow = &pixt<uint64_t>(fill.top()); - for (int32_t x = fill.left(); x <= fill.right(); x++) - destrow[x] = uint64_t(color); - - // For the other lines, just copy the first one - uint64_t *destrow0 = &pixt<uint64_t>(fill.top(), fill.left()); - for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++) - { - destrow = &pixt<uint64_t>(y, fill.left()); - memcpy(destrow, destrow0, fill.width() * 8); - } - } + for (int32_t y = fill.top(); y <= fill.bottom(); ++y) + std::fill_n(&pixt<uint64_t>(y, fill.left()), fill.width(), uint64_t(color)); break; + } } } + + +//************************************************************************** +// EXPLICIT TEMPLATE INSTANTIATIONS +//************************************************************************** + +template class bitmap_specific<uint8_t>; +template class bitmap_specific<uint16_t>; +template class bitmap_specific<uint32_t>; +template class bitmap_specific<uint64_t>; diff --git a/src/lib/util/bitmap.h b/src/lib/util/bitmap.h index ed6a5382a61..57ed0bc1775 100644 --- a/src/lib/util/bitmap.h +++ b/src/lib/util/bitmap.h @@ -16,6 +16,9 @@ #include "osdcore.h" #include "palette.h" +#include <algorithm> +#include <memory> + //************************************************************************** // TYPE DEFINITIONS @@ -151,23 +154,23 @@ public: // operations void set_palette(palette_t *palette); - void fill(uint32_t color) { fill(color, m_cliprect); } - void fill(uint32_t color, const rectangle &cliprect); - void plot_box(int x, int y, int width, int height, uint32_t color) + void fill(uint64_t color) { fill(color, m_cliprect); } + void fill(uint64_t color, const rectangle &bounds); + void plot_box(int32_t x, int32_t y, int32_t width, int32_t height, uint64_t color) { - rectangle clip(x, x + width - 1, y, y + height - 1); - fill(color, clip); + fill(color, rectangle(x, x + width - 1, y, y + height - 1)); } // pixel access - template<typename PixelType> - PixelType &pixt(int32_t y, int32_t x = 0) const { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); } - void *raw_pixptr(int32_t y, int32_t x = 0) const { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; } + void *raw_pixptr(int32_t y, int32_t x = 0) { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; } + void const *raw_pixptr(int32_t y, int32_t x = 0) const { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; } protected: // for use by subclasses only to ensure type correctness + template <typename PixelType> PixelType &pixt(int32_t y, int32_t x = 0) { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); } + template <typename PixelType> PixelType const &pixt(int32_t y, int32_t x = 0) const { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); } void wrap(void *base, int width, int height, int rowpixels); - void wrap(const bitmap_t &source, const rectangle &subrect); + void wrap(bitmap_t &source, const rectangle &subrect); private: // internal helpers @@ -191,17 +194,17 @@ private: // ======================> bitmap_specific, bitmap8_t, bitmap16_t, bitmap32_t, bitmap64_t -template<typename PixelType> +template <typename PixelType> class bitmap_specific : public bitmap_t { - static constexpr int PixelBits = 8 * sizeof(PixelType); + static constexpr int PIXEL_BITS = 8 * sizeof(PixelType); protected: // construction/destruction -- subclasses only bitmap_specific(bitmap_specific<PixelType> &&) = default; - bitmap_specific(bitmap_format format, int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap_t(format, PixelBits, width, height, xslop, yslop) { } - bitmap_specific(bitmap_format format, PixelType *base, int width, int height, int rowpixels) : bitmap_t(format, PixelBits, base, width, height, rowpixels) { } - bitmap_specific(bitmap_format format, bitmap_specific<PixelType> &source, const rectangle &subrect) : bitmap_t(format, PixelBits, source, subrect) { } + bitmap_specific(bitmap_format format, int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap_t(format, PIXEL_BITS, width, height, xslop, yslop) { } + bitmap_specific(bitmap_format format, PixelType *base, int width, int height, int rowpixels) : bitmap_t(format, PIXEL_BITS, base, width, height, rowpixels) { } + bitmap_specific(bitmap_format format, bitmap_specific<PixelType> &source, const rectangle &subrect) : bitmap_t(format, PIXEL_BITS, source, subrect) { } bitmap_specific<PixelType> &operator=(bitmap_specific<PixelType> &&) = default; @@ -209,27 +212,46 @@ public: using pixel_t = PixelType; // getters - uint8_t bpp() const { return PixelBits; } + uint8_t bpp() const { return PIXEL_BITS; } // pixel accessors - PixelType &pix(int32_t y, int32_t x = 0) const { return pixt<PixelType>(y, x); } - PixelType &pix8(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 8, "must be 8bpp"); return pixt<PixelType>(y, x); } - PixelType &pix16(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 16, "must be 16bpp"); return pixt<PixelType>(y, x); } - PixelType &pix32(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 32, "must be 32bpp"); return pixt<PixelType>(y, x); } - PixelType &pix64(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 64, "must be 64bpp"); return pixt<PixelType>(y, x); } + PixelType &pix(int32_t y, int32_t x = 0) { return pixt<PixelType>(y, x); } + PixelType const &pix(int32_t y, int32_t x = 0) const { return pixt<PixelType>(y, x); } + + // operations + void fill(PixelType color) { fill(color, cliprect()); } + void fill(PixelType color, const rectangle &bounds) + { + // if we have a cliprect, intersect with that + rectangle fill(bounds); + fill &= cliprect(); + if (!fill.empty()) + { + for (int32_t y = fill.top(); y <= fill.bottom(); y++) + std::fill_n(&pix(y, fill.left()), fill.width(), color); + } + } + void plot_box(int32_t x, int32_t y, int32_t width, int32_t height, PixelType color) + { + fill(color, rectangle(x, x + width - 1, y, y + height - 1)); + } }; // 8bpp bitmaps using bitmap8_t = bitmap_specific<uint8_t>; +extern template class bitmap_specific<uint8_t>; // 16bpp bitmaps using bitmap16_t = bitmap_specific<uint16_t>; +extern template class bitmap_specific<uint16_t>; // 32bpp bitmaps using bitmap32_t = bitmap_specific<uint32_t>; +extern template class bitmap_specific<uint32_t>; // 64bpp bitmaps using bitmap64_t = bitmap_specific<uint64_t>; +extern template class bitmap_specific<uint64_t>; // ======================> bitmap_ind8, bitmap_ind16, bitmap_ind32, bitmap_ind64 @@ -246,7 +268,7 @@ public: bitmap_ind8(uint8_t *base, int width, int height, int rowpixels) : bitmap8_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_ind8(bitmap_ind8 &source, const rectangle &subrect) : bitmap8_t(k_bitmap_format, source, subrect) { } void wrap(uint8_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -266,7 +288,7 @@ public: bitmap_ind16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_ind16(bitmap_ind16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { } void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -286,7 +308,7 @@ public: bitmap_ind32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_ind32(bitmap_ind32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { } void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -306,7 +328,7 @@ public: bitmap_ind64(uint64_t *base, int width, int height, int rowpixels) : bitmap64_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_ind64(bitmap_ind64 &source, const rectangle &subrect) : bitmap64_t(k_bitmap_format, source, subrect) { } void wrap(uint64_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -329,7 +351,7 @@ public: bitmap_yuy16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_yuy16(bitmap_yuy16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { } void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -349,7 +371,7 @@ public: bitmap_rgb32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_rgb32(bitmap_rgb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { } void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -369,7 +391,7 @@ public: bitmap_argb32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { } bitmap_argb32(bitmap_argb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { } void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); } - void wrap(const bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); } + void wrap(bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); } // getters bitmap_format format() const { return k_bitmap_format; } @@ -377,5 +399,4 @@ public: bitmap_argb32 &operator=(bitmap_argb32 &&) = default; }; - -#endif // MAME_UTIL_BITMAP_H +#endif // MAME_UTIL_BITMAP_H diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp index 58f7b4291db..7f6e0f018cd 100644 --- a/src/lib/util/chdcodec.cpp +++ b/src/lib/util/chdcodec.cpp @@ -1786,7 +1786,7 @@ void chd_avhuff_decompressor::configure(int param, void *config) { // if we're getting the decompression configuration, apply it now if (param == AVHUFF_CODEC_DECOMPRESS_CONFIG) - m_decoder.configure(*reinterpret_cast<avhuff_decompress_config *>(config)); + m_decoder.configure(*reinterpret_cast<avhuff_decoder::config const *>(config)); // anything else is invalid else diff --git a/src/lib/util/corealloc.h b/src/lib/util/corealloc.h index 5d1f055e19b..db8aacf6cb2 100644 --- a/src/lib/util/corealloc.h +++ b/src/lib/util/corealloc.h @@ -8,54 +8,24 @@ ***************************************************************************/ -#pragma once - #ifndef MAME_LIB_UTIL_COREALLOC_H #define MAME_LIB_UTIL_COREALLOC_H -#include "osdcore.h" +#pragma once -#include <cstdlib> +#include "osdcore.h" #include <cstddef> +#include <cstdlib> #include <cstring> -#include <new> #include <memory> +#include <new> #include <type_traits> #include <utility> -//************************************************************************** -// MACROS -//************************************************************************** - -// global allocation helpers -- use these instead of new and delete -#define global_alloc(Type) new Type -#define global_alloc_array(Type, Num) new Type[Num] -#define global_free(Ptr) do { delete Ptr; } while (0) -#define global_free_array(Ptr) do { delete[] Ptr; } while (0) - - - -template<typename T, typename... Params> -inline T* global_alloc_clear(Params &&... args) -{ - void *const ptr = ::operator new(sizeof(T)); // allocate memory - std::memset(ptr, 0, sizeof(T)); - return new(ptr) T(std::forward<Params>(args)...); -} - -template<typename T> -inline T* global_alloc_array_clear(std::size_t num) -{ - auto const size = sizeof(T) * num; - void *const ptr = new unsigned char[size]; // allocate memory - std::memset(ptr, 0, size); - return new(ptr) T[num](); -} - - +// global allocation helpers template<typename Tp> struct MakeUniqClearT { typedef std::unique_ptr<Tp> single_object; }; diff --git a/src/lib/util/coretmpl.h b/src/lib/util/coretmpl.h index 95d8230f565..a06c4fb8a46 100644 --- a/src/lib/util/coretmpl.h +++ b/src/lib/util/coretmpl.h @@ -202,7 +202,7 @@ public: if (m_tail == &toreplace) m_tail = &object; object.m_next = toreplace.m_next; - global_free(&toreplace); + delete &toreplace; return object; } return append(object); @@ -253,7 +253,7 @@ public: // remove the given object and free its memory void remove(ElementType &object) noexcept { - global_free(&detach(object)); + delete &detach(object); } // find an object by index in the list @@ -305,7 +305,7 @@ public: { ItemType *result = m_freelist.detach_head(); if (result == nullptr) - result = global_alloc(ItemType); + result = new ItemType; return result; } diff --git a/src/lib/util/msdib.cpp b/src/lib/util/msdib.cpp new file mode 100644 index 00000000000..a1ae5eaddf0 --- /dev/null +++ b/src/lib/util/msdib.cpp @@ -0,0 +1,642 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + msdib.h + + Microsoft Device-Independent Bitmap file loading. + +***************************************************************************/ + +#include "msdib.h" + +#include "eminline.h" + +#include <cassert> +#include <cstdlib> +#include <cstring> + + +#define LOG_GENERAL (1U << 0) +#define LOG_DIB (1U << 1) + +//#define VERBOSE (LOG_GENERAL | LOG_DIB) + +#define LOG_OUTPUT_FUNC osd_printf_verbose + +#ifndef VERBOSE +#define VERBOSE 0 +#endif + +#define LOGMASKED(mask, ...) do { if (VERBOSE & (mask)) (LOG_OUTPUT_FUNC)(__VA_ARGS__); } while (false) + +#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__) + + +namespace util { + +namespace { + +// DIB compression schemes +enum : std::uint32_t +{ + DIB_COMP_NONE = 0, + DIB_COMP_RLE8 = 1, + DIB_COMP_RLE4 = 2, + DIB_COMP_BITFIELDS = 3 +}; + + +// file header doesn't use natural alignment +using bitmap_file_header = std::uint8_t [14]; + + +// old-style DIB header +struct bitmap_core_header +{ + std::uint32_t size; // size of the header (12, 16 or 64) + std::int16_t width; // width of bitmap in pixels + std::int16_t height; // height of the image in pixels + std::uint16_t planes; // number of colour planes (must be 1) + std::uint16_t bpp; // bits per pixel +}; + +// new-style DIB header +struct bitmap_info_header +{ + std::uint32_t size; // size of the header + std::int32_t width; // width of bitmap in pixels + std::int32_t height; // height of bitmap in pixels + std::uint16_t planes; // number of colour planes (must be 1) + std::uint16_t bpp; // bits per pixel + std::uint32_t comp; // compression method + std::uint32_t rawsize; // size of bitmap data after decompression or 0 if uncompressed + std::int32_t hres; // horizontal resolution in pixels/metre + std::int32_t vres; // horizontal resolution in pixels/metre + std::uint32_t colors; // number of colours or 0 for 1 << bpp + std::uint32_t important; // number of important colours or 0 if all important + std::uint32_t red; // red field mask - must be contiguous + std::uint32_t green; // green field mask - must be contiguous + std::uint32_t blue; // blue field mask - must be contiguous + std::uint32_t alpha; // alpha field mask - must be contiguous +}; + + +union bitmap_headers +{ + bitmap_core_header core; + bitmap_info_header info; +}; + + +bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits) +{ + shift = count_leading_zeros(mask); + mask <<= shift; + bits = count_leading_ones(mask); + mask <<= shift; + shift = 32 - shift - bits; + return !mask; +} + + +void dib_truncate_channel(unsigned &shift, unsigned &bits) +{ + if (8U < bits) + { + unsigned const excess(bits - 8); + shift += excess; + bits -= excess; + } +} + + +uint8_t dib_splat_sample(uint8_t val, unsigned bits) +{ + assert(8U >= bits); + for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1) + val |= val >> bits; + return val; +} + + +msdib_error dib_read_file_header(core_file &fp, std::uint32_t &filelen) +{ + // the bitmap file header doesn't use natural alignment + bitmap_file_header file_header; + if (fp.read(file_header, sizeof(file_header)) != sizeof(file_header)) + { + LOG("Error reading DIB file header\n"); + return msdib_error::FILE_TRUNCATED; + } + + // only support Windows bitmaps for now + if ((0x42 != file_header[0]) || (0x4d != file_header[1])) + return msdib_error::BAD_SIGNATURE; + + // do a very basic check on the file length + std::uint32_t const file_length( + (std::uint32_t(file_header[2]) << 0) | + (std::uint32_t(file_header[3]) << 8) | + (std::uint32_t(file_header[4]) << 16) | + (std::uint32_t(file_header[5]) << 24)); + if ((sizeof(file_header) + sizeof(bitmap_core_header)) > file_length) + return msdib_error::FILE_CORRUPT; + + // check that the offset to the pixel data looks half sane + std::uint32_t const pixel_offset( + (std::uint32_t(file_header[10]) << 0) | + (std::uint32_t(file_header[11]) << 8) | + (std::uint32_t(file_header[12]) << 16) | + (std::uint32_t(file_header[13]) << 24)); + if (((sizeof(file_header) + sizeof(bitmap_core_header)) > pixel_offset) || (file_length < pixel_offset)) + return msdib_error::FILE_CORRUPT; + + // looks OK enough + filelen = file_length; + return msdib_error::NONE; +} + + +msdib_error dib_read_bitmap_header( + core_file &fp, + bitmap_headers &header, + unsigned &palette_bytes, + bool &indexed, + std::size_t &palette_entries, + std::size_t &palette_size, + std::size_t &row_bytes, + std::uint32_t length) +{ + // check that these things haven't been padded somehow + static_assert(sizeof(bitmap_core_header) == 12U, "compiler has applied padding to bitmap_core_header"); + static_assert(sizeof(bitmap_info_header) == 56U, "compiler has applied padding to bitmap_info_header"); + + // ensure the header fits in the space for the image data + assert(&header.core.size == &header.info.size); + if (sizeof(header.core) > length) + return msdib_error::FILE_TRUNCATED; + std::memset(&header, 0, sizeof(header)); + if (fp.read(&header.core.size, sizeof(header.core.size)) != sizeof(header.core.size)) + { + LOG("Error reading DIB header size (length %u)\n", length); + return msdib_error::FILE_TRUNCATED; + } + header.core.size = little_endianize_int32(header.core.size); + if (length < header.core.size) + { + LOG("DIB image data (%u bytes) is too small for DIB header (%u bytes)\n", length, header.core.size); + return msdib_error::FILE_CORRUPT; + } + + // identify and read the header - convert OS/2 headers to Windows 3 format + palette_bytes = 4U; + switch (header.core.size) + { + case 16U: + case 64U: + // extended OS/2 bitmap header with support for compression + LOG( + "DIB image data (%u bytes) uses unsupported OS/2 DIB header (size %u)\n", + length, + header.core.size); + return msdib_error::UNSUPPORTED_FORMAT; + + case 12U: + // introduced in OS/2 and Windows 2.0 + { + palette_bytes = 3U; + std::uint32_t const header_read(std::min<std::uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size)); + if (fp.read(&header.core.width, header_read) != header_read) + { + LOG("Error reading DIB core header from image data (%u bytes)\n", length); + return msdib_error::FILE_TRUNCATED; + } + fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR); + header.core.width = little_endianize_int16(header.core.width); + header.core.height = little_endianize_int16(header.core.height); + header.core.planes = little_endianize_int16(header.core.planes); + header.core.bpp = little_endianize_int16(header.core.bpp); + LOGMASKED( + LOG_DIB, + "Read DIB core header from image data : %d*%d, %u planes, %u bpp\n", + header.core.width, + header.core.height, + header.core.planes, + header.core.bpp); + + // this works because the core header only aliases the width/height of the info header + header.info.bpp = header.core.bpp; + header.info.planes = header.core.planes; + header.info.height = header.core.height; + header.info.width = header.core.width; + header.info.size = 40U; + } + break; + + default: + // the next version will be longer + if (124U >= header.core.size) + { + LOG( + "DIB image data (%u bytes) uses unsupported DIB header format (size %u)\n", + length, + header.core.size); + return msdib_error::UNSUPPORTED_FORMAT; + } + // fall through + case 40U: + case 52U: + case 56U: + case 108U: + case 124U: + // the Windows 3 bitmap header with optional extensions + { + palette_bytes = 4U; + std::uint32_t const header_read(std::min<std::uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size)); + if (fp.read(&header.info.width, header_read) != header_read) + { + LOG("Error reading DIB info header from image data (%u bytes)\n", length); + return msdib_error::FILE_TRUNCATED; + } + fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR); + header.info.width = little_endianize_int32(header.info.width); + header.info.height = little_endianize_int32(header.info.height); + header.info.planes = little_endianize_int16(header.info.planes); + header.info.bpp = little_endianize_int16(header.info.bpp); + header.info.comp = little_endianize_int32(header.info.comp); + header.info.rawsize = little_endianize_int32(header.info.rawsize); + header.info.hres = little_endianize_int32(header.info.hres); + header.info.vres = little_endianize_int32(header.info.vres); + header.info.colors = little_endianize_int32(header.info.colors); + header.info.important = little_endianize_int32(header.info.important); + header.info.red = little_endianize_int32(header.info.red); + header.info.green = little_endianize_int32(header.info.green); + header.info.blue = little_endianize_int32(header.info.blue); + header.info.alpha = little_endianize_int32(header.info.alpha); + LOGMASKED( + LOG_DIB, + "Read DIB info header from image data: %d*%d (%d*%d ppm), %u planes, %u bpp %u/%s%u colors\n", + header.info.width, + header.info.height, + header.info.hres, + header.info.vres, + header.info.planes, + header.info.bpp, + header.info.important, + header.info.colors ? "" : "2^", + header.info.colors ? header.info.colors : header.info.bpp); + } + break; + } + + // check for unsupported planes/bit depth + if ((1U != header.info.planes) || !header.info.bpp || (32U < header.info.bpp) || ((8U < header.info.bpp) ? (header.info.bpp % 8) : (8 % header.info.bpp))) + { + LOG("DIB image data uses unsupported planes/bits per pixel %u*%u\n", header.info.planes, header.info.bpp); + return msdib_error::UNSUPPORTED_FORMAT; + } + + // check dimensions + if ((0 >= header.info.width) || (0 == header.info.height)) + { + LOG("DIB image data has invalid dimensions %u*%u\n", header.info.width, header.info.height); + return msdib_error::FILE_CORRUPT; + } + + // ensure compression scheme is supported + bool no_palette(false); + indexed = true; + switch (header.info.comp) + { + case DIB_COMP_NONE: + // uncompressed - direct colour with implied bitfields if more than eight bits/pixel + indexed = 8U >= header.info.bpp; + if (indexed) + { + if ((1U << header.info.bpp) < header.info.colors) + { + osd_printf_verbose( + "DIB image data has oversized palette with %u entries for %u bits per pixel\n", + header.info.colors, + header.info.bpp); + } + } + if (!indexed) + { + no_palette = true; + switch(header.info.bpp) + { + case 16U: + header.info.red = 0x00007c00; + header.info.green = 0x000003e0; + header.info.blue = 0x0000001f; + header.info.alpha = 0x00000000; + break; + case 24U: + case 32U: + header.info.red = 0x00ff0000; + header.info.green = 0x0000ff00; + header.info.blue = 0x000000ff; + header.info.alpha = 0x00000000; + break; + } + } + break; + + case DIB_COMP_BITFIELDS: + // uncompressed direct colour with explicitly-specified bitfields + indexed = false; + if (offsetof(bitmap_info_header, alpha) > header.info.size) + { + osd_printf_verbose( + "DIB image data specifies bit masks but is too small (size %u)\n", + header.info.size); + return msdib_error::FILE_CORRUPT; + } + break; + + default: + LOG("DIB image data uses unsupported compression scheme %u\n", header.info.comp); + return msdib_error::UNSUPPORTED_FORMAT; + } + + // we can now calculate the size of the palette and row data + palette_entries = + indexed + ? ((1U == header.info.bpp) ? 2U : header.info.colors ? header.info.colors : (1U << header.info.bpp)) + : (no_palette ? 0U : header.info.colors); + palette_size = palette_bytes * palette_entries; + row_bytes = ((31 + (header.info.width * header.info.bpp)) >> 5) << 2; + + // header looks OK + return msdib_error::NONE; +} + +} // anonymous namespace + + + +msdib_error msdib_verify_header(core_file &fp) +{ + msdib_error err; + + // file header + std::uint32_t file_length; + err = dib_read_file_header(fp, file_length); + if (msdib_error::NONE != err) + return err; + + // bitmap header + bitmap_headers header; + unsigned palette_bytes; + bool indexed; + std::size_t palette_entries, palette_size, row_bytes; + err = dib_read_bitmap_header( + fp, + header, + palette_bytes, + indexed, + palette_entries, + palette_size, + row_bytes, + file_length - sizeof(bitmap_file_header)); + if (msdib_error::NONE != err) + return err; + + // check length + std::size_t const required_size( + sizeof(bitmap_file_header) + + header.info.size + + palette_size + + (row_bytes * std::abs(header.info.height))); + if (required_size > file_length) + return msdib_error::FILE_TRUNCATED; + + // good chance this file is supported + return msdib_error::NONE; +} + + +msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap) +{ + std::uint32_t file_length; + msdib_error const headerr(dib_read_file_header(fp, file_length)); + if (msdib_error::NONE != headerr) + return headerr; + + return msdib_read_bitmap_data(fp, bitmap, file_length - sizeof(bitmap_file_header), 0U); +} + + +msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight) +{ + // read the bitmap header + bitmap_headers header; + unsigned palette_bytes; + bool indexed; + std::size_t palette_entries, palette_size, row_bytes; + msdib_error const head_error(dib_read_bitmap_header(fp, header, palette_bytes, indexed, palette_entries, palette_size, row_bytes, length)); + if (msdib_error::NONE != head_error) + return head_error; + + // check dimensions + bool const top_down(0 > header.info.height); + if (top_down) + header.info.height = -header.info.height; + bool have_and_mask((2 * dirheight) == header.info.height); + if (!have_and_mask && (0 < dirheight) && (dirheight != header.info.height)) + { + osd_printf_verbose( + "DIB image data height %d doesn't match directory height %u with or without AND mask\n", + header.info.height, + dirheight); + return msdib_error::UNSUPPORTED_FORMAT; + } + if (have_and_mask) + header.info.height >>= 1; + + // we can now calculate the size of the image data + std::size_t const mask_row_bytes(((31 + header.info.width) >> 5) << 2); + std::size_t const required_size( + header.info.size + + palette_size + + ((row_bytes + (have_and_mask ? mask_row_bytes : 0U)) * header.info.height)); + if (required_size > length) + { + LOG("DIB image data (%u bytes) smaller than calculated DIB data size (%u bytes)\n", length, required_size); + return msdib_error::FILE_TRUNCATED; + } + + // load the palette for indexed colour formats or the shifts for direct colour formats + unsigned red_shift(0), green_shift(0), blue_shift(0), alpha_shift(0); + unsigned red_bits(0), green_bits(0), blue_bits(0), alpha_bits(0); + std::unique_ptr<rgb_t []> palette; + if (indexed) + { + // read palette and convert + std::unique_ptr<std::uint8_t []> palette_data; + try { palette_data.reset(new std::uint8_t [palette_size]); } + catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; } + if (fp.read(palette_data.get(), palette_size) != palette_size) + { + LOG("Error reading palette from DIB image data (%u bytes)\n", length); + return msdib_error::FILE_TRUNCATED; + } + std::size_t const palette_usable(std::min<std::size_t>(palette_entries, std::size_t(1) << header.info.bpp)); + try { palette.reset(new rgb_t [palette_usable]); } + catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; } + std::uint8_t const *ptr(palette_data.get()); + for (std::size_t i = 0; palette_usable > i; ++i, ptr += palette_bytes) + palette[i] = rgb_t(ptr[2], ptr[1], ptr[0]); + } + else + { + // skip over the palette if necessary + if (palette_entries) + fp.seek(palette_bytes * palette_entries, SEEK_CUR); + + // convert masks to shifts + bool const masks_contiguous( + dib_parse_mask(header.info.red, red_shift, red_bits) && + dib_parse_mask(header.info.green, green_shift, green_bits) && + dib_parse_mask(header.info.blue, blue_shift, blue_bits) && + dib_parse_mask(header.info.alpha, alpha_shift, alpha_bits)); + if (!masks_contiguous) + { + osd_printf_verbose( + "DIB image data specifies non-contiguous channel masks 0x%x | 0x%x | 0x%x | 0x%x\n", + header.info.red, + header.info.green, + header.info.blue, + header.info.alpha); + } + if ((32U != header.info.bpp) && ((header.info.red | header.info.green | header.info.blue | header.info.alpha) >> header.info.bpp)) + { + LOG( + "DIB image data specifies channel masks 0x%x | 0x%x | 0x%x | 0x%x that exceed %u bits per pixel\n", + header.info.red, + header.info.green, + header.info.blue, + header.info.alpha, + header.info.bpp); + return msdib_error::FILE_CORRUPT; + } + LOGMASKED( + LOG_DIB, + "DIB image data using channels: R((x >> %2$u) & 0x%3$0*1$x) G((x >> %4$u) & 0x%5$0*1$x) B((x >> %6$u) & 0x%7$0*1$x) A((x >> %8$u) & 0x%9$0*1$x)\n", + (header.info.bpp + 3) >> 2, + red_shift, + (std::uint32_t(1) << red_bits) - 1, + green_shift, + (std::uint32_t(1) << green_bits) - 1, + blue_shift, + (std::uint32_t(1) << blue_bits) - 1, + alpha_shift, + (std::uint32_t(1) << alpha_bits) - 1); + + // the MAME bitmap only supports 8 bits/sample maximum + dib_truncate_channel(red_shift, red_bits); + dib_truncate_channel(green_shift, green_bits); + dib_truncate_channel(blue_shift, blue_bits); + dib_truncate_channel(alpha_shift, alpha_bits); + } + + // allocate the bitmap and process row data + std::unique_ptr<std::uint8_t []> row_data; + try {row_data.reset(new std::uint8_t [row_bytes]); } + catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; } + bitmap.allocate(header.info.width, header.info.height); + int const y_inc(top_down ? 1 : -1); + for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc) + { + if (fp.read(row_data.get(), row_bytes) != row_bytes) + { + LOG("Error reading DIB row %d data from image data\n", i); + return msdib_error::FILE_TRUNCATED; + } + std::uint8_t *src(row_data.get()); + std::uint32_t *dest(&bitmap.pix(y)); + unsigned shift(0U); + for (std::int32_t x = 0; header.info.width > x; ++x, ++dest) + { + // extract or compose a pixel + std::uint32_t pix(0U); + if (8U >= header.info.bpp) + { + assert(8U > shift); + pix = *src >> (8U - header.info.bpp); + *src <<= header.info.bpp; + shift += header.info.bpp; + if (8U <= shift) + { + shift = 0U; + ++src; + } + } + else for (shift = 0; header.info.bpp > shift; shift += 8U, ++src) + { + pix |= std::uint32_t(*src) << shift; + } + + // convert to RGB + if (indexed) + { + if (palette_entries > pix) + { + *dest = palette[pix]; + } + else + { + *dest = rgb_t::transparent(); + osd_printf_verbose( + "DIB image data has out-of-range color %u at (%d, %d) with %u palette entries\n", + pix, + x, + y, + palette_entries); + } + } + else + { + std::uint8_t r(dib_splat_sample((pix >> red_shift) & ((std::uint32_t(1) << red_bits) - 1), red_bits)); + std::uint8_t g(dib_splat_sample((pix >> green_shift) & ((std::uint32_t(1) << green_bits) - 1), green_bits)); + std::uint8_t b(dib_splat_sample((pix >> blue_shift) & ((std::uint32_t(1) << blue_bits) - 1), blue_bits)); + std::uint8_t a(dib_splat_sample((pix >> alpha_shift) & ((std::uint32_t(1) << alpha_bits) - 1), alpha_bits)); + *dest = rgb_t(alpha_bits ? a : 255, r, g, b); + } + } + } + + // process the AND mask if present + if (have_and_mask) + { + for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc) + { + if (fp.read(row_data.get(), mask_row_bytes) != mask_row_bytes) + { + LOG("Error reading DIB mask row %d data from image data\n", i); + return msdib_error::FILE_TRUNCATED; + } + std::uint8_t *src(row_data.get()); + std::uint32_t *dest(&bitmap.pix(y)); + unsigned shift(0U); + for (std::int32_t x = 0; header.info.width > x; ++x, ++dest) + { + assert(8U > shift); + rgb_t pix(*dest); + *dest = pix.set_a(BIT(*src, 7U - shift) ? 0U : pix.a()); + if (8U <= ++shift) + { + shift = 0U; + ++src; + } + } + } + } + + // we're done! + return msdib_error::NONE; +} + +} // namespace util diff --git a/src/lib/util/msdib.h b/src/lib/util/msdib.h new file mode 100644 index 00000000000..54767e216fb --- /dev/null +++ b/src/lib/util/msdib.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + msdib.h + + Microsoft Device-Independent Bitmap file loading. + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_MSDIB_H +#define MAME_LIB_UTIL_MSDIB_H + +#pragma once + +#include "bitmap.h" +#include "corefile.h" +#include "osdcore.h" + +#include <cstdint> + + +namespace util { + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +// Error types +enum class msdib_error +{ + NONE, + OUT_OF_MEMORY, + FILE_ERROR, + BAD_SIGNATURE, + FILE_TRUNCATED, + FILE_CORRUPT, + UNSUPPORTED_FORMAT +}; + +msdib_error msdib_verify_header(core_file &fp); +msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap); +msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight = 0U); + +} // namespace util + +#endif // MAME_LIB_UTIL_MSDIB_H diff --git a/src/lib/util/nanosvg.cpp b/src/lib/util/nanosvg.cpp index 09973865675..0cb05308d19 100644 --- a/src/lib/util/nanosvg.cpp +++ b/src/lib/util/nanosvg.cpp @@ -1,6 +1,10 @@ +#include <stdio.h> +#include <string.h> +#include <math.h> + +#define NANOSVG_ALL_COLOR_KEYWORDS #define NANOSVG_IMPLEMENTATION #define NANOSVGRAST_IMPLEMENTATION -#define NANOSVG_ALL_COLOR_KEYWORDS #include <nanosvg/src/nanosvg.h> #include <nanosvg/src/nanosvgrast.h> diff --git a/src/lib/util/nanosvg.h b/src/lib/util/nanosvg.h new file mode 100644 index 00000000000..49940f0b9be --- /dev/null +++ b/src/lib/util/nanosvg.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + nanosvg.h + + NanoSVG helpers. + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_NANOSVG_H +#define MAME_LIB_UTIL_NANOSVG_H + +#include <nanosvg/src/nanosvg.h> +#include <nanosvg/src/nanosvgrast.h> + +#include <memory> + + +namespace util { + +struct nsvg_deleter +{ + void operator()(NSVGimage *ptr) const { nsvgDelete(ptr); } + void operator()(NSVGrasterizer *ptr) const { nsvgDeleteRasterizer(ptr); } +}; + + +using nsvg_image_ptr = std::unique_ptr<NSVGimage, nsvg_deleter>; +using nsvg_rasterizer_ptr = std::unique_ptr<NSVGrasterizer, nsvg_deleter>; + +} // namespace util + +#endif // MAME_LIB_UTIL_NANOSVG_H diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp index 6b59436750c..50aeb28c5fe 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. @@ -16,34 +16,13 @@ #include <algorithm> #include <cassert> -#include <cstdint> -#include <cstring> -#include <cmath> -#include <new> - #include <cmath> #include <cstdlib> +#include <cstring> +#include <new> - -/*************************************************************************** - 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; -} - - +namespace util { /*************************************************************************** GENERAL FUNCTIONS @@ -66,6 +45,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,6 +86,12 @@ constexpr std::uint8_t PNG_PF_Average = 3; constexpr std::uint8_t PNG_PF_Paeth = 4; +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +inline int compute_rowbytes(const png_info &pnginfo) { return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8; } + 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)); } @@ -132,11 +123,11 @@ private: { // 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 + 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()); @@ -146,13 +137,13 @@ private: // 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; } + catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; } // decompress image data - png_error error = PNGERR_NONE; + png_error error = png_error::NONE; 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) && (png_error::NONE == error); ++pass) { // compute some basic parameters std::pair<std::uint32_t, std::uint32_t> const dimensions(get_pass_dimensions(pass)); @@ -161,7 +152,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) && (png_error::NONE == error); ++y) { // first byte of each row is the filter type uint8_t const filter(*src++); @@ -172,7 +163,7 @@ private: } // if we errored, free the image data - if (error != PNGERR_NONE) + if (error != png_error::NONE) pnginfo.image.reset(); return error; @@ -182,7 +173,7 @@ private: { // only deflate is permitted if (0 != pnginfo.compression_method) - return PNGERR_DECOMPRESS_ERROR; + return png_error::DECOMPRESS_ERROR; // allocate zlib stream z_stream stream; @@ -195,7 +186,7 @@ private: stream.next_in = Z_NULL; zerr = inflateInit(&stream); if (Z_OK != zerr) - return PNGERR_DECOMPRESS_ERROR; + return png_error::DECOMPRESS_ERROR; // decompress IDAT blocks stream.next_out = pnginfo.image.get(); @@ -217,28 +208,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 png_error::NONE; else - return PNGERR_DECOMPRESS_ERROR; + return png_error::DECOMPRESS_ERROR; } 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) { 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 png_error::NONE; 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 png_error::NONE; case PNG_PF_Up: // UP = pixel above if (dstprev) @@ -250,7 +241,7 @@ private: { std::copy_n(src, rowbytes, dst); } - return PNGERR_NONE; + return png_error::NONE; case PNG_PF_Average: // AVERAGE = average of pixel above and previous pixel if (dstprev) @@ -267,7 +258,7 @@ private: for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst) *dst = *src + (dst[-bpp] >> 1); } - return PNGERR_NONE; + return png_error::NONE; case PNG_PF_Paeth: // PAETH = special filter for (std::uint32_t x = 0; rowbytes > x; ++x, ++src, ++dst) @@ -281,10 +272,10 @@ 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 png_error::NONE; default: // unknown filter type - return PNGERR_UNKNOWN_FILTER; + return png_error::UNKNOWN_FILTER; } } @@ -294,7 +285,7 @@ private: { 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 +298,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 png_error::OUT_OF_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,17 +352,17 @@ private: } catch (std::bad_alloc const &) { - return PNGERR_OUT_OF_MEMORY; + return png_error::OUT_OF_MEMORY; } break; /* anything else */ default: if ((type & 0x20000000) == 0) - return PNGERR_UNKNOWN_CHUNK; + return png_error::UNKNOWN_CHUNK; break; } - return PNGERR_NONE; + return png_error::NONE; } unsigned get_pass_count() const @@ -413,23 +404,23 @@ private: 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 png_error read_chunk(core_file &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length) { std::uint8_t tempbuff[4]; /* fetch the length of this chunk */ if (fp.read(tempbuff, 4) != 4) - return PNGERR_FILE_TRUNCATED; + 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; + return png_error::FILE_TRUNCATED; type = fetch_32bit(tempbuff); /* stop when we hit an IEND chunk */ if (type == PNG_CN_IEND) - return PNGERR_NONE; + return png_error::NONE; /* start the CRC with the chunk type (but not the length) */ std::uint32_t crc = crc32(0, tempbuff, 4); @@ -439,13 +430,13 @@ private: { /* allocate memory for this chunk */ try { data.reset(new std::uint8_t [length]); } - catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; } + catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; } /* read the data from the file */ if (fp.read(data.get(), length) != length) { data.reset(); - return PNGERR_FILE_TRUNCATED; + return png_error::FILE_TRUNCATED; } /* update the CRC */ @@ -456,7 +447,7 @@ private: if (fp.read(tempbuff, 4) != 4) { data.reset(); - return PNGERR_FILE_TRUNCATED; + return png_error::FILE_TRUNCATED; } std::uint32_t const chunk_crc = fetch_32bit(tempbuff); @@ -464,10 +455,10 @@ private: if (crc != chunk_crc) { data.reset(); - return PNGERR_FILE_CORRUPT; + return png_error::FILE_CORRUPT; } - return PNGERR_NONE; + return png_error::NONE; } png_info & pnginfo; @@ -481,13 +472,13 @@ public: { // 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 + return png_error::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; // 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 bitmap.allocate(pnginfo.width, pnginfo.height); @@ -519,7 +510,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 +528,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 +543,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 +569,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 +586,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 +594,22 @@ public: // set hasalpha flag and return hasalpha = 0xffU != accumalpha; - return PNGERR_NONE; + return png_error::NONE; } png_error expand_buffer_8bit() { // nothing to do if we're at 8 or greater already if (pnginfo.bit_depth >= 8) - return PNGERR_NONE; + return png_error::NONE; // 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()); @@ -633,7 +624,7 @@ 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; } + catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; } // upsample bitmap std::uint8_t const bytesamples(8 / pnginfo.bit_depth); @@ -687,13 +678,13 @@ public: pnginfo.image = std::move(outbuf); pnginfo.bit_depth = 8; - return PNGERR_NONE; + return png_error::NONE; } - png_error read_file(util::core_file &fp) + png_error read_file(core_file &fp) { // initialize the data structures - png_error error = PNGERR_NONE; + png_error error = png_error::NONE; pnginfo.reset(); std::list<image_data_chunk> idata; @@ -701,13 +692,13 @@ public: error = verify_header(fp); // loop until we hit an IEND chunk - while (PNGERR_NONE == error) + while (png_error::NONE == 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 (png_error::NONE == error) { if (chunk_type == PNG_CN_IEND) break; // stop when we hit an IEND chunk @@ -717,29 +708,29 @@ public: } // finish processing the image - if (PNGERR_NONE == error) + if (png_error::NONE == error) error = process(idata); // if we have an error, free all the output data - if (error != PNGERR_NONE) + if (error != png_error::NONE) pnginfo.reset(); return error; } - static png_error verify_header(util::core_file &fp) + static png_error verify_header(core_file &fp) { EQUIVALENT_ARRAY(PNG_SIGNATURE, std::uint8_t) signature; // read 8 bytes if (fp.read(signature, sizeof(signature)) != sizeof(signature)) - return PNGERR_FILE_TRUNCATED; + 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 png_error::NONE; } }; @@ -760,7 +751,7 @@ constexpr unsigned png_private::ADAM7_Y_OFFS[7]; core stream -------------------------------------------------*/ -png_error png_info::verify_header(util::core_file &fp) +png_error png_info::verify_header(core_file &fp) { return png_private::verify_header(fp); } @@ -770,7 +761,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) +png_error png_info::read_file(core_file &fp) { return png_private(*this).read_file(fp); } @@ -781,7 +772,7 @@ png_error png_info::read_file(util::core_file &fp) bitmap -------------------------------------------------*/ -png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap) +png_error png_read_bitmap(core_file &fp, bitmap_argb32 &bitmap) { png_error result; png_info pnginfo; @@ -789,12 +780,12 @@ png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap) // read the PNG data result = png.read_file(fp); - if (PNGERR_NONE != result) + if (png_error::NONE != result) return result; // resample to 8bpp if necessary result = png.expand_buffer_8bit(); - if (PNGERR_NONE != result) + if (png_error::NONE != result) { pnginfo.free_data(); return result; @@ -848,13 +839,13 @@ png_error png_info::add_text(const char *keyword, const char *text) 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; + return png_error::UNSUPPORTED_FORMAT; prev = ch; ++cnt; ptr += 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)); @@ -863,14 +854,14 @@ png_error png_info::add_text(const char *keyword, const char *text) char32_t ch; int const len(uchar_from_utf8(&ch, ptr, textend - ptr)); if ((0 >= len) || (1 > ch) || (255 < ch)) - return PNGERR_UNSUPPORTED_FORMAT; + return png_error::UNSUPPORTED_FORMAT; ptr += 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; + catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; } + return png_error::NONE; } @@ -879,7 +870,7 @@ 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 png_error write_chunk(core_file &fp, const uint8_t *data, uint32_t type, uint32_t length) { uint8_t tempbuff[8]; uint32_t crc; @@ -891,22 +882,22 @@ static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t /* write that data */ if (fp.write(tempbuff, 8) != 8) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; /* append the actual data */ if (length > 0) { if (fp.write(data, length) != length) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; crc = crc32(crc, data, length); } /* write the CRC */ put_32bit(tempbuff, crc); if (fp.write(tempbuff, 4) != 4) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; - return PNGERR_NONE; + return png_error::NONE; } @@ -915,7 +906,7 @@ 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 png_error write_deflated_chunk(core_file &fp, uint8_t *data, uint32_t type, uint32_t length) { uint64_t lengthpos = fp.tell(); uint8_t tempbuff[8192]; @@ -931,7 +922,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32 /* write that data */ if (fp.write(tempbuff, 8) != 8) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; /* initialize the stream */ memset(&stream, 0, sizeof(stream)); @@ -939,7 +930,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32 stream.avail_in = length; zerr = deflateInit(&stream, Z_DEFAULT_COMPRESSION); if (zerr != Z_OK) - return PNGERR_COMPRESS_ERROR; + return png_error::COMPRESS_ERROR; /* now loop until we run out of data */ for ( ; ; ) @@ -956,7 +947,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32 if (fp.write(tempbuff, bytes) != bytes) { deflateEnd(&stream); - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; } crc = crc32(crc, tempbuff, bytes); zlength += bytes; @@ -970,29 +961,29 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32 if (zerr != Z_OK) { deflateEnd(&stream); - return PNGERR_COMPRESS_ERROR; + return png_error::COMPRESS_ERROR; } } /* clean up deflater(maus) */ zerr = deflateEnd(&stream); if (zerr != Z_OK) - return PNGERR_COMPRESS_ERROR; + return png_error::COMPRESS_ERROR; /* write the CRC */ put_32bit(tempbuff, crc); if (fp.write(tempbuff, 4) != 4) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; /* seek back and update the length */ fp.seek(lengthpos, SEEK_SET); put_32bit(tempbuff + 0, zlength); if (fp.write(tempbuff, 4) != 4) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; /* return to the end */ fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET); - return PNGERR_NONE; + return png_error::NONE; } @@ -1016,7 +1007,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap /* 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; } + catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; } /* build the palette */ std::fill_n(pnginfo.palette.get(), 3 * 256, 0); @@ -1036,13 +1027,13 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap catch (std::bad_alloc const &) { pnginfo.palette.reset(); - return PNGERR_OUT_OF_MEMORY; + return png_error::OUT_OF_MEMORY; } /* copy in the pixels, specifying a nullptr filter */ for (y = 0; y < pnginfo.height; y++) { - auto *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 */ @@ -1051,7 +1042,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap *dst++ = *src++; } - return PNGERR_NONE; + return png_error::NONE; } @@ -1075,7 +1066,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t & /* 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; } + catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; } /* copy in the pixels, specifying a nullptr filter */ for (y = 0; y < pnginfo.height; y++) @@ -1088,7 +1079,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t & /* 16bpp palettized format */ if (bitmap.format() == BITMAP_FORMAT_IND16) { - auto *src16 = reinterpret_cast<uint16_t *>(bitmap.raw_pixptr(y)); + uint16_t const *src16 = reinterpret_cast<uint16_t const *>(bitmap.raw_pixptr(y)); for (x = 0; x < pnginfo.width; x++) { rgb_t color = palette[*src16++]; @@ -1101,7 +1092,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t & /* 32-bit RGB direct */ else if (bitmap.format() == BITMAP_FORMAT_RGB32) { - auto *src32 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y)); + uint32_t const *src32 = reinterpret_cast<uint32_t const *>(bitmap.raw_pixptr(y)); for (x = 0; x < pnginfo.width; x++) { rgb_t raw = *src32++; @@ -1114,7 +1105,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t & /* 32-bit ARGB direct */ else if (bitmap.format() == BITMAP_FORMAT_ARGB32) { - auto *src32 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y)); + uint32_t const *src32 = reinterpret_cast<uint32_t const *>(bitmap.raw_pixptr(y)); for (x = 0; x < pnginfo.width; x++) { rgb_t raw = *src32++; @@ -1127,10 +1118,10 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t & /* unsupported format */ else - return PNGERR_UNSUPPORTED_FORMAT; + return png_error::UNSUPPORTED_FORMAT; } - return PNGERR_NONE; + return png_error::NONE; } @@ -1139,7 +1130,7 @@ 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 png_error write_png_stream(core_file &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette) { uint8_t tempbuff[16]; png_error error; @@ -1149,7 +1140,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const 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 != png_error::NONE) return error; // if we wanted to get clever and do filtering, we would do it here @@ -1163,18 +1154,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 != png_error::NONE) 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 != png_error::NONE) 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 != png_error::NONE) return error; // write TEXT chunks @@ -1182,7 +1173,7 @@ 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 png_error::OUT_OF_MEMORY; } std::uint8_t *dst(&textbuf[0]); // convert keyword to ISO-8859-1 @@ -1213,7 +1204,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const } error = write_chunk(fp, &textbuf[0], PNG_CN_tEXt, dst - &textbuf[0]); - if (error != PNGERR_NONE) + if (error != png_error::NONE) return error; } @@ -1222,7 +1213,7 @@ 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) +png_error png_write_bitmap(core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette) { // use a dummy pnginfo if none passed to us png_info pnginfo; @@ -1231,7 +1222,7 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const & // write the PNG signature if (fp.write(PNG_SIGNATURE, sizeof(PNG_SIGNATURE)) != sizeof(PNG_SIGNATURE)) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; /* write the rest of the PNG data */ return write_png_stream(fp, *info, bitmap, palette_length, palette); @@ -1246,7 +1237,7 @@ 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, unsigned rate) + * @fn png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate) * * @brief Mng capture start. * @@ -1257,12 +1248,12 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const & * @return A png_error. */ -png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate) +png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate) { uint8_t mhdr[28]; if (fp.write(MNG_Signature, 8) != 8) - return PNGERR_FILE_ERROR; + return png_error::FILE_ERROR; memset(mhdr, 0, 28); put_32bit(mhdr + 0, bitmap.width()); @@ -1273,7 +1264,7 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate } /** - * @fn png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette) + * @fn png_error mng_capture_frame(core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette) * * @brief Mng capture frame. * @@ -1286,13 +1277,13 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate * @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) +png_error mng_capture_frame(core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette) { return write_png_stream(fp, info, bitmap, palette_length, palette); } /** - * @fn png_error mng_capture_stop(util::core_file &fp) + * @fn png_error mng_capture_stop(core_file &fp) * * @brief Mng capture stop. * @@ -1301,7 +1292,9 @@ png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const * @return A png_error. */ -png_error mng_capture_stop(util::core_file &fp) +png_error mng_capture_stop(core_file &fp) { return write_chunk(fp, nullptr, MNG_CN_MEND, 0); } + +} // namespace util diff --git a/src/lib/util/png.h b/src/lib/util/png.h index 5f852fd8c16..784c92646e6 100644 --- a/src/lib/util/png.h +++ b/src/lib/util/png.h @@ -17,31 +17,33 @@ #include "corefile.h" #include "osdcore.h" +#include <cstdint> #include <list> #include <memory> #include <string> #include <utility> +namespace util { /*************************************************************************** CONSTANTS ***************************************************************************/ /* Error types */ -enum png_error +enum class png_error { - PNGERR_NONE, - PNGERR_OUT_OF_MEMORY, - PNGERR_UNKNOWN_FILTER, - PNGERR_FILE_ERROR, - PNGERR_BAD_SIGNATURE, - PNGERR_DECOMPRESS_ERROR, - PNGERR_FILE_TRUNCATED, - PNGERR_FILE_CORRUPT, - PNGERR_UNKNOWN_CHUNK, - PNGERR_COMPRESS_ERROR, - PNGERR_UNSUPPORTED_FORMAT + NONE, + OUT_OF_MEMORY, + UNKNOWN_FILTER, + FILE_ERROR, + BAD_SIGNATURE, + DECOMPRESS_ERROR, + FILE_TRUNCATED, + FILE_CORRUPT, + UNKNOWN_CHUNK, + COMPRESS_ERROR, + UNSUPPORTED_FORMAT }; @@ -57,7 +59,7 @@ public: ~png_info() { free_data(); } - png_error read_file(util::core_file &fp); + png_error read_file(core_file &fp); png_error copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha); png_error expand_buffer_8bit(); @@ -66,7 +68,7 @@ public: void free_data(); void reset() { free_data(); operator=(png_info()); } - static png_error verify_header(util::core_file &fp); + static png_error verify_header(core_file &fp); std::unique_ptr<std::uint8_t []> image; std::uint32_t width, height; @@ -99,12 +101,14 @@ private: FUNCTION PROTOTYPES ***************************************************************************/ -png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap); +png_error png_read_bitmap(core_file &fp, bitmap_argb32 &bitmap); -png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette); +png_error png_write_bitmap(core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette); -png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate); -png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette); -png_error mng_capture_stop(util::core_file &fp); +png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate); +png_error mng_capture_frame(core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette); +png_error mng_capture_stop(core_file &fp); + +} // namespace util #endif // MAME_LIB_UTIL_PNG_H diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp index a61c20d2e3c..8ee3c33fe26 100644 --- a/src/lib/util/xmlfile.cpp +++ b/src/lib/util/xmlfile.cpp @@ -31,7 +31,6 @@ namespace { ***************************************************************************/ constexpr unsigned TEMP_BUFFER_SIZE(4096U); -std::locale const f_portable_locale("C"); /*************************************************************************** @@ -629,7 +628,7 @@ long long data_node::get_attribute_int(const char *attribute, long long defvalue return defvalue; std::istringstream stream; - stream.imbue(f_portable_locale); + stream.imbue(std::locale::classic()); long long result; if (string[0] == '$') { @@ -694,7 +693,7 @@ float data_node::get_attribute_float(const char *attribute, float defvalue) cons return defvalue; std::istringstream stream(string); - stream.imbue(f_portable_locale); + stream.imbue(std::locale::classic()); float result; return (stream >> result) ? result : defvalue; } @@ -732,7 +731,7 @@ void data_node::set_attribute(const char *name, const char *value) void data_node::set_attribute_int(const char *name, long long value) { - set_attribute(name, string_format(f_portable_locale, "%d", value).c_str()); + set_attribute(name, string_format(std::locale::classic(), "%d", value).c_str()); } @@ -743,7 +742,7 @@ void data_node::set_attribute_int(const char *name, long long value) void data_node::set_attribute_float(const char *name, float value) { - set_attribute(name, string_format(f_portable_locale, "%f", value).c_str()); + set_attribute(name, string_format(std::locale::classic(), "%f", value).c_str()); } |