summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/util/msdib.cpp642
-rw-r--r--src/lib/util/msdib.h46
-rw-r--r--src/lib/util/nanosvg.h33
-rw-r--r--src/lib/util/png.cpp253
-rw-r--r--src/lib/util/png.h42
5 files changed, 867 insertions, 149 deletions
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.h b/src/lib/util/nanosvg.h
new file mode 100644
index 00000000000..6be55cdae32
--- /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) { nsvgDelete(ptr); }
+ void operator()(NSVGrasterizer *ptr) { 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 69835e54051..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);
@@ -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,7 +1027,7 @@ 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 */
@@ -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++)
@@ -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