diff options
Diffstat (limited to 'src/lib/util/msdib.cpp')
-rw-r--r-- | src/lib/util/msdib.cpp | 117 |
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; |