diff options
Diffstat (limited to 'src/lib/util/chdcodec.cpp')
-rw-r--r-- | src/lib/util/chdcodec.cpp | 616 |
1 files changed, 404 insertions, 212 deletions
diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp index 71763163a87..c8a1f573bd0 100644 --- a/src/lib/util/chdcodec.cpp +++ b/src/lib/util/chdcodec.cpp @@ -2,30 +2,35 @@ // copyright-holders:Aaron Giles /*************************************************************************** - chdcodec.c - Codecs used by the CHD format ***************************************************************************/ -#include <assert.h> +#include "chdcodec.h" -#include "chd.h" -#include "hashing.h" #include "avhuff.h" -#include "flac.h" #include "cdrom.h" -#include <zlib.h> -#include "lzma/C/LzmaEnc.h" +#include "chd.h" +#include "flac.h" +#include "hashing.h" +#include "multibyte.h" + #include "lzma/C/LzmaDec.h" +#include "lzma/C/LzmaEnc.h" + +#include <zlib.h> +#include <zstd.h> + #include <new> +namespace { + //************************************************************************** // GLOBAL VARIABLES //************************************************************************** -static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; +constexpr uint8_t f_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; @@ -35,7 +40,7 @@ static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff // ======================> chd_zlib_allocator -// allocation helper clas for zlib +// allocation helper class for zlib class chd_zlib_allocator { public: @@ -51,7 +56,8 @@ private: static voidpf fast_alloc(voidpf opaque, uInt items, uInt size); static void fast_free(voidpf opaque, voidpf address); - static const int MAX_ZLIB_ALLOCS = 64; + static constexpr int MAX_ZLIB_ALLOCS = 64; + uint32_t * m_allocptr[MAX_ZLIB_ALLOCS]; }; @@ -96,6 +102,44 @@ private: }; +// ======================> chd_zstd_compressor + +// Zstandard compressor +class chd_zstd_compressor : public chd_compressor +{ +public: + // construction/destruction + chd_zstd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy); + ~chd_zstd_compressor(); + + // core functionality + virtual uint32_t compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) override; + +private: + // internal state + ZSTD_CStream * m_stream; +}; + + +// ======================> chd_zstd_decompressor + +// Zstandard decompressor +class chd_zstd_decompressor : public chd_decompressor +{ +public: + // construction/destruction + chd_zstd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy); + ~chd_zstd_decompressor(); + + // core functionality + virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) override; + +private: + // internal state + ZSTD_DStream * m_stream; +}; + + // ======================> chd_lzma_allocator // allocation helper clas for zlib @@ -108,11 +152,11 @@ public: private: // internal helpers - static void *fast_alloc(void *p, size_t size); - static void fast_free(void *p, void *address); + static void *fast_alloc(ISzAllocPtr p, size_t size); + static void fast_free(ISzAllocPtr p, void *address); - static const int MAX_LZMA_ALLOCS = 64; - uint32_t * m_allocptr[MAX_LZMA_ALLOCS]; + static constexpr int MAX_LZMA_ALLOCS = 64; + uint32_t *m_allocptr[MAX_LZMA_ALLOCS]; }; @@ -287,27 +331,27 @@ private: // ======================> chd_cd_compressor -template<class _BaseCompressor, class _SubcodeCompressor> +template <class BaseCompressor, class SubcodeCompressor> class chd_cd_compressor : public chd_compressor { public: // construction/destruction chd_cd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_compressor(chd, hunkbytes, lossy), - m_base_compressor(chd, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA, lossy), - m_subcode_compressor(chd, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA, lossy), - m_buffer(hunkbytes + (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA) + : chd_compressor(chd, hunkbytes, lossy) + , m_base_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy) + , m_subcode_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy) + , m_buffer(hunkbytes + (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA) { // make sure the CHD's hunk size is an even multiple of the frame size - if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + if (hunkbytes % cdrom_file::FRAME_SIZE != 0) + throw std::error_condition(chd_file::error::CODEC_ERROR); } // core functionality virtual uint32_t compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) override { // determine header bytes - uint32_t frames = srclen / CD_FRAME_SIZE; + uint32_t frames = srclen / cdrom_file::FRAME_SIZE; uint32_t complen_bytes = (srclen < 65536) ? 2 : 3; uint32_t ecc_bytes = (frames + 7) / 8; uint32_t header_bytes = ecc_bytes + complen_bytes; @@ -318,98 +362,96 @@ public: // copy audio data followed by subcode data for (uint32_t framenum = 0; framenum < frames; framenum++) { - memcpy(&m_buffer[framenum * CD_MAX_SECTOR_DATA], &src[framenum * CD_FRAME_SIZE], CD_MAX_SECTOR_DATA); - memcpy(&m_buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], &src[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], CD_MAX_SUBCODE_DATA); + memcpy(&m_buffer[framenum * cdrom_file::MAX_SECTOR_DATA], &src[framenum * cdrom_file::FRAME_SIZE], cdrom_file::MAX_SECTOR_DATA); + memcpy(&m_buffer[frames * cdrom_file::MAX_SECTOR_DATA + framenum * cdrom_file::MAX_SUBCODE_DATA], &src[framenum * cdrom_file::FRAME_SIZE + cdrom_file::MAX_SECTOR_DATA], cdrom_file::MAX_SUBCODE_DATA); // clear out ECC data if we can - uint8_t *sector = &m_buffer[framenum * CD_MAX_SECTOR_DATA]; - if (memcmp(sector, s_cd_sync_header, sizeof(s_cd_sync_header)) == 0 && ecc_verify(sector)) + uint8_t *sector = &m_buffer[framenum * cdrom_file::MAX_SECTOR_DATA]; + if (memcmp(sector, f_cd_sync_header, sizeof(f_cd_sync_header)) == 0 && cdrom_file::ecc_verify(sector)) { dest[framenum / 8] |= 1 << (framenum % 8); - memset(sector, 0, sizeof(s_cd_sync_header)); - ecc_clear(sector); + memset(sector, 0, sizeof(f_cd_sync_header)); + cdrom_file::ecc_clear(sector); } } // encode the base portion - uint32_t complen = m_base_compressor.compress(&m_buffer[0], frames * CD_MAX_SECTOR_DATA, &dest[header_bytes]); + uint32_t complen = m_base_compressor.compress(&m_buffer[0], frames * cdrom_file::MAX_SECTOR_DATA, &dest[header_bytes]); if (complen >= srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // write compressed length - dest[ecc_bytes + 0] = complen >> ((complen_bytes - 1) * 8); - dest[ecc_bytes + 1] = complen >> ((complen_bytes - 2) * 8); if (complen_bytes > 2) - dest[ecc_bytes + 2] = complen >> ((complen_bytes - 3) * 8); + put_u24be(&dest[ecc_bytes], complen); + else + put_u16be(&dest[ecc_bytes], complen); // encode the subcode - return header_bytes + complen + m_subcode_compressor.compress(&m_buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA, &dest[header_bytes + complen]); + return header_bytes + complen + m_subcode_compressor.compress(&m_buffer[frames * cdrom_file::MAX_SECTOR_DATA], frames * cdrom_file::MAX_SUBCODE_DATA, &dest[header_bytes + complen]); } private: // internal state - _BaseCompressor m_base_compressor; - _SubcodeCompressor m_subcode_compressor; + BaseCompressor m_base_compressor; + SubcodeCompressor m_subcode_compressor; std::vector<uint8_t> m_buffer; }; // ======================> chd_cd_decompressor -template<class _BaseDecompressor, class _SubcodeDecompressor> +template <class BaseDecompressor, class SubcodeDecompressor> class chd_cd_decompressor : public chd_decompressor { public: // construction/destruction chd_cd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_decompressor(chd, hunkbytes, lossy), - m_base_decompressor(chd, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA, lossy), - m_subcode_decompressor(chd, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA, lossy), - m_buffer(hunkbytes) + : chd_decompressor(chd, hunkbytes, lossy) + , m_base_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy) + , m_subcode_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy) + , m_buffer(hunkbytes) { // make sure the CHD's hunk size is an even multiple of the frame size - if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + if (hunkbytes % cdrom_file::FRAME_SIZE != 0) + throw std::error_condition(chd_file::error::CODEC_ERROR); } // core functionality virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) override { // determine header bytes - uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t frames = destlen / cdrom_file::FRAME_SIZE; uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; uint32_t ecc_bytes = (frames + 7) / 8; uint32_t header_bytes = ecc_bytes + complen_bytes; // extract compressed length of base - uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; - if (complen_bytes > 2) - complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + uint32_t complen_base = (complen_bytes > 2) ? get_u24be(&src[ecc_bytes]) : get_u16be(&src[ecc_bytes]); // reset and decode - m_base_decompressor.decompress(&src[header_bytes], complen_base, &m_buffer[0], frames * CD_MAX_SECTOR_DATA); - m_subcode_decompressor.decompress(&src[header_bytes + complen_base], complen - complen_base - header_bytes, &m_buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + m_base_decompressor.decompress(&src[header_bytes], complen_base, &m_buffer[0], frames * cdrom_file::MAX_SECTOR_DATA); + m_subcode_decompressor.decompress(&src[header_bytes + complen_base], complen - complen_base - header_bytes, &m_buffer[frames * cdrom_file::MAX_SECTOR_DATA], frames * cdrom_file::MAX_SUBCODE_DATA); // reassemble the data for (uint32_t framenum = 0; framenum < frames; framenum++) { - memcpy(&dest[framenum * CD_FRAME_SIZE], &m_buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); - memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &m_buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + memcpy(&dest[framenum * cdrom_file::FRAME_SIZE], &m_buffer[framenum * cdrom_file::MAX_SECTOR_DATA], cdrom_file::MAX_SECTOR_DATA); + memcpy(&dest[framenum * cdrom_file::FRAME_SIZE + cdrom_file::MAX_SECTOR_DATA], &m_buffer[frames * cdrom_file::MAX_SECTOR_DATA + framenum * cdrom_file::MAX_SUBCODE_DATA], cdrom_file::MAX_SUBCODE_DATA); // reconstitute the ECC data and sync header - uint8_t *sector = &dest[framenum * CD_FRAME_SIZE]; + uint8_t *sector = &dest[framenum * cdrom_file::FRAME_SIZE]; if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) { - memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); - ecc_generate(sector); + memcpy(sector, f_cd_sync_header, sizeof(f_cd_sync_header)); + cdrom_file::ecc_generate(sector); } } } private: // internal state - _BaseDecompressor m_base_decompressor; - _SubcodeDecompressor m_subcode_decompressor; + BaseDecompressor m_base_decompressor; + SubcodeDecompressor m_subcode_decompressor; std::vector<uint8_t> m_buffer; }; @@ -446,6 +488,7 @@ public: chd_avhuff_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy); // core functionality + virtual void process(const uint8_t *src, uint32_t complen) override; virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) override; virtual void configure(int param, void *config) override; @@ -460,25 +503,67 @@ private: // CODEC LIST //************************************************************************** +// an entry in the list +struct codec_entry +{ + chd_codec_type m_type; + bool m_lossy; + const char * m_name; + chd_compressor::ptr (*m_construct_compressor)(chd_file &, uint32_t, bool); + chd_decompressor::ptr (*m_construct_decompressor)(chd_file &, uint32_t, bool); + + template <class CompressorClass> + static chd_compressor::ptr construct_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) + { + return std::make_unique<CompressorClass>(chd, hunkbytes, lossy); + } + + template <class DecompressorClass> + static chd_decompressor::ptr construct_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) + { + return std::make_unique<DecompressorClass>(chd, hunkbytes, lossy); + } +}; + + // static list of available known codecs -const chd_codec_list::codec_entry chd_codec_list::s_codec_list[] = +const codec_entry f_codec_list[] = { // general codecs - { CHD_CODEC_ZLIB, false, "Deflate", &chd_codec_list::construct_compressor<chd_zlib_compressor>, &chd_codec_list::construct_decompressor<chd_zlib_decompressor> }, - { CHD_CODEC_LZMA, false, "LZMA", &chd_codec_list::construct_compressor<chd_lzma_compressor>, &chd_codec_list::construct_decompressor<chd_lzma_decompressor> }, - { CHD_CODEC_HUFFMAN, false, "Huffman", &chd_codec_list::construct_compressor<chd_huffman_compressor>, &chd_codec_list::construct_decompressor<chd_huffman_decompressor> }, - { CHD_CODEC_FLAC, false, "FLAC", &chd_codec_list::construct_compressor<chd_flac_compressor>, &chd_codec_list::construct_decompressor<chd_flac_decompressor> }, + { CHD_CODEC_ZLIB, false, "Deflate", &codec_entry::construct_compressor<chd_zlib_compressor>, &codec_entry::construct_decompressor<chd_zlib_decompressor> }, + { CHD_CODEC_ZSTD, false, "Zstandard", &codec_entry::construct_compressor<chd_zstd_compressor>, &codec_entry::construct_decompressor<chd_zstd_decompressor> }, + { CHD_CODEC_LZMA, false, "LZMA", &codec_entry::construct_compressor<chd_lzma_compressor>, &codec_entry::construct_decompressor<chd_lzma_decompressor> }, + { CHD_CODEC_HUFFMAN, false, "Huffman", &codec_entry::construct_compressor<chd_huffman_compressor>, &codec_entry::construct_decompressor<chd_huffman_decompressor> }, + { CHD_CODEC_FLAC, false, "FLAC", &codec_entry::construct_compressor<chd_flac_compressor>, &codec_entry::construct_decompressor<chd_flac_decompressor> }, // general codecs with CD frontend - { CHD_CODEC_CD_ZLIB, false, "CD Deflate", &chd_codec_list::construct_compressor<chd_cd_compressor<chd_zlib_compressor, chd_zlib_compressor> >, &chd_codec_list::construct_decompressor<chd_cd_decompressor<chd_zlib_decompressor, chd_zlib_decompressor> > }, - { CHD_CODEC_CD_LZMA, false, "CD LZMA", &chd_codec_list::construct_compressor<chd_cd_compressor<chd_lzma_compressor, chd_zlib_compressor> >, &chd_codec_list::construct_decompressor<chd_cd_decompressor<chd_lzma_decompressor, chd_zlib_decompressor> > }, - { CHD_CODEC_CD_FLAC, false, "CD FLAC", &chd_codec_list::construct_compressor<chd_cd_flac_compressor>, &chd_codec_list::construct_decompressor<chd_cd_flac_decompressor> }, + { CHD_CODEC_CD_ZLIB, false, "CD Deflate", &codec_entry::construct_compressor<chd_cd_compressor<chd_zlib_compressor, chd_zlib_compressor> >, &codec_entry::construct_decompressor<chd_cd_decompressor<chd_zlib_decompressor, chd_zlib_decompressor> > }, + { CHD_CODEC_CD_ZSTD, false, "CD Zstandard", &codec_entry::construct_compressor<chd_cd_compressor<chd_zstd_compressor, chd_zstd_compressor> >, &codec_entry::construct_decompressor<chd_cd_decompressor<chd_zstd_decompressor, chd_zstd_decompressor> > }, + { CHD_CODEC_CD_LZMA, false, "CD LZMA", &codec_entry::construct_compressor<chd_cd_compressor<chd_lzma_compressor, chd_zlib_compressor> >, &codec_entry::construct_decompressor<chd_cd_decompressor<chd_lzma_decompressor, chd_zlib_decompressor> > }, + { CHD_CODEC_CD_FLAC, false, "CD FLAC", &codec_entry::construct_compressor<chd_cd_flac_compressor>, &codec_entry::construct_decompressor<chd_cd_flac_decompressor> }, // A/V codecs - { CHD_CODEC_AVHUFF, false, "A/V Huffman", &chd_codec_list::construct_compressor<chd_avhuff_compressor>, &chd_codec_list::construct_decompressor<chd_avhuff_decompressor> }, + { CHD_CODEC_AVHUFF, false, "A/V Huffman", &codec_entry::construct_compressor<chd_avhuff_compressor>, &codec_entry::construct_decompressor<chd_avhuff_decompressor> }, }; +//------------------------------------------------- +// find_in_list - create a new compressor +// instance of the given type +//------------------------------------------------- + +const codec_entry *find_in_list(chd_codec_type type) noexcept +{ + // find in the list and construct the class + for (auto & elem : f_codec_list) + if (elem.m_type == type) + return &elem; + return nullptr; +} + +} // anonymous namespace + + //************************************************************************** // CHD CODEC @@ -489,9 +574,9 @@ const chd_codec_list::codec_entry chd_codec_list::s_codec_list[] = //------------------------------------------------- chd_codec::chd_codec(chd_file &chd, uint32_t hunkbytes, bool lossy) - : m_chd(chd), - m_hunkbytes(hunkbytes), - m_lossy(lossy) + : m_chd(chd) + , m_hunkbytes(hunkbytes) + , m_lossy(lossy) { } @@ -512,7 +597,7 @@ chd_codec::~chd_codec() void chd_codec::configure(int param, void *config) { // if not overridden, it is always a failure - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); } @@ -521,10 +606,6 @@ void chd_codec::configure(int param, void *config) // CHD COMPRESSOR //************************************************************************** -//------------------------------------------------- -// chd_compressor - constructor -//------------------------------------------------- - chd_compressor::chd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) : chd_codec(chd, hunkbytes, lossy) { @@ -536,15 +617,16 @@ chd_compressor::chd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) // CHD DECOMPRESSOR //************************************************************************** -//------------------------------------------------- -// chd_decompressor - constructor -//------------------------------------------------- - chd_decompressor::chd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) : chd_codec(chd, hunkbytes, lossy) { } +void chd_decompressor::process(const uint8_t *src, uint32_t complen) +{ + throw std::error_condition(chd_file::error::UNSUPPORTED_FORMAT); +} + //************************************************************************** @@ -556,11 +638,11 @@ chd_decompressor::chd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy // instance of the given type //------------------------------------------------- -chd_compressor *chd_codec_list::new_compressor(chd_codec_type type, chd_file &chd) +chd_compressor::ptr chd_codec_list::new_compressor(chd_codec_type type, chd_file &chd) { // find in the list and construct the class - const codec_entry *entry = find_in_list(type); - return (entry == nullptr) ? nullptr : (*entry->m_construct_compressor)(chd, chd.hunk_bytes(), entry->m_lossy); + codec_entry const *const entry = find_in_list(type); + return entry ? (*entry->m_construct_compressor)(chd, chd.hunk_bytes(), entry->m_lossy) : nullptr; } @@ -569,39 +651,36 @@ chd_compressor *chd_codec_list::new_compressor(chd_codec_type type, chd_file &ch // instance of the given type //------------------------------------------------- -chd_decompressor *chd_codec_list::new_decompressor(chd_codec_type type, chd_file &chd) +chd_decompressor::ptr chd_codec_list::new_decompressor(chd_codec_type type, chd_file &chd) { // find in the list and construct the class const codec_entry *entry = find_in_list(type); - return (entry == nullptr) ? nullptr : (*entry->m_construct_decompressor)(chd, chd.hunk_bytes(), entry->m_lossy); + return entry ? (*entry->m_construct_decompressor)(chd, chd.hunk_bytes(), entry->m_lossy) : nullptr; } //------------------------------------------------- -// codec_name - return the name of the given -// codec +// codec_exists - determine whether a codec type +// corresponds to a supported codec //------------------------------------------------- -const char *chd_codec_list::codec_name(chd_codec_type type) +bool chd_codec_list::codec_exists(chd_codec_type type) noexcept { // find in the list and construct the class - const codec_entry *entry = find_in_list(type); - return (entry == nullptr) ? nullptr : entry->m_name; + return bool(find_in_list(type)); } //------------------------------------------------- -// find_in_list - create a new compressor -// instance of the given type +// codec_name - return the name of the given +// codec //------------------------------------------------- -const chd_codec_list::codec_entry *chd_codec_list::find_in_list(chd_codec_type type) +const char *chd_codec_list::codec_name(chd_codec_type type) noexcept { // find in the list and construct the class - for (auto & elem : s_codec_list) - if (elem.m_type == type) - return &elem; - return nullptr; + const codec_entry *entry = find_in_list(type); + return entry ? entry->m_name : nullptr; } @@ -615,25 +694,24 @@ const chd_codec_list::codec_entry *chd_codec_list::find_in_list(chd_codec_type t //------------------------------------------------- chd_compressor_group::chd_compressor_group(chd_file &chd, uint32_t compressor_list[4]) - : m_hunkbytes(chd.hunk_bytes()), - m_compress_test(m_hunkbytes) + : m_hunkbytes(chd.hunk_bytes()) + , m_compress_test(m_hunkbytes) #if CHDCODEC_VERIFY_COMPRESSION - ,m_decompressed(m_hunkbytes) + , m_decompressed(m_hunkbytes) #endif { // verify the compression types and initialize the codecs - for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compressor); codecnum++) + for (int codecnum = 0; codecnum < std::size(m_compressor); codecnum++) { - m_compressor[codecnum] = nullptr; if (compressor_list[codecnum] != CHD_CODEC_NONE) { m_compressor[codecnum] = chd_codec_list::new_compressor(compressor_list[codecnum], chd); - if (m_compressor[codecnum] == nullptr) - throw CHDERR_UNKNOWN_COMPRESSION; + if (!m_compressor[codecnum]) + throw std::error_condition(chd_file::error::UNKNOWN_COMPRESSION); #if CHDCODEC_VERIFY_COMPRESSION m_decompressor[codecnum] = chd_codec_list::new_decompressor(compressor_list[codecnum], chd); - if (m_decompressor[codecnum] == nullptr) - throw CHDERR_UNKNOWN_COMPRESSION; + if (!m_decompressor[codecnum]) + throw std::error_condition(chd_file::error::UNKNOWN_COMPRESSION); #endif } } @@ -646,9 +724,7 @@ chd_compressor_group::chd_compressor_group(chd_file &chd, uint32_t compressor_li chd_compressor_group::~chd_compressor_group() { - // delete the codecs and the test buffer - for (auto & elem : m_compressor) - delete elem; + // codecs and test buffer deleted automatically } @@ -663,8 +739,8 @@ int8_t chd_compressor_group::find_best_compressor(const uint8_t *src, uint8_t *c // determine best compression technique complen = m_hunkbytes; int8_t compression = -1; - for (int codecnum = 0; codecnum < ARRAY_LENGTH(m_compressor); codecnum++) - if (m_compressor[codecnum] != nullptr) + for (int codecnum = 0; codecnum < std::size(m_compressor); codecnum++) + if (m_compressor[codecnum]) { // attempt to compress, swallowing errors try @@ -702,7 +778,9 @@ printf(" codec%d=%d bytes \n", codecnum, compbytes); memcpy(compressed, &m_compress_test[0], compbytes); } } - catch (...) { } + catch (...) + { + } } // if the best is none, copy it over @@ -729,7 +807,7 @@ chd_zlib_allocator::chd_zlib_allocator() //------------------------------------------------- -// ~chd_zlib_allocator - constructor +// ~chd_zlib_allocator - destructor //------------------------------------------------- chd_zlib_allocator::~chd_zlib_allocator() @@ -760,7 +838,7 @@ void chd_zlib_allocator::install(z_stream &stream) voidpf chd_zlib_allocator::fast_alloc(voidpf opaque, uInt items, uInt size) { - chd_zlib_allocator *codec = reinterpret_cast<chd_zlib_allocator *>(opaque); + auto *codec = reinterpret_cast<chd_zlib_allocator *>(opaque); // compute the size, rounding to the nearest 1k size = (size * items + 0x3ff) & ~0x3ff; @@ -778,7 +856,7 @@ voidpf chd_zlib_allocator::fast_alloc(voidpf opaque, uInt items, uInt size) } // alloc a new one and put it into the list - uint32_t *ptr = reinterpret_cast<uint32_t *>(new uint8_t[size + sizeof(uint32_t)]); + auto *ptr = reinterpret_cast<uint32_t *>(new uint8_t[size + sizeof(uint32_t)]); for (int scan = 0; scan < MAX_ZLIB_ALLOCS; scan++) if (codec->m_allocptr[scan] == nullptr) { @@ -799,7 +877,7 @@ voidpf chd_zlib_allocator::fast_alloc(voidpf opaque, uInt items, uInt size) void chd_zlib_allocator::fast_free(voidpf opaque, voidpf address) { - chd_zlib_allocator *codec = reinterpret_cast<chd_zlib_allocator *>(opaque); + auto *codec = reinterpret_cast<chd_zlib_allocator *>(opaque); // find the hunk uint32_t *ptr = reinterpret_cast<uint32_t *>(address) - 1; @@ -835,7 +913,7 @@ chd_zlib_compressor::chd_zlib_compressor(chd_file &chd, uint32_t hunkbytes, bool if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } @@ -855,7 +933,7 @@ chd_zlib_compressor::~chd_zlib_compressor() uint32_t chd_zlib_compressor::compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) { - // reset the decompressor + // reset the compressor m_deflater.next_in = const_cast<Bytef *>(src); m_deflater.avail_in = srclen; m_deflater.total_in = 0; @@ -864,14 +942,14 @@ uint32_t chd_zlib_compressor::compress(const uint8_t *src, uint32_t srclen, uint m_deflater.total_out = 0; int zerr = deflateReset(&m_deflater); if (zerr != Z_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // do it zerr = deflate(&m_deflater, Z_FINISH); // if we ended up with more data than we started with, return an error if (zerr != Z_STREAM_END || m_deflater.total_out >= srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // otherwise, return the length return m_deflater.total_out; @@ -900,7 +978,7 @@ chd_zlib_decompressor::chd_zlib_decompressor(chd_file &chd, uint32_t hunkbytes, if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } @@ -930,14 +1008,139 @@ void chd_zlib_decompressor::decompress(const uint8_t *src, uint32_t complen, uin m_inflater.total_out = 0; int zerr = inflateReset(&m_inflater); if (zerr != Z_OK) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // do it zerr = inflate(&m_inflater, Z_FINISH); if (zerr != Z_STREAM_END) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (m_inflater.total_out != destlen) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); +} + + + +//************************************************************************** +// ZSTANDARD COMPRESSOR +//************************************************************************** + +//------------------------------------------------- +// chd_zstd_compressor - constructor +//------------------------------------------------- + +chd_zstd_compressor::chd_zstd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) + : chd_compressor(chd, hunkbytes, lossy) + , m_stream(nullptr) +{ + // initialize the stream + m_stream = ZSTD_createCStream(); + + // convert errors + if (!m_stream) + throw std::bad_alloc(); +} + + +//------------------------------------------------- +// ~chd_zstd_compressor - destructor +//------------------------------------------------- + +chd_zstd_compressor::~chd_zstd_compressor() +{ + ZSTD_freeCStream(m_stream); +} + + +//------------------------------------------------- +// compress - compress data using the Zstandard +// codec +//------------------------------------------------- + +uint32_t chd_zstd_compressor::compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) +{ + // reset the compressor + auto result = ZSTD_initCStream(m_stream, ZSTD_maxCLevel()); + if (ZSTD_isError(result)) + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); + + // do it + ZSTD_inBuffer input{ src, srclen, 0 }; + ZSTD_outBuffer output = { dest, srclen, 0 }; + while (output.pos < output.size) + { + result = ZSTD_compressStream2(m_stream, &output, &input, ZSTD_e_end); + if (ZSTD_isError(result)) + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); + else if (!result) + break; + } + + // if we ended up with more data than we started with, return an error + if (output.pos == output.size) + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); + + // otherwise, return the length + return output.pos; +} + + + +//************************************************************************** +// ZSTANDARD DECOMPRESSOR +//************************************************************************** + +//------------------------------------------------- +// chd_zstd_compressor - constructor +//------------------------------------------------- + +chd_zstd_decompressor::chd_zstd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) + : chd_decompressor(chd, hunkbytes, lossy) + , m_stream(nullptr) +{ + // initialize the stream + m_stream = ZSTD_createDStream(); + + // convert errors + if (!m_stream) + throw std::bad_alloc(); +} + + +//------------------------------------------------- +// ~chd_zstd_decompressor - destructor +//------------------------------------------------- + +chd_zstd_decompressor::~chd_zstd_decompressor() +{ + ZSTD_freeDStream(m_stream); +} + + +//------------------------------------------------- +// decompress - decompress data using the +// Zstandard codec +//------------------------------------------------- + +void chd_zstd_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + // reset the decompressor + auto result = ZSTD_initDStream(m_stream); + if (ZSTD_isError(result)) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); + + // do it + ZSTD_inBuffer input{ src, complen, 0 }; + ZSTD_outBuffer output = { dest, destlen, 0 }; + while ((input.pos < input.size) && (output.pos < output.size)) + { + result = ZSTD_decompressStream(m_stream, &output, &input); + if (ZSTD_isError(result)) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); + } + + // ensure the expected amount of output was generated + if (output.pos != output.size) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } @@ -978,9 +1181,9 @@ chd_lzma_allocator::~chd_lzma_allocator() // allocates and frees memory frequently //------------------------------------------------- -void *chd_lzma_allocator::fast_alloc(void *p, size_t size) +void *chd_lzma_allocator::fast_alloc(ISzAllocPtr p, size_t size) { - chd_lzma_allocator *codec = reinterpret_cast<chd_lzma_allocator *>(p); + auto *const codec = static_cast<chd_lzma_allocator *>(const_cast<ISzAlloc *>(p)); // compute the size, rounding to the nearest 1k size = (size + 0x3ff) & ~0x3ff; @@ -998,7 +1201,7 @@ void *chd_lzma_allocator::fast_alloc(void *p, size_t size) } // alloc a new one and put it into the list - uint32_t *ptr = reinterpret_cast<uint32_t *>(new uint8_t[size + sizeof(uint32_t)]); + auto *ptr = reinterpret_cast<uint32_t *>(new uint8_t[size + sizeof(uint32_t)]); for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++) if (codec->m_allocptr[scan] == nullptr) { @@ -1017,12 +1220,12 @@ void *chd_lzma_allocator::fast_alloc(void *p, size_t size) // allocates and frees memory frequently //------------------------------------------------- -void chd_lzma_allocator::fast_free(void *p, void *address) +void chd_lzma_allocator::fast_free(ISzAllocPtr p, void *address) { if (address == nullptr) return; - chd_lzma_allocator *codec = reinterpret_cast<chd_lzma_allocator *>(p); + auto *const codec = static_cast<chd_lzma_allocator *>(const_cast<ISzAlloc *>(p)); // find the hunk uint32_t *ptr = reinterpret_cast<uint32_t *>(address) - 1; @@ -1071,20 +1274,20 @@ uint32_t chd_lzma_compressor::compress(const uint8_t *src, uint32_t srclen, uint // allocate the encoder CLzmaEncHandle encoder = LzmaEnc_Create(&m_allocator); if (encoder == nullptr) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); try { // configure the encoder SRes res = LzmaEnc_SetProps(encoder, &m_props); if (res != SZ_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // run it SizeT complen = srclen; res = LzmaEnc_MemEncode(encoder, dest, &complen, src, srclen, 0, nullptr, &m_allocator, &m_allocator); if (res != SZ_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // clean up LzmaEnc_Destroy(encoder, &m_allocator, &m_allocator); @@ -1107,7 +1310,7 @@ uint32_t chd_lzma_compressor::compress(const uint8_t *src, uint32_t srclen, uint void chd_lzma_compressor::configure_properties(CLzmaEncProps &props, uint32_t hunkbytes) { LzmaEncProps_Init(&props); - props.level = 9; + props.level = 8; props.reduceSize = hunkbytes; LzmaEncProps_Normalize(&props); } @@ -1140,24 +1343,24 @@ chd_lzma_decompressor::chd_lzma_decompressor(chd_file &chd, uint32_t hunkbytes, // convert to decoder properties CLzmaEncHandle enc = LzmaEnc_Create(&m_allocator); if (!enc) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) { LzmaEnc_Destroy(enc, &m_allocator, &m_allocator); - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } Byte decoder_props[LZMA_PROPS_SIZE]; SizeT props_size = sizeof(decoder_props); if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) { LzmaEnc_Destroy(enc, &m_allocator, &m_allocator); - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } LzmaEnc_Destroy(enc, &m_allocator, &m_allocator); // do memory allocations if (LzmaDec_Allocate(&m_decoder, decoder_props, LZMA_PROPS_SIZE, &m_allocator) != SZ_OK) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } @@ -1188,7 +1391,7 @@ void chd_lzma_decompressor::decompress(const uint8_t *src, uint32_t complen, uin ELzmaStatus status; SRes res = LzmaDec_DecodeToBuf(&m_decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } @@ -1216,7 +1419,7 @@ uint32_t chd_huffman_compressor::compress(const uint8_t *src, uint32_t srclen, u { uint32_t complen; if (m_encoder.encode(src, srclen, dest, srclen, complen) != HUFFERR_NONE) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); return complen; } @@ -1244,7 +1447,7 @@ chd_huffman_decompressor::chd_huffman_decompressor(chd_file &chd, uint32_t hunkb void chd_huffman_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { if (m_decoder.decode(src, complen, dest, destlen) != HUFFERR_NONE) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); } @@ -1282,19 +1485,19 @@ uint32_t chd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, uint // reset and encode big-endian m_encoder.reset(dest + 1, hunkbytes() - 1); if (!m_encoder.encode_interleaved(reinterpret_cast<const int16_t *>(src), srclen / 4, !m_big_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); uint32_t complen_be = m_encoder.finish(); // reset and encode little-endian m_encoder.reset(dest + 1, hunkbytes() - 1); if (!m_encoder.encode_interleaved(reinterpret_cast<const int16_t *>(src), srclen / 4, m_big_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); uint32_t complen_le = m_encoder.finish(); // pick the best one and add a byte uint32_t complen = std::min(complen_le, complen_be); if (complen + 1 >= hunkbytes()) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // if big-endian was better, re-do it dest[0] = 'L'; @@ -1303,7 +1506,7 @@ uint32_t chd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, uint dest[0] = 'B'; m_encoder.reset(dest + 1, hunkbytes() - 1); if (!m_encoder.encode_interleaved(reinterpret_cast<const int16_t *>(src), srclen / 4, !m_big_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); m_encoder.finish(); } return complen + 1; @@ -1358,13 +1561,13 @@ void chd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, uin else if (src[0] == 'B') swap_endian = !m_big_endian; else - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // reset and decode if (!m_decoder.reset(44100, 2, chd_flac_compressor::blocksize(destlen), src + 1, complen - 1)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (!m_decoder.decode_interleaved(reinterpret_cast<int16_t *>(dest), destlen / 4, swap_endian)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // finish up m_decoder.finish(); @@ -1381,12 +1584,12 @@ void chd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, uin //------------------------------------------------- chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_compressor(chd, hunkbytes, lossy), - m_buffer(hunkbytes) + : chd_compressor(chd, hunkbytes, lossy) + , m_buffer(hunkbytes) { // make sure the CHD's hunk size is an even multiple of the frame size - if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + if (hunkbytes % cdrom_file::FRAME_SIZE != 0) + throw std::error_condition(chd_file::error::CODEC_ERROR); // determine whether we want native or swapped samples uint16_t native_endian = 0; @@ -1396,7 +1599,7 @@ chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes // configure the encoder m_encoder.set_sample_rate(44100); m_encoder.set_num_channels(2); - m_encoder.set_block_size(blocksize((hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA)); + m_encoder.set_block_size(blocksize((hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA)); m_encoder.set_strip_metadata(true); // initialize the deflater @@ -1409,7 +1612,7 @@ chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } @@ -1431,32 +1634,32 @@ chd_cd_flac_compressor::~chd_cd_flac_compressor() uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) { // copy audio data followed by subcode data - uint32_t frames = hunkbytes() / CD_FRAME_SIZE; + uint32_t frames = hunkbytes() / cdrom_file::FRAME_SIZE; for (uint32_t framenum = 0; framenum < frames; framenum++) { - memcpy(&m_buffer[framenum * CD_MAX_SECTOR_DATA], &src[framenum * CD_FRAME_SIZE], CD_MAX_SECTOR_DATA); - memcpy(&m_buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], &src[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], CD_MAX_SUBCODE_DATA); + memcpy(&m_buffer[framenum * cdrom_file::MAX_SECTOR_DATA], &src[framenum * cdrom_file::FRAME_SIZE], cdrom_file::MAX_SECTOR_DATA); + memcpy(&m_buffer[frames * cdrom_file::MAX_SECTOR_DATA + framenum * cdrom_file::MAX_SUBCODE_DATA], &src[framenum * cdrom_file::FRAME_SIZE + cdrom_file::MAX_SECTOR_DATA], cdrom_file::MAX_SUBCODE_DATA); } // reset and encode the audio portion m_encoder.reset(dest, hunkbytes()); uint8_t *buffer = &m_buffer[0]; - if (!m_encoder.encode_interleaved(reinterpret_cast<int16_t *>(buffer), frames * CD_MAX_SECTOR_DATA/4, m_swap_endian)) - throw CHDERR_COMPRESSION_ERROR; + if (!m_encoder.encode_interleaved(reinterpret_cast<int16_t *>(buffer), frames * cdrom_file::MAX_SECTOR_DATA/4, m_swap_endian)) + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // finish up uint32_t complen = m_encoder.finish(); // deflate the subcode data - m_deflater.next_in = const_cast<Bytef *>(&m_buffer[frames * CD_MAX_SECTOR_DATA]); - m_deflater.avail_in = frames * CD_MAX_SUBCODE_DATA; + m_deflater.next_in = const_cast<Bytef *>(&m_buffer[frames * cdrom_file::MAX_SECTOR_DATA]); + m_deflater.avail_in = frames * cdrom_file::MAX_SUBCODE_DATA; m_deflater.total_in = 0; m_deflater.next_out = &dest[complen]; m_deflater.avail_out = hunkbytes() - complen; m_deflater.total_out = 0; int zerr = deflateReset(&m_deflater); if (zerr != Z_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // do it zerr = deflate(&m_deflater, Z_FINISH); @@ -1464,7 +1667,7 @@ uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, u // if we ended up with more data than we started with, return an error complen += m_deflater.total_out; if (zerr != Z_STREAM_END || complen >= srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); return complen; } @@ -1484,7 +1687,7 @@ uint32_t chd_cd_flac_compressor::blocksize(uint32_t bytes) { // for CDs it seems that CD_MAX_SECTOR_DATA is the right target uint32_t blocksize = bytes / 4; - while (blocksize > CD_MAX_SECTOR_DATA) + while (blocksize > cdrom_file::MAX_SECTOR_DATA) blocksize /= 2; return blocksize; } @@ -1510,12 +1713,12 @@ uint32_t chd_cd_flac_compressor::blocksize(uint32_t bytes) */ chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_decompressor(chd, hunkbytes, lossy), - m_buffer(hunkbytes) + : chd_decompressor(chd, hunkbytes, lossy) + , m_buffer(hunkbytes) { // make sure the CHD's hunk size is an even multiple of the frame size - if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + if (hunkbytes % cdrom_file::FRAME_SIZE != 0) + throw std::error_condition(chd_file::error::CODEC_ERROR); // determine whether we want native or swapped samples uint16_t native_endian = 0; @@ -1532,7 +1735,7 @@ chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkb if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } /** @@ -1567,37 +1770,37 @@ chd_cd_flac_decompressor::~chd_cd_flac_decompressor() void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { // reset and decode - uint32_t frames = destlen / CD_FRAME_SIZE; - if (!m_decoder.reset(44100, 2, chd_cd_flac_compressor::blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) - throw CHDERR_DECOMPRESSION_ERROR; + uint32_t frames = destlen / cdrom_file::FRAME_SIZE; + if (!m_decoder.reset(44100, 2, chd_cd_flac_compressor::blocksize(frames * cdrom_file::MAX_SECTOR_DATA), src, complen)) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); uint8_t *buffer = &m_buffer[0]; - if (!m_decoder.decode_interleaved(reinterpret_cast<int16_t *>(buffer), frames * CD_MAX_SECTOR_DATA/4, m_swap_endian)) - throw CHDERR_DECOMPRESSION_ERROR; + if (!m_decoder.decode_interleaved(reinterpret_cast<int16_t *>(buffer), frames * cdrom_file::MAX_SECTOR_DATA/4, m_swap_endian)) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // inflate the subcode data uint32_t offset = m_decoder.finish(); m_inflater.next_in = const_cast<Bytef *>(src + offset); m_inflater.avail_in = complen - offset; m_inflater.total_in = 0; - m_inflater.next_out = &m_buffer[frames * CD_MAX_SECTOR_DATA]; - m_inflater.avail_out = frames * CD_MAX_SUBCODE_DATA; + m_inflater.next_out = &m_buffer[frames * cdrom_file::MAX_SECTOR_DATA]; + m_inflater.avail_out = frames * cdrom_file::MAX_SUBCODE_DATA; m_inflater.total_out = 0; int zerr = inflateReset(&m_inflater); if (zerr != Z_OK) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // do it zerr = inflate(&m_inflater, Z_FINISH); if (zerr != Z_STREAM_END) - throw CHDERR_DECOMPRESSION_ERROR; - if (m_inflater.total_out != frames * CD_MAX_SUBCODE_DATA) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); + if (m_inflater.total_out != frames * cdrom_file::MAX_SUBCODE_DATA) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // reassemble the data for (uint32_t framenum = 0; framenum < frames; framenum++) { - memcpy(&dest[framenum * CD_FRAME_SIZE], &m_buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); - memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &m_buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + memcpy(&dest[framenum * cdrom_file::FRAME_SIZE], &m_buffer[framenum * cdrom_file::MAX_SECTOR_DATA], cdrom_file::MAX_SECTOR_DATA); + memcpy(&dest[framenum * cdrom_file::FRAME_SIZE + cdrom_file::MAX_SECTOR_DATA], &m_buffer[frames * cdrom_file::MAX_SECTOR_DATA + framenum * cdrom_file::MAX_SUBCODE_DATA], cdrom_file::MAX_SUBCODE_DATA); } } @@ -1620,15 +1823,15 @@ void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, */ chd_avhuff_compressor::chd_avhuff_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_compressor(chd, hunkbytes, lossy), - m_postinit(false) + : chd_compressor(chd, hunkbytes, lossy) + , m_postinit(false) { try { // attempt to do a post-init now postinit(); } - catch (chd_error &) + catch (std::error_condition const &) { // if we're creating a new CHD, it won't work but that's ok } @@ -1665,14 +1868,14 @@ uint32_t chd_avhuff_compressor::compress(const uint8_t *src, uint32_t srclen, ui int size = avhuff_encoder::raw_data_size(src); while (size < srclen) if (src[size++] != 0) - throw CHDERR_INVALID_DATA; + throw std::error_condition(chd_file::error::INVALID_DATA); } // encode the audio and video uint32_t complen; avhuff_error averr = m_encoder.encode_data(src, dest, complen); if (averr != AVHERR_NONE || complen > srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); return complen; } @@ -1693,21 +1896,21 @@ void chd_avhuff_compressor::postinit() { // get the metadata std::string metadata; - chd_error err = chd().read_metadata(AV_METADATA_TAG, 0, metadata); - if (err != CHDERR_NONE) + std::error_condition err = chd().read_metadata(AV_METADATA_TAG, 0, metadata); + if (err) throw err; // extract the info int fps, fpsfrac, width, height, interlaced, channels, rate; if (sscanf(metadata.c_str(), AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7) - throw CHDERR_INVALID_METADATA; + throw std::error_condition(chd_file::error::INVALID_METADATA); // compute the bytes per frame uint32_t fps_times_1million = fps * 1000000 + fpsfrac; uint32_t max_samples_per_frame = (uint64_t(rate) * 1000000 + fps_times_1million - 1) / fps_times_1million; uint32_t bytes_per_frame = 12 + channels * max_samples_per_frame * 2 + width * height * 2; if (bytes_per_frame > hunkbytes()) - throw CHDERR_INVALID_METADATA; + throw std::error_condition(chd_file::error::INVALID_METADATA); // done with post-init m_postinit = true; @@ -1736,36 +1939,25 @@ chd_avhuff_decompressor::chd_avhuff_decompressor(chd_file &chd, uint32_t hunkbyt { } -/** - * @fn void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) - * - * @brief ------------------------------------------------- - * decompress - decompress data using the A/V codec - * -------------------------------------------------. - * - * @exception CHDERR_DECOMPRESSION_ERROR Thrown when a chderr decompression error error - * condition occurs. - * - * @param src Source for the. - * @param complen The complen. - * @param [in,out] dest If non-null, destination for the. - * @param destlen The destlen. - */ +void chd_avhuff_decompressor::process(const uint8_t *src, uint32_t complen) +{ + // decode the audio and video + avhuff_error averr = m_decoder.decode_data(src, complen, nullptr); + if (averr != AVHERR_NONE) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); +} void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { // decode the audio and video avhuff_error averr = m_decoder.decode_data(src, complen, dest); if (averr != AVHERR_NONE) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // pad short frames with 0 - if (dest != nullptr) - { - int size = avhuff_encoder::raw_data_size(dest); - if (size < destlen) - memset(dest + size, 0, destlen - size); - } + auto const size = avhuff_encoder::raw_data_size(dest); + if (size < destlen) + memset(dest + size, 0, destlen - size); } /** @@ -1786,9 +1978,9 @@ 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 - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); } |