summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/msdib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/msdib.cpp')
-rw-r--r--src/lib/util/msdib.cpp117
1 files changed, 73 insertions, 44 deletions
diff --git a/src/lib/util/msdib.cpp b/src/lib/util/msdib.cpp
index c084442f44b..bf33991f116 100644
--- a/src/lib/util/msdib.cpp
+++ b/src/lib/util/msdib.cpp
@@ -11,12 +11,16 @@
#include "msdib.h"
#include "coretmpl.h"
+#include "ioprocs.h"
+#include "multibyte.h"
+
#include "eminline.h"
#include "osdcore.h"
#include <cassert>
#include <cstdlib>
#include <cstring>
+#include <tuple>
#define LOG_GENERAL (1U << 0)
@@ -91,18 +95,18 @@ union bitmap_headers
};
-bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits)
+bool dib_parse_mask(std::uint32_t mask, unsigned &shift, unsigned &bits) noexcept
{
- shift = count_leading_zeros(mask);
+ shift = count_leading_zeros_32(mask);
mask <<= shift;
- bits = count_leading_ones(mask);
+ bits = count_leading_ones_32(mask);
mask <<= shift;
shift = 32 - shift - bits;
return !mask;
}
-void dib_truncate_channel(unsigned &shift, unsigned &bits)
+void dib_truncate_channel(unsigned &shift, unsigned &bits) noexcept
{
if (8U < bits)
{
@@ -113,7 +117,7 @@ void dib_truncate_channel(unsigned &shift, unsigned &bits)
}
-uint8_t dib_splat_sample(uint8_t val, unsigned bits)
+std::uint8_t dib_splat_sample(std::uint8_t val, unsigned bits) noexcept
{
assert(8U >= bits);
for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1)
@@ -122,11 +126,12 @@ uint8_t dib_splat_sample(uint8_t val, unsigned bits)
}
-msdib_error dib_read_file_header(core_file &fp, std::uint32_t &filelen)
+msdib_error dib_read_file_header(read_stream &fp, std::uint32_t &filelen) noexcept
{
// 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))
+ auto const [err, actual] = read(fp, file_header, sizeof(file_header));
+ if (err || (sizeof(file_header) != actual))
{
LOG("Error reading DIB file header\n");
return msdib_error::FILE_TRUNCATED;
@@ -137,20 +142,12 @@ msdib_error dib_read_file_header(core_file &fp, std::uint32_t &filelen)
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));
+ std::uint32_t const file_length(get_u32le(&file_header[2]));
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));
+ std::uint32_t const pixel_offset(get_u32le(&file_header[10]));
if (((sizeof(file_header) + sizeof(bitmap_core_header)) > pixel_offset) || (file_length < pixel_offset))
return msdib_error::FILE_CORRUPT;
@@ -161,15 +158,18 @@ msdib_error dib_read_file_header(core_file &fp, std::uint32_t &filelen)
msdib_error dib_read_bitmap_header(
- core_file &fp,
+ random_read &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)
+ std::uint32_t length) noexcept
{
+ std::error_condition err;
+ std::size_t actual;
+
// 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");
@@ -179,7 +179,8 @@ msdib_error dib_read_bitmap_header(
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))
+ std::tie(err, actual) = read(fp, &header.core.size, sizeof(header.core.size));
+ if (err || (sizeof(header.core.size) != actual))
{
LOG("Error reading DIB header size (length %u)\n", length);
return msdib_error::FILE_TRUNCATED;
@@ -209,12 +210,19 @@ msdib_error dib_read_bitmap_header(
{
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)
+ std::tie(err, actual) = read(fp, &header.core.width, header_read);
+ if (err || (header_read != actual))
{
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);
+ if (fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR))
+ {
+ LOG(
+ "Error seeking past additional DIB header data (%u bytes)\n",
+ header.core.size - sizeof(header.core.size) - header_read);
+ return msdib_error::FILE_ERROR;
+ }
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);
@@ -256,12 +264,19 @@ msdib_error dib_read_bitmap_header(
{
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)
+ std::tie(err, actual) = read(fp, &header.info.width, header_read);
+ if (err || (header_read != actual))
{
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);
+ if (fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR))
+ {
+ LOG(
+ "Error seeking past additional DIB header data (%u bytes)\n",
+ header.info.size - sizeof(header.info.size) - header_read);
+ return msdib_error::FILE_ERROR;
+ }
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);
@@ -379,7 +394,7 @@ msdib_error dib_read_bitmap_header(
-msdib_error msdib_verify_header(core_file &fp)
+msdib_error msdib_verify_header(random_read &fp) noexcept
{
msdib_error err;
@@ -420,7 +435,7 @@ msdib_error msdib_verify_header(core_file &fp)
}
-msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap)
+msdib_error msdib_read_bitmap(random_read &fp, bitmap_argb32 &bitmap) noexcept
{
std::uint32_t file_length;
msdib_error const headerr(dib_read_file_header(fp, file_length));
@@ -431,7 +446,7 @@ 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)
+msdib_error msdib_read_bitmap_data(random_read &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight) noexcept
{
// read the bitmap header
bitmap_headers header;
@@ -477,17 +492,19 @@ msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::ui
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)
+ std::unique_ptr<std::uint8_t []> palette_data(new (std::nothrow) std::uint8_t [palette_size]);
+ if (!palette_data)
+ return msdib_error::OUT_OF_MEMORY;
+ auto const [err, actual] = read(fp, palette_data.get(), palette_size);
+ if (err || (palette_size != actual))
{
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; }
+ palette.reset(new (std::nothrow) rgb_t [palette_usable]);
+ if (!palette)
+ 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]);
@@ -496,7 +513,13 @@ msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::ui
{
// skip over the palette if necessary
if (palette_entries)
- fp.seek(palette_bytes * palette_entries, SEEK_CUR);
+ {
+ if (fp.seek(palette_bytes * palette_entries, SEEK_CUR))
+ {
+ LOG("Error seeking past DIB palette data (%u bytes)\n", palette_bytes * palette_entries);
+ return msdib_error::FILE_ERROR;
+ }
+ }
// convert masks to shifts
bool const masks_contiguous(
@@ -544,15 +567,20 @@ msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::ui
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; }
+ // allocate a row buffer as well as the destination bitmap
+ std::unique_ptr<std::uint8_t []> row_data(new (std::nothrow) std::uint8_t [row_bytes]);
+ if (!row_data)
+ return msdib_error::OUT_OF_MEMORY;
bitmap.allocate(header.info.width, header.info.height);
+ if (!bitmap.valid())
+ return msdib_error::OUT_OF_MEMORY;
+
+ // process row data
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)
+ auto const [err, actual] = read(fp, row_data.get(), row_bytes);
+ if (err || (row_bytes != actual))
{
LOG("Error reading DIB row %d data from image data\n", i);
return msdib_error::FILE_TRUNCATED;
@@ -601,10 +629,10 @@ msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::ui
}
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));
+ std::uint8_t r(dib_splat_sample(BIT(pix, red_shift, red_bits), red_bits));
+ std::uint8_t g(dib_splat_sample(BIT(pix, green_shift, green_bits), green_bits));
+ std::uint8_t b(dib_splat_sample(BIT(pix, blue_shift, blue_bits), blue_bits));
+ std::uint8_t a(dib_splat_sample(BIT(pix, alpha_shift, alpha_bits), alpha_bits));
*dest = rgb_t(alpha_bits ? a : 255, r, g, b);
}
}
@@ -615,7 +643,8 @@ msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::ui
{
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)
+ auto const [err, actual] = read(fp, row_data.get(), mask_row_bytes);
+ if (err || (mask_row_bytes != actual))
{
LOG("Error reading DIB mask row %d data from image data\n", i);
return msdib_error::FILE_TRUNCATED;