summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util
diff options
context:
space:
mode:
author Vas Crabb <cuavas@users.noreply.github.com>2021-08-22 09:06:15 +1000
committer GitHub <noreply@github.com>2021-08-22 09:06:15 +1000
commite8bbea1fc6e94e14768509d322f6c624403ffb36 (patch)
tree74dd1606a900d83de8aecff17a6737af4113308d /src/lib/util
parente319bde5fc3696d7f48f62b15b6366c4377fe5d1 (diff)
formats, osd, util: Started refactoring file I/O stuff. (#8456)
Added more modern generic I/O interfaces with implementation backed by stdio, osd_file and core_file, replacing io_generic. Also replaced core_file's build-in zlib compression with a filter. unzip.cpp, un7z.cpp: Added option to supply abstract I/O interface rather than filename. Converted osd_file, core_file, archive_file, chd_file and device_image_interface to use std::error_condition rather than their own error enums. Allow mounting TI-99 RPK from inside archives.
Diffstat (limited to 'src/lib/util')
-rw-r--r--src/lib/util/avhuff.cpp4
-rw-r--r--src/lib/util/aviio.cpp84
-rw-r--r--src/lib/util/cdrom.cpp91
-rw-r--r--src/lib/util/cdrom.h14
-rw-r--r--src/lib/util/chd.cpp711
-rw-r--r--src/lib/util/chd.h274
-rw-r--r--src/lib/util/chdcd.cpp186
-rw-r--r--src/lib/util/chdcd.h12
-rw-r--r--src/lib/util/chdcodec.cpp260
-rw-r--r--src/lib/util/chdcodec.h95
-rw-r--r--src/lib/util/corefile.cpp441
-rw-r--r--src/lib/util/corefile.h49
-rw-r--r--src/lib/util/harddisk.cpp18
-rw-r--r--src/lib/util/harddisk.h10
-rw-r--r--src/lib/util/ioprocs.cpp1248
-rw-r--r--src/lib/util/ioprocs.h130
-rw-r--r--src/lib/util/ioprocsfill.h163
-rw-r--r--src/lib/util/ioprocsfilter.cpp598
-rw-r--r--src/lib/util/ioprocsfilter.h31
-rw-r--r--src/lib/util/ioprocsvec.h211
-rw-r--r--src/lib/util/path.cpp0
-rw-r--r--src/lib/util/path.h65
-rw-r--r--src/lib/util/strformat.h54
-rw-r--r--src/lib/util/timeconv.cpp69
-rw-r--r--src/lib/util/timeconv.h39
-rw-r--r--src/lib/util/un7z.cpp467
-rw-r--r--src/lib/util/unzip.cpp1050
-rw-r--r--src/lib/util/unzip.h58
-rw-r--r--src/lib/util/utilfwd.h45
-rw-r--r--src/lib/util/zippath.cpp149
-rw-r--r--src/lib/util/zippath.h5
31 files changed, 4550 insertions, 2081 deletions
diff --git a/src/lib/util/avhuff.cpp b/src/lib/util/avhuff.cpp
index ac5cea71526..0689fe25b80 100644
--- a/src/lib/util/avhuff.cpp
+++ b/src/lib/util/avhuff.cpp
@@ -896,9 +896,9 @@ avhuff_error avhuff_decoder::decode_audio(int channels, int samples, const uint8
{
// reset and decode
if (!m_flac_decoder.reset(48000, 1, samples, source, size))
- throw CHDERR_DECOMPRESSION_ERROR;
+ throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR);
if (!m_flac_decoder.decode_interleaved(reinterpret_cast<int16_t *>(curdest), samples, swap_endian))
- throw CHDERR_DECOMPRESSION_ERROR;
+ throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR);
// finish up
m_flac_decoder.finish();
diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp
index 03014611873..3a3a1a412f6 100644
--- a/src/lib/util/aviio.cpp
+++ b/src/lib/util/aviio.cpp
@@ -1710,8 +1710,8 @@ avi_file::error avi_file_impl::read_uncompressed_video_frame(std::uint32_t frame
/* read in the data */
std::uint32_t bytes_read;
- osd_file::error const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read);
- if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(framenum).length)
+ std::error_condition const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read);
+ if (filerr || bytes_read != stream->chunk(framenum).length)
return error::READ_ERROR;
/* validate this is good data */
@@ -1765,8 +1765,8 @@ avi_file::error avi_file_impl::read_video_frame(std::uint32_t framenum, bitmap_y
/* read in the data */
std::uint32_t bytes_read;
- osd_file::error const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read);
- if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(framenum).length)
+ std::error_condition const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read);
+ if (filerr || bytes_read != stream->chunk(framenum).length)
return error::READ_ERROR;
/* validate this is good data */
@@ -1857,8 +1857,8 @@ avi_file::error avi_file_impl::read_sound_samples(int channel, std::uint32_t fir
return avierr;
/* read in the data */
- auto const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(chunknum).offset, stream->chunk(chunknum).length, bytes_read);
- if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(chunknum).length)
+ std::error_condition const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(chunknum).offset, stream->chunk(chunknum).length, bytes_read);
+ if (filerr || bytes_read != stream->chunk(chunknum).length)
return error::READ_ERROR;
/* validate this is good data */
@@ -2085,14 +2085,15 @@ avi_file::error avi_file_impl::append_sound_samples(int channel, const std::int1
avi_file::error avi_file_impl::read_chunk_data(avi_chunk const &chunk, std::unique_ptr<std::uint8_t []> &buffer)
{
- /* allocate memory for the data */
- try { buffer.reset(new std::uint8_t[chunk.size]); }
- catch (...) { return error::NO_MEMORY; }
+ // allocate memory for the data
+ buffer.reset(new (std::nothrow) std::uint8_t[chunk.size]);
+ if (!buffer)
+ return error::NO_MEMORY;
- /* read from the file */
+ // read from the file
std::uint32_t bytes_read;
- osd_file::error const filerr = m_file->read(&buffer[0], chunk.offset + 8, chunk.size, bytes_read);
- if (filerr != osd_file::error::NONE || bytes_read != chunk.size)
+ std::error_condition const filerr = m_file->read(&buffer[0], chunk.offset + 8, chunk.size, bytes_read);
+ if (filerr || bytes_read != chunk.size)
{
buffer.reset();
return error::READ_ERROR;
@@ -2292,35 +2293,33 @@ avi_file::error avi_file_impl::find_next_list(std::uint32_t findme, const avi_ch
avi_file::error avi_file_impl::get_next_chunk_internal(const avi_chunk *parent, avi_chunk &newchunk, std::uint64_t offset)
{
- osd_file::error filerr;
- std::uint8_t buffer[12];
- std::uint32_t bytesread;
-
- /* nullptr parent implies the root */
- if (parent == nullptr)
+ // nullptr parent implies the root
+ if (!parent)
parent = &m_rootchunk;
- /* start at the current offset */
+ // start at the current offset
newchunk.offset = offset;
- /* if we're past the bounds of the parent, bail */
+ // if we're past the bounds of the parent, bail
if (newchunk.offset + 8 >= parent->offset + 8 + parent->size)
return error::END;
- /* read the header */
- filerr = m_file->read(buffer, newchunk.offset, 8, bytesread);
- if (filerr != osd_file::error::NONE || bytesread != 8)
+ // read the header
+ std::uint8_t buffer[12];
+ std::uint32_t bytesread;
+ std::error_condition filerr = m_file->read(buffer, newchunk.offset, 8, bytesread);
+ if (filerr || bytesread != 8)
return error::INVALID_DATA;
- /* fill in the new chunk */
+ // fill in the new chunk
newchunk.type = fetch_32bits(&buffer[0]);
newchunk.size = fetch_32bits(&buffer[4]);
- /* if we are a list, fetch the list type */
+ // if we are a list, fetch the list type
if (newchunk.type == CHUNKTYPE_LIST || newchunk.type == CHUNKTYPE_RIFF)
{
filerr = m_file->read(&buffer[8], newchunk.offset + 8, 4, bytesread);
- if (filerr != osd_file::error::NONE || bytesread != 4)
+ if (filerr || bytesread != 4)
return error::INVALID_DATA;
newchunk.listtype = fetch_32bits(&buffer[8]);
}
@@ -2643,16 +2642,15 @@ avi_file::error avi_file_impl::parse_indx_chunk(avi_stream &stream, avi_chunk co
/* loop over entries and create subchunks for each */
for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const std::uint8_t *base = &chunkdata[24 + entry * 16];
- osd_file::error filerr;
+ std::uint8_t const *const base = &chunkdata[24 + entry * 16];
avi_chunk subchunk;
- std::uint32_t bytes_read;
- std::uint8_t buffer[8];
/* go read the subchunk */
subchunk.offset = fetch_64bits(&base[0]);
- filerr = m_file->read(buffer, subchunk.offset, sizeof(buffer), bytes_read);
- if (filerr != osd_file::error::NONE || bytes_read != sizeof(buffer))
+ std::uint32_t bytes_read;
+ std::uint8_t buffer[8];
+ std::error_condition const filerr = m_file->read(buffer, subchunk.offset, sizeof(buffer), bytes_read);
+ if (filerr || bytes_read != sizeof(buffer))
{
avierr = error::READ_ERROR;
break;
@@ -2788,8 +2786,8 @@ avi_file::error avi_file_impl::chunk_open(std::uint32_t type, std::uint32_t list
/* write the header */
std::uint32_t written;
- osd_file::error const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written);
- if (filerr != osd_file::error::NONE || written != sizeof(buffer))
+ std::error_condition const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written);
+ if (filerr || written != sizeof(buffer))
return error::WRITE_ERROR;
m_writeoffs += written;
}
@@ -2806,8 +2804,8 @@ avi_file::error avi_file_impl::chunk_open(std::uint32_t type, std::uint32_t list
/* write the header */
std::uint32_t written;
- osd_file::error const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written);
- if (filerr != osd_file::error::NONE || written != sizeof(buffer))
+ std::error_condition const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written);
+ if (filerr || written != sizeof(buffer))
return error::WRITE_ERROR;
m_writeoffs += written;
}
@@ -2846,8 +2844,8 @@ avi_file::error avi_file_impl::chunk_close()
put_32bits(&buffer[0], std::uint32_t(chunksize));
std::uint32_t written;
- osd_file::error const filerr = m_file->write(buffer, chunk.offset + 4, sizeof(buffer), written);
- if (filerr != osd_file::error::NONE || written != sizeof(buffer))
+ std::error_condition const filerr = m_file->write(buffer, chunk.offset + 4, sizeof(buffer), written);
+ if (filerr || written != sizeof(buffer))
return error::WRITE_ERROR;
}
@@ -2925,8 +2923,8 @@ avi_file::error avi_file_impl::chunk_write(std::uint32_t type, const void *data,
/* write the data */
std::uint32_t written;
- osd_file::error const filerr = m_file->write(data, m_writeoffs, length, written);
- if (filerr != osd_file::error::NONE || written != length)
+ std::error_condition const filerr = m_file->write(data, m_writeoffs, length, written);
+ if (filerr || written != length)
return error::WRITE_ERROR;
m_writeoffs += written;
@@ -3678,7 +3676,7 @@ avi_file::error avi_file::open(std::string const &filename, ptr &file)
/* open the file */
osd_file::ptr f;
std::uint64_t length;
- if (osd_file::open(filename, OPEN_FLAG_READ, f, length) != osd_file::error::NONE)
+ if (osd_file::open(filename, OPEN_FLAG_READ, f, length))
return error::CANT_OPEN_FILE;
/* allocate the file */
@@ -3731,8 +3729,8 @@ avi_file::error avi_file::create(std::string const &filename, movie_info const &
/* open the file */
osd_file::ptr f;
std::uint64_t length;
- osd_file::error const filerr = osd_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, f, length);
- if (filerr != osd_file::error::NONE)
+ std::error_condition const filerr = osd_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, f, length);
+ if (filerr)
return error::CANT_OPEN_FILE;
/* allocate the file */
diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp
index 4ac1ab6e865..7510a1f9b47 100644
--- a/src/lib/util/cdrom.cpp
+++ b/src/lib/util/cdrom.cpp
@@ -19,6 +19,7 @@
#include "cdrom.h"
#include "chdcd.h"
+#include "corefile.h"
#include <cassert>
#include <cstdlib>
@@ -223,10 +224,10 @@ cdrom_file *cdrom_open(const char *inputfile)
return nullptr;
// set up the CD-ROM module and get the disc info
- chd_error err = chdcd_parse_toc(inputfile, file->cdtoc, file->track_info);
- if (err != CHDERR_NONE)
+ std::error_condition err = chdcd_parse_toc(inputfile, file->cdtoc, file->track_info);
+ if (err)
{
- fprintf(stderr, "Error reading input file: %s\n", chd_file::error_string(err));
+ fprintf(stderr, "Error reading input file: %s\n", err.message().c_str());
delete file;
return nullptr;
}
@@ -238,14 +239,15 @@ cdrom_file *cdrom_open(const char *inputfile)
for (i = 0; i < file->cdtoc.numtrks; i++)
{
- osd_file::error filerr = util::core_file::open(file->track_info.track[i].fname, OPEN_FLAG_READ, file->fhandle[i]);
- if (filerr != osd_file::error::NONE)
+ std::error_condition const filerr = util::core_file::open(file->track_info.track[i].fname, OPEN_FLAG_READ, file->fhandle[i]);
+ if (filerr)
{
fprintf(stderr, "Unable to open file: %s\n", file->track_info.track[i].fname.c_str());
cdrom_close(file);
return nullptr;
}
}
+
/* calculate the starting frame for each track, keeping in mind that CHDMAN
pads tracks out with extra frames to fit 4-frame size boundries
*/
@@ -336,8 +338,8 @@ cdrom_file *cdrom_open(chd_file *chd)
file->chd = chd;
/* read the CD-ROM metadata */
- chd_error err = cdrom_parse_metadata(chd, &file->cdtoc);
- if (err != CHDERR_NONE)
+ std::error_condition err = cdrom_parse_metadata(chd, &file->cdtoc);
+ if (err)
{
delete file;
return nullptr;
@@ -446,7 +448,7 @@ void cdrom_close(cdrom_file *file)
***************************************************************************/
/**
- * @fn chd_error read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length)
+ * @fn std::error_condition read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length)
*
* @brief Reads partial sector.
*
@@ -461,9 +463,9 @@ void cdrom_close(cdrom_file *file)
* @return The partial sector.
*/
-chd_error read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length, bool phys=false)
+std::error_condition read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length, bool phys=false)
{
- chd_error result = CHDERR_NONE;
+ std::error_condition result;
bool needswap = false;
// if this is pregap info that isn't actually in the file, just return blank data
@@ -570,14 +572,14 @@ uint32_t cdrom_read_data(cdrom_file *file, uint32_t lbasector, void *buffer, uin
if ((datatype == tracktype) || (datatype == CD_TRACK_RAW_DONTCARE))
{
- return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 0, file->cdtoc.tracks[tracknum].datasize, phys) == CHDERR_NONE);
+ return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 0, file->cdtoc.tracks[tracknum].datasize, phys);
}
else
{
// return 2048 bytes of mode 1 data from a 2352 byte mode 1 raw sector
if ((datatype == CD_TRACK_MODE1) && (tracktype == CD_TRACK_MODE1_RAW))
{
- return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2048, phys) == CHDERR_NONE);
+ return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2048, phys);
}
// return 2352 byte mode 1 raw sector from 2048 bytes of mode 1 data
@@ -593,25 +595,25 @@ uint32_t cdrom_read_data(cdrom_file *file, uint32_t lbasector, void *buffer, uin
bufptr[14] = msf&0xff;
bufptr[15] = 1; // mode 1
LOG(("CDROM: promotion of mode1/form1 sector to mode1 raw is not complete!\n"));
- return (read_partial_sector(file, bufptr+16, lbasector, chdsector, tracknum, 0, 2048, phys) == CHDERR_NONE);
+ return !read_partial_sector(file, bufptr+16, lbasector, chdsector, tracknum, 0, 2048, phys);
}
// return 2048 bytes of mode 1 data from a mode2 form1 or raw sector
if ((datatype == CD_TRACK_MODE1) && ((tracktype == CD_TRACK_MODE2_FORM1)||(tracktype == CD_TRACK_MODE2_RAW)))
{
- return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 24, 2048, phys) == CHDERR_NONE);
+ return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 24, 2048, phys);
}
// return 2048 bytes of mode 1 data from a mode2 form2 or XA sector
if ((datatype == CD_TRACK_MODE1) && (tracktype == CD_TRACK_MODE2_FORM_MIX))
{
- return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 8, 2048, phys) == CHDERR_NONE);
+ return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 8, 2048, phys);
}
// return mode 2 2336 byte data from a 2352 byte mode 1 or 2 raw sector (skip the header)
if ((datatype == CD_TRACK_MODE2) && ((tracktype == CD_TRACK_MODE1_RAW) || (tracktype == CD_TRACK_MODE2_RAW)))
{
- return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2336, phys) == CHDERR_NONE);
+ return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2336, phys);
}
LOG(("CDROM: Conversion from type %d to type %d not supported!\n", tracktype, datatype));
@@ -660,8 +662,8 @@ uint32_t cdrom_read_subcode(cdrom_file *file, uint32_t lbasector, void *buffer,
return 0;
// read the data
- chd_error err = read_partial_sector(file, buffer, lbasector, chdsector, tracknum, file->cdtoc.tracks[tracknum].datasize, file->cdtoc.tracks[tracknum].subsize);
- return (err == CHDERR_NONE);
+ std::error_condition err = read_partial_sector(file, buffer, lbasector, chdsector, tracknum, file->cdtoc.tracks[tracknum].datasize, file->cdtoc.tracks[tracknum].subsize);
+ return !err;
}
@@ -1139,21 +1141,20 @@ const char *cdrom_get_subtype_string(uint32_t subtype)
-------------------------------------------------*/
/**
- * @fn chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
+ * @fn std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
*
* @brief Cdrom parse metadata.
*
* @param [in,out] chd If non-null, the chd.
* @param [in,out] toc If non-null, the TOC.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
+std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
{
std::string metadata;
- chd_error err;
- int i;
+ std::error_condition err;
toc->flags = 0;
@@ -1168,49 +1169,49 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
/* fetch the metadata for this track */
err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata);
- if (err == CHDERR_NONE)
+ if (!err)
{
/* parse the metadata */
type[0] = subtype[0] = 0;
pgtype[0] = pgsub[0] = 0;
if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames) != 4)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
track = &toc->tracks[tracknum - 1];
}
else
{
err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata);
- if (err == CHDERR_NONE)
+ if (!err)
{
/* parse the metadata */
type[0] = subtype[0] = 0;
pregap = postgap = 0;
if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
track = &toc->tracks[tracknum - 1];
}
else
{
err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc->numtrks, metadata);
- if (err == CHDERR_NONE)
+ if (!err)
/* legacy GDROM track was detected */
toc->flags |= CD_FLAG_GDROMLE;
else
err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc->numtrks, metadata);
- if (err == CHDERR_NONE)
+ if (!err)
{
/* parse the metadata */
type[0] = subtype[0] = 0;
pregap = postgap = 0;
if (sscanf(metadata.c_str(), GDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames, &padframes, &pregap, pgtype, pgsub, &postgap) != 9)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
if (tracknum == 0 || tracknum > CD_MAX_TRACKS)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
track = &toc->tracks[tracknum - 1];
toc->flags |= CD_FLAG_GDROM;
}
@@ -1226,7 +1227,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
track->datasize = 0;
cdrom_convert_type_string_to_track_info(type, track);
if (track->datasize == 0)
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
/* extract the subtype and determine the subcode data size */
track->subtype = CD_SUB_NONE;
@@ -1261,21 +1262,21 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
/* if we got any tracks this way, we're done */
if (toc->numtrks > 0)
- return CHDERR_NONE;
+ return std::error_condition();
printf("toc->numtrks = %u?!\n", toc->numtrks);
/* look for old-style metadata */
std::vector<uint8_t> oldmetadata;
err = chd->read_metadata(CDROM_OLD_METADATA_TAG, 0, oldmetadata);
- if (err != CHDERR_NONE)
+ if (err)
return err;
/* reconstruct the TOC from it */
auto *mrp = reinterpret_cast<uint32_t *>(&oldmetadata[0]);
toc->numtrks = *mrp++;
- for (i = 0; i < CD_MAX_TRACKS; i++)
+ for (int i = 0; i < CD_MAX_TRACKS; i++)
{
toc->tracks[i].trktype = *mrp++;
toc->tracks[i].subtype = *mrp++;
@@ -1295,7 +1296,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
if (toc->numtrks > CD_MAX_TRACKS)
{
toc->numtrks = swapendian_int32(toc->numtrks);
- for (i = 0; i < CD_MAX_TRACKS; i++)
+ for (int i = 0; i < CD_MAX_TRACKS; i++)
{
toc->tracks[i].trktype = swapendian_int32(toc->tracks[i].trktype);
toc->tracks[i].subtype = swapendian_int32(toc->tracks[i].subtype);
@@ -1307,7 +1308,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
}
}
- return CHDERR_NONE;
+ return std::error_condition();
}
@@ -1316,19 +1317,19 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc)
-------------------------------------------------*/
/**
- * @fn chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
+ * @fn std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
*
* @brief Cdrom write metadata.
*
* @param [in,out] chd If non-null, the chd.
* @param toc The TOC.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
+std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
{
- chd_error err;
+ std::error_condition err;
/* write the metadata */
for (int i = 0; i < toc->numtrks; i++)
@@ -1363,10 +1364,10 @@ chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc)
err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata);
}
- if (err != CHDERR_NONE)
+ if (err)
return err;
}
- return CHDERR_NONE;
+ return std::error_condition();
}
/**
diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h
index 27d41da845e..1847a1db83a 100644
--- a/src/lib/util/cdrom.h
+++ b/src/lib/util/cdrom.h
@@ -7,15 +7,15 @@
Generic MAME cd-rom implementation
***************************************************************************/
-
-#ifndef MAME_UTIL_CDROM_H
-#define MAME_UTIL_CDROM_H
+#ifndef MAME_LIB_UTIL_CDROM_H
+#define MAME_LIB_UTIL_CDROM_H
#pragma once
-#include "osdcore.h"
#include "chd.h"
+#include "osdcore.h"
+
/***************************************************************************
@@ -137,8 +137,8 @@ void cdrom_convert_subtype_string_to_track_info(const char *typestring, cdrom_tr
void cdrom_convert_subtype_string_to_pregap_info(const char *typestring, cdrom_track_info *info);
const char *cdrom_get_type_string(uint32_t trktype);
const char *cdrom_get_subtype_string(uint32_t subtype);
-chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc);
-chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc);
+std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc);
+std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc);
// ECC utilities
bool ecc_verify(const uint8_t *sector);
@@ -184,4 +184,4 @@ static inline uint32_t lba_to_msf_alt(int lba)
return ret;
}
-#endif // MAME_UTIL_CDROM_H
+#endif // MAME_LIB_UTIL_CDROM_H
diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp
index 0de05849cdd..29792fc36df 100644
--- a/src/lib/util/chd.cpp
+++ b/src/lib/util/chd.cpp
@@ -8,20 +8,24 @@
***************************************************************************/
-#include <cassert>
-
#include "chd.h"
+
#include "avhuff.h"
-#include "hashing.h"
-#include "flac.h"
#include "cdrom.h"
+#include "corefile.h"
#include "coretmpl.h"
+#include "flac.h"
+#include "hashing.h"
+
+#include "eminline.h"
+
#include <zlib.h>
-#include <ctime>
+
+#include <cassert>
#include <cstddef>
#include <cstdlib>
+#include <ctime>
#include <new>
-#include "eminline.h"
//**************************************************************************
@@ -186,14 +190,17 @@ inline void chd_file::be_write_sha1(uint8_t *base, util::sha1_t value)
inline void chd_file::file_read(uint64_t offset, void *dest, uint32_t length)
{
// no file = failure
- if (m_file == nullptr)
- throw CHDERR_NOT_OPEN;
+ if (!m_file)
+ throw std::error_condition(error::NOT_OPEN);
// seek and read
m_file->seek(offset, SEEK_SET);
- uint32_t count = m_file->read(dest, length);
- if (count != length)
- throw CHDERR_READ_ERROR;
+ size_t count;
+ std::error_condition err = m_file->read(dest, length, count);
+ if (err)
+ throw err;
+ else if (count != length)
+ throw std::error_condition(std::errc::io_error); // TODO: revisit this error code (happens if file is cut off)
}
@@ -205,14 +212,17 @@ inline void chd_file::file_read(uint64_t offset, void *dest, uint32_t length)
inline void chd_file::file_write(uint64_t offset, const void *source, uint32_t length)
{
// no file = failure
- if (m_file == nullptr)
- throw CHDERR_NOT_OPEN;
+ if (!m_file)
+ throw std::error_condition(error::NOT_OPEN);
// seek and write
m_file->seek(offset, SEEK_SET);
- uint32_t count = m_file->write(source, length);
- if (count != length)
- throw CHDERR_WRITE_ERROR;
+ size_t count;
+ std::error_condition err = m_file->write(source, length, count);
+ if (err)
+ throw err;
+ else if (count != length)
+ throw std::error_condition(std::errc::interrupted); // can theoretically happen if write is inuterrupted by a signal
}
@@ -224,15 +234,22 @@ inline void chd_file::file_write(uint64_t offset, const void *source, uint32_t l
inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint32_t alignment)
{
+ std::error_condition err;
+
// no file = failure
- if (m_file == nullptr)
- throw CHDERR_NOT_OPEN;
+ if (!m_file)
+ throw std::error_condition(error::NOT_OPEN);
// seek to the end and align if necessary
- m_file->seek(0, SEEK_END);
+ err = m_file->seek(0, SEEK_END);
+ if (err)
+ throw err;
if (alignment != 0)
{
- uint64_t offset = m_file->tell();
+ uint64_t offset;
+ err = m_file->tell(offset);
+ if (err)
+ throw err;
uint32_t delta = offset % alignment;
if (delta != 0)
{
@@ -242,20 +259,27 @@ inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint3
delta = alignment - delta;
while (delta != 0)
{
- uint32_t bytes_to_write = (std::min<std::size_t>)(sizeof(buffer), delta);
- uint32_t count = m_file->write(buffer, bytes_to_write);
- if (count != bytes_to_write)
- throw CHDERR_WRITE_ERROR;
- delta -= bytes_to_write;
+ uint32_t bytes_to_write = std::min<std::size_t>(sizeof(buffer), delta);
+ size_t count;
+ err = m_file->write(buffer, bytes_to_write, count);
+ if (err)
+ throw err;
+ delta -= count;
}
}
}
// write the real data
- uint64_t offset = m_file->tell();
- uint32_t count = m_file->write(source, length);
- if (count != length)
- throw CHDERR_READ_ERROR;
+ uint64_t offset;
+ err = m_file->tell(offset);
+ if (err)
+ throw err;
+ size_t count;
+ err = m_file->write(source, length, count);
+ if (err)
+ throw err;
+ else if (count != length)
+ throw std::error_condition(std::errc::interrupted); // can theoretically happen if write is interrupted by a signal
return offset;
}
@@ -288,11 +312,8 @@ inline uint8_t chd_file::bits_for_value(uint64_t value)
*/
chd_file::chd_file()
- : m_file(nullptr),
- m_owns_file(false)
{
// reset state
- memset(m_decompressor, 0, sizeof(m_decompressor));
close();
}
@@ -311,6 +332,22 @@ chd_file::~chd_file()
}
/**
+ * @fn util::random_read chd_file::file()
+ *
+ * @brief -------------------------------------------------
+ * file - return our underlying file
+ * -------------------------------------------------.
+ *
+ * @return A random_read.
+ */
+
+util::random_read &chd_file::file()
+{
+ assert(m_file);
+ return *m_file;
+}
+
+/**
* @fn util::sha1_t chd_file::sha1()
*
* @brief -------------------------------------------------
@@ -329,7 +366,7 @@ util::sha1_t chd_file::sha1()
file_read(m_sha1_offset, rawbuf, sizeof(rawbuf));
return be_read_sha1(rawbuf);
}
- catch (chd_error &)
+ catch (std::error_condition const &)
{
// on failure, return nullptr
return util::sha1_t::null;
@@ -354,15 +391,15 @@ util::sha1_t chd_file::raw_sha1()
try
{
// determine offset within the file for data-only
- if (m_rawsha1_offset == 0)
- throw CHDERR_UNSUPPORTED_VERSION;
+ if (!m_rawsha1_offset)
+ throw std::error_condition(error::UNSUPPORTED_VERSION);
// read the big-endian version
uint8_t rawbuf[sizeof(util::sha1_t)];
file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf));
return be_read_sha1(rawbuf);
}
- catch (chd_error &)
+ catch (std::error_condition const &)
{
// on failure, return nullptr
return util::sha1_t::null;
@@ -387,15 +424,15 @@ util::sha1_t chd_file::parent_sha1()
try
{
// determine offset within the file
- if (m_parentsha1_offset == 0)
- throw CHDERR_UNSUPPORTED_VERSION;
+ if (!m_parentsha1_offset)
+ throw std::error_condition(error::UNSUPPORTED_VERSION);
// read the big-endian version
uint8_t rawbuf[sizeof(util::sha1_t)];
file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf));
return be_read_sha1(rawbuf);
}
- catch (chd_error &)
+ catch (std::error_condition const &)
{
// on failure, return nullptr
return util::sha1_t::null;
@@ -403,7 +440,7 @@ util::sha1_t chd_file::parent_sha1()
}
/**
- * @fn chd_error chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes)
+ * @fn std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes)
*
* @brief -------------------------------------------------
* hunk_info - return information about this hunk
@@ -413,14 +450,14 @@ util::sha1_t chd_file::parent_sha1()
* @param [in,out] compressor The compressor.
* @param [in,out] compbytes The compbytes.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes)
+std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes)
{
// error if invalid
if (hunknum >= m_hunkcount)
- return CHDERR_HUNK_OUT_OF_RANGE;
+ return std::error_condition(error::HUNK_OUT_OF_RANGE);
// get the map pointer
uint8_t *rawmap;
@@ -506,11 +543,11 @@ chd_error chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint
break;
default:
- return CHDERR_UNKNOWN_COMPRESSION;
+ return error::UNKNOWN_COMPRESSION;
}
break;
}
- return CHDERR_NONE;
+ return std::error_condition();
}
/**
@@ -554,8 +591,8 @@ void chd_file::set_raw_sha1(util::sha1_t rawdata)
void chd_file::set_parent_sha1(util::sha1_t parent)
{
// if no file, fail
- if (m_file == nullptr)
- throw CHDERR_INVALID_FILE;
+ if (!m_file)
+ throw std::error_condition(error::INVALID_FILE);
// create a big-endian version
uint8_t rawbuf[sizeof(util::sha1_t)];
@@ -567,7 +604,7 @@ void chd_file::set_parent_sha1(util::sha1_t parent)
}
/**
- * @fn chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
+ * @fn std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
*
* @brief -------------------------------------------------
* create - create a new file with no parent using an existing opened file handle
@@ -579,14 +616,16 @@ void chd_file::set_parent_sha1(util::sha1_t parent)
* @param unitbytes The unitbytes.
* @param compression The compression.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
+std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
{
// make sure we don't already have a file open
- if (m_file != nullptr)
- return CHDERR_ALREADY_OPEN;
+ if (m_file)
+ return error::ALREADY_OPEN;
+ else if (!file)
+ return std::errc::invalid_argument;
// set the header parameters
m_logicalbytes = logicalbytes;
@@ -596,13 +635,12 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_
m_parent = nullptr;
// take ownership of the file
- m_file = &file;
- m_owns_file = false;
+ m_file = std::move(file);
return create_common();
}
/**
- * @fn chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
+ * @fn std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
*
* @brief -------------------------------------------------
* create - create a new file with a parent using an existing opened file handle
@@ -614,14 +652,16 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_
* @param compression The compression.
* @param [in,out] parent The parent.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
+std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
{
// make sure we don't already have a file open
- if (m_file != nullptr)
- return CHDERR_ALREADY_OPEN;
+ if (m_file)
+ return error::ALREADY_OPEN;
+ else if (!file)
+ return std::errc::invalid_argument;
// set the header parameters
m_logicalbytes = logicalbytes;
@@ -631,13 +671,12 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_
m_parent = &parent;
// take ownership of the file
- m_file = &file;
- m_owns_file = false;
+ m_file = std::move(file);
return create_common();
}
/**
- * @fn chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
+ * @fn std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
*
* @brief -------------------------------------------------
* create - create a new file with no parent using a filename
@@ -649,40 +688,38 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_
* @param unitbytes The unitbytes.
* @param compression The compression.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
+std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
{
// make sure we don't already have a file open
- if (m_file != nullptr)
- return CHDERR_ALREADY_OPEN;
+ if (m_file)
+ return error::ALREADY_OPEN;
// create the new file
util::core_file::ptr file;
- const osd_file::error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
- if (filerr != osd_file::error::NONE)
- return CHDERR_FILE_NOT_FOUND;
+ std::error_condition filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
+ if (filerr)
+ return filerr;
+ util::random_read_write::ptr io = util::core_file_read_write(std::move(file));
+ if (!io)
+ return std::errc::not_enough_memory;
// create the file normally, then claim the file
- const chd_error chderr = create(*file, logicalbytes, hunkbytes, unitbytes, compression);
- m_owns_file = true;
+ std::error_condition chderr = create(std::move(io), logicalbytes, hunkbytes, unitbytes, compression);
// if an error happened, close and delete the file
- if (chderr != CHDERR_NONE)
+ if (chderr)
{
- file.reset();
- osd_file::remove(filename);
- }
- else
- {
- file.release();
+ io.reset();
+ osd_file::remove(std::string(filename)); // FIXME: allow osd_file to use std::string_view
}
return chderr;
}
/**
- * @fn chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
+ * @fn std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
*
* @brief -------------------------------------------------
* create - create a new file with a parent using a filename
@@ -694,40 +731,38 @@ chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t
* @param compression The compression.
* @param [in,out] parent The parent.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
+std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
{
// make sure we don't already have a file open
- if (m_file != nullptr)
- return CHDERR_ALREADY_OPEN;
+ if (m_file)
+ return error::ALREADY_OPEN;
// create the new file
util::core_file::ptr file;
- const osd_file::error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
- if (filerr != osd_file::error::NONE)
- return CHDERR_FILE_NOT_FOUND;
+ std::error_condition filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
+ if (filerr)
+ return filerr;
+ util::random_read_write::ptr io = util::core_file_read_write(std::move(file));
+ if (!io)
+ return std::errc::not_enough_memory;
// create the file normally, then claim the file
- const chd_error chderr = create(*file, logicalbytes, hunkbytes, compression, parent);
- m_owns_file = true;
+ std::error_condition chderr = create(std::move(io), logicalbytes, hunkbytes, compression, parent);
// if an error happened, close and delete the file
- if (chderr != CHDERR_NONE)
- {
- file.reset();
- osd_file::remove(filename);
- }
- else
+ if (chderr)
{
- file.release();
+ io.reset();
+ osd_file::remove(std::string(filename)); // FIXME: allow osd_file to use std::string_view
}
return chderr;
}
/**
- * @fn chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
+ * @fn std::error_condition chd_file::open(std::string_view filename, bool writeable, chd_file *parent)
*
* @brief -------------------------------------------------
* open - open an existing file for read or read/write
@@ -737,35 +772,36 @@ chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t
* @param writeable true if writeable.
* @param [in,out] parent If non-null, the parent.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
+std::error_condition chd_file::open(std::string_view filename, bool writeable, chd_file *parent)
{
// make sure we don't already have a file open
- if (m_file != nullptr)
- return CHDERR_ALREADY_OPEN;
+ if (m_file)
+ return error::ALREADY_OPEN;
// open the file
const uint32_t openflags = writeable ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_READ;
util::core_file::ptr file;
- const osd_file::error filerr = util::core_file::open(filename, openflags, file);
- if (filerr != osd_file::error::NONE)
- return CHDERR_FILE_NOT_FOUND;
+ std::error_condition filerr = util::core_file::open(filename, openflags, file);
+ if (filerr)
+ return filerr;
+ util::random_read_write::ptr io = util::core_file_read_write(std::move(file));
+ if (!io)
+ return std::errc::not_enough_memory;
// now open the CHD
- chd_error err = open(*file, writeable, parent);
- if (err != CHDERR_NONE)
+ std::error_condition err = open(std::move(io), writeable, parent);
+ if (err)
return err;
// we now own this file
- file.release();
- m_owns_file = true;
return err;
}
/**
- * @fn chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent)
+ * @fn std::error_condition chd_file::open(util::random_read_write::ptr &&file, bool writeable, chd_file *parent)
*
* @brief -------------------------------------------------
* open - open an existing file for read or read/write
@@ -775,18 +811,19 @@ chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
* @param writeable true if writeable.
* @param [in,out] parent If non-null, the parent.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent)
+std::error_condition chd_file::open(util::random_read_write::ptr &&file, bool writeable, chd_file *parent)
{
// make sure we don't already have a file open
- if (m_file != nullptr)
- return CHDERR_ALREADY_OPEN;
+ if (m_file)
+ return error::ALREADY_OPEN;
+ else if (!file)
+ return std::errc::invalid_argument;
// open the file
- m_file = &file;
- m_owns_file = false;
+ m_file = std::move(file);
m_parent = parent;
m_cachehunk = ~0;
return open_common(writeable);
@@ -803,10 +840,7 @@ chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent
void chd_file::close()
{
// reset file characteristics
- if (m_owns_file && m_file)
- delete m_file;
- m_file = nullptr;
- m_owns_file = false;
+ m_file.reset();
m_allow_reads = false;
m_allow_writes = false;
@@ -836,10 +870,7 @@ void chd_file::close()
// reset compression management
for (auto & elem : m_decompressor)
- {
- delete elem;
- elem = nullptr;
- }
+ elem.reset();
m_compressed.clear();
// reset caching
@@ -848,7 +879,7 @@ void chd_file::close()
}
/**
- * @fn chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer)
+ * @fn std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer)
*
* @brief -------------------------------------------------
* read - read a single hunk from the CHD file
@@ -870,18 +901,18 @@ void chd_file::close()
* @return The hunk.
*/
-chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer)
+std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer)
{
// wrap this for clean reporting
try
{
// punt if no file
- if (m_file == nullptr)
- throw CHDERR_NOT_OPEN;
+ if (!m_file)
+ throw std::error_condition(error::NOT_OPEN);
// return an error if out of range
if (hunknum >= m_hunkcount)
- throw CHDERR_HUNK_OUT_OF_RANGE;
+ throw std::error_condition(error::HUNK_OUT_OF_RANGE);
// get a pointer to the map entry
uint64_t blockoffs;
@@ -904,29 +935,29 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer)
file_read(blockoffs, &m_compressed[0], blocklen);
m_decompressor[0]->decompress(&m_compressed[0], blocklen, dest, m_hunkbytes);
if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != nullptr && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
- return CHDERR_NONE;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
+ return std::error_condition();
case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
file_read(blockoffs, dest, m_hunkbytes);
if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
- return CHDERR_NONE;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
+ return std::error_condition();
case V34_MAP_ENTRY_TYPE_MINI:
be_write(dest, blockoffs, 8);
for (uint32_t bytes = 8; bytes < m_hunkbytes; bytes++)
dest[bytes] = dest[bytes - 8];
if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
- return CHDERR_NONE;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
+ return std::error_condition();
case V34_MAP_ENTRY_TYPE_SELF_HUNK:
return read_hunk(blockoffs, dest);
case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
if (m_parent_missing)
- throw CHDERR_REQUIRES_PARENT;
+ throw std::error_condition(error::REQUIRES_PARENT);
return m_parent->read_hunk(blockoffs, dest);
}
break;
@@ -942,12 +973,12 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer)
if (blockoffs != 0)
file_read(blockoffs, dest, m_hunkbytes);
else if (m_parent_missing)
- throw CHDERR_REQUIRES_PARENT;
+ throw std::error_condition(error::REQUIRES_PARENT);
else if (m_parent != nullptr)
m_parent->read_hunk(hunknum, dest);
else
memset(dest, 0, m_hunkbytes);
- return CHDERR_NONE;
+ return std::error_condition();
}
// compressed case
@@ -963,41 +994,40 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer)
file_read(blockoffs, &m_compressed[0], blocklen);
m_decompressor[rawmap[0]]->decompress(&m_compressed[0], blocklen, dest, m_hunkbytes);
if (!m_decompressor[rawmap[0]]->lossy() && dest != nullptr && util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
if (m_decompressor[rawmap[0]]->lossy() && util::crc16_creator::simple(&m_compressed[0], blocklen) != blockcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
- return CHDERR_NONE;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
+ return std::error_condition();
case COMPRESSION_NONE:
file_read(blockoffs, dest, m_hunkbytes);
if (util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
- return CHDERR_NONE;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
+ return std::error_condition();
case COMPRESSION_SELF:
return read_hunk(blockoffs, dest);
case COMPRESSION_PARENT:
if (m_parent_missing)
- throw CHDERR_REQUIRES_PARENT;
+ throw std::error_condition(error::REQUIRES_PARENT);
return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
}
break;
}
// if we get here, something was wrong
- throw CHDERR_READ_ERROR;
+ throw std::error_condition(std::errc::io_error);
}
-
- // just return errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // just return errors
return err;
}
}
/**
- * @fn chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer)
+ * @fn std::error_condition chd_file::write_hunk(uint32_t hunknum, const void *buffer)
*
* @brief -------------------------------------------------
* write - write a single hunk to the CHD file
@@ -1012,29 +1042,29 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer)
* @param hunknum The hunknum.
* @param buffer The buffer.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer)
+std::error_condition chd_file::write_hunk(uint32_t hunknum, const void *buffer)
{
// wrap this for clean reporting
try
{
// punt if no file
- if (m_file == nullptr)
- throw CHDERR_NOT_OPEN;
+ if (!m_file)
+ throw std::error_condition(error::NOT_OPEN);
// return an error if out of range
if (hunknum >= m_hunkcount)
- throw CHDERR_HUNK_OUT_OF_RANGE;
+ throw std::error_condition(error::HUNK_OUT_OF_RANGE);
// if not writeable, fail
if (!m_allow_writes)
- throw CHDERR_FILE_NOT_WRITEABLE;
+ throw std::error_condition(error::FILE_NOT_WRITEABLE);
// uncompressed writes only via this interface
if (compressed())
- throw CHDERR_FILE_NOT_WRITEABLE;
+ throw std::error_condition(error::FILE_NOT_WRITEABLE);
// see if we have allocated the space on disk for this hunk
uint8_t *rawmap = &m_rawmap[hunknum * 4];
@@ -1055,7 +1085,7 @@ chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer)
// if it's all zeros, do nothing more
if (all_zeros)
- return CHDERR_NONE;
+ return std::error_condition();
// append new data to the end of the file, aligning the first chunk
rawentry = file_append(buffer, m_hunkbytes, m_hunkbytes) / m_hunkbytes;
@@ -1068,22 +1098,22 @@ chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer)
if (hunknum == m_cachehunk && buffer != &m_cache[0])
memcpy(&m_cache[0], buffer, m_hunkbytes);
}
-
- // otherwise, just overwrite
else
+ {
+ // otherwise, just overwrite
file_write(uint64_t(rawentry) * uint64_t(m_hunkbytes), buffer, m_hunkbytes);
- return CHDERR_NONE;
+ }
+ return std::error_condition();
}
-
- // just return errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // just return errors
return err;
}
}
/**
- * @fn chd_error chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count)
+ * @fn std::error_condition chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count)
*
* @brief -------------------------------------------------
* read_units - read the given number of units from the CHD
@@ -1096,13 +1126,13 @@ chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer)
* @return The units.
*/
-chd_error chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count)
+std::error_condition chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count)
{
return read_bytes(unitnum * uint64_t(m_unitbytes), buffer, count * m_unitbytes);
}
/**
- * @fn chd_error chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count)
+ * @fn std::error_condition chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count)
*
* @brief -------------------------------------------------
* write_units - write the given number of units to the CHD
@@ -1112,16 +1142,16 @@ chd_error chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count)
* @param buffer The buffer.
* @param count Number of.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count)
+std::error_condition chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count)
{
return write_bytes(unitnum * uint64_t(m_unitbytes), buffer, count * m_unitbytes);
}
/**
- * @fn chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
+ * @fn std::error_condition chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
*
* @brief -------------------------------------------------
* read_bytes - read from the CHD at a byte level, using the cache to handle partial
@@ -1135,7 +1165,7 @@ chd_error chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t c
* @return The bytes.
*/
-chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
+std::error_condition chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
{
// iterate over hunks
uint32_t first_hunk = offset / m_hunkbytes;
@@ -1148,7 +1178,7 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
uint32_t endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1);
// if it's a full block, just read directly from disk unless it's the cached hunk
- chd_error err = CHDERR_NONE;
+ std::error_condition err;
if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk)
err = read_hunk(curhunk, dest);
@@ -1158,7 +1188,7 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
if (curhunk != m_cachehunk)
{
err = read_hunk(curhunk, &m_cache[0]);
- if (err != CHDERR_NONE)
+ if (err)
return err;
m_cachehunk = curhunk;
}
@@ -1166,15 +1196,15 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
}
// handle errors and advance
- if (err != CHDERR_NONE)
+ if (err)
return err;
dest += endoffs + 1 - startoffs;
}
- return CHDERR_NONE;
+ return std::error_condition();
}
/**
- * @fn chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes)
+ * @fn std::error_condition chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes)
*
* @brief -------------------------------------------------
* write_bytes - write to the CHD at a byte level, using the cache to handle partial
@@ -1185,10 +1215,10 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes)
* @param buffer The buffer.
* @param bytes The bytes.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes)
+std::error_condition chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes)
{
// iterate over hunks
uint32_t first_hunk = offset / m_hunkbytes;
@@ -1201,7 +1231,7 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by
uint32_t endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1);
// if it's a full block, just write directly to disk unless it's the cached hunk
- chd_error err = CHDERR_NONE;
+ std::error_condition err;
if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk)
err = write_hunk(curhunk, source);
@@ -1211,7 +1241,7 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by
if (curhunk != m_cachehunk)
{
err = read_hunk(curhunk, &m_cache[0]);
- if (err != CHDERR_NONE)
+ if (err)
return err;
m_cachehunk = curhunk;
}
@@ -1220,15 +1250,15 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by
}
// handle errors and advance
- if (err != CHDERR_NONE)
+ if (err)
return err;
source += endoffs + 1 - startoffs;
}
- return CHDERR_NONE;
+ return std::error_condition();
}
/**
- * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output)
+ * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output)
*
* @brief -------------------------------------------------
* read_metadata - read the indexed metadata of the given type
@@ -1244,7 +1274,7 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by
* @return The metadata.
*/
-chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output)
+std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output)
{
// wrap this for clean reporting
try
@@ -1252,23 +1282,22 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
// if we didn't find it, just return
metadata_entry metaentry;
if (!metadata_find(searchtag, searchindex, metaentry))
- throw CHDERR_METADATA_NOT_FOUND;
+ throw std::error_condition(error::METADATA_NOT_FOUND);
// read the metadata
output.assign(metaentry.length, '\0');
file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length);
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // just return errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // just return errors
return err;
}
}
/**
- * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output)
+ * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output)
*
* @brief Reads a metadata.
*
@@ -1282,7 +1311,7 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
* @return The metadata.
*/
-chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output)
+std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output)
{
// wrap this for clean reporting
try
@@ -1290,23 +1319,22 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
// if we didn't find it, just return
metadata_entry metaentry;
if (!metadata_find(searchtag, searchindex, metaentry))
- throw CHDERR_METADATA_NOT_FOUND;
+ throw std::error_condition(error::METADATA_NOT_FOUND);
// read the metadata
output.resize(metaentry.length);
file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length);
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // just return errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // just return errors
return err;
}
}
/**
- * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen)
+ * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen)
*
* @brief Reads a metadata.
*
@@ -1322,7 +1350,7 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
* @return The metadata.
*/
-chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen)
+std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen)
{
// wrap this for clean reporting
try
@@ -1330,23 +1358,22 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
// if we didn't find it, just return
metadata_entry metaentry;
if (!metadata_find(searchtag, searchindex, metaentry))
- throw CHDERR_METADATA_NOT_FOUND;
+ throw std::error_condition(error::METADATA_NOT_FOUND);
// read the metadata
resultlen = metaentry.length;
file_read(metaentry.offset + METADATA_HEADER_SIZE, output, std::min(outputlen, resultlen));
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // just return errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // just return errors
return err;
}
}
/**
- * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags)
+ * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags)
*
* @brief Reads a metadata.
*
@@ -1362,7 +1389,7 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
* @return The metadata.
*/
-chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags)
+std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags)
{
// wrap this for clean reporting
try
@@ -1370,25 +1397,24 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
// if we didn't find it, just return
metadata_entry metaentry;
if (!metadata_find(searchtag, searchindex, metaentry))
- throw CHDERR_METADATA_NOT_FOUND;
+ throw std::error_condition(error::METADATA_NOT_FOUND);
// read the metadata
output.resize(metaentry.length);
file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length);
resulttag = metaentry.metatag;
resultflags = metaentry.flags;
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // just return errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // just return errors
return err;
}
}
/**
- * @fn chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags)
+ * @fn std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags)
*
* @brief -------------------------------------------------
* write_metadata - write the indexed metadata of the given type
@@ -1400,17 +1426,17 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind
* @param inputlen The inputlen.
* @param flags The flags.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags)
+std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags)
{
// wrap this for clean reporting
try
{
// must write at least 1 byte and no more than 16MB
if (inputlen < 1 || inputlen >= 16 * 1024 * 1024)
- return CHDERR_INVALID_PARAMETER;
+ return std::error_condition(std::errc::invalid_argument);
// find the entry if it already exists
metadata_entry metaentry;
@@ -1459,18 +1485,17 @@ chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex,
// update the hash
metadata_update_hash();
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // return any errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // return any errors
return err;
}
}
/**
- * @fn chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex)
+ * @fn std::error_condition chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex)
*
* @brief -------------------------------------------------
* delete_metadata - remove the given metadata from the list
@@ -1482,10 +1507,10 @@ chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex,
* @param metatag The metatag.
* @param metaindex The metaindex.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex)
+std::error_condition chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex)
{
// wrap this for clean reporting
try
@@ -1493,22 +1518,21 @@ chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex
// find the entry
metadata_entry metaentry;
if (!metadata_find(metatag, metaindex, metaentry))
- throw CHDERR_METADATA_NOT_FOUND;
+ throw std::error_condition(error::METADATA_NOT_FOUND);
// point the previous to the next, unlinking us
metadata_set_previous_next(metaentry.prev, metaentry.next);
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // return any errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // return any errors
return err;
}
}
/**
- * @fn chd_error chd_file::clone_all_metadata(chd_file &source)
+ * @fn std::error_condition chd_file::clone_all_metadata(chd_file &source)
*
* @brief -------------------------------------------------
* clone_all_metadata - clone the metadata from one CHD to a second
@@ -1518,10 +1542,10 @@ chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex
*
* @param [in,out] source Another instance to copy.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::clone_all_metadata(chd_file &source)
+std::error_condition chd_file::clone_all_metadata(chd_file &source)
{
// wrap this for clean reporting
try
@@ -1540,16 +1564,15 @@ chd_error chd_file::clone_all_metadata(chd_file &source)
source.file_read(metaentry.offset + METADATA_HEADER_SIZE, &filedata[0], metaentry.length);
// write it to the destination
- chd_error err = write_metadata(metaentry.metatag, (uint32_t)-1, &filedata[0], metaentry.length, metaentry.flags);
- if (err != CHDERR_NONE)
+ std::error_condition err = write_metadata(metaentry.metatag, (uint32_t)-1, &filedata[0], metaentry.length, metaentry.flags);
+ if (err)
throw err;
}
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // return any errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // return any errors
return err;
}
}
@@ -1607,7 +1630,7 @@ util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1)
}
/**
- * @fn chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *config)
+ * @fn std::error_condition chd_file::codec_configure(chd_codec_type codec, int param, void *config)
*
* @brief -------------------------------------------------
* codec_config - set internal codec parameters
@@ -1617,10 +1640,10 @@ util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1)
* @param param The parameter.
* @param [in,out] config If non-null, the configuration.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *config)
+std::error_condition chd_file::codec_configure(chd_codec_type codec, int param, void *config)
{
// wrap this for clean reporting
try
@@ -1630,14 +1653,13 @@ chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *confi
if (m_compression[codecnum] == codec)
{
m_decompressor[codecnum]->configure(param, config);
- return CHDERR_NONE;
+ return std::error_condition();
}
- return CHDERR_INVALID_PARAMETER;
+ return std::errc::invalid_argument;
}
-
- // return any errors
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // return any errors
return err;
}
}
@@ -1654,44 +1676,49 @@ chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *confi
* @return null if it fails, else a char*.
*/
-const char *chd_file::error_string(chd_error err)
+std::error_category const &chd_category() noexcept
{
- switch (err)
+ class chd_category_impl : public std::error_category
{
- case CHDERR_NONE: return "no error";
- case CHDERR_NO_INTERFACE: return "no drive interface";
- case CHDERR_OUT_OF_MEMORY: return "out of memory";
- case CHDERR_NOT_OPEN: return "file not open";
- case CHDERR_ALREADY_OPEN: return "file already open";
- case CHDERR_INVALID_FILE: return "invalid file";
- case CHDERR_INVALID_PARAMETER: return "invalid parameter";
- case CHDERR_INVALID_DATA: return "invalid data";
- case CHDERR_FILE_NOT_FOUND: return "file not found";
- case CHDERR_REQUIRES_PARENT: return "requires parent";
- case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable";
- case CHDERR_READ_ERROR: return "read error";
- case CHDERR_WRITE_ERROR: return "write error";
- case CHDERR_CODEC_ERROR: return "codec error";
- case CHDERR_INVALID_PARENT: return "invalid parent";
- case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range";
- case CHDERR_DECOMPRESSION_ERROR: return "decompression error";
- case CHDERR_COMPRESSION_ERROR: return "compression error";
- case CHDERR_CANT_CREATE_FILE: return "can't create file";
- case CHDERR_CANT_VERIFY: return "can't verify file";
- case CHDERR_NOT_SUPPORTED: return "operation not supported";
- case CHDERR_METADATA_NOT_FOUND: return "can't find metadata";
- case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size";
- case CHDERR_UNSUPPORTED_VERSION: return "mismatched DIFF and CHD or unsupported CHD version";
- case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify";
- case CHDERR_INVALID_METADATA: return "invalid metadata";
- case CHDERR_INVALID_STATE: return "invalid state";
- case CHDERR_OPERATION_PENDING: return "operation pending";
- case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format";
- case CHDERR_UNKNOWN_COMPRESSION: return "unknown compression type";
- case CHDERR_WALKING_PARENT: return "currently examining parent";
- case CHDERR_COMPRESSING: return "currently compressing";
- default: return "undocumented error";
- }
+ virtual char const *name() const noexcept override { return "chd"; }
+
+ virtual std::string message(int condition) const override
+ {
+ using namespace std::literals;
+ static std::string_view const s_messages[] = {
+ "No error"sv,
+ "No drive interface"sv,
+ "File not open"sv,
+ "File already open"sv,
+ "Invalid file"sv,
+ "Invalid data"sv,
+ "Requires parent"sv,
+ "File not writeable"sv,
+ "Codec error"sv,
+ "Invalid parent"sv,
+ "Hunk out of range"sv,
+ "Decompression error"sv,
+ "Compression error"sv,
+ "Can't verify file"sv,
+ "Can't find metadata"sv,
+ "Invalid metadata size"sv,
+ "Mismatched DIFF and CHD or unsupported CHD version"sv,
+ "Incomplete verify"sv,
+ "Invalid metadata"sv,
+ "Invalid state"sv,
+ "Operation pending"sv,
+ "Unsupported format"sv,
+ "Unknown compression type"sv,
+ "Currently examining parent"sv,
+ "Currently compressing"sv };
+ if ((0 <= condition) && (std::size(s_messages) > condition))
+ return std::string(s_messages[condition]);
+ else
+ return "Unknown error"s;
+ }
+ };
+ static chd_category_impl const s_chd_category_instance;
+ return s_chd_category_instance;
}
@@ -1716,15 +1743,15 @@ uint32_t chd_file::guess_unitbytes()
// look for hard disk metadata; if found, then the unit size == sector size
std::string metadata;
int i0, i1, i2, i3;
- if (read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) == CHDERR_NONE && sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
+ if (!read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) && sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
return i3;
// look for CD-ROM metadata; if found, then the unit size == CD frame size
- if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
- read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
- read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE ||
- read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
- read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE)
+ if (!read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) ||
+ !read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) ||
+ !read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) ||
+ !read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) ||
+ !read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata))
return CD_FRAME_SIZE;
// otherwise, just map 1:1 with the hunk size
@@ -1751,7 +1778,7 @@ void chd_file::parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1)
{
// verify header length
if (be_read(&rawheader[8], 4) != V3_HEADER_SIZE)
- throw CHDERR_INVALID_FILE;
+ throw std::error_condition(error::INVALID_FILE);
// extract core info
m_logicalbytes = be_read(&rawheader[28], 8);
@@ -1771,7 +1798,7 @@ void chd_file::parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1)
case 1: m_compression[0] = CHD_CODEC_ZLIB; break;
case 2: m_compression[0] = CHD_CODEC_ZLIB; break;
case 3: m_compression[0] = CHD_CODEC_AVHUFF; break;
- default: throw CHDERR_UNKNOWN_COMPRESSION;
+ default: throw std::error_condition(error::UNKNOWN_COMPRESSION);
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE;
@@ -1814,7 +1841,7 @@ void chd_file::parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1)
{
// verify header length
if (be_read(&rawheader[8], 4) != V4_HEADER_SIZE)
- throw CHDERR_INVALID_FILE;
+ throw std::error_condition(error::INVALID_FILE);
// extract core info
m_logicalbytes = be_read(&rawheader[28], 8);
@@ -1834,7 +1861,7 @@ void chd_file::parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1)
case 1: m_compression[0] = CHD_CODEC_ZLIB; break;
case 2: m_compression[0] = CHD_CODEC_ZLIB; break;
case 3: m_compression[0] = CHD_CODEC_AVHUFF; break;
- default: throw CHDERR_UNKNOWN_COMPRESSION;
+ default: throw std::error_condition(error::UNKNOWN_COMPRESSION);
}
m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE;
@@ -1874,7 +1901,7 @@ void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1)
{
// verify header length
if (be_read(&rawheader[8], 4) != V5_HEADER_SIZE)
- throw CHDERR_INVALID_FILE;
+ throw std::error_condition(error::INVALID_FILE);
// extract core info
m_logicalbytes = be_read(&rawheader[32], 8);
@@ -1908,7 +1935,7 @@ void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1)
}
/**
- * @fn chd_error chd_file::compress_v5_map()
+ * @fn std::error_condition chd_file::compress_v5_map()
*
* @brief -------------------------------------------------
* compress_v5_map - compress the v5 map and write it to the end of the file
@@ -1917,10 +1944,10 @@ void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1)
* @exception CHDERR_COMPRESSION_ERROR Thrown when a chderr compression error error
* condition occurs.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::compress_v5_map()
+std::error_condition chd_file::compress_v5_map()
{
try
{
@@ -2015,10 +2042,10 @@ chd_error chd_file::compress_v5_map()
bitstream_out bitbuf(&compressed[16], compressed.size() - 16);
huffman_error err = encoder.compute_tree_from_histo();
if (err != HUFFERR_NONE)
- throw CHDERR_COMPRESSION_ERROR;
+ throw std::error_condition(error::COMPRESSION_ERROR);
err = encoder.export_tree_rle(bitbuf);
if (err != HUFFERR_NONE)
- throw CHDERR_COMPRESSION_ERROR;
+ throw std::error_condition(error::COMPRESSION_ERROR);
// encode the data
for (uint8_t *src = &compression_rle[0]; src < dest; src++)
@@ -2113,9 +2140,9 @@ chd_error chd_file::compress_v5_map()
uint8_t rawbuf[sizeof(uint64_t)];
be_write(rawbuf, m_mapoffset, 8);
file_write(m_mapoffset_offset, rawbuf, sizeof(rawbuf));
- return CHDERR_NONE;
+ return std::error_condition();
}
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
return err;
}
@@ -2160,7 +2187,7 @@ void chd_file::decompress_v5_map()
huffman_decoder<16, 8> decoder;
huffman_error err = decoder.import_tree_rle(bitbuf);
if (err != HUFFERR_NONE)
- throw CHDERR_DECOMPRESSION_ERROR;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
uint8_t lastcomp = 0;
int repcount = 0;
for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
@@ -2244,11 +2271,11 @@ void chd_file::decompress_v5_map()
// verify the final CRC
if (util::crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12) != mapcrc)
- throw CHDERR_DECOMPRESSION_ERROR;
+ throw std::error_condition(error::DECOMPRESSION_ERROR);
}
/**
- * @fn chd_error chd_file::create_common()
+ * @fn std::error_condition chd_file::create_common()
*
* @brief -------------------------------------------------
* create_common - command path when creating a new CHD file
@@ -2264,7 +2291,7 @@ void chd_file::decompress_v5_map()
* @return The new common.
*/
-chd_error chd_file::create_common()
+std::error_condition chd_file::create_common()
{
// wrap in try for proper error handling
try
@@ -2273,14 +2300,14 @@ chd_error chd_file::create_common()
m_metaoffset = 0;
// if we have a parent, it must be V3 or later
- if (m_parent != nullptr && m_parent->version() < 3)
- throw CHDERR_UNSUPPORTED_VERSION;
+ if (m_parent && m_parent->version() < 3)
+ throw std::error_condition(error::UNSUPPORTED_VERSION);
// must be an even number of units per hunk
if (m_hunkbytes % m_unitbytes != 0)
- throw CHDERR_INVALID_PARAMETER;
- if (m_parent != nullptr && m_unitbytes != m_parent->unit_bytes())
- throw CHDERR_INVALID_PARAMETER;
+ throw std::error_condition(std::errc::invalid_argument);
+ if (m_parent && m_unitbytes != m_parent->unit_bytes())
+ throw std::error_condition(std::errc::invalid_argument);
// verify the compression types
bool found_zero = false;
@@ -2290,9 +2317,9 @@ chd_error chd_file::create_common()
if (elem == CHD_CODEC_NONE)
found_zero = true;
else if (found_zero)
- throw CHDERR_INVALID_PARAMETER;
+ throw std::error_condition(std::errc::invalid_argument);
else if (!chd_codec_list::codec_exists(elem))
- throw CHDERR_UNKNOWN_COMPRESSION;
+ throw std::error_condition(error::UNKNOWN_COMPRESSION);
}
// create our V5 header
@@ -2342,10 +2369,9 @@ chd_error chd_file::create_common()
// finish opening the file
create_open_common();
}
-
- // handle errors by closing ourself
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // handle errors by closing ourself
close();
return err;
}
@@ -2354,11 +2380,11 @@ chd_error chd_file::create_common()
close();
throw;
}
- return CHDERR_NONE;
+ return std::error_condition();
}
/**
- * @fn chd_error chd_file::open_common(bool writeable)
+ * @fn std::error_condition chd_file::open_common(bool writeable)
*
* @brief -------------------------------------------------
* open_common - common path when opening an existing CHD file for input
@@ -2377,10 +2403,10 @@ chd_error chd_file::create_common()
*
* @param writeable true if writeable.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file::open_common(bool writeable)
+std::error_condition chd_file::open_common(bool writeable)
{
// wrap in try for proper error handling
try
@@ -2394,7 +2420,7 @@ chd_error chd_file::open_common(bool writeable)
// verify the signature
if (memcmp(rawheader, "MComprHD", 8) != 0)
- throw CHDERR_INVALID_FILE;
+ throw std::error_condition(error::INVALID_FILE);
m_version = be_read(&rawheader[12], 4);
@@ -2405,7 +2431,7 @@ chd_error chd_file::open_common(bool writeable)
case 3: parse_v3_header(rawheader, parentsha1); break;
case 4: parse_v4_header(rawheader, parentsha1); break;
case 5: parse_v5_header(rawheader, parentsha1); break;
- default: throw CHDERR_UNSUPPORTED_VERSION;
+ default: throw std::error_condition(error::UNSUPPORTED_VERSION);
}
// only allow writes to the most recent version
@@ -2413,27 +2439,26 @@ chd_error chd_file::open_common(bool writeable)
m_allow_writes = false;
if (writeable && !m_allow_writes)
- throw CHDERR_FILE_NOT_WRITEABLE;
+ throw std::error_condition(error::FILE_NOT_WRITEABLE);
// make sure we have a parent if we need one (and don't if we don't)
if (parentsha1 != util::sha1_t::null)
{
- if (m_parent == nullptr)
+ if (!m_parent)
m_parent_missing = true;
else if (m_parent->sha1() != parentsha1)
- throw CHDERR_INVALID_PARENT;
+ throw std::error_condition(error::INVALID_PARENT);
}
- else if (m_parent != nullptr)
- throw CHDERR_INVALID_PARAMETER;
+ else if (m_parent)
+ throw std::error_condition(std::errc::invalid_argument);
// finish opening the file
create_open_common();
- return CHDERR_NONE;
+ return std::error_condition();
}
-
- // handle errors by closing ourself
- catch (chd_error &err)
+ catch (std::error_condition const &err)
{
+ // handle errors by closing ourself
close();
return err;
}
@@ -2457,7 +2482,7 @@ void chd_file::create_open_common()
{
m_decompressor[decompnum] = chd_codec_list::new_decompressor(m_compression[decompnum], *this);
if (m_decompressor[decompnum] == nullptr && m_compression[decompnum] != 0)
- throw CHDERR_UNKNOWN_COMPRESSION;
+ throw std::error_condition(error::UNKNOWN_COMPRESSION);
}
// read the map; v5+ compressed drives need to read and decompress their map
@@ -2494,30 +2519,30 @@ void chd_file::create_open_common()
void chd_file::verify_proper_compression_append(uint32_t hunknum)
{
// punt if no file
- if (m_file == nullptr)
- throw CHDERR_NOT_OPEN;
+ if (!m_file)
+ throw std::error_condition(error::NOT_OPEN);
// return an error if out of range
if (hunknum >= m_hunkcount)
- throw CHDERR_HUNK_OUT_OF_RANGE;
+ throw std::error_condition(error::HUNK_OUT_OF_RANGE);
// if not writeable, fail
if (!m_allow_writes)
- throw CHDERR_FILE_NOT_WRITEABLE;
+ throw std::error_condition(error::FILE_NOT_WRITEABLE);
// compressed writes only via this interface
if (!compressed())
- throw CHDERR_FILE_NOT_WRITEABLE;
+ throw std::error_condition(error::FILE_NOT_WRITEABLE);
// only permitted to write new blocks
uint8_t *rawmap = &m_rawmap[hunknum * 12];
if (rawmap[0] != 0xff)
- throw CHDERR_COMPRESSION_ERROR;
+ throw std::error_condition(error::COMPRESSION_ERROR);
// if this isn't the first block, only permitted to write immediately
// after the previous one
if (hunknum != 0 && rawmap[-12] == 0xff)
- throw CHDERR_COMPRESSION_ERROR;
+ throw std::error_condition(error::COMPRESSION_ERROR);
}
/**
@@ -2572,7 +2597,7 @@ void chd_file::hunk_copy_from_self(uint32_t hunknum, uint32_t otherhunk)
// only permitted to reference prior hunks
if (otherhunk >= hunknum)
- throw CHDERR_INVALID_PARAMETER;
+ throw std::error_condition(std::errc::invalid_argument);
// update the map entry
uint8_t *rawmap = &m_rawmap[hunknum * 12];
@@ -2841,7 +2866,7 @@ void chd_file_compressor::compress_begin()
}
/**
- * @fn chd_error chd_file_compressor::compress_continue(double &progress, double &ratio)
+ * @fn std::error_condition chd_file_compressor::compress_continue(double &progress, double &ratio)
*
* @brief -------------------------------------------------
* compress_continue - continue compression
@@ -2850,14 +2875,14 @@ void chd_file_compressor::compress_begin()
* @param [in,out] progress The progress.
* @param [in,out] ratio The ratio.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chd_file_compressor::compress_continue(double &progress, double &ratio)
+std::error_condition chd_file_compressor::compress_continue(double &progress, double &ratio)
{
// if we got an error, return an error
if (m_read_error)
- return CHDERR_READ_ERROR;
+ return std::errc::io_error;
// if done reading, queue some more
while (m_read_queue_offset < m_logicalbytes && osd_work_queue_items(m_read_queue) < 2)
@@ -2911,8 +2936,8 @@ chd_error chd_file_compressor::compress_continue(double &progress, double &ratio
// if we're uncompressed, use regular writes
else if (!compressed())
{
- chd_error err = write_hunk(item.m_hunknum, item.m_data);
- if (err != CHDERR_NONE)
+ std::error_condition err = write_hunk(item.m_hunknum, item.m_data);
+ if (err)
return err;
// writes of all-0 data don't actually take space, so see if we count this
@@ -2973,7 +2998,7 @@ chd_error chd_file_compressor::compress_continue(double &progress, double &ratio
{
osd_work_queue_wait(m_read_queue, 30 * osd_ticks_per_second());
if (!compressed())
- return CHDERR_NONE;
+ return std::error_condition();
set_raw_sha1(m_compsha1.finish());
return compress_v5_map();
}
@@ -2994,7 +3019,7 @@ chd_error chd_file_compressor::compress_continue(double &progress, double &ratio
m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd != nullptr)
osd_work_item_wait(m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd, osd_ticks_per_second());
- return m_walking_parent ? CHDERR_WALKING_PARENT : CHDERR_COMPRESSING;
+ return m_walking_parent ? error::WALKING_PARENT : error::COMPRESSING;
}
/**
@@ -3171,12 +3196,12 @@ void chd_file_compressor::async_read()
// advance the read pointer
m_read_done_offset += numbytes;
}
- catch (chd_error& err)
+ catch (std::error_condition const &err)
{
- fprintf(stderr, "CHD error occurred: %s\n", chd_file::error_string(err));
+ fprintf(stderr, "CHD error occurred: %s\n", err.message().c_str());
m_read_error = true;
}
- catch (std::exception& ex)
+ catch (std::exception const &ex)
{
fprintf(stderr, "exception occurred: %s\n", ex.what());
m_read_error = true;
diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h
index 705967d3dda..8d3e639438b 100644
--- a/src/lib/util/chd.h
+++ b/src/lib/util/chd.h
@@ -7,18 +7,22 @@
MAME Compressed Hunks of Data file format
***************************************************************************/
-
-#ifndef MAME_UTIL_CHD_H
-#define MAME_UTIL_CHD_H
+#ifndef MAME_LIB_UTIL_CHD_H
+#define MAME_LIB_UTIL_CHD_H
#pragma once
-#include "osdcore.h"
-#include <string>
-#include "corefile.h"
-#include "hashing.h"
#include "chdcodec.h"
+#include "hashing.h"
+#include "ioprocs.h"
+
+#include "osdcore.h"
+
#include <atomic>
+#include <string>
+#include <string_view>
+#include <system_error>
+
/***************************************************************************
@@ -190,86 +194,49 @@
//**************************************************************************
// pseudo-codecs returned by hunk_info
-const chd_codec_type CHD_CODEC_SELF = 1; // copy of another hunk
-const chd_codec_type CHD_CODEC_PARENT = 2; // copy of a parent's hunk
-const chd_codec_type CHD_CODEC_MINI = 3; // legacy "mini" 8-byte repeat
+constexpr chd_codec_type CHD_CODEC_SELF = 1; // copy of another hunk
+constexpr chd_codec_type CHD_CODEC_PARENT = 2; // copy of a parent's hunk
+constexpr chd_codec_type CHD_CODEC_MINI = 3; // legacy "mini" 8-byte repeat
// core types
typedef uint32_t chd_metadata_tag;
// metadata parameters
-const chd_metadata_tag CHDMETATAG_WILDCARD = 0;
-const uint32_t CHDMETAINDEX_APPEND = ~0;
+constexpr chd_metadata_tag CHDMETATAG_WILDCARD = 0;
+constexpr uint32_t CHDMETAINDEX_APPEND = ~0;
// metadata flags
-const uint8_t CHD_MDFLAGS_CHECKSUM = 0x01; // indicates data is checksummed
+constexpr uint8_t CHD_MDFLAGS_CHECKSUM = 0x01; // indicates data is checksummed
// standard hard disk metadata
-const chd_metadata_tag HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','D');
+constexpr chd_metadata_tag HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','D');
extern const char *HARD_DISK_METADATA_FORMAT;
// hard disk identify information
-const chd_metadata_tag HARD_DISK_IDENT_METADATA_TAG = CHD_MAKE_TAG('I','D','N','T');
+constexpr chd_metadata_tag HARD_DISK_IDENT_METADATA_TAG = CHD_MAKE_TAG('I','D','N','T');
// hard disk key information
-const chd_metadata_tag HARD_DISK_KEY_METADATA_TAG = CHD_MAKE_TAG('K','E','Y',' ');
+constexpr chd_metadata_tag HARD_DISK_KEY_METADATA_TAG = CHD_MAKE_TAG('K','E','Y',' ');
// pcmcia CIS information
-const chd_metadata_tag PCMCIA_CIS_METADATA_TAG = CHD_MAKE_TAG('C','I','S',' ');
+constexpr chd_metadata_tag PCMCIA_CIS_METADATA_TAG = CHD_MAKE_TAG('C','I','S',' ');
// standard CD-ROM metadata
-const chd_metadata_tag CDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','C','D');
-const chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R');
+constexpr chd_metadata_tag CDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','C','D');
+constexpr chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R');
extern const char *CDROM_TRACK_METADATA_FORMAT;
-const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2');
+constexpr chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2');
extern const char *CDROM_TRACK_METADATA2_FORMAT;
-const chd_metadata_tag GDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T');
-const chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C', 'H', 'G', 'D');
+constexpr chd_metadata_tag GDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T');
+constexpr chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C', 'H', 'G', 'D');
extern const char *GDROM_TRACK_METADATA_FORMAT;
// standard A/V metadata
-const chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V');
+constexpr chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V');
extern const char *AV_METADATA_FORMAT;
// A/V laserdisc frame metadata
-const chd_metadata_tag AV_LD_METADATA_TAG = CHD_MAKE_TAG('A','V','L','D');
-
-// error types
-enum chd_error
-{
- CHDERR_NONE,
- CHDERR_NO_INTERFACE,
- CHDERR_OUT_OF_MEMORY,
- CHDERR_NOT_OPEN,
- CHDERR_ALREADY_OPEN,
- CHDERR_INVALID_FILE,
- CHDERR_INVALID_PARAMETER,
- CHDERR_INVALID_DATA,
- CHDERR_FILE_NOT_FOUND,
- CHDERR_REQUIRES_PARENT,
- CHDERR_FILE_NOT_WRITEABLE,
- CHDERR_READ_ERROR,
- CHDERR_WRITE_ERROR,
- CHDERR_CODEC_ERROR,
- CHDERR_INVALID_PARENT,
- CHDERR_HUNK_OUT_OF_RANGE,
- CHDERR_DECOMPRESSION_ERROR,
- CHDERR_COMPRESSION_ERROR,
- CHDERR_CANT_CREATE_FILE,
- CHDERR_CANT_VERIFY,
- CHDERR_NOT_SUPPORTED,
- CHDERR_METADATA_NOT_FOUND,
- CHDERR_INVALID_METADATA_SIZE,
- CHDERR_UNSUPPORTED_VERSION,
- CHDERR_VERIFY_INCOMPLETE,
- CHDERR_INVALID_METADATA,
- CHDERR_INVALID_STATE,
- CHDERR_OPERATION_PENDING,
- CHDERR_UNSUPPORTED_FORMAT,
- CHDERR_UNKNOWN_COMPRESSION,
- CHDERR_WALKING_PARENT,
- CHDERR_COMPRESSING
-};
+constexpr chd_metadata_tag AV_LD_METADATA_TAG = CHD_MAKE_TAG('A','V','L','D');
@@ -277,9 +244,6 @@ enum chd_error
// TYPE DEFINITIONS
//**************************************************************************
-class chd_codec;
-
-
// ======================> chd_file
// core file class
@@ -289,22 +253,49 @@ class chd_file
friend class chd_verifier;
// constants
- static const uint32_t HEADER_VERSION = 5;
- static const uint32_t V3_HEADER_SIZE = 120;
- static const uint32_t V4_HEADER_SIZE = 108;
- static const uint32_t V5_HEADER_SIZE = 124;
- static const uint32_t MAX_HEADER_SIZE = V5_HEADER_SIZE;
+ static constexpr uint32_t HEADER_VERSION = 5;
+ static constexpr uint32_t V3_HEADER_SIZE = 120;
+ static constexpr uint32_t V4_HEADER_SIZE = 108;
+ static constexpr uint32_t V5_HEADER_SIZE = 124;
+ static constexpr uint32_t MAX_HEADER_SIZE = V5_HEADER_SIZE;
public:
+ // error types
+ enum class error
+ {
+ NO_INTERFACE = 1,
+ NOT_OPEN,
+ ALREADY_OPEN,
+ INVALID_FILE,
+ INVALID_DATA,
+ REQUIRES_PARENT,
+ FILE_NOT_WRITEABLE,
+ CODEC_ERROR,
+ INVALID_PARENT,
+ HUNK_OUT_OF_RANGE,
+ DECOMPRESSION_ERROR,
+ COMPRESSION_ERROR,
+ CANT_VERIFY,
+ METADATA_NOT_FOUND,
+ INVALID_METADATA_SIZE,
+ UNSUPPORTED_VERSION,
+ VERIFY_INCOMPLETE,
+ INVALID_METADATA,
+ INVALID_STATE,
+ OPERATION_PENDING,
+ UNSUPPORTED_FORMAT,
+ UNKNOWN_COMPRESSION,
+ WALKING_PARENT,
+ COMPRESSING
+ };
+
// construction/destruction
chd_file();
virtual ~chd_file();
- // operators
- operator util::core_file &() { return *m_file; }
-
// getters
- bool opened() const { return (m_file != nullptr); }
+ util::random_read &file();
+ bool opened() const { return bool(m_file); }
uint32_t version() const { return m_version; }
uint64_t logical_bytes() const { return m_logicalbytes; }
uint32_t hunk_bytes() const { return m_hunkbytes; }
@@ -317,52 +308,49 @@ public:
util::sha1_t sha1();
util::sha1_t raw_sha1();
util::sha1_t parent_sha1();
- chd_error hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes);
+ std::error_condition hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes);
// setters
void set_raw_sha1(util::sha1_t rawdata);
void set_parent_sha1(util::sha1_t parent);
// file create
- chd_error create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]);
- chd_error create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]);
- chd_error create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent);
- chd_error create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent);
+ std::error_condition create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]);
+ std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]);
+ std::error_condition create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent);
+ std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent);
// file open
- chd_error open(const char *filename, bool writeable = false, chd_file *parent = nullptr);
- chd_error open(util::core_file &file, bool writeable = false, chd_file *parent = nullptr);
+ std::error_condition open(std::string_view filename, bool writeable = false, chd_file *parent = nullptr);
+ std::error_condition open(util::random_read_write::ptr &&file, bool writeable = false, chd_file *parent = nullptr);
// file close
void close();
// read/write
- chd_error read_hunk(uint32_t hunknum, void *buffer);
- chd_error write_hunk(uint32_t hunknum, const void *buffer);
- chd_error read_units(uint64_t unitnum, void *buffer, uint32_t count = 1);
- chd_error write_units(uint64_t unitnum, const void *buffer, uint32_t count = 1);
- chd_error read_bytes(uint64_t offset, void *buffer, uint32_t bytes);
- chd_error write_bytes(uint64_t offset, const void *buffer, uint32_t bytes);
+ std::error_condition read_hunk(uint32_t hunknum, void *buffer);
+ std::error_condition write_hunk(uint32_t hunknum, const void *buffer);
+ std::error_condition read_units(uint64_t unitnum, void *buffer, uint32_t count = 1);
+ std::error_condition write_units(uint64_t unitnum, const void *buffer, uint32_t count = 1);
+ std::error_condition read_bytes(uint64_t offset, void *buffer, uint32_t bytes);
+ std::error_condition write_bytes(uint64_t offset, const void *buffer, uint32_t bytes);
// metadata management
- chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output);
- chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output);
- chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen);
- chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags);
- chd_error write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags = CHD_MDFLAGS_CHECKSUM);
- chd_error write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::string &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, input.c_str(), input.length() + 1, flags); }
- chd_error write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::vector<uint8_t> &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, &input[0], input.size(), flags); }
- chd_error delete_metadata(chd_metadata_tag metatag, uint32_t metaindex);
- chd_error clone_all_metadata(chd_file &source);
+ std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output);
+ std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output);
+ std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen);
+ std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags);
+ std::error_condition write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags = CHD_MDFLAGS_CHECKSUM);
+ std::error_condition write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::string &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, input.c_str(), input.length() + 1, flags); }
+ std::error_condition write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::vector<uint8_t> &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, &input[0], input.size(), flags); }
+ std::error_condition delete_metadata(chd_metadata_tag metatag, uint32_t metaindex);
+ std::error_condition clone_all_metadata(chd_file &source);
// hashing helper
util::sha1_t compute_overall_sha1(util::sha1_t rawsha1);
// codec interfaces
- chd_error codec_configure(chd_codec_type codec, int param, void *config);
-
- // static helpers
- static const char *error_string(chd_error err);
+ std::error_condition codec_configure(chd_codec_type codec, int param, void *config);
private:
struct metadata_entry;
@@ -383,10 +371,10 @@ private:
void parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1);
void parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1);
void parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1);
- chd_error compress_v5_map();
+ std::error_condition compress_v5_map();
void decompress_v5_map();
- chd_error create_common();
- chd_error open_common(bool writeable);
+ std::error_condition create_common();
+ std::error_condition open_common(bool writeable);
void create_open_common();
void verify_proper_compression_append(uint32_t hunknum);
void hunk_write_compressed(uint32_t hunknum, int8_t compression, const uint8_t *compressed, uint32_t complength, util::crc16_t crc16);
@@ -398,42 +386,41 @@ private:
static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2);
// file characteristics
- util::core_file * m_file; // handle to the open core file
- bool m_owns_file; // flag indicating if this file should be closed on chd_close()
+ util::random_read_write::ptr m_file; // handle to the open core file
bool m_allow_reads; // permit reads from this CHD?
bool m_allow_writes; // permit writes to this CHD?
// core parameters from the header
- uint32_t m_version; // version of the header
- uint64_t m_logicalbytes; // logical size of the raw CHD data in bytes
- uint64_t m_mapoffset; // offset of map
- uint64_t m_metaoffset; // offset to first metadata bit
- uint32_t m_hunkbytes; // size of each raw hunk in bytes
- uint32_t m_hunkcount; // number of hunks represented
- uint32_t m_unitbytes; // size of each unit in bytes
- uint64_t m_unitcount; // number of units represented
+ uint32_t m_version; // version of the header
+ uint64_t m_logicalbytes; // logical size of the raw CHD data in bytes
+ uint64_t m_mapoffset; // offset of map
+ uint64_t m_metaoffset; // offset to first metadata bit
+ uint32_t m_hunkbytes; // size of each raw hunk in bytes
+ uint32_t m_hunkcount; // number of hunks represented
+ uint32_t m_unitbytes; // size of each unit in bytes
+ uint64_t m_unitcount; // number of units represented
chd_codec_type m_compression[4]; // array of compression types used
chd_file * m_parent; // pointer to parent file, or nullptr if none
bool m_parent_missing; // are we missing our parent?
// key offsets within the header
- uint64_t m_mapoffset_offset; // offset of map offset field
- uint64_t m_metaoffset_offset;// offset of metaoffset field
- uint64_t m_sha1_offset; // offset of SHA1 field
- uint64_t m_rawsha1_offset; // offset of raw SHA1 field
- uint64_t m_parentsha1_offset;// offset of paren SHA1 field
+ uint64_t m_mapoffset_offset; // offset of map offset field
+ uint64_t m_metaoffset_offset;// offset of metaoffset field
+ uint64_t m_sha1_offset; // offset of SHA1 field
+ uint64_t m_rawsha1_offset; // offset of raw SHA1 field
+ uint64_t m_parentsha1_offset;// offset of paren SHA1 field
// map information
- uint32_t m_mapentrybytes; // length of each entry in a map
- std::vector<uint8_t> m_rawmap; // raw map data
+ uint32_t m_mapentrybytes; // length of each entry in a map
+ std::vector<uint8_t> m_rawmap; // raw map data
// compression management
- chd_decompressor * m_decompressor[4]; // array of decompression codecs
- std::vector<uint8_t> m_compressed; // temporary buffer for compressed data
+ chd_decompressor::ptr m_decompressor[4]; // array of decompression codecs
+ std::vector<uint8_t> m_compressed; // temporary buffer for compressed data
// caching
- std::vector<uint8_t> m_cache; // single-hunk cache for partial reads/writes
- uint32_t m_cachehunk; // which hunk is in the cache?
+ std::vector<uint8_t> m_cache; // single-hunk cache for partial reads/writes
+ uint32_t m_cachehunk; // which hunk is in the cache?
};
@@ -449,7 +436,7 @@ public:
// compression management
void compress_begin();
- chd_error compress_continue(double &progress, double &ratio);
+ std::error_condition compress_continue(double &progress, double &ratio);
protected:
// required override: read more data
@@ -470,24 +457,24 @@ private:
void add(uint64_t itemnum, util::crc16_t crc16, util::sha1_t sha1);
// constants
- static const uint64_t NOT_FOUND = ~uint64_t(0);
+ static constexpr uint64_t NOT_FOUND = ~uint64_t(0);
+
private:
// internal entry
struct entry_t
{
entry_t * m_next; // next entry in list
- uint64_t m_itemnum; // item number
+ uint64_t m_itemnum; // item number
util::sha1_t m_sha1; // SHA-1 of the block
};
// block of entries
struct entry_block
{
- entry_block(entry_block *prev)
- : m_next(prev), m_nextalloc(0) { }
+ entry_block(entry_block *prev) : m_next(prev), m_nextalloc(0) { }
entry_block * m_next; // next block in list
- uint32_t m_nextalloc; // next to be allocated
+ uint32_t m_nextalloc; // next to be allocated
entry_t m_array[16384]; // array of entries
};
@@ -551,8 +538,8 @@ private:
// current compression status
bool m_walking_parent; // are we building the parent map?
- uint64_t m_total_in; // total bytes in
- uint64_t m_total_out; // total bytes out
+ uint64_t m_total_in; // total bytes in
+ uint64_t m_total_out; // total bytes out
util::sha1_creator m_compsha1; // running SHA-1 on raw data
// hash lookup maps
@@ -561,20 +548,31 @@ private:
// read I/O thread
osd_work_queue * m_read_queue; // work queue for reading
- uint64_t m_read_queue_offset;// next offset to enqueue
- uint64_t m_read_done_offset; // next offset that will complete
+ uint64_t m_read_queue_offset;// next offset to enqueue
+ uint64_t m_read_done_offset; // next offset that will complete
bool m_read_error; // error during reading?
// work item thread
- static const int WORK_BUFFER_HUNKS = 256;
+ static constexpr int WORK_BUFFER_HUNKS = 256;
osd_work_queue * m_work_queue; // queue for doing work on other threads
- std::vector<uint8_t> m_work_buffer; // buffer containing hunk data to work on
- std::vector<uint8_t> m_compressed_buffer;// buffer containing compressed data
+ std::vector<uint8_t> m_work_buffer; // buffer containing hunk data to work on
+ std::vector<uint8_t> m_compressed_buffer;// buffer containing compressed data
work_item m_work_item[WORK_BUFFER_HUNKS]; // status of each hunk
chd_compressor_group * m_codecs[WORK_MAX_THREADS]; // codecs to use
// output state
- uint32_t m_write_hunk; // next hunk to write
+ uint32_t m_write_hunk; // next hunk to write
};
-#endif // MAME_UTIL_CHD_H
+
+// error category for CHD errors
+std::error_category const &chd_category() noexcept;
+inline std::error_condition make_error_condition(chd_file::error err) noexcept { return std::error_condition(int(err), chd_category()); }
+
+namespace std {
+
+template <> struct is_error_condition_enum<chd_file::error> : public std::true_type { };
+
+} // namespace std
+
+#endif // MAME_LIB_UTIL_CHD_H
diff --git a/src/lib/util/chdcd.cpp b/src/lib/util/chdcd.cpp
index ef013b41f48..63b633536bf 100644
--- a/src/lib/util/chdcd.cpp
+++ b/src/lib/util/chdcd.cpp
@@ -7,15 +7,19 @@
***************************************************************************/
-#include <cctype>
-#include <cstdlib>
-#include <cassert>
-#include "osdcore.h"
-#include "chd.h"
#include "chdcd.h"
+
+#include "chd.h"
#include "corefile.h"
#include "corestr.h"
+#include "osdcore.h"
+
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cstdlib>
+
/***************************************************************************
@@ -230,8 +234,8 @@ static uint32_t parse_wav_sample(const char *filename, uint32_t *dataoffs)
uint64_t fsize = 0;
std::uint32_t actual;
- osd_file::error filerr = osd_file::open(filename, OPEN_FLAG_READ, file, fsize);
- if (filerr != osd_file::error::NONE)
+ std::error_condition const filerr = osd_file::open(filename, OPEN_FLAG_READ, file, fsize);
+ if (filerr)
{
printf("ERROR: could not open (%s)\n", filename);
return 0;
@@ -449,7 +453,7 @@ uint64_t read_uint64(FILE *infile)
-------------------------------------------------*/
/**
- * @fn chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+ * @fn std::error_condition chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
*
* @brief Chdcd parse nero.
*
@@ -457,26 +461,25 @@ uint64_t read_uint64(FILE *infile)
* @param [in,out] outtoc The outtoc.
* @param [in,out] outinfo The outinfo.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+std::error_condition chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
{
- FILE *infile;
unsigned char buffer[12];
uint32_t chain_offs, chunk_size;
int done = 0;
std::string path = std::string(tocfname);
- infile = fopen(tocfname, "rb");
- path = get_file_path(path);
-
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rb");
+ if (!infile)
{
- return CHDERR_FILE_NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
}
+ path = get_file_path(path);
+
/* clear structures */
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
@@ -489,7 +492,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
{
printf("ERROR: Not a Nero 5.5 or later image!\n");
fclose(infile);
- return CHDERR_UNSUPPORTED_VERSION;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
chain_offs = buffer[11] | (buffer[10]<<8) | (buffer[9]<<16) | (buffer[8]<<24);
@@ -498,7 +501,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
{
printf("ERROR: File size is > 4GB, this version of CHDMAN cannot handle it.");
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
// printf("NER5 detected, chain offset: %x\n", chain_offs);
@@ -559,12 +562,12 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
case 0x0300: // Mode 2 Form 1
printf("ERROR: Mode 2 Form 1 tracks not supported\n");
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
case 0x0500: // raw data
printf("ERROR: Raw data tracks not supported\n");
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
case 0x0600: // 2352 byte mode 2 raw
outtoc.tracks[track-1].trktype = CD_TRACK_MODE2_RAW;
@@ -579,22 +582,22 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
case 0x0f00: // raw data with sub-channel
printf("ERROR: Raw data tracks with sub-channel not supported\n");
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
case 0x1000: // audio with sub-channel
printf("ERROR: Audio tracks with sub-channel not supported\n");
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
case 0x1100: // raw Mode 2 Form 1 with sub-channel
printf("ERROR: Raw Mode 2 Form 1 tracks with sub-channel not supported\n");
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
default:
printf("ERROR: Unknown track type %x, contact MAMEDEV!\n", mode);
fclose(infile);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
outtoc.tracks[track-1].datasize = size;
@@ -627,7 +630,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
fclose(infile);
- return CHDERR_NONE;
+ return std::error_condition();
}
/*-------------------------------------------------
@@ -635,7 +638,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
-------------------------------------------------*/
/**
- * @fn chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+ * @fn std::error_condition chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
*
* @brief Chdcd parse ISO.
*
@@ -643,22 +646,21 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_
* @param [in,out] outtoc The outtoc.
* @param [in,out] outinfo The outinfo.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+std::error_condition chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
{
- FILE *infile;
std::string path = std::string(tocfname);
- infile = fopen(tocfname, "rb");
- path = get_file_path(path);
-
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rb");
+ if (!infile)
{
- return CHDERR_FILE_NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
}
+ path = get_file_path(path);
+
/* clear structures */
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
@@ -693,7 +695,7 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
outinfo.track[0].swap = false;
} else {
printf("ERROR: Unrecognized track type\n");
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
outtoc.tracks[0].subtype = CD_SUB_NONE;
@@ -709,7 +711,7 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
outtoc.tracks[0].padframes = 0;
- return CHDERR_NONE;
+ return std::error_condition();
}
/*-------------------------------------------------
@@ -717,7 +719,7 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
-------------------------------------------------*/
/**
- * @fn static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+ * @fn static std::error_condition chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
*
* @brief Chdcd parse GDI.
*
@@ -725,24 +727,23 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
* @param [in,out] outtoc The outtoc.
* @param [in,out] outinfo The outinfo.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+static std::error_condition chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
{
- FILE *infile;
int i, numtracks;
std::string path = std::string(tocfname);
- infile = fopen(tocfname, "rt");
- path = get_file_path(path);
-
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rt");
+ if (!infile)
{
- return CHDERR_FILE_NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
}
+ path = get_file_path(path);
+
/* clear structures */
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
@@ -841,7 +842,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
/* store the number of tracks found */
outtoc.numtrks = numtracks;
- return CHDERR_NONE;
+ return std::error_condition();
}
/*-------------------------------------------------
@@ -849,7 +850,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
-------------------------------------------------*/
/**
- * @fn chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+ * @fn std::error_condition chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
*
* @brief Chdcd parse cue.
*
@@ -857,25 +858,25 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_
* @param [in,out] outtoc The outtoc.
* @param [in,out] outinfo The outinfo.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+std::error_condition chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
{
- FILE *infile;
int i, trknum;
static char token[512];
std::string lastfname;
uint32_t wavlen, wavoffs;
std::string path = std::string(tocfname);
- infile = fopen(tocfname, "rt");
- path = get_file_path(path);
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rt");
+ if (!infile)
{
- return CHDERR_FILE_NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
}
+ path = get_file_path(path);
+
/* clear structures */
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
@@ -921,14 +922,14 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
{
fclose(infile);
printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname.c_str());
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
}
}
else
{
fclose(infile);
printf("ERROR: Unhandled track type %s\n", token);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
}
else if (!strcmp(token, "TRACK"))
@@ -970,7 +971,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
{
fclose(infile);
printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
/* next (optional) token on the line is the subcode type */
@@ -1083,7 +1084,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
if (tlen == 0)
{
printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
@@ -1094,7 +1095,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
if (tlen == 0)
{
printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
outtoc.tracks[trknum].frames = tlen;
@@ -1120,7 +1121,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
if (!outtoc.tracks[trknum].frames)
{
printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1);
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
}
}
else /* data files are different */
@@ -1129,7 +1130,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
if (tlen == 0)
{
printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str());
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
outtoc.tracks[trknum].frames = tlen;
@@ -1140,7 +1141,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
//printf("trk %d: %d frames @ offset %d\n", trknum+1, outtoc.tracks[trknum].frames, outinfo.track[trknum].offset);
}
- return CHDERR_NONE;
+ return std::error_condition();
}
/*---------------------------------------------------------------------------------------
@@ -1161,18 +1162,18 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
bool chdcd_is_gdicue(const char *tocfname)
{
- FILE *infile;
bool has_rem_singledensity = false;
bool has_rem_highdensity = false;
std::string path = std::string(tocfname);
- infile = fopen(tocfname, "rt");
- path = get_file_path(path);
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rt");
+ if (!infile)
{
return false;
}
+ path = get_file_path(path);
+
while (!feof(infile))
{
fgets(linebuffer, 511, infile);
@@ -1195,7 +1196,7 @@ bool chdcd_is_gdicue(const char *tocfname)
------------------------------------------------------------------*/
/**
- * @fn chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+ * @fn std::error_condition chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
*
* @brief Chdcd parse cue.
*
@@ -1203,7 +1204,7 @@ bool chdcd_is_gdicue(const char *tocfname)
* @param [in,out] outtoc The outtoc.
* @param [in,out] outinfo The outinfo.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*
* Dreamcast discs have two images on a single disc. The first image is SINGLE-DENSITY and the second image
* is HIGH-DENSITY. The SINGLE-DENSITY area starts 0 LBA and HIGH-DENSITY area starts 45000 LBA.
@@ -1218,9 +1219,8 @@ bool chdcd_is_gdicue(const char *tocfname)
* layout from a TOSEC .gdi.
*/
-chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+std::error_condition chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
{
- FILE *infile;
int i, trknum;
static char token[512];
std::string lastfname;
@@ -1229,13 +1229,14 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
enum gdi_area current_area = SINGLE_DENSITY;
enum gdi_pattern disc_pattern = TYPE_UNKNOWN;
- infile = fopen(tocfname, "rt");
- path = get_file_path(path);
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rt");
+ if (!infile)
{
- return CHDERR_FILE_NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
}
+ path = get_file_path(path);
+
/* clear structures */
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
@@ -1297,14 +1298,14 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
{
fclose(infile);
printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname.c_str());
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
}
}
else
{
fclose(infile);
printf("ERROR: Unhandled track type %s\n", token);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
}
else if (!strcmp(token, "TRACK"))
@@ -1349,7 +1350,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
{
fclose(infile);
printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
/* next (optional) token on the line is the subcode type */
@@ -1462,7 +1463,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
if (tlen == 0)
{
printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize);
outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
@@ -1473,7 +1474,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
if (tlen == 0)
{
printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str());
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
outtoc.tracks[trknum].frames = tlen;
@@ -1499,7 +1500,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
if (!outtoc.tracks[trknum].frames)
{
printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1);
- return CHDERR_INVALID_DATA;
+ return chd_file::error::INVALID_DATA;
}
}
else /* data files are different */
@@ -1508,7 +1509,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
if (tlen == 0)
{
printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str());
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize);
outtoc.tracks[trknum].frames = tlen;
@@ -1638,7 +1639,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
}
#endif
- return CHDERR_NONE;
+ return std::error_condition();
}
/*-------------------------------------------------
@@ -1646,7 +1647,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
-------------------------------------------------*/
/**
- * @fn chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+ * @fn std::error_condition chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
*
* @brief Chdcd parse TOC.
*
@@ -1654,12 +1655,11 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
* @param [in,out] outtoc The outtoc.
* @param [in,out] outinfo The outinfo.
*
- * @return A chd_error.
+ * @return A std::error_condition.
*/
-chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
+std::error_condition chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo)
{
- FILE *infile;
int i, trknum;
static char token[512];
char tocftemp[512];
@@ -1695,14 +1695,14 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
std::string path = std::string(tocfname);
- infile = fopen(tocfname, "rt");
- path = get_file_path(path);
-
- if (infile == (FILE *)nullptr)
+ FILE *infile = fopen(tocfname, "rt");
+ if (!infile)
{
- return CHDERR_FILE_NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
}
+ path = get_file_path(path);
+
/* clear structures */
memset(&outtoc, 0, sizeof(outtoc));
outinfo.reset();
@@ -1817,7 +1817,7 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
{
fclose(infile);
printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token);
- return CHDERR_UNSUPPORTED_FORMAT;
+ return chd_file::error::UNSUPPORTED_FORMAT;
}
/* next (optional) token on the line is the subcode type */
@@ -1844,5 +1844,5 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i
/* store the number of tracks found */
outtoc.numtrks = trknum + 1;
- return CHDERR_NONE;
+ return std::error_condition();
}
diff --git a/src/lib/util/chdcd.h b/src/lib/util/chdcd.h
index 65e4b943964..95f214e5831 100644
--- a/src/lib/util/chdcd.h
+++ b/src/lib/util/chdcd.h
@@ -5,14 +5,16 @@
CDRDAO TOC parser for CHD compression frontend
***************************************************************************/
-
-#ifndef MAME_UTIL_CHDCD_H
-#define MAME_UTIL_CHDCD_H
+#ifndef MAME_LIB_UTIL_CHDCD_H
+#define MAME_LIB_UTIL_CHDCD_H
#pragma once
#include "cdrom.h"
+#include <system_error>
+
+
struct chdcd_track_input_entry
{
chdcd_track_input_entry() { reset(); }
@@ -33,6 +35,6 @@ struct chdcd_track_input_info
};
-chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo);
+std::error_condition chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo);
-#endif // MAME_UTIL_CHDCD_H
+#endif // MAME_LIB_UTIL_CHDCD_H
diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp
index 4f5c23b3104..eca9403b56c 100644
--- a/src/lib/util/chdcodec.cpp
+++ b/src/lib/util/chdcodec.cpp
@@ -8,24 +8,29 @@
***************************************************************************/
-#include <cassert>
+#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 "lzma/C/LzmaDec.h"
+#include "lzma/C/LzmaEnc.h"
+
+#include <zlib.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];
};
@@ -111,7 +117,7 @@ private:
static void *fast_alloc(void *p, size_t size);
static void fast_free(void *p, void *address);
- static const int MAX_LZMA_ALLOCS = 64;
+ static constexpr int MAX_LZMA_ALLOCS = 64;
uint32_t * m_allocptr[MAX_LZMA_ALLOCS];
};
@@ -287,7 +293,7 @@ private:
// ======================> chd_cd_compressor
-template<class _BaseCompressor, class _SubcodeCompressor>
+template<class BaseCompressor, class SubcodeCompressor>
class chd_cd_compressor : public chd_compressor
{
public:
@@ -300,7 +306,7 @@ public:
{
// 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;
+ throw std::error_condition(chd_file::error::CODEC_ERROR);
}
// core functionality
@@ -323,10 +329,10 @@ public:
// 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))
+ if (memcmp(sector, f_cd_sync_header, sizeof(f_cd_sync_header)) == 0 && ecc_verify(sector))
{
dest[framenum / 8] |= 1 << (framenum % 8);
- memset(sector, 0, sizeof(s_cd_sync_header));
+ memset(sector, 0, sizeof(f_cd_sync_header));
ecc_clear(sector);
}
}
@@ -334,7 +340,7 @@ public:
// encode the base portion
uint32_t complen = m_base_compressor.compress(&m_buffer[0], frames * CD_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);
@@ -348,15 +354,15 @@ public:
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:
@@ -369,7 +375,7 @@ public:
{
// 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;
+ throw std::error_condition(chd_file::error::CODEC_ERROR);
}
// core functionality
@@ -400,7 +406,7 @@ public:
uint8_t *sector = &dest[framenum * CD_FRAME_SIZE];
if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
{
- memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
+ memcpy(sector, f_cd_sync_header, sizeof(f_cd_sync_header));
ecc_generate(sector);
}
}
@@ -408,8 +414,8 @@ public:
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;
};
@@ -460,25 +466,65 @@ 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_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_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)
+{
+ // 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
@@ -512,7 +558,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);
}
@@ -556,11 +602,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 +615,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)
{
// 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)
{
// 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 +658,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 < 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 +688,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
}
@@ -664,7 +704,7 @@ int8_t chd_compressor_group::find_best_compressor(const uint8_t *src, uint8_t *c
complen = m_hunkbytes;
int8_t compression = -1;
for (int codecnum = 0; codecnum < std::size(m_compressor); codecnum++)
- if (m_compressor[codecnum] != nullptr)
+ if (m_compressor[codecnum])
{
// attempt to compress, swallowing errors
try
@@ -702,7 +742,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
@@ -835,7 +877,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);
}
@@ -864,14 +906,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 +942,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 +972,14 @@ 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);
}
@@ -1071,20 +1113,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);
@@ -1140,24 +1182,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 +1230,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 +1258,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 +1286,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 +1324,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 +1345,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 +1400,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();
@@ -1386,7 +1428,7 @@ chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t 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;
+ throw std::error_condition(chd_file::error::CODEC_ERROR);
// determine whether we want native or swapped samples
uint16_t native_endian = 0;
@@ -1409,7 +1451,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);
}
@@ -1442,7 +1484,7 @@ uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, u
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;
+ throw std::error_condition(chd_file::error::COMPRESSION_ERROR);
// finish up
uint32_t complen = m_encoder.finish();
@@ -1456,7 +1498,7 @@ uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, u
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 +1506,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;
}
@@ -1515,7 +1557,7 @@ chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkb
{
// 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;
+ throw std::error_condition(chd_file::error::CODEC_ERROR);
// determine whether we want native or swapped samples
uint16_t native_endian = 0;
@@ -1532,7 +1574,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);
}
/**
@@ -1569,10 +1611,10 @@ void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen,
// 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;
+ 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;
+ throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR);
// inflate the subcode data
uint32_t offset = m_decoder.finish();
@@ -1584,14 +1626,14 @@ void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen,
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 != frames * CD_MAX_SUBCODE_DATA)
- throw CHDERR_DECOMPRESSION_ERROR;
+ throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR);
// reassemble the data
for (uint32_t framenum = 0; framenum < frames; framenum++)
@@ -1620,15 +1662,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 +1707,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 +1735,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;
@@ -1757,7 +1799,7 @@ void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, u
// 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)
@@ -1790,5 +1832,5 @@ void chd_avhuff_decompressor::configure(int param, void *config)
// anything else is invalid
else
- throw CHDERR_INVALID_PARAMETER;
+ throw std::error_condition(std::errc::invalid_argument);
}
diff --git a/src/lib/util/chdcodec.h b/src/lib/util/chdcodec.h
index dc9c074fd37..700ae8f8979 100644
--- a/src/lib/util/chdcodec.h
+++ b/src/lib/util/chdcodec.h
@@ -7,13 +7,15 @@
Codecs used by the CHD format
***************************************************************************/
-
-#ifndef MAME_UTIL_CHDCODEC_H
-#define MAME_UTIL_CHDCODEC_H
+#ifndef MAME_LIB_UTIL_CHDCODEC_H
+#define MAME_LIB_UTIL_CHDCODEC_H
#pragma once
+#include "utilfwd.h"
+
#include <cstdint>
+#include <memory>
#include <vector>
@@ -21,20 +23,9 @@
//**************************************************************************
-// MACROS
-//**************************************************************************
-
-#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
-
-
-
-//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-// forward references
-class chd_file;
-
// base types
typedef uint32_t chd_codec_type;
@@ -63,7 +54,7 @@ public:
private:
// internal state
chd_file & m_chd;
- uint32_t m_hunkbytes;
+ uint32_t m_hunkbytes;
bool m_lossy;
};
@@ -78,6 +69,8 @@ protected:
chd_compressor(chd_file &file, uint32_t hunkbytes, bool lossy);
public:
+ using ptr = std::unique_ptr<chd_compressor>;
+
// implementation
virtual uint32_t compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) = 0;
};
@@ -93,6 +86,8 @@ protected:
chd_decompressor(chd_file &file, uint32_t hunkbytes, bool lossy);
public:
+ using ptr = std::unique_ptr<chd_decompressor>;
+
// implementation
virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) = 0;
};
@@ -105,35 +100,12 @@ class chd_codec_list
{
public:
// create compressors or decompressors
- static chd_compressor *new_compressor(chd_codec_type type, chd_file &file);
- static chd_decompressor *new_decompressor(chd_codec_type type, chd_file &file);
+ static chd_compressor::ptr new_compressor(chd_codec_type type, chd_file &file);
+ static chd_decompressor::ptr new_decompressor(chd_codec_type type, chd_file &file);
// utilities
- static bool codec_exists(chd_codec_type type) { return (find_in_list(type) != nullptr); }
+ static bool codec_exists(chd_codec_type type);
static const char *codec_name(chd_codec_type type);
-
-private:
- // an entry in the list
- struct codec_entry
- {
- chd_codec_type m_type;
- bool m_lossy;
- const char * m_name;
- chd_compressor * (*m_construct_compressor)(chd_file &, uint32_t, bool);
- chd_decompressor * (*m_construct_decompressor)(chd_file &, uint32_t, bool);
- };
-
- // internal helper functions
- static const codec_entry *find_in_list(chd_codec_type type);
-
- template<class _CompressorClass>
- static chd_compressor *construct_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) { return new _CompressorClass(chd, hunkbytes, lossy); }
-
- template<class _DecompressorClass>
- static chd_decompressor *construct_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) { return new _DecompressorClass(chd, hunkbytes, lossy); }
-
- // the static list
- static const codec_entry s_codec_list[];
};
@@ -152,37 +124,48 @@ public:
private:
// internal state
- uint32_t m_hunkbytes; // number of bytes in a hunk
- chd_compressor * m_compressor[4]; // array of active codecs
- std::vector<uint8_t> m_compress_test; // test buffer for compression
+ uint32_t m_hunkbytes; // number of bytes in a hunk
+ chd_compressor::ptr m_compressor[4]; // array of active codecs
+ std::vector<uint8_t> m_compress_test; // test buffer for compression
#if CHDCODEC_VERIFY_COMPRESSION
- chd_decompressor * m_decompressor[4]; // array of active codecs
- std::vector<uint8_t> m_decompressed; // verification buffer
+ chd_decompressor::ptr m_decompressor[4]; // array of active codecs
+ std::vector<uint8_t> m_decompressed; // verification buffer
#endif
};
//**************************************************************************
+// MACROS
+//**************************************************************************
+
+constexpr chd_codec_type CHD_MAKE_TAG(char a, char b, char c, char d)
+{
+ return (uint32_t(uint8_t(a)) << 24) | uint32_t(uint8_t((b)) << 16) | uint32_t(uint8_t((c)) << 8) | uint32_t(uint8_t(d));
+}
+
+
+
+//**************************************************************************
// CONSTANTS
//**************************************************************************
// currently-defined codecs
-const chd_codec_type CHD_CODEC_NONE = 0;
+constexpr chd_codec_type CHD_CODEC_NONE = 0;
// general codecs
-const chd_codec_type CHD_CODEC_ZLIB = CHD_MAKE_TAG('z','l','i','b');
-const chd_codec_type CHD_CODEC_LZMA = CHD_MAKE_TAG('l','z','m','a');
-const chd_codec_type CHD_CODEC_HUFFMAN = CHD_MAKE_TAG('h','u','f','f');
-const chd_codec_type CHD_CODEC_FLAC = CHD_MAKE_TAG('f','l','a','c');
+constexpr chd_codec_type CHD_CODEC_ZLIB = CHD_MAKE_TAG('z','l','i','b');
+constexpr chd_codec_type CHD_CODEC_LZMA = CHD_MAKE_TAG('l','z','m','a');
+constexpr chd_codec_type CHD_CODEC_HUFFMAN = CHD_MAKE_TAG('h','u','f','f');
+constexpr chd_codec_type CHD_CODEC_FLAC = CHD_MAKE_TAG('f','l','a','c');
// general codecs with CD frontend
-const chd_codec_type CHD_CODEC_CD_ZLIB = CHD_MAKE_TAG('c','d','z','l');
-const chd_codec_type CHD_CODEC_CD_LZMA = CHD_MAKE_TAG('c','d','l','z');
-const chd_codec_type CHD_CODEC_CD_FLAC = CHD_MAKE_TAG('c','d','f','l');
+constexpr chd_codec_type CHD_CODEC_CD_ZLIB = CHD_MAKE_TAG('c','d','z','l');
+constexpr chd_codec_type CHD_CODEC_CD_LZMA = CHD_MAKE_TAG('c','d','l','z');
+constexpr chd_codec_type CHD_CODEC_CD_FLAC = CHD_MAKE_TAG('c','d','f','l');
// A/V codecs
-const chd_codec_type CHD_CODEC_AVHUFF = CHD_MAKE_TAG('a','v','h','u');
+constexpr chd_codec_type CHD_CODEC_AVHUFF = CHD_MAKE_TAG('a','v','h','u');
// A/V codec configuration parameters
enum
@@ -190,4 +173,4 @@ enum
AVHUFF_CODEC_DECOMPRESS_CONFIG = 1
};
-#endif // MAME_UTIL_CHDCODEC_H
+#endif // MAME_LIB_UTIL_CHDCODEC_H
diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp
index e681c0f1fac..0c72e1337be 100644
--- a/src/lib/util/corefile.cpp
+++ b/src/lib/util/corefile.cpp
@@ -12,18 +12,16 @@
#include "coretmpl.h"
#include "osdcore.h"
+#include "path.h"
#include "unicode.h"
#include "vecstream.h"
-#include <zlib.h>
-
#include <algorithm>
#include <cassert>
+#include <cctype>
#include <cstring>
#include <iterator>
-#include <cctype>
-
namespace util {
@@ -43,110 +41,11 @@ namespace {
TYPE DEFINITIONS
***************************************************************************/
-class zlib_data
-{
-public:
- typedef std::unique_ptr<zlib_data> ptr;
-
- static int start_compression(int level, std::uint64_t offset, ptr &data)
- {
- ptr result(new zlib_data(offset));
- result->reset_output();
- auto const zerr = deflateInit(&result->m_stream, level);
- result->m_compress = (Z_OK == zerr);
- if (result->m_compress) data = std::move(result);
- return zerr;
- }
- static int start_decompression(std::uint64_t offset, ptr &data)
- {
- ptr result(new zlib_data(offset));
- auto const zerr = inflateInit(&result->m_stream);
- result->m_decompress = (Z_OK == zerr);
- if (result->m_decompress) data = std::move(result);
- return zerr;
- }
-
- ~zlib_data()
- {
- if (m_compress) deflateEnd(&m_stream);
- else if (m_decompress) inflateEnd(&m_stream);
- }
-
- std::size_t buffer_size() const { return sizeof(m_buffer); }
- void const *buffer_data() const { return m_buffer; }
- void *buffer_data() { return m_buffer; }
-
- // general-purpose output buffer manipulation
- bool output_full() const { return 0 == m_stream.avail_out; }
- std::size_t output_space() const { return m_stream.avail_out; }
- void set_output(void *data, std::uint32_t size)
- {
- m_stream.next_out = reinterpret_cast<Bytef *>(data);
- m_stream.avail_out = size;
- }
-
- // working with output to the internal buffer
- bool has_output() const { return m_stream.avail_out != sizeof(m_buffer); }
- std::size_t output_size() const { return sizeof(m_buffer) - m_stream.avail_out; }
- void reset_output()
- {
- m_stream.next_out = m_buffer;
- m_stream.avail_out = sizeof(m_buffer);
- }
-
- // general-purpose input buffer manipulation
- bool has_input() const { return 0 != m_stream.avail_in; }
- std::size_t input_size() const { return m_stream.avail_in; }
- void set_input(void const *data, std::uint32_t size)
- {
- m_stream.next_in = const_cast<Bytef *>(reinterpret_cast<Bytef const *>(data));
- m_stream.avail_in = size;
- }
-
- // working with input from the internal buffer
- void reset_input(std::uint32_t size)
- {
- m_stream.next_in = m_buffer;
- m_stream.avail_in = size;
- }
-
- int compress() { assert(m_compress); return deflate(&m_stream, Z_NO_FLUSH); }
- int finalise() { assert(m_compress); return deflate(&m_stream, Z_FINISH); }
- int decompress() { assert(m_decompress); return inflate(&m_stream, Z_SYNC_FLUSH); }
-
- std::uint64_t realoffset() const { return m_realoffset; }
- void add_realoffset(std::uint32_t increment) { m_realoffset += increment; }
-
- bool is_nextoffset(std::uint64_t value) const { return m_nextoffset == value; }
- void add_nextoffset(std::uint32_t increment) { m_nextoffset += increment; }
-
-private:
- zlib_data(std::uint64_t offset)
- : m_compress(false)
- , m_decompress(false)
- , m_realoffset(offset)
- , m_nextoffset(offset)
- {
- m_stream.zalloc = Z_NULL;
- m_stream.zfree = Z_NULL;
- m_stream.opaque = Z_NULL;
- m_stream.avail_in = m_stream.avail_out = 0;
- }
-
- bool m_compress, m_decompress;
- z_stream m_stream;
- std::uint8_t m_buffer[1024];
- std::uint64_t m_realoffset;
- std::uint64_t m_nextoffset;
-};
-
-
class core_proxy_file : public core_file
{
public:
- core_proxy_file(core_file &file) : m_file(file) { }
+ core_proxy_file(core_file &file) noexcept : m_file(file) { }
virtual ~core_proxy_file() override { }
- virtual osd_file::error compress(int level) override { return m_file.compress(level); }
virtual int seek(std::int64_t offset, int whence) override { return m_file.seek(offset, whence); }
virtual std::uint64_t tell() const override { return m_file.tell(); }
@@ -162,9 +61,9 @@ public:
virtual std::uint32_t write(const void *buffer, std::uint32_t length) override { return m_file.write(buffer, length); }
virtual int puts(std::string_view s) override { return m_file.puts(s); }
virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override { return m_file.vprintf(args); }
- virtual osd_file::error truncate(std::uint64_t offset) override { return m_file.truncate(offset); }
+ virtual std::error_condition truncate(std::uint64_t offset) override { return m_file.truncate(offset); }
- virtual osd_file::error flush() override { return m_file.flush(); }
+ virtual std::error_condition flush() override { return m_file.flush(); }
private:
core_file &m_file;
@@ -230,12 +129,12 @@ public:
if (copy)
{
void *const buf = allocate();
- if (buf) std::memcpy(buf, data, length);
+ if (buf)
+ std::memcpy(buf, data, length);
}
}
~core_in_memory_file() override { purge(); }
- virtual osd_file::error compress(int level) override { return osd_file::error::INVALID_ACCESS; }
virtual int seek(std::int64_t offset, int whence) override;
virtual std::uint64_t tell() const override { return m_offset; }
@@ -246,8 +145,8 @@ public:
virtual void const *buffer() override { return m_data; }
virtual std::uint32_t write(void const *buffer, std::uint32_t length) override { return 0; }
- virtual osd_file::error truncate(std::uint64_t offset) override;
- virtual osd_file::error flush() override { clear_putback(); return osd_file::error::NONE; }
+ virtual std::error_condition truncate(std::uint64_t offset) override;
+ virtual std::error_condition flush() override { clear_putback(); return std::error_condition(); }
protected:
core_in_memory_file(std::uint32_t openflags, std::uint64_t length)
@@ -262,7 +161,8 @@ protected:
bool is_loaded() const { return nullptr != m_data; }
void *allocate()
{
- if (m_data) return nullptr;
+ if (m_data)
+ return nullptr;
void *data = malloc(m_length);
if (data)
{
@@ -273,7 +173,8 @@ protected:
}
void purge()
{
- if (m_data && m_data_allocated) free(const_cast<void *>(m_data));
+ if (m_data && m_data_allocated)
+ free(const_cast<void *>(m_data));
m_data_allocated = false;
m_data = nullptr;
}
@@ -301,23 +202,18 @@ public:
core_osd_file(std::uint32_t openmode, osd_file::ptr &&file, std::uint64_t length)
: core_in_memory_file(openmode, length)
, m_file(std::move(file))
- , m_zdata()
, m_bufferbase(0)
, m_bufferbytes(0)
{
}
~core_osd_file() override;
- virtual osd_file::error compress(int level) override;
-
- virtual int seek(std::int64_t offset, int whence) override;
-
virtual std::uint32_t read(void *buffer, std::uint32_t length) override;
virtual void const *buffer() override;
virtual std::uint32_t write(void const *buffer, std::uint32_t length) override;
- virtual osd_file::error truncate(std::uint64_t offset) override;
- virtual osd_file::error flush() override;
+ virtual std::error_condition truncate(std::uint64_t offset) override;
+ virtual std::error_condition flush() override;
protected:
@@ -326,11 +222,7 @@ protected:
private:
static constexpr std::size_t FILE_BUFFER_SIZE = 512;
- osd_file::error osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual);
- osd_file::error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual);
-
osd_file::ptr m_file; // OSD file handle
- zlib_data::ptr m_zdata; // compression data
std::uint64_t m_bufferbase; // base offset of internal buffer
std::uint32_t m_bufferbytes; // bytes currently loaded into buffer
std::uint8_t m_buffer[FILE_BUFFER_SIZE]; // buffer data
@@ -673,14 +565,14 @@ std::uint32_t core_in_memory_file::read(void *buffer, std::uint32_t length)
truncate - truncate a file
-------------------------------------------------*/
-osd_file::error core_in_memory_file::truncate(std::uint64_t offset)
+std::error_condition core_in_memory_file::truncate(std::uint64_t offset)
{
if (m_length < offset)
- return osd_file::error::FAILURE;
+ return std::errc::io_error; // TODO: revisit this error code
// adjust to new length and offset
set_length(offset);
- return osd_file::error::NONE;
+ return std::error_condition();
}
@@ -719,91 +611,6 @@ std::size_t core_in_memory_file::safe_buffer_copy(
core_osd_file::~core_osd_file()
{
// close files and free memory
- if (m_zdata)
- core_osd_file::compress(FCOMPRESS_NONE);
-}
-
-
-/*-------------------------------------------------
- compress - enable/disable streaming file
- compression via zlib; level is 0 to disable
- compression, or up to 9 for max compression
--------------------------------------------------*/
-
-osd_file::error core_osd_file::compress(int level)
-{
- osd_file::error result = osd_file::error::NONE;
-
- // can only do this for read-only and write-only cases
- if (read_access() && write_access())
- return osd_file::error::INVALID_ACCESS;
-
- // if we have been compressing, flush and free the data
- if (m_zdata && (level == FCOMPRESS_NONE))
- {
- int zerr = Z_OK;
-
- // flush any remaining data if we are writing
- while (write_access() && (zerr != Z_STREAM_END))
- {
- // deflate some more
- zerr = m_zdata->finalise();
- if ((zerr != Z_STREAM_END) && (zerr != Z_OK))
- {
- result = osd_file::error::INVALID_DATA;
- break;
- }
-
- // write the data
- if (m_zdata->has_output())
- {
- std::uint32_t actualdata;
- auto const filerr = m_file->write(m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), actualdata);
- if (filerr != osd_file::error::NONE)
- break;
- m_zdata->add_realoffset(actualdata);
- m_zdata->reset_output();
- }
- }
-
- // free memory
- m_zdata.reset();
- }
-
- // if we are just starting to compress, allocate a new buffer
- if (!m_zdata && (level > FCOMPRESS_NONE))
- {
- int zerr;
-
- // initialize the stream and compressor
- if (write_access())
- zerr = zlib_data::start_compression(level, offset(), m_zdata);
- else
- zerr = zlib_data::start_decompression(offset(), m_zdata);
-
- // on error, return an error
- if (zerr != Z_OK)
- return osd_file::error::OUT_OF_MEMORY;
-
- // flush buffers
- m_bufferbytes = 0;
- }
-
- return result;
-}
-
-
-/*-------------------------------------------------
- seek - seek within a file
--------------------------------------------------*/
-
-int core_osd_file::seek(std::int64_t offset, int whence)
-{
- // error if compressing
- if (m_zdata)
- return 1;
- else
- return core_in_memory_file::seek(offset, whence);
}
@@ -833,7 +640,7 @@ std::uint32_t core_osd_file::read(void *buffer, std::uint32_t length)
// read as much as makes sense into the buffer
m_bufferbase = offset() + bytes_read;
m_bufferbytes = 0;
- osd_or_zlib_read(m_buffer, m_bufferbase, sizeof(m_buffer), m_bufferbytes);
+ m_file->read(m_buffer, m_bufferbase, sizeof(m_buffer), m_bufferbytes);
// do a bounded copy from the buffer to the destination
bytes_read += safe_buffer_copy(m_buffer, 0, m_bufferbytes, buffer, bytes_read, length);
@@ -842,7 +649,7 @@ std::uint32_t core_osd_file::read(void *buffer, std::uint32_t length)
{
// read the remainder directly from the file
std::uint32_t new_bytes_read = 0;
- osd_or_zlib_read(reinterpret_cast<std::uint8_t *>(buffer) + bytes_read, offset() + bytes_read, length - bytes_read, new_bytes_read);
+ m_file->read(reinterpret_cast<std::uint8_t *>(buffer) + bytes_read, offset() + bytes_read, length - bytes_read, new_bytes_read);
bytes_read += new_bytes_read;
}
}
@@ -866,18 +673,16 @@ void const *core_osd_file::buffer()
{
// allocate some memory
void *buf = allocate();
- if (!buf) return nullptr;
+ if (!buf)
+ return nullptr;
// read the file
std::uint32_t read_length = 0;
- auto const filerr = osd_or_zlib_read(buf, 0, length(), read_length);
- if ((filerr != osd_file::error::NONE) || (read_length != length()))
+ auto const filerr = m_file->read(buf, 0, length(), read_length);
+ if (filerr || (read_length != length()))
purge();
else
- {
- // close the file because we don't need it anymore
- m_file.reset();
- }
+ m_file.reset(); // close the file because we don't need it anymore
}
return core_in_memory_file::buffer();
}
@@ -901,7 +706,7 @@ std::uint32_t core_osd_file::write(void const *buffer, std::uint32_t length)
// do the write
std::uint32_t bytes_written = 0;
- osd_or_zlib_write(buffer, offset(), length, bytes_written);
+ m_file->write(buffer, offset(), length, bytes_written);
// return the number of bytes written
add_offset(bytes_written);
@@ -913,19 +718,19 @@ std::uint32_t core_osd_file::write(void const *buffer, std::uint32_t length)
truncate - truncate a file
-------------------------------------------------*/
-osd_file::error core_osd_file::truncate(std::uint64_t offset)
+std::error_condition core_osd_file::truncate(std::uint64_t offset)
{
if (is_loaded())
return core_in_memory_file::truncate(offset);
// truncate file
auto const err = m_file->truncate(offset);
- if (err != osd_file::error::NONE)
+ if (err)
return err;
// and adjust to new length and offset
set_length(offset);
- return osd_file::error::NONE;
+ return std::error_condition();
}
@@ -933,7 +738,7 @@ osd_file::error core_osd_file::truncate(std::uint64_t offset)
flush - flush file buffers
-------------------------------------------------*/
-osd_file::error core_osd_file::flush()
+std::error_condition core_osd_file::flush()
{
if (is_loaded())
return core_in_memory_file::flush();
@@ -947,116 +752,6 @@ osd_file::error core_osd_file::flush()
return m_file->flush();
}
-
-/*-------------------------------------------------
- osd_or_zlib_read - wrapper for osd_read that
- handles zlib-compressed data
--------------------------------------------------*/
-
-osd_file::error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual)
-{
- // if no compression, just pass through
- if (!m_zdata)
- return m_file->read(buffer, offset, length, actual);
-
- // if the offset doesn't match the next offset, fail
- if (!m_zdata->is_nextoffset(offset))
- return osd_file::error::INVALID_ACCESS;
-
- // set up the destination
- osd_file::error filerr = osd_file::error::NONE;
- m_zdata->set_output(buffer, length);
- while (!m_zdata->output_full())
- {
- // if we didn't make progress, report an error or the end
- if (m_zdata->has_input())
- {
- auto const zerr = m_zdata->decompress();
- if (Z_OK != zerr)
- {
- if (Z_STREAM_END != zerr) filerr = osd_file::error::INVALID_DATA;
- break;
- }
- }
-
- // fetch more data if needed
- if (!m_zdata->has_input())
- {
- std::uint32_t actualdata = 0;
- filerr = m_file->read(m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->buffer_size(), actualdata);
- if (filerr != osd_file::error::NONE) break;
- m_zdata->add_realoffset(actualdata);
- m_zdata->reset_input(actualdata);
- if (!m_zdata->has_input()) break;
- }
- }
-
- // adjust everything
- actual = length - m_zdata->output_space();
- m_zdata->add_nextoffset(actual);
- return filerr;
-}
-
-
-/*-------------------------------------------------
- osd_or_zlib_write - wrapper for osd_write that
- handles zlib-compressed data
--------------------------------------------------*/
-
-/**
- * @fn osd_file::error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t actual)
- *
- * @brief OSD or zlib write.
- *
- * @param buffer The buffer.
- * @param offset The offset.
- * @param length The length.
- * @param [in,out] actual The actual.
- *
- * @return A osd_file::error.
- */
-
-osd_file::error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual)
-{
- // if no compression, just pass through
- if (!m_zdata)
- return m_file->write(buffer, offset, length, actual);
-
- // if the offset doesn't match the next offset, fail
- if (!m_zdata->is_nextoffset(offset))
- return osd_file::error::INVALID_ACCESS;
-
- // set up the source
- m_zdata->set_input(buffer, length);
- while (m_zdata->has_input())
- {
- // if we didn't make progress, report an error or the end
- auto const zerr = m_zdata->compress();
- if (zerr != Z_OK)
- {
- actual = length - m_zdata->input_size();
- m_zdata->add_nextoffset(actual);
- return osd_file::error::INVALID_DATA;
- }
-
- // write more data if we are full up
- if (m_zdata->output_full())
- {
- std::uint32_t actualdata = 0;
- auto const filerr = m_file->write(m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), actualdata);
- if (filerr != osd_file::error::NONE)
- return filerr;
- m_zdata->add_realoffset(actualdata);
- m_zdata->reset_output();
- }
- }
-
- // we wrote everything
- actual = length;
- m_zdata->add_nextoffset(actual);
- return osd_file::error::NONE;
-}
-
} // anonymous namespace
@@ -1070,23 +765,23 @@ osd_file::error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64
return an error code
-------------------------------------------------*/
-osd_file::error core_file::open(std::string const &filename, std::uint32_t openflags, ptr &file)
+std::error_condition core_file::open(std::string_view filename, std::uint32_t openflags, ptr &file)
{
try
{
// attempt to open the file
osd_file::ptr f;
std::uint64_t length = 0;
- auto const filerr = osd_file::open(filename, openflags, f, length);
- if (filerr != osd_file::error::NONE)
+ auto const filerr = osd_file::open(std::string(filename), openflags, f, length); // FIXME: allow osd_file to accept std::string_view
+ if (filerr)
return filerr;
file = std::make_unique<core_osd_file>(openflags, std::move(f), length);
- return osd_file::error::NONE;
+ return std::error_condition();
}
catch (...)
{
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -1096,20 +791,20 @@ osd_file::error core_file::open(std::string const &filename, std::uint32_t openf
like access and return an error code
-------------------------------------------------*/
-osd_file::error core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
+std::error_condition core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
{
// can only do this for read access
if ((openflags & OPEN_FLAG_WRITE) || (openflags & OPEN_FLAG_CREATE))
- return osd_file::error::INVALID_ACCESS;
+ return std::errc::invalid_argument;
try
{
file.reset(new core_in_memory_file(openflags, data, length, false));
- return osd_file::error::NONE;
+ return std::error_condition();
}
catch (...)
{
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -1120,24 +815,24 @@ osd_file::error core_file::open_ram(void const *data, std::size_t length, std::u
error code
-------------------------------------------------*/
-osd_file::error core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
+std::error_condition core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
{
// can only do this for read access
if ((openflags & OPEN_FLAG_WRITE) || (openflags & OPEN_FLAG_CREATE))
- return osd_file::error::INVALID_ACCESS;
+ return std::errc::invalid_argument;
try
{
ptr result(new core_in_memory_file(openflags, data, length, true));
if (!result->buffer())
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
file = std::move(result);
- return osd_file::error::NONE;
+ return std::error_condition();
}
catch (...)
{
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -1147,17 +842,14 @@ osd_file::error core_file::open_ram_copy(void const *data, std::size_t length, s
object and return an error code
-------------------------------------------------*/
-osd_file::error core_file::open_proxy(core_file &file, ptr &proxy)
+std::error_condition core_file::open_proxy(core_file &file, ptr &proxy)
{
- try
- {
- proxy = std::make_unique<core_proxy_file>(file);
- return osd_file::error::NONE;
- }
- catch (...)
- {
- return osd_file::error::OUT_OF_MEMORY;
- }
+ ptr result(new (std::nothrow) core_proxy_file(file));
+ if (!result)
+ return std::errc::not_enough_memory;
+
+ proxy = std::move(result);
+ return std::error_condition();
}
@@ -1176,61 +868,64 @@ core_file::~core_file()
pointer
-------------------------------------------------*/
-osd_file::error core_file::load(std::string const &filename, void **data, std::uint32_t &length)
+std::error_condition core_file::load(std::string_view filename, void **data, std::uint32_t &length)
{
ptr file;
// attempt to open the file
auto const err = open(filename, OPEN_FLAG_READ, file);
- if (err != osd_file::error::NONE)
+ if (err)
return err;
// get the size
auto const size = file->size();
if (std::uint32_t(size) != size)
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::file_too_large;
// allocate memory
*data = malloc(size);
+ if (!*data)
+ return std::errc::not_enough_memory;
length = std::uint32_t(size);
// read the data
if (file->read(*data, size) != size)
{
free(*data);
- return osd_file::error::FAILURE;
+ return std::errc::io_error; // TODO: revisit this error code
}
// close the file and return data
- return osd_file::error::NONE;
+ return std::error_condition();
}
-osd_file::error core_file::load(std::string const &filename, std::vector<uint8_t> &data)
+std::error_condition core_file::load(std::string_view filename, std::vector<uint8_t> &data)
{
ptr file;
// attempt to open the file
auto const err = open(filename, OPEN_FLAG_READ, file);
- if (err != osd_file::error::NONE)
+ if (err)
return err;
// get the size
auto const size = file->size();
if (std::uint32_t(size) != size)
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::file_too_large;
// allocate memory
- data.resize(size);
+ try { data.resize(size); }
+ catch (...) { return std::errc::not_enough_memory; }
// read the data
if (file->read(&data[0], size) != size)
{
data.clear();
- return osd_file::error::FAILURE;
+ return std::errc::io_error; // TODO: revisit this error code
}
// close the file and return data
- return osd_file::error::NONE;
+ return std::error_condition();
}
@@ -1256,7 +951,7 @@ core_file::core_file()
// assumptions about path separators
// -------------------------------------------------
-std::string_view core_filename_extract_base(std::string_view name, bool strip_extension)
+std::string_view core_filename_extract_base(std::string_view name, bool strip_extension) noexcept
{
// find the start of the basename
auto const start = std::find_if(name.rbegin(), name.rend(), &util::is_directory_separator);
@@ -1279,7 +974,7 @@ std::string_view core_filename_extract_base(std::string_view name, bool strip_ex
// core_filename_extract_extension
// -------------------------------------------------
-std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period)
+std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period) noexcept
{
auto loc = filename.find_last_of('.');
if (loc != std::string_view::npos)
@@ -1294,7 +989,7 @@ std::string_view core_filename_extract_extension(std::string_view filename, bool
// filename end with the specified extension?
// -------------------------------------------------
-bool core_filename_ends_with(std::string_view filename, std::string_view extension)
+bool core_filename_ends_with(std::string_view filename, std::string_view extension) noexcept
{
auto namelen = filename.length();
auto extlen = extension.length();
diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h
index 6aaa8f609e1..19febbb46f1 100644
--- a/src/lib/util/corefile.h
+++ b/src/lib/util/corefile.h
@@ -12,14 +12,13 @@
#pragma once
-
#include "osdfile.h"
#include "strformat.h"
#include <cstdint>
#include <memory>
-#include <string>
#include <string_view>
+#include <system_error>
namespace util {
@@ -30,11 +29,6 @@ namespace util {
#define OPEN_FLAG_NO_BOM 0x0100 /* don't output BOM */
-#define FCOMPRESS_NONE 0 /* no compression */
-#define FCOMPRESS_MIN 1 /* minimal compression */
-#define FCOMPRESS_MEDIUM 6 /* standard compression */
-#define FCOMPRESS_MAX 9 /* maximum compression */
-
/***************************************************************************
TYPE DEFINITIONS
@@ -49,23 +43,20 @@ public:
// ----- file open/close -----
// open a file with the specified filename
- static osd_file::error open(std::string const &filename, std::uint32_t openflags, ptr &file);
+ static std::error_condition open(std::string_view filename, std::uint32_t openflags, ptr &file);
// open a RAM-based "file" using the given data and length (read-only)
- static osd_file::error open_ram(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
+ static std::error_condition open_ram(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
// open a RAM-based "file" using the given data and length (read-only), copying the data
- static osd_file::error open_ram_copy(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
+ static std::error_condition open_ram_copy(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
// open a proxy "file" that forwards requests to another file object
- static osd_file::error open_proxy(core_file &file, ptr &proxy);
+ static std::error_condition open_proxy(core_file &file, ptr &proxy);
// close an open file
virtual ~core_file();
- // enable/disable streaming file compression via zlib; level is 0 to disable compression, or up to 9 for max compression
- virtual osd_file::error compress(int level) = 0;
-
// ----- file positioning -----
@@ -101,8 +92,8 @@ public:
virtual const void *buffer() = 0;
// open a file with the specified filename, read it into memory, and return a pointer
- static osd_file::error load(std::string const &filename, void **data, std::uint32_t &length);
- static osd_file::error load(std::string const &filename, std::vector<uint8_t> &data);
+ static std::error_condition load(std::string_view filename, void **data, std::uint32_t &length);
+ static std::error_condition load(std::string_view filename, std::vector<uint8_t> &data);
// ----- file write -----
@@ -121,32 +112,16 @@ public:
}
// file truncation
- virtual osd_file::error truncate(std::uint64_t offset) = 0;
+ virtual std::error_condition truncate(std::uint64_t offset) = 0;
// flush file buffers
- virtual osd_file::error flush() = 0;
+ virtual std::error_condition flush() = 0;
protected:
core_file();
};
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-// is a given character a directory separator?
-
-constexpr bool is_directory_separator(char c)
-{
-#if defined(WIN32)
- return ('\\' == c) || ('/' == c) || (':' == c);
-#else
- return '/' == c;
-#endif
-}
-
} // namespace util
@@ -157,13 +132,13 @@ constexpr bool is_directory_separator(char c)
/* ----- filename utilities ----- */
// extract the base part of a filename (remove extensions and paths)
-std::string_view core_filename_extract_base(std::string_view name, bool strip_extension = false);
+std::string_view core_filename_extract_base(std::string_view name, bool strip_extension = false) noexcept;
// extracts the file extension from a filename
-std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period = false);
+std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period = false) noexcept;
// true if the given filename ends with a particular extension
-bool core_filename_ends_with(std::string_view filename, std::string_view extension);
+bool core_filename_ends_with(std::string_view filename, std::string_view extension) noexcept;
#endif // MAME_LIB_UTIL_COREFILE_H
diff --git a/src/lib/util/harddisk.cpp b/src/lib/util/harddisk.cpp
index e91759c44f2..2e8d14f9a8a 100644
--- a/src/lib/util/harddisk.cpp
+++ b/src/lib/util/harddisk.cpp
@@ -8,11 +8,13 @@
***************************************************************************/
-#include <cassert>
#include "harddisk.h"
-#include "osdcore.h"
+
+#include "corefile.h"
+
#include <cstdlib>
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -40,7 +42,7 @@ hard_disk_file *hard_disk_open(chd_file *chd)
int cylinders, heads, sectors, sectorbytes;
hard_disk_file *file;
std::string metadata;
- chd_error err;
+ std::error_condition err;
/* punt if no CHD */
if (chd == nullptr)
@@ -48,7 +50,7 @@ hard_disk_file *hard_disk_open(chd_file *chd)
/* read the hard disk metadata */
err = chd->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
- if (err != CHDERR_NONE)
+ if (err)
return nullptr;
/* parse the metadata */
@@ -177,8 +179,8 @@ uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer)
{
if (file->chd)
{
- chd_error err = file->chd->read_units(lbasector, buffer);
- return (err == CHDERR_NONE);
+ std::error_condition err = file->chd->read_units(lbasector, buffer);
+ return !err;
}
else
{
@@ -211,8 +213,8 @@ uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *b
{
if (file->chd)
{
- chd_error err = file->chd->write_units(lbasector, buffer);
- return (err == CHDERR_NONE);
+ std::error_condition err = file->chd->write_units(lbasector, buffer);
+ return !err;
}
else
{
diff --git a/src/lib/util/harddisk.h b/src/lib/util/harddisk.h
index 2a4b727e7e7..e6fae165f19 100644
--- a/src/lib/util/harddisk.h
+++ b/src/lib/util/harddisk.h
@@ -8,13 +8,15 @@
***************************************************************************/
-#ifndef MAME_UTIL_HARDDISK_H
-#define MAME_UTIL_HARDDISK_H
+#ifndef MAME_LIB_UTIL_HARDDISK_H
+#define MAME_LIB_UTIL_HARDDISK_H
#pragma once
-#include "osdcore.h"
#include "chd.h"
+#include "utilfwd.h"
+
+#include "osdcore.h"
/***************************************************************************
@@ -49,4 +51,4 @@ hard_disk_info *hard_disk_get_info(hard_disk_file *file);
uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer);
uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer);
-#endif // MAME_UTIL_HARDDISK_H
+#endif // MAME_LIB_UTIL_HARDDISK_H
diff --git a/src/lib/util/ioprocs.cpp b/src/lib/util/ioprocs.cpp
new file mode 100644
index 00000000000..1f52a3daf97
--- /dev/null
+++ b/src/lib/util/ioprocs.cpp
@@ -0,0 +1,1248 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ioprocs.h
+
+ I/O interfaces
+
+***************************************************************************/
+
+#include "ioprocs.h"
+
+#include "corefile.h"
+#include "ioprocsfill.h"
+
+#include "osdfile.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+
+
+namespace util {
+
+namespace {
+
+// helper for holding a block of memory and deallocating it (or not) as necessary
+
+template <typename T, bool Owned>
+class ram_adapter_base : public virtual random_access
+{
+public:
+ virtual ~ram_adapter_base()
+ {
+ if constexpr (Owned)
+ std::free(m_data);
+ }
+
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ if (0 > offset)
+ return std::errc::invalid_argument;
+ m_pointer = std::uint64_t(offset);
+ return std::error_condition();
+
+ case SEEK_CUR:
+ if (0 > offset)
+ {
+ if (std::uint64_t(-offset) > m_pointer)
+ return std::errc::invalid_argument;
+ }
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_pointer)
+ {
+ return std::errc::invalid_argument;
+ }
+ m_pointer += offset;
+ return std::error_condition();
+
+ case SEEK_END:
+ if (0 > offset)
+ {
+ if (std::uint64_t(-offset) > m_size)
+ return std::errc::invalid_argument;
+ }
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_size)
+ {
+ return std::errc::invalid_argument;
+ }
+ m_pointer = std::uint64_t(m_size) + offset;
+ return std::error_condition();
+
+ default:
+ return std::errc::invalid_argument;
+ }
+ }
+
+ virtual std::error_condition tell(std::uint64_t &result) noexcept override
+ {
+ result = m_pointer;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition length(std::uint64_t &result) noexcept override
+ {
+ if (std::numeric_limits<uint64_t>::max() < m_size)
+ return std::errc::file_too_large;
+
+ result = m_size;
+ return std::error_condition();
+ }
+
+protected:
+ template <typename U>
+ ram_adapter_base(U *data, std::size_t size) noexcept : m_data(reinterpret_cast<T>(data)), m_size(size)
+ {
+ static_assert(sizeof(*m_data) == 1U, "Element type must be byte-sized");
+ assert(m_data || !m_size);
+ }
+
+ T m_data;
+ std::uint64_t m_pointer = 0U;
+ std::size_t m_size;
+};
+
+
+// RAM read implementation
+
+template <typename T, bool Owned>
+class ram_read_adapter : public ram_adapter_base<T, Owned>, public virtual random_read
+{
+public:
+ template <typename U>
+ ram_read_adapter(U *data, std::size_t size) noexcept : ram_adapter_base<T, Owned>(data, size)
+ {
+ }
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ do_read(this->m_pointer, buffer, length, actual);
+ this->m_pointer += actual;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ do_read(offset, buffer, length, actual);
+ return std::error_condition();
+ }
+
+private:
+ void do_read(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) const noexcept
+ {
+ if ((offset < this->m_size) && length)
+ {
+ actual = std::min(std::size_t(this->m_size - offset), length);
+ if constexpr (Owned)
+ std::memcpy(buffer, this->m_data + offset, actual);
+ else
+ std::memmove(buffer, this->m_data + offset, actual);
+ }
+ else
+ {
+ actual = 0U;
+ }
+ }
+};
+
+
+// helper for holding a stdio FILE and closing it (or not) as necessary
+
+class stdio_adapter_base : public virtual random_access
+{
+public:
+ virtual ~stdio_adapter_base()
+ {
+ if (m_close)
+ std::fclose(m_file);
+ }
+
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override
+ {
+ if ((std::numeric_limits<long>::max() < offset) || (std::numeric_limits<long>::min() > offset))
+ return std::errc::invalid_argument;
+ else if (!std::fseek(m_file, long(offset), whence))
+ return std::error_condition();
+ else
+ return std::error_condition(errno, std::generic_category());
+ }
+
+ virtual std::error_condition tell(std::uint64_t &result) noexcept override
+ {
+ long const pos = std::ftell(m_file);
+ if (0 > pos)
+ return std::error_condition(errno, std::generic_category());
+ result = static_cast<unsigned long>(pos);
+ return std::error_condition();
+ }
+
+ virtual std::error_condition length(std::uint64_t &result) noexcept override
+ {
+ std::fpos_t oldpos;
+ if (std::fgetpos(m_file, &oldpos))
+ return std::error_condition(errno, std::generic_category());
+
+ long endpos = -1;
+ if (!std::fseek(m_file, 0, SEEK_END))
+ {
+ m_dangling_read = m_dangling_write = false;
+ endpos = std::ftell(m_file);
+ }
+ std::error_condition err;
+ if (0 > endpos)
+ err.assign(errno, std::generic_category());
+ else if (std::numeric_limits<std::uint64_t>::max() < static_cast<unsigned long>(endpos))
+ err = std::errc::file_too_large;
+ else
+ result = static_cast<unsigned long>(endpos);
+
+ if (!std::fsetpos(m_file, &oldpos))
+ m_dangling_read = m_dangling_write = false;
+ else if (!err)
+ err.assign(errno, std::generic_category());
+
+ return err;
+ }
+
+protected:
+ stdio_adapter_base(FILE *file, bool close) noexcept : m_file(file), m_close(close)
+ {
+ assert(m_file);
+ }
+
+ FILE *file() noexcept
+ {
+ return m_file;
+ }
+
+private:
+ FILE *const m_file;
+ bool const m_close;
+
+protected:
+ bool m_dangling_read = true, m_dangling_write = true;
+};
+
+
+// stdio read implementation
+
+class stdio_read_adapter : public stdio_adapter_base, public virtual random_read
+{
+public:
+ stdio_read_adapter(FILE *file, bool close) noexcept : stdio_adapter_base(file, close)
+ {
+ }
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ if (m_dangling_write)
+ {
+ if (std::fflush(file()))
+ {
+ std::clearerr(file());
+ actual = 0U;
+ return std::error_condition(errno, std::generic_category());
+ }
+ m_dangling_write = false;
+ }
+
+ actual = std::fread(buffer, sizeof(std::uint8_t), length, file());
+ m_dangling_read = true;
+ if (length != actual)
+ {
+ if (std::ferror(file()))
+ {
+ std::clearerr(file());
+ return std::error_condition(errno, std::generic_category());
+ }
+ else if (std::feof(file()))
+ {
+ m_dangling_read = false;
+ }
+ }
+
+ return std::error_condition();
+ }
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ if (static_cast<unsigned long>(std::numeric_limits<long>::max()) < offset)
+ return std::errc::invalid_argument;
+
+ std::fpos_t oldpos;
+ if (std::fgetpos(file(), &oldpos))
+ return std::error_condition(errno, std::generic_category());
+
+ std::error_condition err;
+ if (std::fseek(file(), long(static_cast<unsigned long>(offset)), SEEK_SET))
+ {
+ err.assign(errno, std::generic_category());
+ }
+ else
+ {
+ m_dangling_write = false;
+ actual = std::fread(buffer, sizeof(std::uint8_t), length, file());
+ m_dangling_read = true;
+ if (length != actual)
+ {
+ if (std::ferror(file()))
+ {
+ err.assign(errno, std::generic_category());
+ std::clearerr(file());
+ }
+ else if (std::feof(file()))
+ {
+ m_dangling_read = false;
+ }
+ }
+ }
+
+ if (!std::fsetpos(file(), &oldpos))
+ m_dangling_read = m_dangling_write = false;
+ else if (!err)
+ err.assign(errno, std::generic_category());
+
+ return err;
+ }
+};
+
+
+// stdio read/write implementation
+
+class stdio_read_write_adapter : public stdio_read_adapter, public random_read_write
+{
+public:
+ using stdio_read_adapter::stdio_read_adapter;
+
+ virtual std::error_condition finalize() noexcept override
+ {
+ return std::error_condition();
+ }
+
+ virtual std::error_condition flush() noexcept override
+ {
+ if (std::fflush(file()))
+ {
+ std::clearerr(file());
+ return std::error_condition(errno, std::generic_category());
+ }
+ m_dangling_write = false;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ if (m_dangling_read)
+ {
+ if (std::fseek(file(), 0, SEEK_CUR))
+ {
+ actual = 0U;
+ return std::error_condition(errno, std::generic_category());
+ }
+ m_dangling_read = false;
+ }
+
+ actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file());
+ m_dangling_write = true;
+ if (length != actual)
+ {
+ std::clearerr(file());
+ return std::error_condition(errno, std::generic_category());
+ }
+
+ return std::error_condition();
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ if (static_cast<unsigned long>(std::numeric_limits<long>::max()) < offset)
+ return std::errc::invalid_argument;
+
+ std::fpos_t oldpos;
+ if (std::fgetpos(file(), &oldpos))
+ return std::error_condition(errno, std::generic_category());
+
+ std::error_condition err;
+ if (std::fseek(file(), long(static_cast<unsigned long>(offset)), SEEK_SET))
+ {
+ err.assign(errno, std::generic_category());
+ }
+ else
+ {
+ m_dangling_read = false;
+ actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file());
+ m_dangling_write = true;
+ if (length != actual)
+ {
+ err.assign(errno, std::generic_category());
+ std::clearerr(file());
+ }
+ }
+
+ if (!std::fsetpos(file(), &oldpos))
+ m_dangling_read = m_dangling_write = false;
+ else if (!err)
+ err.assign(errno, std::generic_category());
+
+ return err;
+ }
+};
+
+
+// stdio helper that fills space when writing past the end-of-file
+
+class stdio_read_write_filler : public random_read_fill_wrapper<stdio_read_write_adapter>
+{
+public:
+ stdio_read_write_filler(FILE *file, bool close, std::uint8_t fill) noexcept : random_read_fill_wrapper<stdio_read_write_adapter>(file, close)
+ {
+ set_filler(fill);
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ long const offset = std::ftell(file());
+ if (0 > offset)
+ return std::error_condition(errno, std::generic_category());
+
+ if (std::fseek(file(), 0, SEEK_END))
+ {
+ std::error_condition err(errno, std::generic_category());
+ if (!std::fseek(file(), offset, SEEK_SET))
+ m_dangling_read = m_dangling_write = false;
+ return err;
+ }
+ m_dangling_read = m_dangling_write = false;
+ long endpos = std::ftell(file());
+ if (0 > endpos)
+ {
+ std::error_condition err(errno, std::generic_category());
+ std::fseek(file(), offset, SEEK_SET);
+ return err;
+ }
+
+ if (offset > endpos)
+ {
+ std::uint8_t block[1024];
+ std::fill_n(
+ block,
+ std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos),
+ get_filler());
+ do
+ {
+ std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos);
+ std::size_t const filled = std::fwrite(block, sizeof(block[0]), chunk, file());
+ endpos += filled;
+ m_dangling_write = true;
+ if (chunk != filled)
+ {
+ std::error_condition err(errno, std::generic_category());
+ std::clearerr(file());
+ if (!std::fseek(file(), offset, SEEK_SET))
+ m_dangling_write = false;
+ return err;
+ }
+ }
+ while (static_cast<unsigned long>(endpos) < offset);
+ }
+ else if ((offset < endpos) && std::fseek(file(), offset, SEEK_SET))
+ {
+ return std::error_condition(errno, std::generic_category());
+ }
+
+ actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file());
+ m_dangling_write = true;
+ if (length != actual)
+ {
+ std::clearerr(file());
+ return std::error_condition(errno, std::generic_category());
+ }
+
+ return std::error_condition();
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ if (static_cast<unsigned long>(std::numeric_limits<long>::max()) < offset)
+ return std::errc::invalid_argument;
+
+ std::fpos_t oldpos;
+ if (std::fgetpos(file(), &oldpos))
+ return std::error_condition(errno, std::generic_category());
+
+ std::error_condition err;
+ if (std::fseek(file(), 0, SEEK_END))
+ {
+ err.assign(errno, std::generic_category());
+ }
+ else
+ {
+ m_dangling_read = m_dangling_write = false;
+ long endpos = std::ftell(file());
+ if (0 > endpos)
+ {
+ err.assign(errno, std::generic_category());
+ }
+ else if (static_cast<unsigned long>(endpos) > offset)
+ {
+ if (std::fseek(file(), long(static_cast<unsigned long>(offset)), SEEK_SET))
+ err.assign(errno, std::generic_category());
+ }
+ else if (static_cast<unsigned long>(endpos) < offset)
+ {
+ std::uint8_t block[1024];
+ std::fill_n(
+ block,
+ std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos),
+ get_filler());
+ do
+ {
+ std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos);
+ std::size_t const filled = std::fwrite(block, sizeof(block[0]), chunk, file());
+ endpos += filled;
+ m_dangling_write = true;
+ if (chunk != filled)
+ {
+ err.assign(errno, std::generic_category());
+ std::clearerr(file());
+ }
+ }
+ while (!err && (static_cast<unsigned long>(endpos) < offset));
+ }
+ }
+
+ if (!err)
+ {
+ actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file());
+ m_dangling_write = true;
+ if (length != actual)
+ {
+ err.assign(errno, std::generic_category());
+ std::clearerr(file());
+ }
+ }
+
+ if (!std::fsetpos(file(), &oldpos))
+ m_dangling_read = m_dangling_write = false;
+ else if (!err)
+ err.assign(errno, std::generic_category());
+
+ return err;
+ }
+};
+
+
+// helper class for holding an osd_file and closing it (or not) as necessary
+
+class osd_file_adapter_base : public virtual random_access
+{
+public:
+ virtual ~osd_file_adapter_base()
+ {
+ if (m_close)
+ delete m_file;
+ }
+
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ if (0 > offset)
+ return std::errc::invalid_argument;
+ m_pointer = std::uint64_t(offset);
+ return std::error_condition();
+
+ case SEEK_CUR:
+ if (0 > offset)
+ {
+ if (std::uint64_t(-offset) > m_pointer)
+ return std::errc::invalid_argument;
+ }
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_pointer)
+ {
+ return std::errc::invalid_argument;
+ }
+ m_pointer += offset;
+ return std::error_condition();
+
+ // TODO: add SEEK_END when osd_file can support it - should it return a different error?
+ default:
+ return std::errc::invalid_argument;
+ }
+ }
+
+ virtual std::error_condition tell(std::uint64_t &result) noexcept override
+ {
+ result = m_pointer;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition length(std::uint64_t &result) noexcept override
+ {
+ // not supported by osd_file
+ return std::errc::not_supported; // TODO: revisit this error code
+ }
+
+protected:
+ osd_file_adapter_base(osd_file::ptr &&file) noexcept : m_file(file.release()), m_close(true)
+ {
+ assert(m_file);
+ }
+
+ osd_file_adapter_base(osd_file &file) noexcept : m_file(&file), m_close(false)
+ {
+ }
+
+ osd_file &file() noexcept
+ {
+ return *m_file;
+ }
+
+ std::uint64_t m_pointer = 0U;
+
+private:
+ osd_file *const m_file;
+ bool const m_close;
+};
+
+
+// osd_file read implementation
+
+class osd_file_read_adapter : public osd_file_adapter_base, public virtual random_read
+{
+public:
+ osd_file_read_adapter(osd_file::ptr &&file) noexcept : osd_file_adapter_base(std::move(file))
+ {
+ }
+
+ osd_file_read_adapter(osd_file &file) noexcept : osd_file_adapter_base(file)
+ {
+ }
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ // TODO: should the client have to deal with reading less than expected even if EOF isn't hit?
+ if (std::numeric_limits<std::uint32_t>::max() < length)
+ {
+ actual = 0U;
+ return std::errc::invalid_argument;
+ }
+
+ // actual length not valid on error
+ std::uint32_t count;
+ std::error_condition err = file().read(buffer, m_pointer, std::uint32_t(length), count);
+ if (!err)
+ {
+ m_pointer += count;
+ actual = std::size_t(count);
+ }
+ else
+ {
+ actual = 0U;
+ }
+ return err;
+ }
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ // TODO: should the client have to deal with reading less than expected even if EOF isn't hit?
+ if (std::numeric_limits<std::uint32_t>::max() < length)
+ {
+ actual = 0U;
+ return std::errc::invalid_argument;
+ }
+
+ // actual length not valid on error
+ std::uint32_t count;
+ std::error_condition err = file().read(buffer, offset, std::uint32_t(length), count);
+ if (!err)
+ actual = std::size_t(count);
+ else
+ actual = 0U;
+ return err;
+ }
+};
+
+
+// osd_file read/write implementation
+
+class osd_file_read_write_adapter : public osd_file_read_adapter, public random_read_write
+{
+public:
+ using osd_file_read_adapter::osd_file_read_adapter;
+
+ virtual std::error_condition finalize() noexcept override
+ {
+ return std::error_condition();
+ }
+
+ virtual std::error_condition flush() noexcept override
+ {
+ return file().flush();
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+ while (length)
+ {
+ // actual length not valid on error
+ std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length);
+ std::uint32_t written;
+ std::error_condition err = file().write(buffer, m_pointer, chunk, written);
+ if (err)
+ return err;
+ m_pointer += written;
+ buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written;
+ length -= written;
+ actual += written;
+ }
+ return std::error_condition();
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+ while (length)
+ {
+ // actual length not valid on error
+ std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length);
+ std::uint32_t written;
+ std::error_condition err = file().write(buffer, offset, chunk, written);
+ if (err)
+ return err;
+ offset += written;
+ buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written;
+ length -= written;
+ actual += written;
+ }
+ return std::error_condition();
+ }
+};
+
+
+// helper class for holding a core_file and closing it (or not) as necessary
+
+class core_file_adapter_base : public virtual random_access
+{
+public:
+ virtual ~core_file_adapter_base()
+ {
+ if (m_close)
+ delete m_file;
+ }
+
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override
+ {
+ if (!m_file->seek(offset, whence))
+ return std::error_condition();
+ else
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+
+ virtual std::error_condition tell(std::uint64_t &result) noexcept override
+ {
+ // no error reporting
+ result = m_file->tell();
+ return std::error_condition();
+ }
+
+ virtual std::error_condition length(std::uint64_t &result) noexcept override
+ {
+ // no error reporting
+ result = m_file->size();
+ return std::error_condition();
+ }
+
+protected:
+ core_file_adapter_base(core_file::ptr &&file) noexcept : m_file(file.release()), m_close(true)
+ {
+ assert(m_file);
+ }
+
+ core_file_adapter_base(core_file &file) noexcept : m_file(&file), m_close(false)
+ {
+ }
+
+ core_file &file() noexcept
+ {
+ return *m_file;
+ }
+
+private:
+ core_file *const m_file;
+ bool const m_close;
+};
+
+
+// core_file read implementation
+
+class core_file_read_adapter : public core_file_adapter_base, public virtual random_read
+{
+public:
+ core_file_read_adapter(core_file::ptr &&file) noexcept : core_file_adapter_base(std::move(file))
+ {
+ }
+
+ core_file_read_adapter(core_file &file) noexcept : core_file_adapter_base(file)
+ {
+ }
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ // TODO: should the client have to deal with reading less than expected even if EOF isn't hit?
+ if (std::numeric_limits<std::uint32_t>::max() < length)
+ {
+ actual = 0U;
+ return std::errc::invalid_argument;
+ }
+
+ // no way to distinguish between EOF and error
+ actual = file().read(buffer, std::uint32_t(length));
+ return std::error_condition();
+ }
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ // TODO: should the client have to deal with reading less than expected even if EOF isn't hit?
+ if (std::numeric_limits<std::uint32_t>::max() < length)
+ return std::errc::invalid_argument;
+
+ // no error reporting for tell
+ std::uint64_t const oldpos = file().tell();
+ if (file().seek(offset, SEEK_SET))
+ {
+ file().seek(oldpos, SEEK_SET);
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+
+ // no way to distinguish between EOF and error
+ actual = file().read(buffer, std::uint32_t(length));
+
+ if (!file().seek(oldpos, SEEK_SET))
+ return std::error_condition();
+ else
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+};
+
+
+// core_file read/write implementation
+
+class core_file_read_write_adapter : public core_file_read_adapter, public random_read_write
+{
+public:
+ using core_file_read_adapter::core_file_read_adapter;
+
+ virtual std::error_condition finalize() noexcept override
+ {
+ return std::error_condition();
+ }
+
+ virtual std::error_condition flush() noexcept override
+ {
+ return file().flush();
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+ while (length)
+ {
+ std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length);
+ std::uint32_t const written = file().write(buffer, chunk);
+ actual += written;
+ if (written < chunk)
+ return std::errc::io_error; // TODO: better error reporting for core_file
+ buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written;
+ length -= written;
+ }
+ return std::error_condition();
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ // no error reporting for tell
+ std::uint64_t const oldpos = file().tell();
+ if (file().seek(offset, SEEK_SET))
+ {
+ file().seek(oldpos, SEEK_SET);
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+
+ std::error_condition err;
+ while (!err && length)
+ {
+ std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length);
+ std::uint32_t const written = file().write(buffer, chunk);
+ actual += written;
+ if (written < chunk)
+ {
+ err = std::errc::io_error; // TODO: better error reporting for core_file
+ }
+ else
+ {
+ buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written;
+ length -= written;
+ }
+ }
+
+ if (!file().seek(oldpos, SEEK_SET) || err)
+ return err;
+ else
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+};
+
+
+// core_file helper that fills space when writing past the end-of-file
+
+class core_file_read_write_filler : public random_read_fill_wrapper<core_file_read_write_adapter>
+{
+public:
+ core_file_read_write_filler(core_file::ptr &&file, std::uint8_t fill) noexcept : random_read_fill_wrapper<core_file_read_write_adapter>(std::move(file))
+ {
+ set_filler(fill);
+ }
+
+ core_file_read_write_filler(core_file &file, std::uint8_t fill) noexcept : random_read_fill_wrapper<core_file_read_write_adapter>(file)
+ {
+ set_filler(fill);
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ // no error reporting for tell or size
+ std::uint64_t const offset = file().tell();
+ std::uint64_t endpos = file().size();
+ if (endpos < offset)
+ {
+ if (file().seek(endpos, SEEK_SET))
+ {
+ file().seek(offset, SEEK_SET);
+ actual = 0U;
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+ std::uint8_t block[1024];
+ std::fill_n(
+ block,
+ std::min<std::common_type_t<std::size_t, std::uint64_t> >(std::size(block), offset - endpos),
+ get_filler());
+ do
+ {
+ std::uint32_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(sizeof(block), offset - endpos);
+ std::uint32_t const filled = file().write(block, chunk);
+ endpos += filled;
+ if (chunk != filled)
+ {
+ file().seek(offset, SEEK_SET);
+ actual = 0U;
+ return std::errc::io_error; // TODO: better error reporting for core_file
+ }
+ }
+ while (endpos < offset);
+ }
+
+ return core_file_read_write_adapter::write(buffer, length, actual);
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ actual = 0U;
+
+ // no error reporting for tell
+ std::uint64_t const oldpos = file().tell();
+ if (file().seek(0, SEEK_END))
+ {
+ file().seek(oldpos, SEEK_SET);
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+ std::uint64_t endpos = file().tell();
+
+ std::error_condition err;
+ if (endpos > offset)
+ {
+ if (file().seek(offset, SEEK_SET))
+ err = std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+ else if (endpos < offset)
+ {
+ std::uint8_t block[1024];
+ std::fill_n(
+ block,
+ std::min<std::common_type_t<std::size_t, std::uint64_t> >(std::size(block), offset - endpos),
+ get_filler());
+ do
+ {
+ std::uint32_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(sizeof(block), offset - endpos);
+ std::uint32_t const filled = file().write(block, chunk);
+ endpos += filled;
+ if (chunk != filled)
+ err = std::errc::io_error; // TODO: better error reporting for core_file
+ }
+ while (!err && (endpos < offset));
+ }
+
+ while (!err && length)
+ {
+ std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length);
+ std::uint32_t const written = file().write(buffer, chunk);
+ actual += written;
+ if (written < chunk)
+ {
+ err = std::errc::io_error; // TODO: better error reporting for core_file
+ }
+ else
+ {
+ buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written;
+ length -= written;
+ }
+ }
+
+ if (!file().seek(oldpos, SEEK_SET) || err)
+ return err;
+ else
+ return std::errc::invalid_argument; // TODO: better error reporting for core_file
+ }
+};
+
+} // anonymous namespace
+
+
+// creating RAM read adapters
+
+random_read::ptr ram_read(void const *data, std::size_t size) noexcept
+{
+ random_read::ptr result;
+ if (data || !size)
+ result.reset(new (std::nothrow) ram_read_adapter<std::uint8_t const *const, false>(data, size));
+ return result;
+}
+
+random_read::ptr ram_read(void const *data, std::size_t size, std::uint8_t filler) noexcept
+{
+ std::unique_ptr<random_read_fill_wrapper<ram_read_adapter<std::uint8_t const *const, false> > > result;
+ if (data || !size)
+ result.reset(new (std::nothrow) decltype(result)::element_type(data, size));
+ if (result)
+ result->set_filler(filler);
+ return result;
+}
+
+random_read::ptr ram_read_copy(void const *data, std::size_t size) noexcept
+{
+ random_read::ptr result;
+ void *const copy = size ? std::malloc(size) : nullptr;
+ if (copy)
+ std::memcpy(copy, data, size);
+ if (copy || !size)
+ result.reset(new (std::nothrow) ram_read_adapter<std::uint8_t *const, true>(copy, size));
+ if (!result)
+ std::free(copy);
+ return result;
+}
+
+random_read::ptr ram_read_copy(void const *data, std::size_t size, std::uint8_t filler) noexcept
+{
+ std::unique_ptr<random_read_fill_wrapper<ram_read_adapter<std::uint8_t *const, true> > > result;
+ void *const copy = size ? std::malloc(size) : nullptr;
+ if (copy)
+ std::memcpy(copy, data, size);
+ if (copy || !size)
+ result.reset(new (std::nothrow) decltype(result)::element_type(copy, size));
+ if (!result)
+ std::free(copy);
+ return result;
+}
+
+
+// creating stdio read adapters
+
+random_read::ptr stdio_read(FILE *file) noexcept
+{
+ random_read::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) stdio_read_adapter(file, true));
+ return result;
+}
+
+random_read::ptr stdio_read(FILE *file, std::uint8_t filler) noexcept
+{
+ std::unique_ptr<random_read_fill_wrapper<stdio_read_adapter> > result;
+ if (file)
+ result.reset(new (std::nothrow) decltype(result)::element_type(file, true));
+ if (result)
+ result->set_filler(filler);
+ return result;
+}
+
+random_read::ptr stdio_read_noclose(FILE *file) noexcept
+{
+ random_read::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) stdio_read_adapter(file, false));
+ return result;
+}
+
+random_read::ptr stdio_read_noclose(FILE *file, std::uint8_t filler) noexcept
+{
+ std::unique_ptr<random_read_fill_wrapper<stdio_read_adapter> > result;
+ if (file)
+ result.reset(new (std::nothrow) decltype(result)::element_type(file, false));
+ if (result)
+ result->set_filler(filler);
+ return result;
+}
+
+
+// creating stdio read/write adapters
+
+random_read_write::ptr stdio_read_write(FILE *file) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) stdio_read_write_adapter(file, true));
+ return result;
+}
+
+random_read_write::ptr stdio_read_write(FILE *file, std::uint8_t filler) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) stdio_read_write_filler(file, true, filler));
+ return result;
+}
+
+random_read_write::ptr stdio_read_write_noclose(FILE *file) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) stdio_read_write_adapter(file, false));
+ return result;
+}
+
+random_read_write::ptr stdio_read_write_noclose(FILE *file, std::uint8_t filler) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) stdio_read_write_filler(file, false, filler));
+ return result;
+}
+
+
+// creating osd_file read adapters
+
+random_read::ptr osd_file_read(osd_file::ptr &&file) noexcept
+{
+ random_read::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) osd_file_read_adapter(std::move(file)));
+ return result;
+}
+
+random_read::ptr osd_file_read(osd_file &file) noexcept
+{
+ return random_read::ptr(new (std::nothrow) osd_file_read_adapter(file));
+}
+
+
+// creating osd_file read/write adapters
+
+random_read_write::ptr osd_file_read_write(osd_file::ptr &&file) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) osd_file_read_write_adapter(std::move(file)));
+ return result;
+}
+
+random_read_write::ptr osd_file_read_write(osd_file &file) noexcept
+{
+ return random_read_write::ptr(new (std::nothrow) osd_file_read_write_adapter(file));
+}
+
+
+// creating core_file read adapters
+
+random_read::ptr core_file_read(core_file::ptr &&file) noexcept
+{
+ random_read::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) core_file_read_adapter(std::move(file)));
+ return result;
+}
+
+random_read::ptr core_file_read(core_file::ptr &&file, std::uint8_t filler) noexcept
+{
+ std::unique_ptr<random_read_fill_wrapper<core_file_read_adapter> > result;
+ if (file)
+ result.reset(new (std::nothrow) decltype(result)::element_type(std::move(file)));
+ if (result)
+ result->set_filler(filler);
+ return result;
+}
+
+random_read::ptr core_file_read(core_file &file) noexcept
+{
+ return random_read::ptr(new (std::nothrow) core_file_read_adapter(file));
+}
+
+random_read::ptr core_file_read(core_file &file, std::uint8_t filler) noexcept
+{
+ std::unique_ptr<random_read_fill_wrapper<core_file_read_adapter> > result;
+ result.reset(new (std::nothrow) decltype(result)::element_type(file));
+ if (result)
+ result->set_filler(filler);
+ return result;
+}
+
+
+// creating core_file read/write adapters
+
+random_read_write::ptr core_file_read_write(core_file::ptr &&file) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) core_file_read_write_adapter(std::move(file)));
+ return result;
+}
+
+random_read_write::ptr core_file_read_write(core_file::ptr &&file, std::uint8_t filler) noexcept
+{
+ random_read_write::ptr result;
+ if (file)
+ result.reset(new (std::nothrow) core_file_read_write_filler(std::move(file), filler));
+ return result;
+}
+
+random_read_write::ptr core_file_read_write(core_file &file) noexcept
+{
+ return random_read_write::ptr(new (std::nothrow) core_file_read_write_adapter(file));
+}
+
+random_read_write::ptr core_file_read_write(core_file &file, std::uint8_t filler) noexcept
+{
+ return random_read_write::ptr(new (std::nothrow) core_file_read_write_filler(file, filler));
+}
+
+} // namespace util
diff --git a/src/lib/util/ioprocs.h b/src/lib/util/ioprocs.h
new file mode 100644
index 00000000000..78c06e71318
--- /dev/null
+++ b/src/lib/util/ioprocs.h
@@ -0,0 +1,130 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ioprocs.h
+
+ I/O interfaces
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_IOPROCS_H
+#define MAME_LIB_UTIL_IOPROCS_H
+
+#pragma once
+
+#include "utilfwd.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <system_error>
+
+
+// FIXME: make a proper place for OSD forward declarations
+class osd_file;
+
+
+namespace util {
+
+class read_stream
+{
+public:
+ using ptr = std::unique_ptr<read_stream>;
+
+ virtual ~read_stream() = default;
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
+};
+
+
+class write_stream
+{
+public:
+ using ptr = std::unique_ptr<write_stream>;
+
+ virtual ~write_stream() = default;
+
+ virtual std::error_condition finalize() noexcept = 0;
+ virtual std::error_condition flush() noexcept = 0;
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
+};
+
+
+class read_write_stream : public virtual read_stream, public virtual write_stream
+{
+public:
+ using ptr = std::unique_ptr<read_write_stream>;
+};
+
+
+class random_access
+{
+public:
+ virtual ~random_access() = default;
+
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept = 0;
+ virtual std::error_condition tell(std::uint64_t &result) noexcept = 0;
+ virtual std::error_condition length(std::uint64_t &result) noexcept = 0;
+};
+
+
+class random_read : public virtual read_stream, public virtual random_access
+{
+public:
+ using ptr = std::unique_ptr<random_read>;
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
+};
+
+
+class random_write : public virtual write_stream, public virtual random_access
+{
+public:
+ using ptr = std::unique_ptr<random_write>;
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0;
+};
+
+
+class random_read_write : public read_write_stream, public virtual random_read, public virtual random_write
+{
+public:
+ using ptr = std::unique_ptr<random_read_write>;
+};
+
+
+random_read::ptr ram_read(void const *data, std::size_t size) noexcept;
+random_read::ptr ram_read(void const *data, std::size_t size, std::uint8_t filler) noexcept;
+random_read::ptr ram_read_copy(void const *data, std::size_t size) noexcept;
+random_read::ptr ram_read_copy(void const *data, std::size_t size, std::uint8_t filler) noexcept;
+
+random_read::ptr stdio_read(FILE *file) noexcept;
+random_read::ptr stdio_read(FILE *file, std::uint8_t filler) noexcept;
+random_read::ptr stdio_read_noclose(FILE *file) noexcept;
+random_read::ptr stdio_read_noclose(FILE *file, std::uint8_t filler) noexcept;
+
+random_read_write::ptr stdio_read_write(FILE *file) noexcept;
+random_read_write::ptr stdio_read_write(FILE *file, std::uint8_t filler) noexcept;
+random_read_write::ptr stdio_read_write_noclose(FILE *file) noexcept;
+random_read_write::ptr stdio_read_write_noclose(FILE *file, std::uint8_t filler) noexcept;
+
+random_read::ptr osd_file_read(std::unique_ptr<osd_file> &&file) noexcept;
+random_read::ptr osd_file_read(osd_file &file) noexcept;
+
+random_read_write::ptr osd_file_read_write(std::unique_ptr<osd_file> &&file) noexcept;
+random_read_write::ptr osd_file_read_write(osd_file &file) noexcept;
+
+random_read::ptr core_file_read(std::unique_ptr<core_file> &&file) noexcept;
+random_read::ptr core_file_read(std::unique_ptr<core_file> &&file, std::uint8_t filler) noexcept;
+random_read::ptr core_file_read(core_file &file) noexcept;
+random_read::ptr core_file_read(core_file &file, std::uint8_t filler) noexcept;
+
+random_read_write::ptr core_file_read_write(std::unique_ptr<core_file> &&file) noexcept;
+random_read_write::ptr core_file_read_write(std::unique_ptr<core_file> &&file, std::uint8_t filler) noexcept;
+random_read_write::ptr core_file_read_write(core_file &file) noexcept;
+random_read_write::ptr core_file_read_write(core_file &file, std::uint8_t filler) noexcept;
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_IOPROCS_H
diff --git a/src/lib/util/ioprocsfill.h b/src/lib/util/ioprocsfill.h
new file mode 100644
index 00000000000..e49b10687f0
--- /dev/null
+++ b/src/lib/util/ioprocsfill.h
@@ -0,0 +1,163 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ioprocsfill.h
+
+ Wrappers that automatically fill extra space
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_IOPROCSFILL_H
+#define MAME_LIB_UTIL_IOPROCSFILL_H
+
+#pragma once
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <system_error>
+
+
+namespace util {
+
+template <std::uint8_t DefaultFiller>
+class fill_wrapper_base
+{
+public:
+ std::uint8_t get_filler() const noexcept
+ {
+ return m_filler;
+ }
+
+ void set_filler(std::uint8_t filler) noexcept
+ {
+ m_filler = filler;
+ }
+
+private:
+ std::uint8_t m_filler = DefaultFiller;
+};
+
+
+template <typename Base, std::uint8_t DefaultFiller = 0U>
+class read_stream_fill_wrapper : public Base, public virtual fill_wrapper_base<DefaultFiller>
+{
+public:
+ using Base::Base;
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition err = Base::read(buffer, length, actual);
+ assert(length >= actual);
+ std::fill(
+ reinterpret_cast<std::uint8_t *>(buffer) + actual,
+ reinterpret_cast<std::uint8_t *>(buffer) + length,
+ fill_wrapper_base<DefaultFiller>::get_filler());
+ return err;
+ }
+};
+
+
+template <typename Base, std::uint8_t DefaultFiller = 0U>
+class random_read_fill_wrapper : public read_stream_fill_wrapper<Base, DefaultFiller>
+{
+public:
+ using read_stream_fill_wrapper<Base, DefaultFiller>::read_stream_fill_wrapper;
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition err = Base::read_at(offset, buffer, length, actual);
+ assert(length >= actual);
+ std::fill(
+ reinterpret_cast<std::uint8_t *>(buffer) + actual,
+ reinterpret_cast<std::uint8_t *>(buffer) + length,
+ fill_wrapper_base<DefaultFiller>::get_filler());
+ return err;
+ }
+};
+
+
+template <typename Base, std::uint8_t DefaultFiller = 0U, std::size_t FillBlock = 1024U>
+class random_write_fill_wrapper : public Base, public virtual fill_wrapper_base<DefaultFiller>
+{
+public:
+ using Base::Base;
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition err;
+ actual = 0U;
+
+ std::uint64_t offset;
+ std::uint64_t current;
+ err = Base::tell(offset);
+ if (err)
+ return err;
+ err = Base::length(current);
+ if (err)
+ return err;
+
+ if (current < offset)
+ {
+ std::uint64_t unfilled = offset - current;
+ std::uint8_t fill_buffer[FillBlock];
+ std::fill(
+ fill_buffer,
+ fill_buffer + std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled),
+ fill_wrapper_base<DefaultFiller>::get_filler());
+ do
+ {
+ std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled);
+ err = Base::write_at(current, fill_buffer, chunk, actual);
+ if (err)
+ {
+ actual = 0U;
+ return err;
+ }
+ current += chunk;
+ unfilled -= chunk;
+ }
+ while (unfilled);
+ }
+
+ return Base::write(buffer, length, actual);
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition err;
+ std::uint64_t current;
+ err = Base::length(current);
+ if (!err && (current < offset))
+ {
+ std::uint64_t unfilled = offset - current;
+ std::uint8_t fill_buffer[FillBlock];
+ std::fill(
+ fill_buffer,
+ fill_buffer + std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled),
+ fill_wrapper_base<DefaultFiller>::get_filler());
+ do
+ {
+ std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled);
+ err = Base::write_at(current, fill_buffer, chunk, actual);
+ current += chunk;
+ unfilled -= chunk;
+ }
+ while (unfilled && !err);
+ }
+ if (err)
+ {
+ actual = 0U;
+ return err;
+ }
+ return Base::write_at(offset, buffer, length, actual);
+ }
+};
+
+
+template <typename Base, std::uint8_t DefaultFiller = 0U, std::size_t FillBlock = 1024U>
+using random_read_write_fill_wrapper = random_write_fill_wrapper<random_read_fill_wrapper<Base, DefaultFiller>, DefaultFiller, FillBlock>;
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_IOPROCSFILL_H
diff --git a/src/lib/util/ioprocsfilter.cpp b/src/lib/util/ioprocsfilter.cpp
new file mode 100644
index 00000000000..da67b8c41f2
--- /dev/null
+++ b/src/lib/util/ioprocsfilter.cpp
@@ -0,0 +1,598 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ioprocs.h
+
+ I/O filters
+
+***************************************************************************/
+
+#include "ioprocsfilter.h"
+
+#include "ioprocs.h"
+
+#include <zlib.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstdint>
+#include <limits>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+
+
+namespace util {
+
+namespace {
+
+// helper class for holding zlib data
+
+class zlib_data
+{
+protected:
+ zlib_data(std::size_t buffer_size) noexcept :
+ m_buffer_size(std::min<std::common_type_t<uInt, std::size_t> >(std::numeric_limits<uInt>::max(), buffer_size))
+ {
+ assert(buffer_size);
+ }
+
+ z_stream &get_z_stream() noexcept { return m_z_stream; }
+ z_stream const &get_z_stream() const noexcept { return m_z_stream; }
+ Bytef *get_buffer() noexcept { return m_buffer.get(); }
+ Bytef const *get_buffer() const noexcept { return m_buffer.get(); }
+ std::size_t get_buffer_size() const noexcept { return m_buffer_size; }
+
+ bool input_empty() const noexcept { return !m_z_stream.avail_in; }
+ bool output_available() const noexcept { return bool(m_z_stream.avail_out); }
+
+ void initialize_z_stream() noexcept
+ {
+ m_z_stream.zalloc = Z_NULL;
+ m_z_stream.zfree = Z_NULL;
+ m_z_stream.opaque = Z_NULL;
+ }
+
+ std::error_condition allocate_buffer() noexcept
+ {
+ if (!m_buffer)
+ m_buffer.reset(new (std::nothrow) Bytef [m_buffer_size]);
+ return m_buffer ? std::error_condition() : std::errc::not_enough_memory;
+ }
+
+ void release_buffer() noexcept
+ {
+ m_buffer.reset();
+ }
+
+ static std::error_condition convert_z_error(int err) noexcept
+ {
+ switch (err)
+ {
+ case Z_OK:
+ case Z_STREAM_END:
+ return std::error_condition();
+ case Z_NEED_DICT:
+ return std::errc::invalid_argument;
+ case Z_ERRNO:
+ return std::error_condition(errno, std::generic_category());
+ case Z_STREAM_ERROR:
+ return std::errc::invalid_argument;
+ case Z_DATA_ERROR:
+ return std::errc::invalid_argument; // TODO: revisit this error code
+ case Z_MEM_ERROR:
+ return std::errc::not_enough_memory;
+ case Z_BUF_ERROR:
+ return std::errc::operation_would_block; // TODO: revisit this error code (should be handled internally)
+ case Z_VERSION_ERROR:
+ return std::errc::invalid_argument; // TODO: revisit this error code (library ABI mismatch)
+ default:
+ return std::errc::io_error; // TODO: better default error code
+ }
+ }
+
+private:
+ z_stream m_z_stream;
+ std::unique_ptr<Bytef []> m_buffer;
+ std::size_t const m_buffer_size;
+};
+
+
+// helper class for decompressing deflated data
+
+class inflate_data : private zlib_data
+{
+protected:
+ using zlib_data::zlib_data;
+
+ ~inflate_data()
+ {
+ if (m_inflate_initialized)
+ inflateEnd(&get_z_stream());
+ }
+
+ using zlib_data::input_empty;
+
+ bool stream_initialized() const noexcept
+ {
+ return m_inflate_initialized;
+ }
+
+ std::error_condition initialize_z_stream() noexcept
+ {
+ if (m_inflate_initialized)
+ return std::errc::invalid_argument;
+ std::error_condition err = allocate_buffer();
+ if (err)
+ return err;
+ zlib_data::initialize_z_stream();
+ int const zerr = inflateInit(&get_z_stream());
+ if (Z_OK == zerr)
+ m_inflate_initialized = true;
+ return convert_z_error(zerr);
+ }
+
+ std::error_condition close_z_stream() noexcept
+ {
+ if (!m_inflate_initialized)
+ return std::errc::invalid_argument;
+ int const zerr = inflateEnd(&get_z_stream());
+ m_inflate_initialized = false;
+ return convert_z_error(zerr);
+ }
+
+ std::error_condition decompress_some(bool &stream_end) noexcept
+ {
+ assert(m_inflate_initialized);
+ int const zerr = inflate(&get_z_stream(), Z_SYNC_FLUSH);
+ if (!get_z_stream().avail_in)
+ reset_input();
+ stream_end = Z_STREAM_END == zerr;
+ return convert_z_error(zerr);
+ }
+
+ std::size_t input_available() const noexcept
+ {
+ return std::size_t(get_z_stream().avail_in);
+ }
+
+ void reset_input() noexcept
+ {
+ get_z_stream().next_in = get_buffer();
+ get_z_stream().avail_in = 0U;
+ }
+
+ std::pair<void *, std::size_t> get_unfilled_input() noexcept
+ {
+ assert(get_buffer());
+ Bytef *const base = get_z_stream().next_in + get_z_stream().avail_in;
+ return std::make_pair(base, get_buffer() + get_buffer_size() - base);
+ }
+
+ void add_input(std::size_t length) noexcept
+ {
+ assert(get_buffer());
+ get_z_stream().avail_in += length;
+ assert((get_buffer() + get_buffer_size()) >= (get_z_stream().next_in + get_z_stream().avail_in));
+ }
+
+ std::size_t output_produced() const noexcept
+ {
+ return m_output_max - get_z_stream().avail_out;
+ }
+
+ void set_output(void *buffer, std::size_t length) noexcept
+ {
+ m_output_max = std::min<std::common_type_t<uInt, std::size_t> >(std::numeric_limits<uInt>::max(), length);
+ get_z_stream().next_out = reinterpret_cast<Bytef *>(buffer);
+ get_z_stream().avail_out = uInt(m_output_max);
+ }
+
+private:
+ std::error_condition allocate_buffer() noexcept
+ {
+ std::error_condition err;
+ if (!get_buffer())
+ {
+ err = zlib_data::allocate_buffer();
+ reset_input();
+ }
+ return err;
+ }
+
+ bool m_inflate_initialized = false;
+ std::size_t m_output_max = 0U;
+};
+
+
+// helper class for deflating data
+
+class deflate_data : private zlib_data
+{
+protected:
+ deflate_data(int level, std::size_t buffer_size) noexcept : zlib_data(buffer_size), m_level(level)
+ {
+ }
+
+ ~deflate_data()
+ {
+ if (m_deflate_initialized)
+ deflateEnd(&get_z_stream());
+ }
+
+ using zlib_data::input_empty;
+ using zlib_data::output_available;
+
+ bool stream_initialized() const noexcept
+ {
+ return m_deflate_initialized;
+ }
+
+ bool compression_finished() const noexcept
+ {
+ return m_compression_finished;
+ }
+
+ std::error_condition initialize_z_stream() noexcept
+ {
+ if (m_deflate_initialized)
+ return std::errc::invalid_argument;
+ std::error_condition err = allocate_buffer();
+ if (err)
+ return err;
+ zlib_data::initialize_z_stream();
+ int const zerr = deflateInit(&get_z_stream(), m_level);
+ reset_output();
+ if (Z_OK == zerr)
+ m_deflate_initialized = true;
+ return convert_z_error(zerr);
+ }
+
+ std::error_condition close_z_stream() noexcept
+ {
+ if (!m_deflate_initialized)
+ return std::errc::invalid_argument;
+ m_deflate_initialized = m_compression_finished = false;
+ return convert_z_error(deflateEnd(&get_z_stream()));
+ }
+
+ std::error_condition reset_z_stream() noexcept
+ {
+ if (!m_deflate_initialized)
+ return std::errc::invalid_argument;
+ assert(get_buffer());
+ reset_output();
+ m_compression_finished = false;
+ return convert_z_error(deflateReset(&get_z_stream()));
+ }
+
+ std::error_condition compress_some() noexcept
+ {
+ assert(m_deflate_initialized);
+ return convert_z_error(deflate(&get_z_stream(), Z_NO_FLUSH));
+ }
+
+ std::error_condition finish_compression() noexcept
+ {
+ assert(m_deflate_initialized);
+ int const zerr = deflate(&get_z_stream(), Z_FINISH);
+ if (Z_STREAM_END == zerr)
+ m_compression_finished = true;
+ return convert_z_error(zerr);
+ }
+
+ std::size_t input_used() const noexcept
+ {
+ return m_input_max - get_z_stream().avail_in;
+ }
+
+ void set_input(void const *data, std::size_t length) noexcept
+ {
+ m_input_max = std::min<std::common_type_t<uInt, std::size_t> >(std::numeric_limits<uInt>::max(), length);
+ get_z_stream().next_in = const_cast<Bytef z_const *>(reinterpret_cast<Bytef const *>(data));
+ get_z_stream().avail_in = uInt(m_input_max);
+ }
+
+ std::pair<void const *, std::size_t> get_output() const noexcept
+ {
+ assert(get_buffer());
+ return std::make_pair(
+ &get_buffer()[m_output_used],
+ get_buffer_size() - get_z_stream().avail_out - m_output_used);
+ }
+
+ void consume_output(std::size_t length) noexcept
+ {
+ m_output_used += length;
+ assert(m_output_used <= (get_buffer_size() - get_z_stream().avail_out));
+ if (m_output_used == (get_buffer_size() - get_z_stream().avail_out))
+ reset_output();
+ }
+
+private:
+ void reset_output() noexcept
+ {
+ assert(get_buffer());
+ m_output_used = 0U;
+ get_z_stream().next_out = get_buffer();
+ get_z_stream().avail_out = uInt(get_buffer_size());
+ }
+
+ int const m_level;
+ bool m_deflate_initialized = false;
+ bool m_compression_finished = false;
+ std::size_t m_output_used = 0U;
+ std::size_t m_input_max = 0U;
+};
+
+
+// helper for holding an object and deleting it (or not) as necessary
+
+template <typename T>
+class filter_base
+{
+protected:
+ filter_base(std::unique_ptr<T> &&object) noexcept : m_object(object.release()), m_owned(true)
+ {
+ assert(m_object);
+ }
+
+ filter_base(T &object) noexcept : m_object(&object), m_owned(false)
+ {
+ }
+
+ ~filter_base()
+ {
+ if (m_owned)
+ delete m_object;
+ }
+
+ T &object() noexcept
+ {
+ return *m_object;
+ }
+
+private:
+ T *const m_object;
+ bool const m_owned;
+};
+
+
+// filter for decompressing deflated data
+
+template <typename Stream>
+class zlib_read_filter : public read_stream, protected filter_base<Stream>, protected inflate_data
+{
+public:
+ zlib_read_filter(std::unique_ptr<Stream> &&stream, std::size_t read_chunk) noexcept :
+ filter_base<Stream>(std::move(stream)),
+ inflate_data(read_chunk)
+ {
+ }
+
+ zlib_read_filter(Stream &stream, std::size_t read_chunk) noexcept :
+ filter_base<Stream>(stream),
+ inflate_data(read_chunk)
+ {
+ }
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition err;
+ actual = 0U;
+
+ if (!stream_initialized())
+ err = initialize_z_stream();
+
+ if (!err && (length > actual))
+ {
+ bool short_input = false;
+ do
+ {
+ if (input_empty())
+ {
+ auto const space = get_unfilled_input();
+ std::size_t filled;
+ err = this->object().read(space.first, space.second, filled);
+ add_input(filled);
+ short_input = space.second > filled;
+ }
+
+ if (!err && !input_empty())
+ {
+ set_output(reinterpret_cast<std::uint8_t *>(buffer) + actual, length - actual);
+ bool stream_end;
+ err = decompress_some(stream_end);
+ actual += output_produced();
+
+ if (stream_end)
+ {
+ assert(!err);
+ if constexpr (std::is_base_of_v<random_read, Stream>)
+ {
+ if (!input_empty())
+ {
+ std::int64_t const overshoot = std::uint64_t(input_available());
+ reset_input();
+ return this->object().seek(-overshoot, SEEK_CUR);
+ }
+ }
+ else
+ {
+ return std::error_condition();
+ }
+ }
+ }
+ }
+ while (!err && (length > actual) && !short_input);
+ }
+
+ return err;
+ }
+};
+
+
+// filter for deflating data
+
+class zlib_write_filter : public write_stream, protected filter_base<write_stream>, protected deflate_data
+{
+public:
+ zlib_write_filter(write_stream::ptr &&stream, int level, std::size_t buffer_size) noexcept :
+ filter_base<write_stream>(std::move(stream)),
+ deflate_data(level, buffer_size)
+ {
+ }
+
+ zlib_write_filter(write_stream &stream, int level, std::size_t buffer_size) noexcept :
+ filter_base<write_stream>(stream),
+ deflate_data(level, buffer_size)
+ {
+ }
+
+ ~zlib_write_filter()
+ {
+ finalize();
+ }
+
+ virtual std::error_condition finalize() noexcept override
+ {
+ if (!stream_initialized())
+ return std::error_condition();
+
+ do
+ {
+ if (!compression_finished() && output_available())
+ {
+ std::error_condition err = finish_compression();
+ if (err)
+ return err;
+ }
+
+ while ((compression_finished() && get_output().second) || !output_available())
+ {
+ std::error_condition err = write_some();
+ if (err)
+ return err;
+ }
+ }
+ while (!compression_finished());
+
+ return close_z_stream();
+ }
+
+ virtual std::error_condition flush() noexcept override
+ {
+ if (stream_initialized())
+ {
+ auto const output = get_output();
+ if (output.second)
+ {
+ std::size_t written;
+ std::error_condition err = object().write(output.first, output.second, written);
+ consume_output(written);
+ if (err)
+ {
+ object().flush();
+ return err;
+ }
+ }
+ }
+ return object().flush();
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition err;
+ actual = 0U;
+
+ if (!stream_initialized())
+ {
+ err = initialize_z_stream();
+ }
+ else if (compression_finished())
+ {
+ while (!err && get_output().second)
+ err = write_some();
+ if (!err)
+ err = reset_z_stream();
+ }
+
+ while (!err && (length > actual))
+ {
+ set_input(reinterpret_cast<std::uint8_t const *>(buffer) + actual, length - actual);
+ do
+ {
+ if (output_available())
+ err = compress_some();
+
+ while (!err && !output_available())
+ err = write_some();
+ }
+ while (!err && !input_empty());
+ actual += input_used();
+ }
+
+ return err;
+ }
+
+private:
+ std::error_condition write_some() noexcept
+ {
+ auto const output = get_output();
+ std::size_t written;
+ std::error_condition err = object().write(output.first, output.second, written);
+ consume_output(written);
+ return err;
+ }
+};
+
+} // anonymous namespace
+
+
+// creating decompressing filters
+
+read_stream::ptr zlib_read(read_stream::ptr &&stream, std::size_t read_chunk) noexcept
+{
+ read_stream::ptr result;
+ if (stream)
+ result.reset(new (std::nothrow) zlib_read_filter<read_stream>(std::move(stream), read_chunk));
+ return result;
+}
+
+read_stream::ptr zlib_read(random_read::ptr &&stream, std::size_t read_chunk) noexcept
+{
+ read_stream::ptr result;
+ if (stream)
+ result.reset(new (std::nothrow) zlib_read_filter<random_read>(std::move(stream), read_chunk));
+ return result;
+}
+
+read_stream::ptr zlib_read(read_stream &stream, std::size_t read_chunk) noexcept
+{
+ return read_stream::ptr(new (std::nothrow) zlib_read_filter<read_stream>(stream, read_chunk));
+}
+
+read_stream::ptr zlib_read(random_read &stream, std::size_t read_chunk) noexcept
+{
+ return read_stream::ptr(new (std::nothrow) zlib_read_filter<random_read>(stream, read_chunk));
+}
+
+
+// creating compressing filters
+
+write_stream::ptr zlib_write(write_stream::ptr &&stream, int level, std::size_t buffer_size) noexcept
+{
+ write_stream::ptr result;
+ if (stream)
+ result.reset(new (std::nothrow) zlib_write_filter(std::move(stream), level, buffer_size));
+ return result;
+}
+
+write_stream::ptr zlib_write(write_stream &stream, int level, std::size_t buffer_size) noexcept
+{
+ return write_stream::ptr(new (std::nothrow) zlib_write_filter(stream, level, buffer_size));
+}
+
+} // namespace util
diff --git a/src/lib/util/ioprocsfilter.h b/src/lib/util/ioprocsfilter.h
new file mode 100644
index 00000000000..a146dd737ce
--- /dev/null
+++ b/src/lib/util/ioprocsfilter.h
@@ -0,0 +1,31 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ioprocs.h
+
+ I/O filters
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_IOPROCSFILTER_H
+#define MAME_LIB_UTIL_IOPROCSFILTER_H
+
+#include "utilfwd.h"
+
+#include <cstdlib>
+#include <memory>
+
+
+namespace util {
+
+std::unique_ptr<read_stream> zlib_read(std::unique_ptr<read_stream> &&stream, std::size_t read_chunk) noexcept;
+std::unique_ptr<read_stream> zlib_read(std::unique_ptr<random_read> &&stream, std::size_t read_chunk) noexcept;
+std::unique_ptr<read_stream> zlib_read(read_stream &stream, std::size_t read_chunk) noexcept;
+std::unique_ptr<read_stream> zlib_read(random_read &stream, std::size_t read_chunk) noexcept;
+
+std::unique_ptr<write_stream> zlib_write(std::unique_ptr<write_stream> &&stream, int level, std::size_t buffer_size) noexcept;
+std::unique_ptr<write_stream> zlib_write(write_stream &stream, int level, std::size_t buffer_size) noexcept;
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_IOPROCSFILTER_H
diff --git a/src/lib/util/ioprocsvec.h b/src/lib/util/ioprocsvec.h
new file mode 100644
index 00000000000..27dda095ad3
--- /dev/null
+++ b/src/lib/util/ioprocsvec.h
@@ -0,0 +1,211 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ioprocsvec.h
+
+ Helper for using a vector as an in-memory file
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_IOPROCSVEC_H
+#define MAME_LIB_UTIL_IOPROCSVEC_H
+
+#include "ioprocs.h"
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <system_error>
+#include <type_traits>
+#include <vector>
+
+
+namespace util {
+
+template <typename T = std::uint8_t>
+class vector_read_write_adapter : public random_read_write
+{
+public:
+ vector_read_write_adapter(std::vector<T> &storage) noexcept : m_storage(storage)
+ {
+ check_resized();
+ }
+
+ virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ if (0 > offset)
+ return std::errc::invalid_argument;
+ m_pointer = std::uint64_t(offset);
+ return std::error_condition();
+
+ case SEEK_CUR:
+ if (0 > offset)
+ {
+ if (std::uint64_t(-offset) > m_pointer)
+ return std::errc::invalid_argument;
+ }
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_pointer)
+ {
+ return std::errc::invalid_argument;
+ }
+ m_pointer += offset;
+ return std::error_condition();
+
+ case SEEK_END:
+ check_resized();
+ if (0 > offset)
+ {
+ if (std::uint64_t(-offset) > m_size)
+ return std::errc::invalid_argument;
+ }
+ else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_size)
+ {
+ return std::errc::invalid_argument;
+ }
+ m_pointer = std::uint64_t(m_size) + offset;
+ return std::error_condition();
+
+ default:
+ return std::errc::invalid_argument;
+ }
+ }
+
+ virtual std::error_condition tell(std::uint64_t &result) noexcept override
+ {
+ result = m_pointer;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition length(std::uint64_t &result) noexcept override
+ {
+ check_resized();
+ if (std::numeric_limits<uint64_t>::max() < m_size)
+ return std::errc::file_too_large;
+
+ result = m_size;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ do_read(m_pointer, buffer, length, actual);
+ m_pointer += actual;
+ return std::error_condition();
+ }
+
+ virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ do_read(offset, buffer, length, actual);
+ return std::error_condition();
+ }
+
+ virtual std::error_condition finalize() noexcept override
+ {
+ return std::error_condition();
+ }
+
+ virtual std::error_condition flush() noexcept override
+ {
+ return std::error_condition();
+ }
+
+ virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ std::error_condition result = do_write(m_pointer, buffer, length, actual);
+ m_pointer += actual;
+ return result;
+ }
+
+ virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override
+ {
+ return do_write(offset, buffer, length, actual);
+ }
+
+private:
+ using elements_type = typename std::vector<T>::size_type;
+ using common_size_type = std::common_type_t<std::uint64_t, std::size_t>;
+
+ void check_resized() noexcept
+ {
+ if (m_storage.size() != m_elements)
+ {
+ m_elements = m_storage.size();
+ m_size = m_elements * sizeof(T);
+ }
+ }
+
+ void do_read(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept
+ {
+ check_resized();
+ if ((offset < m_size) && length)
+ {
+ actual = std::min(std::size_t(m_size - offset), length);
+ std::memmove(buffer, reinterpret_cast<std::uint8_t *>(m_storage.data()) + offset, actual);
+ }
+ else
+ {
+ actual = 0U;
+ }
+ }
+
+ std::error_condition do_write(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept
+ {
+ check_resized();
+ std::size_t allocated = m_elements * sizeof(T);
+ std::uint64_t const target = ((std::numeric_limits<std::uint64_t>::max() - offset) >= length)
+ ? (offset + length)
+ : std::numeric_limits<std::uint64_t>::max();
+
+ std::error_condition result;
+ if (target > allocated)
+ {
+ elements_type const required = std::min<std::common_type_t<elements_type, std::uint64_t> >(
+ std::numeric_limits<elements_type>::max(),
+ (target + sizeof(T) - 1) / sizeof(T)); // technically can overflow but unlikely
+ try { m_storage.resize(required); } // unpredictable if constructing/assigning T can throw
+ catch (...) { result = std::errc::not_enough_memory; }
+ m_elements = m_storage.size();
+ allocated = m_elements * sizeof(T);
+ assert(allocated >= m_size);
+
+ if (offset > m_size)
+ {
+ std::size_t const new_size = std::size_t(std::min<common_size_type>(allocated, offset));
+ std::memset(
+ reinterpret_cast<std::uint8_t *>(m_storage.data()) + m_size,
+ 0x00, // POSIX says unwritten areas of files should read as zero
+ new_size - m_size);
+ m_size = new_size;
+ }
+ }
+
+ std::size_t const limit = std::min<common_size_type>(target, allocated);
+ if (limit > offset)
+ {
+ actual = std::size_t(limit - offset);
+ std::memmove(reinterpret_cast<std::uint8_t *>(m_storage.data()) + offset, buffer, actual);
+ m_size = limit;
+ }
+ else
+ {
+ actual = 0U;
+ }
+ if (!result && (actual < length))
+ result = std::errc::no_space_on_device;
+
+ return result;
+ }
+
+ std::vector<T> &m_storage;
+ std::uint64_t m_pointer = 0U;
+ elements_type m_elements = 0U;
+ std::size_t m_size = 0U;
+};
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_IOPROCSVEC_H
diff --git a/src/lib/util/path.cpp b/src/lib/util/path.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/lib/util/path.cpp
diff --git a/src/lib/util/path.h b/src/lib/util/path.h
new file mode 100644
index 00000000000..1291d7b17d3
--- /dev/null
+++ b/src/lib/util/path.h
@@ -0,0 +1,65 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ path.h
+
+ Filesystem path utilties
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_PATH_H
+#define MAME_LIB_UTIL_PATH_H
+
+#include "osdfile.h" // for PATH_SEPARATOR
+
+#include <string>
+#include <utility>
+
+
+namespace util {
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+// is a given character a directory separator?
+
+constexpr bool is_directory_separator(char c)
+{
+#if defined(WIN32)
+ return ('\\' == c) || ('/' == c) || (':' == c);
+#else
+ return '/' == c;
+#endif
+}
+
+
+// append to a path
+
+template <typename T, typename... U>
+inline std::string &path_append(std::string &path, T &&next, U &&... more)
+{
+ if (!path.empty() && !is_directory_separator(path.back()))
+ path.append(PATH_SEPARATOR);
+ path.append(std::forward<T>(next));
+ if constexpr (sizeof...(U))
+ return path_append(std::forward<U>(more)...);
+ else
+ return path;
+}
+
+
+// concatenate paths
+
+template <typename T, typename... U>
+inline std::string path_concat(T &&first, U &&... more)
+{
+ std::string result(std::forward<T>(first));
+ if constexpr (sizeof...(U))
+ path_append(result, std::forward<U>(more)...);
+ return result;
+}
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_PATH_H
diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h
index b8c9b4f1a99..a3ba1d11261 100644
--- a/src/lib/util/strformat.h
+++ b/src/lib/util/strformat.h
@@ -578,16 +578,16 @@ template <typename Stream, typename T>
class format_output
{
private:
- template <typename U> struct string_semantics
- { static constexpr bool value = false; };
- template <typename CharT, typename Traits, typename Allocator> struct string_semantics<std::basic_string<CharT, Traits, Allocator> >
- { static constexpr bool value = true; };
- template <typename CharT, typename Traits> struct string_semantics<std::basic_string_view<CharT, Traits> >
- { static constexpr bool value = true; };
- template <typename U> struct signed_integer_semantics
- { static constexpr bool value = std::is_integral_v<U>&& std::is_signed_v<U>; };
- template <typename U> struct unsigned_integer_semantics
- { static constexpr bool value = std::is_integral_v<U>&& !std::is_signed_v<U>; };
+ template <typename U>
+ struct string_semantics : public std::false_type { };
+ template <typename CharT, typename Traits, typename Allocator>
+ struct string_semantics<std::basic_string<CharT, Traits, Allocator> > : public std::true_type { };
+ template <typename CharT, typename Traits>
+ struct string_semantics<std::basic_string_view<CharT, Traits> > : public std::true_type { };
+ template <typename U>
+ using signed_integer_semantics = std::bool_constant<std::is_integral_v<U> && std::is_signed_v<U> >;
+ template <typename U>
+ using unsigned_integer_semantics = std::bool_constant<std::is_integral_v<U> && !std::is_signed_v<U> >;
static void apply_signed(Stream &str, char16_t const &value)
{
@@ -865,8 +865,8 @@ template <typename Stream, typename T>
class format_output<Stream, T *>
{
protected:
- template <typename U> struct string_semantics
- { static constexpr bool value = std::is_same<std::remove_const_t<U>, typename Stream::char_type>::value; };
+ template <typename U>
+ using string_semantics = std::bool_constant<std::is_same_v<std::remove_const_t<U>, typename Stream::char_type> >;
public:
template <typename U>
@@ -940,10 +940,10 @@ template <typename T>
class format_make_integer
{
private:
- template <typename U> struct use_unsigned_cast
- { static constexpr bool value = std::is_convertible<U const, unsigned>::value && std::is_unsigned<U>::value; };
- template <typename U> struct use_signed_cast
- { static constexpr bool value = !use_unsigned_cast<U>::value && std::is_convertible<U const, int>::value; };
+ template <typename U>
+ using use_unsigned_cast = std::bool_constant<std::is_convertible_v<U const, unsigned> && std::is_unsigned_v<U> >;
+ template <typename U>
+ using use_signed_cast = std::bool_constant<!use_unsigned_cast<U>::value && std::is_convertible_v<U const, int> >;
public:
template <typename U> static bool apply(U const &value, int &result)
@@ -974,14 +974,14 @@ template <typename T>
class format_store_integer
{
private:
- template <typename U> struct is_non_const_ptr
- { static constexpr bool value = std::is_pointer<U>::value && !std::is_const<std::remove_pointer_t<U> >::value; };
- template <typename U> struct is_unsigned_ptr
- { static constexpr bool value = std::is_pointer<U>::value && std::is_unsigned<std::remove_pointer_t<U> >::value; };
- template <typename U> struct use_unsigned_cast
- { static constexpr bool value = is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> >::value; };
- template <typename U> struct use_signed_cast
- { static constexpr bool value = is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible<std::streamoff, std::remove_pointer_t<U> >::value; };
+ template <typename U>
+ using is_non_const_ptr = std::bool_constant<std::is_pointer_v<U> && !std::is_const_v<std::remove_pointer_t<U> > >;
+ template <typename U>
+ using is_unsigned_ptr = std::bool_constant<std::is_pointer_v<U> && std::is_unsigned_v<std::remove_pointer_t<U> > >;
+ template <typename U>
+ using use_unsigned_cast = std::bool_constant<is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible_v<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> > >;
+ template <typename U>
+ using use_signed_cast = std::bool_constant<is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible_v<std::streamoff, std::remove_pointer_t<U> > >;
public:
template <typename U> static bool apply(U const &value, std::streamoff data)
@@ -1091,11 +1091,11 @@ public:
protected:
template <typename T>
- struct handle_char_ptr { static constexpr bool value = std::is_pointer<T>::value && std::is_same<std::remove_cv_t<std::remove_pointer_t<T> >, char_type>::value; };
+ using handle_char_ptr = std::bool_constant<std::is_pointer_v<T> && std::is_same_v<std::remove_cv_t<std::remove_pointer_t<T> >, char_type> >;
template <typename T>
- struct handle_char_array { static constexpr bool value = std::is_array<T>::value && std::is_same<std::remove_cv_t<std::remove_extent_t<T> >, char_type>::value; };
+ using handle_char_array = std::bool_constant<std::is_array_v<T> && std::is_same_v<std::remove_cv_t<std::remove_extent_t<T> >, char_type> >;
template <typename T>
- struct handle_container { static constexpr bool value = !handle_char_ptr<T>::value && !handle_char_array<T>::value; };
+ using handle_container = std::bool_constant<!handle_char_ptr<T>::value && !handle_char_array<T>::value>;
template <typename Format>
format_argument_pack(
diff --git a/src/lib/util/timeconv.cpp b/src/lib/util/timeconv.cpp
index 99953712003..469b6b592a2 100644
--- a/src/lib/util/timeconv.cpp
+++ b/src/lib/util/timeconv.cpp
@@ -14,42 +14,10 @@
namespace util {
-/***************************************************************************
- PROTOTYPES
-***************************************************************************/
-
-static std::chrono::system_clock::duration calculate_system_clock_adjustment();
-
-
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
-
-std::chrono::system_clock::duration system_clock_adjustment(calculate_system_clock_adjustment());
-
-
-/***************************************************************************
- IMPLEMENTATION
-***************************************************************************/
-
-arbitrary_datetime arbitrary_datetime::now()
-{
- time_t sec;
- time(&sec);
- auto t = *localtime(&sec);
-
- arbitrary_datetime dt;
- dt.year = t.tm_year + 1900;
- dt.month = t.tm_mon + 1;
- dt.day_of_month = t.tm_mday;
- dt.hour = t.tm_hour;
- dt.minute = t.tm_min;
- dt.second = t.tm_sec;
- return dt;
-}
+namespace {
-static std::chrono::system_clock::duration calculate_system_clock_adjustment()
+std::chrono::system_clock::duration calculate_system_clock_adjustment()
{
constexpr auto days_in_year(365);
constexpr auto days_in_four_years((days_in_year * 4) + 1);
@@ -84,6 +52,39 @@ static std::chrono::system_clock::duration calculate_system_clock_adjustment()
return result - std::chrono::system_clock::from_time_t(0).time_since_epoch();
}
+} // anonymous namespace
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+std::chrono::system_clock::duration system_clock_adjustment(calculate_system_clock_adjustment());
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+arbitrary_datetime arbitrary_datetime::now()
+{
+ time_t sec;
+ time(&sec);
+ auto t = *localtime(&sec);
+
+ arbitrary_datetime dt;
+ dt.year = t.tm_year + 1900;
+ dt.month = t.tm_mon + 1;
+ dt.day_of_month = t.tm_mday;
+ dt.hour = t.tm_hour;
+ dt.minute = t.tm_min;
+ dt.second = t.tm_sec;
+
+ return dt;
+}
+
// -------------------------------------------------
diff --git a/src/lib/util/timeconv.h b/src/lib/util/timeconv.h
index f9d1b070012..91327dbac16 100644
--- a/src/lib/util/timeconv.h
+++ b/src/lib/util/timeconv.h
@@ -22,6 +22,7 @@
namespace util {
+
/***************************************************************************
GLOBAL VARIABLES
***************************************************************************/
@@ -58,7 +59,7 @@ struct arbitrary_datetime
// date of the epoch's begining
//---------------------------------------------------------
-template<typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio>
+template <typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio>
class arbitrary_clock
{
public:
@@ -89,7 +90,7 @@ public:
// with a different scale to this arbitrary_clock's scale
//---------------------------------------------------------
- template<typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2>
+ template <typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2>
static time_point from_arbitrary_time_point(const std::chrono::time_point<arbitrary_clock<Rep2, YY, MM, DD, HH, NN, SS, Ratio2> > &tp)
{
arbitrary_datetime dt;
@@ -111,7 +112,7 @@ public:
// of this scale to one of different scale
//---------------------------------------------------------
- template<typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2>
+ template <typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2>
static std::chrono::time_point<arbitrary_clock<Rep2, YY, MM, DD, HH, NN, SS, Ratio2> > to_arbitrary_time_point(const time_point &tp)
{
return arbitrary_clock<Rep2, YY, MM, DD, HH, NN, SS, Ratio2>::from_arbitrary_time_point(tp);
@@ -125,14 +126,14 @@ public:
static struct tm to_tm(const time_point &tp)
{
std::chrono::time_point<tm_conversion_clock> normalized_tp = to_arbitrary_time_point<
- std::int64_t,
- tm_conversion_clock::base_year,
- tm_conversion_clock::base_month,
- tm_conversion_clock::base_day,
- tm_conversion_clock::base_hour,
- tm_conversion_clock::base_minute,
- tm_conversion_clock::base_second,
- tm_conversion_clock::period>(tp);
+ std::int64_t,
+ tm_conversion_clock::base_year,
+ tm_conversion_clock::base_month,
+ tm_conversion_clock::base_day,
+ tm_conversion_clock::base_hour,
+ tm_conversion_clock::base_minute,
+ tm_conversion_clock::base_second,
+ tm_conversion_clock::period>(tp);
return internal_to_tm(normalized_tp.time_since_epoch());
}
@@ -144,14 +145,14 @@ public:
static std::chrono::time_point<std::chrono::system_clock> to_system_clock(const time_point &tp)
{
auto normalized_tp = to_arbitrary_time_point<
- std::int64_t,
- system_conversion_clock::base_year,
- system_conversion_clock::base_month,
- system_conversion_clock::base_day,
- system_conversion_clock::base_hour,
- system_conversion_clock::base_minute,
- system_conversion_clock::base_second,
- system_conversion_clock::period>(tp);
+ std::int64_t,
+ system_conversion_clock::base_year,
+ system_conversion_clock::base_month,
+ system_conversion_clock::base_day,
+ system_conversion_clock::base_hour,
+ system_conversion_clock::base_minute,
+ system_conversion_clock::base_second,
+ system_conversion_clock::period>(tp);
return std::chrono::time_point<std::chrono::system_clock>(normalized_tp.time_since_epoch() + system_clock_adjustment);
}
diff --git a/src/lib/util/un7z.cpp b/src/lib/util/un7z.cpp
index 879da294c69..b35af479d5d 100644
--- a/src/lib/util/un7z.cpp
+++ b/src/lib/util/un7z.cpp
@@ -13,11 +13,13 @@
#include "unzip.h"
#include "corestr.h"
-#include "osdcore.h"
-#include "osdfile.h"
+#include "ioprocs.h"
#include "unicode.h"
#include "timeconv.h"
+#include "osdcore.h"
+#include "osdfile.h"
+
#include "lzma/C/7z.h"
#include "lzma/C/7zAlloc.h"
#include "lzma/C/7zCrc.h"
@@ -38,47 +40,71 @@
namespace util {
+
namespace {
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
-struct CSzFile
+struct CFileInStream : public ISeekInStream
{
- CSzFile() : currfpos(0), length(0), osdfile() {}
+ CFileInStream() noexcept
+ {
+ Read = [] (void *pp, void *buf, size_t *size) { return reinterpret_cast<CFileInStream *>(pp)->read(buf, *size); };
+ Seek = [] (void *pp, Int64 *pos, ESzSeek origin) { return reinterpret_cast<CFileInStream *>(pp)->seek(*pos, origin); };
+ }
- std::uint64_t currfpos;
- std::uint64_t length;
- osd_file::ptr osdfile;
+ random_read::ptr file;
+ std::uint64_t currfpos = 0;
+ std::uint64_t length = 0;
- SRes read(void *data, std::size_t &size)
+private:
+ SRes read(void *data, std::size_t &size) noexcept
{
- if (!osdfile)
+ if (!file)
{
- osd_printf_error("un7z: called CSzFile::read without file\n");
+ osd_printf_error("un7z: called CFileInStream::read without file\n");
return SZ_ERROR_READ;
}
if (!size)
return SZ_OK;
- // TODO: this casts a size_t to a uint32_t, so it will fail if >=4GB is requested at once (need a loop)
- std::uint32_t read_length(0);
- auto const err = osdfile->read(data, currfpos, size, read_length);
+ std::size_t read_length(0);
+ std::error_condition const err = file->read_at(currfpos, data, size, read_length);
size = read_length;
currfpos += read_length;
- return (osd_file::error::NONE == err) ? SZ_OK : SZ_ERROR_READ;
+ return !err ? SZ_OK : SZ_ERROR_READ;
}
- SRes seek(Int64 &pos, ESzSeek origin)
+ SRes seek(Int64 &pos, ESzSeek origin) noexcept
{
+ // need to synthesise this because the OSD file wrapper doesn't implement SEEK_END
switch (origin)
{
- case SZ_SEEK_CUR: currfpos += pos; break;
- case SZ_SEEK_SET: currfpos = pos; break;
- case SZ_SEEK_END: currfpos = length + pos; break;
- default: return SZ_ERROR_READ;
+ case SZ_SEEK_CUR:
+ if ((0 > pos) && (-pos > currfpos))
+ {
+ osd_printf_error("un7z: attemped to seek back %d bytes when current offset is %u\n", -pos, currfpos);
+ return SZ_ERROR_READ;
+ }
+ currfpos += pos;
+ break;
+ case SZ_SEEK_SET:
+ currfpos = pos;
+ break;
+ case SZ_SEEK_END:
+ if ((0 > pos) && (-pos > length))
+ {
+ osd_printf_error("un7z: attemped to seek %d bytes before end of file %u\n", -pos, currfpos);
+ return SZ_ERROR_READ;
+ }
+ currfpos = length + pos;
+ break;
+ default:
+ return SZ_ERROR_READ;
}
pos = currfpos;
return SZ_OK;
@@ -86,18 +112,18 @@ struct CSzFile
};
-struct CFileInStream : public ISeekInStream, public CSzFile
-{
- CFileInStream();
-};
-
-
-class m7z_file_impl
+class m7z_file_impl
{
public:
typedef std::unique_ptr<m7z_file_impl> ptr;
- m7z_file_impl(const std::string &filename);
+ m7z_file_impl(std::string &&filename) noexcept;
+
+ m7z_file_impl(random_read::ptr &&file) noexcept
+ : m7z_file_impl(std::string())
+ {
+ m_archive_stream.file = std::move(file);
+ }
virtual ~m7z_file_impl()
{
@@ -107,7 +133,7 @@ public:
SzArEx_Free(&m_db, &m_alloc_imp);
}
- static ptr find_cached(const std::string &filename)
+ static ptr find_cached(std::string_view filename) noexcept
{
std::lock_guard<std::mutex> guard(s_cache_mutex);
for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++)
@@ -115,47 +141,60 @@ public:
// if we have a valid entry and it matches our filename, use it and remove from the cache
if (s_cache[cachenum] && (filename == s_cache[cachenum]->m_filename))
{
+ using std::swap;
ptr result;
- std::swap(s_cache[cachenum], result);
+ swap(s_cache[cachenum], result);
osd_printf_verbose("un7z: found %s in cache\n", filename);
return result;
}
}
return ptr();
}
- static void close(ptr &&archive);
- static void cache_clear()
+
+ static void close(ptr &&archive) noexcept;
+
+ static void cache_clear() noexcept
{
// clear call cache entries
std::lock_guard<std::mutex> guard(s_cache_mutex);
- for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { }
+ for (auto &cached : s_cache)
+ cached.reset();
}
- archive_file::error initialize();
+ std::error_condition initialize() noexcept;
- int first_file() { return search(0, 0, std::string(), false, false, false); }
- int next_file() { return (m_curr_file_idx < 0) ? -1 : search(m_curr_file_idx + 1, 0, std::string(), false, false, false); }
+ int first_file() noexcept
+ {
+ return search(0, 0, std::string_view(), false, false, false);
+ }
- int search(std::uint32_t crc)
+ int next_file() noexcept
{
- return search(0, crc, std::string(), true, false, false);
+ return (m_curr_file_idx < 0) ? -1 : search(m_curr_file_idx + 1, 0, std::string_view(), false, false, false);
}
- int search(const std::string &filename, bool partialpath)
+
+ int search(std::uint32_t crc) noexcept
+ {
+ return search(0, crc, std::string_view(), true, false, false);
+ }
+
+ int search(std::string_view filename, bool partialpath) noexcept
{
return search(0, 0, filename, false, true, partialpath);
}
- int search(std::uint32_t crc, const std::string &filename, bool partialpath)
+
+ int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept
{
return search(0, crc, filename, true, true, partialpath);
}
- bool current_is_directory() const { return m_curr_is_dir; }
- const std::string &current_name() const { return m_curr_name; }
- std::uint64_t current_uncompressed_length() const { return m_curr_length; }
- virtual std::chrono::system_clock::time_point current_last_modified() const { return m_curr_modified; }
- std::uint32_t current_crc() const { return m_curr_crc; }
+ bool current_is_directory() const noexcept { return m_curr_is_dir; }
+ const std::string &current_name() const noexcept { return m_curr_name; }
+ std::uint64_t current_uncompressed_length() const noexcept { return m_curr_length; }
+ virtual std::chrono::system_clock::time_point current_last_modified() const noexcept { return m_curr_modified; }
+ std::uint32_t current_crc() const noexcept { return m_curr_crc; }
- archive_file::error decompress(void *buffer, std::uint32_t length);
+ std::error_condition decompress(void *buffer, std::size_t length) noexcept;
private:
m7z_file_impl(const m7z_file_impl &) = delete;
@@ -166,12 +205,12 @@ private:
int search(
int i,
std::uint32_t search_crc,
- const std::string &search_filename,
+ std::string_view search_filename,
bool matchcrc,
bool matchname,
- bool partialpath);
+ bool partialpath) noexcept;
void make_utf8_name(int index);
- void set_curr_modified();
+ void set_curr_modified() noexcept;
static constexpr std::size_t CACHE_SIZE = 8;
static std::array<ptr, CACHE_SIZE> s_cache;
@@ -187,7 +226,7 @@ private:
std::uint32_t m_curr_crc; // current file crc
std::vector<UInt16> m_utf16_buf;
- std::vector<char32_t> m_uchar_buf;
+ std::vector<char32_t> m_uchar_buf;
std::vector<char> m_utf8_buf;
CFileInStream m_archive_stream;
@@ -201,39 +240,38 @@ private:
UInt32 m_block_index;
Byte * m_out_buffer;
std::size_t m_out_buffer_size;
-
};
class m7z_file_wrapper : public archive_file
{
public:
- m7z_file_wrapper(m7z_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); }
+ m7z_file_wrapper(m7z_file_impl::ptr &&impl) noexcept : m_impl(std::move(impl)) { assert(m_impl); }
virtual ~m7z_file_wrapper() override { m7z_file_impl::close(std::move(m_impl)); }
- virtual int first_file() override { return m_impl->first_file(); }
- virtual int next_file() override { return m_impl->next_file(); }
+ virtual int first_file() noexcept override { return m_impl->first_file(); }
+ virtual int next_file() noexcept override { return m_impl->next_file(); }
- virtual int search(std::uint32_t crc) override
+ virtual int search(std::uint32_t crc) noexcept override
{
return m_impl->search(crc);
}
- virtual int search(const std::string &filename, bool partialpath) override
+ virtual int search(std::string_view filename, bool partialpath) noexcept override
{
return m_impl->search(filename, partialpath);
}
- virtual int search(std::uint32_t crc, const std::string &filename, bool partialpath) override
+ virtual int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept override
{
return m_impl->search(crc, filename, partialpath);
}
- virtual bool current_is_directory() const override { return m_impl->current_is_directory(); }
- virtual const std::string &current_name() const override { return m_impl->current_name(); }
- virtual std::uint64_t current_uncompressed_length() const override { return m_impl->current_uncompressed_length(); }
- virtual std::chrono::system_clock::time_point current_last_modified() const override { return m_impl->current_last_modified(); }
- virtual std::uint32_t current_crc() const override { return m_impl->current_crc(); }
+ virtual bool current_is_directory() const noexcept override { return m_impl->current_is_directory(); }
+ virtual const std::string &current_name() const noexcept override { return m_impl->current_name(); }
+ virtual std::uint64_t current_uncompressed_length() const noexcept override { return m_impl->current_uncompressed_length(); }
+ virtual std::chrono::system_clock::time_point current_last_modified() const noexcept override { return m_impl->current_last_modified(); }
+ virtual std::uint32_t current_crc() const noexcept override { return m_impl->current_crc(); }
- virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); }
+ virtual std::error_condition decompress(void *buffer, std::size_t length) noexcept override { return m_impl->decompress(buffer, length); }
private:
m7z_file_impl::ptr m_impl;
@@ -251,48 +289,20 @@ std::mutex m7z_file_impl::s_cache_mutex;
/***************************************************************************
- 7Zip Memory / File handling (adapted from 7zfile.c/.h and 7zalloc.c/.h)
-***************************************************************************/
-
-/* ---------- FileInStream ---------- */
-
-extern "C" {
-static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
-{
- return (reinterpret_cast<CFileInStream *>(pp)->read(buf, *size) == 0) ? SZ_OK : SZ_ERROR_READ;
-}
-
-static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
-{
- return reinterpret_cast<CFileInStream *>(pp)->seek(*pos, origin);
-}
-
-} // extern "C"
-
-
-CFileInStream::CFileInStream()
-{
- Read = &FileInStream_Read;
- Seek = &FileInStream_Seek;
-}
-
-
-
-/***************************************************************************
CACHE MANAGEMENT
***************************************************************************/
-m7z_file_impl::m7z_file_impl(const std::string &filename)
- : m_filename(filename)
+m7z_file_impl::m7z_file_impl(std::string &&filename) noexcept
+ : m_filename(std::move(filename))
, m_curr_file_idx(-1)
, m_curr_is_dir(false)
, m_curr_name()
, m_curr_length(0)
, m_curr_modified()
, m_curr_crc(0)
- , m_utf16_buf(128)
- , m_uchar_buf(128)
- , m_utf8_buf(512)
+ , m_utf16_buf()
+ , m_uchar_buf()
+ , m_utf8_buf()
, m_inited(false)
, m_block_index(0)
, m_out_buffer(nullptr)
@@ -310,15 +320,45 @@ m7z_file_impl::m7z_file_impl(const std::string &filename)
}
-archive_file::error m7z_file_impl::initialize()
+std::error_condition m7z_file_impl::initialize() noexcept
{
- osd_file::error const err = osd_file::open(m_filename, OPEN_FLAG_READ, m_archive_stream.osdfile, m_archive_stream.length);
- if (err != osd_file::error::NONE)
- return archive_file::error::FILE_ERROR;
+ try
+ {
+ if (m_utf16_buf.size() < 128)
+ m_utf16_buf.resize(128);
+ if (m_uchar_buf.size() < 128)
+ m_uchar_buf.resize(128);
+ m_utf8_buf.reserve(512);
+ }
+ catch (...)
+ {
+ return std::errc::not_enough_memory;
+ }
- osd_printf_verbose("un7z: opened archive file %s\n", m_filename);
+ if (!m_archive_stream.file)
+ {
+ osd_file::ptr file;
+ std::error_condition const err = osd_file::open(m_filename, OPEN_FLAG_READ, file, m_archive_stream.length);
+ if (err)
+ return err;
+ m_archive_stream.file = osd_file_read(std::move(file));
+ osd_printf_verbose("un7z: opened archive file %s\n", m_filename);
+ }
+ else if (!m_archive_stream.length)
+ {
+ std::error_condition const err = m_archive_stream.file->length(m_archive_stream.length);
+ if (err)
+ {
+ osd_printf_verbose(
+ "un7z: error getting length of archive file %s (%s:%d %s)\n",
+ m_filename, err.category().name(), err.value(), err.message());
+ return err;
+ }
+ }
- CrcGenerateTable(); // FIXME: doesn't belong here - it should be called once statically
+ // TODO: coordinate this with other LZMA users in the codebase?
+ struct crc_table_generator { crc_table_generator() { CrcGenerateTable(); } };
+ static crc_table_generator crc_table;
SzArEx_Init(&m_db);
m_inited = true;
@@ -329,13 +369,13 @@ archive_file::error m7z_file_impl::initialize()
switch (res)
{
case SZ_ERROR_UNSUPPORTED: return archive_file::error::UNSUPPORTED;
- case SZ_ERROR_MEM: return archive_file::error::OUT_OF_MEMORY;
+ case SZ_ERROR_MEM: return std::errc::not_enough_memory;
case SZ_ERROR_INPUT_EOF: return archive_file::error::FILE_TRUNCATED;
- default: return archive_file::error::FILE_ERROR;
+ default: return std::errc::io_error; // TODO: better default error?
}
}
- return archive_file::error::NONE;
+ return std::error_condition();
}
@@ -344,33 +384,38 @@ archive_file::error m7z_file_impl::initialize()
to the cache
-------------------------------------------------*/
-void m7z_file_impl::close(ptr &&archive)
+void m7z_file_impl::close(ptr &&archive) noexcept
{
- if (!archive) return;
+ // if the filename isn't empty, the implementation can be cached
+ if (archive && !archive->m_filename.empty())
+ {
+ // close the open files
+ osd_printf_verbose("un7z: closing archive file %s and sending to cache\n", archive->m_filename);
+ archive->m_archive_stream.file.reset();
- // close the open files
- osd_printf_verbose("un7z: closing archive file %s and sending to cache\n", archive->m_filename);
- archive->m_archive_stream.osdfile.reset();
+ // find the first nullptr entry in the cache
+ std::lock_guard<std::mutex> guard(s_cache_mutex);
+ std::size_t cachenum;
+ for (cachenum = 0; cachenum < s_cache.size(); cachenum++)
+ if (!s_cache[cachenum])
+ break;
- // find the first nullptr entry in the cache
- std::lock_guard<std::mutex> guard(s_cache_mutex);
- std::size_t cachenum;
- for (cachenum = 0; cachenum < s_cache.size(); cachenum++)
- if (!s_cache[cachenum])
- break;
+ // if no room left in the cache, free the bottommost entry
+ if (cachenum == s_cache.size())
+ {
+ cachenum--;
+ osd_printf_verbose("un7z: removing %s from cache to make space\n", s_cache[cachenum]->m_filename);
+ s_cache[cachenum].reset();
+ }
- // if no room left in the cache, free the bottommost entry
- if (cachenum == s_cache.size())
- {
- cachenum--;
- osd_printf_verbose("un7z: removing %s from cache to make space\n", s_cache[cachenum]->m_filename);
- s_cache[cachenum].reset();
+ // move everyone else down and place us at the top
+ for ( ; cachenum > 0; cachenum--)
+ s_cache[cachenum] = std::move(s_cache[cachenum - 1]);
+ s_cache[0] = std::move(archive);
}
- // move everyone else down and place us at the top
- for ( ; cachenum > 0; cachenum--)
- s_cache[cachenum] = std::move(s_cache[cachenum - 1]);
- s_cache[0] = std::move(archive);
+ // make sure it's cleaned up
+ archive.reset();
}
@@ -384,7 +429,7 @@ void m7z_file_impl::close(ptr &&archive)
from a _7Z into the target buffer
-------------------------------------------------*/
-archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length)
+std::error_condition m7z_file_impl::decompress(void *buffer, std::size_t length) noexcept
{
// if we don't have enough buffer, error
if (length < m_curr_length)
@@ -394,15 +439,19 @@ archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length
}
// make sure the file is open..
- if (!m_archive_stream.osdfile)
+ if (!m_archive_stream.file)
{
- m_archive_stream.currfpos = 0;
- osd_file::error const err = osd_file::open(m_filename, OPEN_FLAG_READ, m_archive_stream.osdfile, m_archive_stream.length);
- if (err != osd_file::error::NONE)
+ m_archive_stream.currfpos = 0; // FIXME: should it really be changing the file pointer out from under LZMA?
+ osd_file::ptr file;
+ std::error_condition const err = osd_file::open(m_filename, OPEN_FLAG_READ, file, m_archive_stream.length);
+ if (err)
{
- osd_printf_error("un7z: error reopening archive file %s (%d)\n", m_filename, int(err));
- return archive_file::error::FILE_ERROR;
+ osd_printf_error(
+ "un7z: error reopening archive file %s (%s:%d %s)\n",
+ m_filename, err.category().name(), err.value(), err.message());
+ return err;
}
+ m_archive_stream.file = osd_file_read(std::move(file));
osd_printf_verbose("un7z: reopened archive file %s\n", m_filename);
}
@@ -419,7 +468,7 @@ archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length
switch (res)
{
case SZ_ERROR_UNSUPPORTED: return archive_file::error::UNSUPPORTED;
- case SZ_ERROR_MEM: return archive_file::error::OUT_OF_MEMORY;
+ case SZ_ERROR_MEM: return std::errc::not_enough_memory;
case SZ_ERROR_INPUT_EOF: return archive_file::error::FILE_TRUNCATED;
default: return archive_file::error::DECOMPRESS_ERROR;
}
@@ -427,45 +476,64 @@ archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length
// copy to destination buffer
std::memcpy(buffer, m_out_buffer + offset, (std::min<std::size_t>)(length, out_size_processed));
- return archive_file::error::NONE;
+ return std::error_condition();
}
int m7z_file_impl::search(
int i,
std::uint32_t search_crc,
- const std::string &search_filename,
+ std::string_view search_filename,
bool matchcrc,
bool matchname,
- bool partialpath)
+ bool partialpath) noexcept
{
- for ( ; i < m_db.NumFiles; i++)
- {
- make_utf8_name(i);
- bool const is_dir(SzArEx_IsDir(&m_db, i));
- const std::uint64_t size(SzArEx_GetFileSize(&m_db, i));
- const std::uint32_t crc(m_db.CRCs.Vals[i]);
- const bool crcmatch(SzBitArray_Check(m_db.CRCs.Defs, i) && (crc == search_crc));
- auto const partialoffset(m_utf8_buf.size() - 1 - search_filename.length());
- bool const partialpossible((m_utf8_buf.size() > (search_filename.length() + 1)) && (m_utf8_buf[partialoffset - 1] == '/'));
- const bool namematch(
- !core_stricmp(search_filename.c_str(), &m_utf8_buf[0]) ||
- (partialpath && partialpossible && !core_stricmp(search_filename.c_str(), &m_utf8_buf[partialoffset])));
-
- const bool found = ((!matchcrc && !matchname) || !is_dir) && (!matchcrc || crcmatch) && (!matchname || namematch);
- if (found)
+ try
+ {
+ for ( ; i < m_db.NumFiles; i++)
{
- m_curr_file_idx = i;
- m_curr_is_dir = is_dir;
- m_curr_name = &m_utf8_buf[0];
- m_curr_length = size;
- set_curr_modified();
- m_curr_crc = crc;
-
- return i;
+ make_utf8_name(i);
+ bool const is_dir(SzArEx_IsDir(&m_db, i));
+ const std::uint64_t size(SzArEx_GetFileSize(&m_db, i));
+ const std::uint32_t crc(m_db.CRCs.Vals[i]);
+
+ const bool crcmatch(SzBitArray_Check(m_db.CRCs.Defs, i) && (crc == search_crc));
+ bool found;
+ if (!matchname)
+ {
+ found = !matchcrc || (crcmatch && !is_dir);
+ }
+ else
+ {
+ auto const partialoffset = m_utf8_buf.size() - search_filename.length();
+ const bool namematch =
+ (search_filename.length() == m_utf8_buf.size()) &&
+ (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_utf8_buf[0], search_filename.length()));
+ bool const partialmatch =
+ partialpath &&
+ ((m_utf8_buf.size() > search_filename.length()) && (m_utf8_buf[partialoffset - 1] == '/')) &&
+ (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_utf8_buf[partialoffset], search_filename.length()));
+ found = (!matchcrc || crcmatch) && (namematch || partialmatch);
+ }
+
+ if (found)
+ {
+ // set the name first - resizing it can throw an exception, and we want the state to be consistent
+ m_curr_name.assign(m_utf8_buf.begin(), m_utf8_buf.end());
+ m_curr_file_idx = i;
+ m_curr_is_dir = is_dir;
+ m_curr_length = size;
+ set_curr_modified();
+ m_curr_crc = crc;
+
+ return i;
+ }
}
}
-
+ catch (...)
+ {
+ // allocation error handling name
+ }
return -1;
}
@@ -475,14 +543,14 @@ void m7z_file_impl::make_utf8_name(int index)
std::size_t len, out_pos;
len = SzArEx_GetFileNameUtf16(&m_db, index, nullptr);
- m_utf16_buf.resize((std::max<std::size_t>)(m_utf16_buf.size(), len));
+ m_utf16_buf.resize(std::max<std::size_t>(m_utf16_buf.size(), len));
SzArEx_GetFileNameUtf16(&m_db, index, &m_utf16_buf[0]);
- m_uchar_buf.resize((std::max<std::size_t>)(m_uchar_buf.size(), len));
+ m_uchar_buf.resize(std::max<std::size_t>(m_uchar_buf.size(), len));
out_pos = 0;
for (std::size_t in_pos = 0; in_pos < (len - 1); )
{
- const int used = uchar_from_utf16(&m_uchar_buf[out_pos], (char16_t *)&m_utf16_buf[in_pos], len - in_pos);
+ const int used = uchar_from_utf16(&m_uchar_buf[out_pos], reinterpret_cast<char16_t const *>(&m_utf16_buf[in_pos]), len - in_pos);
if (used < 0)
{
in_pos++;
@@ -497,7 +565,7 @@ void m7z_file_impl::make_utf8_name(int index)
}
len = out_pos;
- m_utf8_buf.resize((std::max<std::size_t>)(m_utf8_buf.size(), 4 * len + 1));
+ m_utf8_buf.resize((std::max<std::size_t>)(m_utf8_buf.size(), 4 * len));
out_pos = 0;
for (std::size_t in_pos = 0; in_pos < len; in_pos++)
{
@@ -508,30 +576,35 @@ void m7z_file_impl::make_utf8_name(int index)
out_pos += produced;
assert(out_pos < m_utf8_buf.size());
}
- m_utf8_buf[out_pos++] = '\0';
m_utf8_buf.resize(out_pos);
}
-void m7z_file_impl::set_curr_modified()
+void m7z_file_impl::set_curr_modified() noexcept
{
if (SzBitWithVals_Check(&m_db.MTime, m_curr_file_idx))
{
CNtfsFileTime const &file_time(m_db.MTime.Vals[m_curr_file_idx]);
- auto ticks = ntfs_duration_from_filetime(file_time.High, file_time.Low);
- m_curr_modified = system_clock_time_point_from_ntfs_duration(ticks);
- }
- else
- {
- // FIXME: what do we do about a lack of time?
+ try
+ {
+ auto ticks = ntfs_duration_from_filetime(file_time.High, file_time.Low);
+ m_curr_modified = system_clock_time_point_from_ntfs_duration(ticks);
+ return;
+ }
+ catch (...)
+ {
+ }
}
+
+ // no modification time available, or out-of-range exception
+ m_curr_modified = std::chrono::system_clock::from_time_t(std::time_t(0));
}
} // anonymous namespace
-archive_file::error archive_file::open_7z(const std::string &filename, ptr &result)
+std::error_condition archive_file::open_7z(std::string_view filename, ptr &result) noexcept
{
// ensure we start with a nullptr result
result.reset();
@@ -542,21 +615,49 @@ archive_file::error archive_file::open_7z(const std::string &filename, ptr &resu
if (!newimpl)
{
// allocate memory for the 7z file structure
- try { newimpl = std::make_unique<m7z_file_impl>(filename); }
- catch (...) { return error::OUT_OF_MEMORY; }
- error const err = newimpl->initialize();
- if (err != error::NONE) return err;
+ try { newimpl = std::make_unique<m7z_file_impl>(std::string(filename)); }
+ catch (...) { return std::errc::not_enough_memory; }
+ auto const err = newimpl->initialize();
+ if (err)
+ return err;
}
- try
+ // allocate the archive API wrapper
+ result.reset(new (std::nothrow) m7z_file_wrapper(std::move(newimpl)));
+ if (result)
{
- result = std::make_unique<m7z_file_wrapper>(std::move(newimpl));
- return error::NONE;
+ return std::error_condition();
}
- catch (...)
+ else
+ {
+ m7z_file_impl::close(std::move(newimpl));
+ return std::errc::not_enough_memory;
+ }
+}
+
+std::error_condition archive_file::open_7z(random_read::ptr &&file, ptr &result) noexcept
+{
+ // ensure we start with a nullptr result
+ result.reset();
+
+ // allocate memory for the zip_file structure
+ m7z_file_impl::ptr newimpl(new (std::nothrow) m7z_file_impl(std::move(file)));
+ if (!newimpl)
+ return std::errc::not_enough_memory;
+ auto const err = newimpl->initialize();
+ if (err)
+ return err;
+
+ // allocate the archive API wrapper
+ result.reset(new (std::nothrow) m7z_file_wrapper(std::move(newimpl)));
+ if (result)
+ {
+ return std::error_condition();
+ }
+ else
{
m7z_file_impl::close(std::move(newimpl));
- return error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -566,7 +667,7 @@ archive_file::error archive_file::open_7z(const std::string &filename, ptr &resu
cache and free all memory
-------------------------------------------------*/
-void m7z_file_cache_clear()
+void m7z_file_cache_clear() noexcept
{
// This is a trampoline called from unzip.cpp to avoid the need to have the zip and 7zip code in one file
m7z_file_impl::cache_clear();
diff --git a/src/lib/util/unzip.cpp b/src/lib/util/unzip.cpp
index a275cc7df06..d7df8fa5ce9 100644
--- a/src/lib/util/unzip.cpp
+++ b/src/lib/util/unzip.cpp
@@ -12,9 +12,11 @@
#include "corestr.h"
#include "hashing.h"
+#include "ioprocs.h"
+#include "timeconv.h"
+
#include "osdcore.h"
#include "osdfile.h"
-#include "timeconv.h"
#include "lzma/C/LzmaDec.h"
@@ -23,6 +25,7 @@
#include <algorithm>
#include <array>
#include <cassert>
+#include <cerrno>
#include <chrono>
#include <cstring>
#include <cstdlib>
@@ -34,31 +37,55 @@
namespace util {
+
namespace {
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
+class archive_category_impl : public std::error_category
+{
+public:
+ virtual char const *name() const noexcept override { return "archive"; }
+
+ virtual std::string message(int condition) const override
+ {
+ using namespace std::literals;
+ static std::string_view const s_messages[] = {
+ "No error"sv,
+ "Bad archive signature"sv,
+ "Decompression error"sv,
+ "Archive file truncated"sv,
+ "Archive file corrupt"sv,
+ "Archive file uses unsupported features"sv,
+ "Buffer too small for data"sv };
+ if ((0 <= condition) && (std::size(s_messages) > condition))
+ return std::string(s_messages[condition]);
+ else
+ return "Unknown error"s;
+ }
+};
+
+
class zip_file_impl
{
public:
- typedef std::unique_ptr<zip_file_impl> ptr;
-
- zip_file_impl(const std::string &filename)
- : m_filename(filename)
- , m_file()
- , m_length(0)
- , m_ecd()
- , m_cd()
- , m_cd_pos(0)
- , m_header()
- , m_curr_is_dir(false)
- , m_buffer()
+ using ptr = std::unique_ptr<zip_file_impl>;
+
+ zip_file_impl(std::string &&filename) noexcept
+ : m_filename(std::move(filename))
{
std::fill(m_buffer.begin(), m_buffer.end(), 0);
}
- static ptr find_cached(const std::string &filename)
+ zip_file_impl(random_read::ptr &&file) noexcept
+ : zip_file_impl(std::string())
+ {
+ m_file = std::move(file);
+ }
+
+ static ptr find_cached(std::string_view filename) noexcept
{
std::lock_guard<std::mutex> guard(s_cache_mutex);
for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++)
@@ -66,27 +93,31 @@ public:
// if we have a valid entry and it matches our filename, use it and remove from the cache
if (s_cache[cachenum] && (filename == s_cache[cachenum]->m_filename))
{
+ using std::swap;
ptr result;
- std::swap(s_cache[cachenum], result);
+ swap(s_cache[cachenum], result);
osd_printf_verbose("unzip: found %s in cache\n", filename);
return result;
}
}
return ptr();
}
- static void close(ptr &&zip);
- static void cache_clear()
+
+ static void close(ptr &&zip) noexcept;
+
+ static void cache_clear() noexcept
{
// clear call cache entries
std::lock_guard<std::mutex> guard(s_cache_mutex);
- for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { }
+ for (auto &cached : s_cache)
+ cached.reset();
}
- archive_file::error initialize()
+ std::error_condition initialize() noexcept
{
// read ecd data
auto const ziperr = read_ecd();
- if (ziperr != archive_file::error::NONE)
+ if (ziperr)
return ziperr;
// verify that we can work with this zipfile (no disk spanning allowed)
@@ -111,7 +142,7 @@ public:
catch (...)
{
osd_printf_error("unzip: %s failed to allocate memory for central directory\n", m_filename);
- return archive_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
// read the central directory
@@ -119,13 +150,15 @@ public:
std::size_t cd_offs(0);
while (cd_remaining)
{
- std::uint32_t const chunk(std::uint32_t((std::min<std::uint64_t>)(std::numeric_limits<std::uint32_t>::max(), cd_remaining)));
- std::uint32_t read_length(0);
- auto const filerr = m_file->read(&m_cd[cd_offs], m_ecd.cd_start_disk_offset + cd_offs, chunk, read_length);
- if (filerr != osd_file::error::NONE)
+ std::size_t const chunk(std::size_t(std::min<std::uint64_t>(std::numeric_limits<std::size_t>::max(), cd_remaining)));
+ std::size_t read_length(0);
+ std::error_condition const filerr = m_file->read_at(m_ecd.cd_start_disk_offset + cd_offs, &m_cd[cd_offs], chunk, read_length);
+ if (filerr)
{
- osd_printf_error("unzip: %s error reading central directory (%d)\n", m_filename, int(filerr));
- return archive_file::error::FILE_ERROR;
+ osd_printf_error(
+ "unzip: %s error reading central directory (%s:%d %s)\n",
+ m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
if (!read_length)
{
@@ -137,39 +170,45 @@ public:
}
osd_printf_verbose("unzip: read %s central directory\n", m_filename);
- return archive_file::error::NONE;
+ return std::error_condition();
}
- int first_file()
+ int first_file() noexcept
{
m_cd_pos = 0;
- return search(0, std::string(), false, false, false);
+ return search(0, std::string_view(), false, false, false);
}
- int next_file()
+
+ int next_file() noexcept
{
- return search(0, std::string(), false, false, false);
+ return search(0, std::string_view(), false, false, false);
}
- int search(std::uint32_t crc)
+ int search(std::uint32_t crc) noexcept
{
m_cd_pos = 0;
- return search(crc, std::string(), true, false, false);
+ return search(crc, std::string_view(), true, false, false);
}
- int search(const std::string &filename, bool partialpath)
+
+ int search(std::string_view filename, bool partialpath) noexcept
{
m_cd_pos = 0;
return search(0, filename, false, true, partialpath);
}
- int search(std::uint32_t crc, const std::string &filename, bool partialpath)
+
+ int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept
{
m_cd_pos = 0;
return search(crc, filename, true, true, partialpath);
}
- bool current_is_directory() const { return m_curr_is_dir; }
- const std::string &current_name() const { return m_header.file_name; }
- std::uint64_t current_uncompressed_length() const { return m_header.uncompressed_length; }
- std::chrono::system_clock::time_point current_last_modified() const
+ bool current_is_directory() const noexcept { return m_curr_is_dir; }
+
+ const std::string &current_name() const noexcept { return m_header.file_name; }
+
+ std::uint64_t current_uncompressed_length() const noexcept { return m_header.uncompressed_length; }
+
+ std::chrono::system_clock::time_point current_last_modified() const noexcept
{
if (!m_header.modified_cached)
{
@@ -178,9 +217,10 @@ public:
}
return m_header.modified;
}
- std::uint32_t current_crc() const { return m_header.crc; }
- archive_file::error decompress(void *buffer, std::uint32_t length);
+ std::uint32_t current_crc() const noexcept { return m_header.crc; }
+
+ std::error_condition decompress(void *buffer, std::size_t length) noexcept;
private:
zip_file_impl(const zip_file_impl &) = delete;
@@ -188,28 +228,43 @@ private:
zip_file_impl &operator=(const zip_file_impl &) = delete;
zip_file_impl &operator=(zip_file_impl &&) = delete;
- int search(std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname, bool partialpath);
+ int search(std::uint32_t search_crc, std::string_view search_filename, bool matchcrc, bool matchname, bool partialpath) noexcept;
- archive_file::error reopen()
+ std::error_condition reopen() noexcept
{
if (!m_file)
{
- auto const filerr = osd_file::open(m_filename, OPEN_FLAG_READ, m_file, m_length);
- if (filerr != osd_file::error::NONE)
+ osd_file::ptr file;
+ auto const filerr = osd_file::open(m_filename, OPEN_FLAG_READ, file, m_length);
+ if (filerr)
{
// this would spam every time it looks for a non-existent archive, which is a lot
- //osd_printf_error("unzip: error reopening archive file %s (%d)\n", m_filename, int(filerr));
- return archive_file::error::FILE_ERROR;
+ //osd_printf_error("unzip: error reopening archive file %s (%s:%d %s)\n", m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
- else
+ m_file = osd_file_read(std::move(file));
+ if (!m_file)
{
- osd_printf_verbose("unzip: opened archive file %s\n", m_filename);
+ osd_printf_error("unzip: not enough memory to open archive file %s\n", m_filename);
+ return std::errc::not_enough_memory;
}
+ osd_printf_verbose("unzip: opened archive file %s\n", m_filename);
}
- return archive_file::error::NONE;
+ else if (!m_length)
+ {
+ auto const filerr = m_file->length(m_length);
+ if (filerr)
+ {
+ osd_printf_verbose(
+ "unzip: error getting length of archive file %s (%s:%d %s)\n",
+ m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
+ }
+ }
+ return std::error_condition();
}
- static std::chrono::system_clock::time_point decode_dos_time(std::uint16_t date, std::uint16_t time)
+ static std::chrono::system_clock::time_point decode_dos_time(std::uint16_t date, std::uint16_t time) noexcept
{
// FIXME: work out why this doesn't always work
// negative tm_isdst should automatically determine whether DST is in effect for the date,
@@ -228,16 +283,22 @@ private:
}
// ZIP file parsing
- archive_file::error read_ecd();
- archive_file::error get_compressed_data_offset(std::uint64_t &offset);
+ std::error_condition read_ecd() noexcept;
+ std::error_condition get_compressed_data_offset(std::uint64_t &offset) noexcept;
// decompression interfaces
- archive_file::error decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length);
- archive_file::error decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length);
- archive_file::error decompress_data_type_14(std::uint64_t offset, void *buffer, std::uint32_t length);
+ std::error_condition decompress_data_type_0(std::uint64_t offset, void *buffer, std::size_t length) noexcept;
+ std::error_condition decompress_data_type_8(std::uint64_t offset, void *buffer, std::size_t length) noexcept;
+ std::error_condition decompress_data_type_14(std::uint64_t offset, void *buffer, std::size_t length) noexcept;
struct file_header
{
+ file_header() noexcept { }
+ file_header(file_header const &) = default;
+ file_header(file_header &&) noexcept = default;
+ file_header &operator=(file_header const &) = default;
+ file_header &operator=(file_header &&) noexcept = default;
+
std::uint16_t version_created; // version made by
std::uint16_t version_needed; // version needed to extract
std::uint16_t bit_flag; // general purpose bit flag
@@ -271,15 +332,15 @@ private:
static std::mutex s_cache_mutex;
const std::string m_filename; // copy of ZIP filename (for caching)
- osd_file::ptr m_file; // OSD file handle
- std::uint64_t m_length; // length of zip file
+ random_read::ptr m_file; // file handle
+ std::uint64_t m_length = 0; // length of zip file
ecd m_ecd; // end of central directory
std::vector<std::uint8_t> m_cd; // central directory raw data
- std::uint32_t m_cd_pos; // position in central directory
+ std::uint32_t m_cd_pos = 0; // position in central directory
file_header m_header; // current file header
- bool m_curr_is_dir; // current file is directory
+ bool m_curr_is_dir = false; // current file is directory
std::array<std::uint8_t, DECOMPRESS_BUFSIZE> m_buffer; // buffer for decompression
};
@@ -288,32 +349,32 @@ private:
class zip_file_wrapper : public archive_file
{
public:
- zip_file_wrapper(zip_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); }
+ zip_file_wrapper(zip_file_impl::ptr &&impl) noexcept : m_impl(std::move(impl)) { assert(m_impl); }
virtual ~zip_file_wrapper() { zip_file_impl::close(std::move(m_impl)); }
- virtual int first_file() override { return m_impl->first_file(); }
- virtual int next_file() override { return m_impl->next_file(); }
+ virtual int first_file() noexcept override { return m_impl->first_file(); }
+ virtual int next_file() noexcept override { return m_impl->next_file(); }
- virtual int search(std::uint32_t crc) override
+ virtual int search(std::uint32_t crc) noexcept override
{
return m_impl->search(crc);
}
- virtual int search(const std::string &filename, bool partialpath) override
+ virtual int search(std::string_view filename, bool partialpath) noexcept override
{
return m_impl->search(filename, partialpath);
}
- virtual int search(std::uint32_t crc, const std::string &filename, bool partialpath) override
+ virtual int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept override
{
return m_impl->search(crc, filename, partialpath);
}
- virtual bool current_is_directory() const override { return m_impl->current_is_directory(); }
- virtual const std::string &current_name() const override { return m_impl->current_name(); }
- virtual std::uint64_t current_uncompressed_length() const override { return m_impl->current_uncompressed_length(); }
- virtual std::chrono::system_clock::time_point current_last_modified() const override { return m_impl->current_last_modified(); }
- virtual std::uint32_t current_crc() const override { return m_impl->current_crc(); }
+ virtual bool current_is_directory() const noexcept override { return m_impl->current_is_directory(); }
+ virtual const std::string &current_name() const noexcept override { return m_impl->current_name(); }
+ virtual std::uint64_t current_uncompressed_length() const noexcept override { return m_impl->current_uncompressed_length(); }
+ virtual std::chrono::system_clock::time_point current_last_modified() const noexcept override { return m_impl->current_last_modified(); }
+ virtual std::uint32_t current_crc() const noexcept override { return m_impl->current_crc(); }
- virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); }
+ virtual std::error_condition decompress(void *buffer, std::size_t length) noexcept override { return m_impl->decompress(buffer, length); }
private:
zip_file_impl::ptr m_impl;
@@ -323,19 +384,19 @@ private:
class reader_base
{
protected:
- reader_base(void const *buf) : m_buffer(reinterpret_cast<std::uint8_t const *>(buf)) { }
+ reader_base(void const *buf) noexcept : m_buffer(reinterpret_cast<std::uint8_t const *>(buf)) { }
- std::uint8_t read_byte(std::size_t offs) const
+ std::uint8_t read_byte(std::size_t offs) const noexcept
{
return m_buffer[offs];
}
- std::uint16_t read_word(std::size_t offs) const
+ std::uint16_t read_word(std::size_t offs) const noexcept
{
return
(std::uint16_t(m_buffer[offs + 1]) << 8) |
(std::uint16_t(m_buffer[offs + 0]) << 0);
}
- std::uint32_t read_dword(std::size_t offs) const
+ std::uint32_t read_dword(std::size_t offs) const noexcept
{
return
(std::uint32_t(m_buffer[offs + 3]) << 24) |
@@ -343,7 +404,7 @@ protected:
(std::uint32_t(m_buffer[offs + 1]) << 8) |
(std::uint32_t(m_buffer[offs + 0]) << 0);
}
- std::uint64_t read_qword(std::size_t offs) const
+ std::uint64_t read_qword(std::size_t offs) const noexcept
{
return
(std::uint64_t(m_buffer[offs + 7]) << 56) |
@@ -371,17 +432,17 @@ protected:
class extra_field_reader : private reader_base
{
public:
- extra_field_reader(void const *buf, std::size_t len) : reader_base(buf), m_length(len) { }
+ extra_field_reader(void const *buf, std::size_t len) noexcept : reader_base(buf), m_length(len) { }
- std::uint16_t header_id() const { return read_word(0x00); }
- std::uint16_t data_size() const { return read_word(0x02); }
- void const * data() const { return m_buffer + 0x04; }
- extra_field_reader next() const { return extra_field_reader(m_buffer + total_length(), m_length - total_length()); }
+ std::uint16_t header_id() const noexcept { return read_word(0x00); }
+ std::uint16_t data_size() const noexcept { return read_word(0x02); }
+ void const * data() const noexcept { return m_buffer + 0x04; }
+ extra_field_reader next() const noexcept { return extra_field_reader(m_buffer + total_length(), m_length - total_length()); }
- bool length_sufficient() const { return (m_length >= minimum_length()) && (m_length >= total_length()); }
+ bool length_sufficient() const noexcept { return (m_length >= minimum_length()) && (m_length >= total_length()); }
- std::size_t total_length() const { return minimum_length() + data_size(); }
- static std::size_t minimum_length() { return 0x04; }
+ std::size_t total_length() const noexcept { return minimum_length() + data_size(); }
+ static constexpr std::size_t minimum_length() { return 0x04; }
private:
std::size_t m_length;
@@ -391,131 +452,131 @@ private:
class local_file_header_reader : private reader_base
{
public:
- local_file_header_reader(void const *buf) : reader_base(buf) { }
-
- std::uint32_t signature() const { return read_dword(0x00); }
- std::uint8_t version_needed() const { return m_buffer[0x04]; }
- std::uint8_t os_needed() const { return m_buffer[0x05]; }
- std::uint16_t general_flag() const { return read_word(0x06); }
- std::uint16_t compression_method() const { return read_word(0x08); }
- std::uint16_t modified_time() const { return read_word(0x0a); }
- std::uint16_t modified_date() const { return read_word(0x0c); }
- std::uint32_t crc32() const { return read_dword(0x0e); }
- std::uint32_t compressed_size() const { return read_dword(0x12); }
- std::uint32_t uncompressed_size() const { return read_dword(0x16); }
- std::uint16_t file_name_length() const { return read_word(0x1a); }
- std::uint16_t extra_field_length() const { return read_word(0x1c); }
+ local_file_header_reader(void const *buf) noexcept : reader_base(buf) { }
+
+ std::uint32_t signature() const noexcept { return read_dword(0x00); }
+ std::uint8_t version_needed() const noexcept { return m_buffer[0x04]; }
+ std::uint8_t os_needed() const noexcept { return m_buffer[0x05]; }
+ std::uint16_t general_flag() const noexcept { return read_word(0x06); }
+ std::uint16_t compression_method() const noexcept { return read_word(0x08); }
+ std::uint16_t modified_time() const noexcept { return read_word(0x0a); }
+ std::uint16_t modified_date() const noexcept { return read_word(0x0c); }
+ std::uint32_t crc32() const noexcept { return read_dword(0x0e); }
+ std::uint32_t compressed_size() const noexcept { return read_dword(0x12); }
+ std::uint32_t uncompressed_size() const noexcept { return read_dword(0x16); }
+ std::uint16_t file_name_length() const noexcept { return read_word(0x1a); }
+ std::uint16_t extra_field_length() const noexcept { return read_word(0x1c); }
std::string file_name() const { return read_string(0x1e, file_name_length()); }
void file_name(std::string &result) const { read_string(result, 0x1e, file_name_length()); }
- extra_field_reader extra_field() const { return extra_field_reader(m_buffer + 0x1e + file_name_length(), extra_field_length()); }
+ extra_field_reader extra_field() const noexcept { return extra_field_reader(m_buffer + 0x1e + file_name_length(), extra_field_length()); }
- bool signature_correct() const { return signature() == 0x04034b50; }
+ bool signature_correct() const noexcept { return signature() == 0x04034b50; }
- std::size_t total_length() const { return minimum_length() + file_name_length() + extra_field_length(); }
- static std::size_t minimum_length() { return 0x1e; }
+ std::size_t total_length() const noexcept { return minimum_length() + file_name_length() + extra_field_length(); }
+ static constexpr std::size_t minimum_length() { return 0x1e; }
};
class central_dir_entry_reader : private reader_base
{
public:
- central_dir_entry_reader(void const *buf) : reader_base(buf) { }
-
- std::uint32_t signature() const { return read_dword(0x00); }
- std::uint8_t version_created() const { return m_buffer[0x04]; }
- std::uint8_t os_created() const { return m_buffer[0x05]; }
- std::uint8_t version_needed() const { return m_buffer[0x06]; }
- std::uint8_t os_needed() const { return m_buffer[0x07]; }
- std::uint16_t general_flag() const { return read_word(0x08); }
- std::uint16_t compression_method() const { return read_word(0x0a); }
- std::uint16_t modified_time() const { return read_word(0x0c); }
- std::uint16_t modified_date() const { return read_word(0x0e); }
- std::uint32_t crc32() const { return read_dword(0x10); }
- std::uint32_t compressed_size() const { return read_dword(0x14); }
- std::uint32_t uncompressed_size() const { return read_dword(0x18); }
- std::uint16_t file_name_length() const { return read_word(0x1c); }
- std::uint16_t extra_field_length() const { return read_word(0x1e); }
- std::uint16_t file_comment_length() const { return read_word(0x20); }
- std::uint16_t start_disk() const { return read_word(0x22); }
- std::uint16_t int_file_attr() const { return read_word(0x24); }
- std::uint32_t ext_file_attr() const { return read_dword(0x26); }
- std::uint32_t header_offset() const { return read_dword(0x2a); }
+ central_dir_entry_reader(void const *buf) noexcept : reader_base(buf) { }
+
+ std::uint32_t signature() const noexcept { return read_dword(0x00); }
+ std::uint8_t version_created() const noexcept { return m_buffer[0x04]; }
+ std::uint8_t os_created() const noexcept { return m_buffer[0x05]; }
+ std::uint8_t version_needed() const noexcept { return m_buffer[0x06]; }
+ std::uint8_t os_needed() const noexcept { return m_buffer[0x07]; }
+ std::uint16_t general_flag() const noexcept { return read_word(0x08); }
+ std::uint16_t compression_method() const noexcept { return read_word(0x0a); }
+ std::uint16_t modified_time() const noexcept { return read_word(0x0c); }
+ std::uint16_t modified_date() const noexcept { return read_word(0x0e); }
+ std::uint32_t crc32() const noexcept { return read_dword(0x10); }
+ std::uint32_t compressed_size() const noexcept { return read_dword(0x14); }
+ std::uint32_t uncompressed_size() const noexcept { return read_dword(0x18); }
+ std::uint16_t file_name_length() const noexcept { return read_word(0x1c); }
+ std::uint16_t extra_field_length() const noexcept { return read_word(0x1e); }
+ std::uint16_t file_comment_length() const noexcept { return read_word(0x20); }
+ std::uint16_t start_disk() const noexcept { return read_word(0x22); }
+ std::uint16_t int_file_attr() const noexcept { return read_word(0x24); }
+ std::uint32_t ext_file_attr() const noexcept { return read_dword(0x26); }
+ std::uint32_t header_offset() const noexcept { return read_dword(0x2a); }
std::string file_name() const { return read_string(0x2e, file_name_length()); }
void file_name(std::string &result) const { read_string(result, 0x2e, file_name_length()); }
- extra_field_reader extra_field() const { return extra_field_reader(m_buffer + 0x2e + file_name_length(), extra_field_length()); }
+ extra_field_reader extra_field() const noexcept { return extra_field_reader(m_buffer + 0x2e + file_name_length(), extra_field_length()); }
std::string file_comment() const { return read_string(0x2e + file_name_length() + extra_field_length(), file_comment_length()); }
void file_comment(std::string &result) const { read_string(result, 0x2e + file_name_length() + extra_field_length(), file_comment_length()); }
- bool signature_correct() const { return signature() == 0x02014b50; }
+ bool signature_correct() const noexcept { return signature() == 0x02014b50; }
- std::size_t total_length() const { return minimum_length() + file_name_length() + extra_field_length() + file_comment_length(); }
- static std::size_t minimum_length() { return 0x2e; }
+ std::size_t total_length() const noexcept { return minimum_length() + file_name_length() + extra_field_length() + file_comment_length(); }
+ static constexpr std::size_t minimum_length() { return 0x2e; }
};
class ecd64_reader : private reader_base
{
public:
- ecd64_reader(void const *buf) : reader_base(buf) { }
-
- std::uint32_t signature() const { return read_dword(0x00); }
- std::uint64_t ecd64_size() const { return read_qword(0x04); }
- std::uint8_t version_created() const { return m_buffer[0x0c]; }
- std::uint8_t os_created() const { return m_buffer[0x0d]; }
- std::uint8_t version_needed() const { return m_buffer[0x0e]; }
- std::uint8_t os_needed() const { return m_buffer[0x0f]; }
- std::uint32_t this_disk_no() const { return read_dword(0x10); }
- std::uint32_t dir_start_disk() const { return read_dword(0x14); }
- std::uint64_t dir_disk_entries() const { return read_qword(0x18); }
- std::uint64_t dir_total_entries() const { return read_qword(0x20); }
- std::uint64_t dir_size() const { return read_qword(0x28); }
- std::uint64_t dir_offset() const { return read_qword(0x30); }
- void const * extensible_data() const { return m_buffer + 0x38; }
-
- bool signature_correct() const { return signature() == 0x06064b50; }
-
- std::size_t total_length() const { return 0x0c + ecd64_size(); }
- static std::size_t minimum_length() { return 0x38; }
+ ecd64_reader(void const *buf) noexcept : reader_base(buf) { }
+
+ std::uint32_t signature() const noexcept { return read_dword(0x00); }
+ std::uint64_t ecd64_size() const noexcept { return read_qword(0x04); }
+ std::uint8_t version_created() const noexcept { return m_buffer[0x0c]; }
+ std::uint8_t os_created() const noexcept { return m_buffer[0x0d]; }
+ std::uint8_t version_needed() const noexcept { return m_buffer[0x0e]; }
+ std::uint8_t os_needed() const noexcept { return m_buffer[0x0f]; }
+ std::uint32_t this_disk_no() const noexcept { return read_dword(0x10); }
+ std::uint32_t dir_start_disk() const noexcept { return read_dword(0x14); }
+ std::uint64_t dir_disk_entries() const noexcept { return read_qword(0x18); }
+ std::uint64_t dir_total_entries() const noexcept { return read_qword(0x20); }
+ std::uint64_t dir_size() const noexcept { return read_qword(0x28); }
+ std::uint64_t dir_offset() const noexcept { return read_qword(0x30); }
+ void const * extensible_data() const noexcept { return m_buffer + 0x38; }
+
+ bool signature_correct() const noexcept { return signature() == 0x06064b50; }
+
+ std::size_t total_length() const noexcept { return 0x0c + ecd64_size(); }
+ static constexpr std::size_t minimum_length() { return 0x38; }
};
class ecd64_locator_reader : private reader_base
{
public:
- ecd64_locator_reader(void const *buf) : reader_base(buf) { }
+ ecd64_locator_reader(void const *buf) noexcept : reader_base(buf) { }
- std::uint32_t signature() const { return read_dword(0x00); }
- std::uint32_t ecd64_disk() const { return read_dword(0x04); }
- std::uint64_t ecd64_offset() const { return read_qword(0x08); }
- std::uint32_t total_disks() const { return read_dword(0x10); }
+ std::uint32_t signature() const noexcept { return read_dword(0x00); }
+ std::uint32_t ecd64_disk() const noexcept { return read_dword(0x04); }
+ std::uint64_t ecd64_offset() const noexcept { return read_qword(0x08); }
+ std::uint32_t total_disks() const noexcept { return read_dword(0x10); }
- bool signature_correct() const { return signature() == 0x07064b50; }
+ bool signature_correct() const noexcept { return signature() == 0x07064b50; }
- std::size_t total_length() const { return minimum_length(); }
- static std::size_t minimum_length() { return 0x14; }
+ std::size_t total_length() const noexcept { return minimum_length(); }
+ static constexpr std::size_t minimum_length() { return 0x14; }
};
class ecd_reader : private reader_base
{
public:
- ecd_reader(void const *buf) : reader_base(buf) { }
-
- std::uint32_t signature() const { return read_dword(0x00); }
- std::uint16_t this_disk_no() const { return read_word(0x04); }
- std::uint16_t dir_start_disk() const { return read_word(0x06); }
- std::uint16_t dir_disk_entries() const { return read_word(0x08); }
- std::uint16_t dir_total_entries() const { return read_word(0x0a); }
- std::uint32_t dir_size() const { return read_dword(0x0c); }
- std::uint32_t dir_offset() const { return read_dword(0x10); }
- std::uint16_t comment_length() const { return read_word(0x14); }
+ ecd_reader(void const *buf) noexcept : reader_base(buf) { }
+
+ std::uint32_t signature() const noexcept { return read_dword(0x00); }
+ std::uint16_t this_disk_no() const noexcept { return read_word(0x04); }
+ std::uint16_t dir_start_disk() const noexcept { return read_word(0x06); }
+ std::uint16_t dir_disk_entries() const noexcept { return read_word(0x08); }
+ std::uint16_t dir_total_entries() const noexcept { return read_word(0x0a); }
+ std::uint32_t dir_size() const noexcept { return read_dword(0x0c); }
+ std::uint32_t dir_offset() const noexcept { return read_dword(0x10); }
+ std::uint16_t comment_length() const noexcept { return read_word(0x14); }
std::string comment() const { return read_string(0x16, comment_length()); }
void comment(std::string &result) const { read_string(result, 0x16, comment_length()); }
- bool signature_correct() const { return signature() == 0x06054b50; }
+ bool signature_correct() const noexcept { return signature() == 0x06054b50; }
- std::size_t total_length() const { return minimum_length() + comment_length(); }
- static std::size_t minimum_length() { return 0x16; }
+ std::size_t total_length() const noexcept { return minimum_length() + comment_length(); }
+ static constexpr std::size_t minimum_length() { return 0x16; }
};
@@ -525,7 +586,7 @@ public:
template <typename T>
zip64_ext_info_reader(
T const &header,
- extra_field_reader const &field)
+ extra_field_reader const &field) noexcept
: reader_base(field.data())
, m_uncompressed_size(header.uncompressed_size())
, m_compressed_size(header.compressed_size())
@@ -538,13 +599,13 @@ public:
{
}
- std::uint64_t uncompressed_size() const { return ~m_uncompressed_size ? m_uncompressed_size : read_qword(0x00); }
- std::uint64_t compressed_size() const { return ~m_compressed_size ? m_compressed_size : read_qword(m_offs_compressed_size); }
- std::uint64_t header_offset() const { return ~m_header_offset ? m_header_offset : read_qword(m_offs_header_offset); }
- std::uint32_t start_disk() const { return ~m_start_disk ? m_start_disk : read_dword(m_offs_start_disk); }
+ std::uint64_t uncompressed_size() const noexcept { return ~m_uncompressed_size ? m_uncompressed_size : read_qword(0x00); }
+ std::uint64_t compressed_size() const noexcept { return ~m_compressed_size ? m_compressed_size : read_qword(m_offs_compressed_size); }
+ std::uint64_t header_offset() const noexcept { return ~m_header_offset ? m_header_offset : read_qword(m_offs_header_offset); }
+ std::uint32_t start_disk() const noexcept { return ~m_start_disk ? m_start_disk : read_dword(m_offs_start_disk); }
- std::size_t total_length() const { return minimum_length() + m_offs_end; }
- static std::size_t minimum_length() { return 0x00; }
+ std::size_t total_length() const noexcept { return minimum_length() + m_offs_end; }
+ static constexpr std::size_t minimum_length() { return 0x00; }
private:
std::uint32_t m_uncompressed_size;
@@ -562,15 +623,15 @@ private:
class utf8_path_reader : private reader_base
{
public:
- utf8_path_reader(extra_field_reader const &field) : reader_base(field.data()), m_length(field.data_size()) { }
+ utf8_path_reader(extra_field_reader const &field) noexcept : reader_base(field.data()), m_length(field.data_size()) { }
- std::uint8_t version() const { return m_buffer[0]; }
- std::uint32_t name_crc32() const { return read_dword(0x01); }
+ std::uint8_t version() const noexcept { return m_buffer[0]; }
+ std::uint32_t name_crc32() const noexcept { return read_dword(0x01); }
std::string unicode_name() const { return read_string(0x05, m_length - 0x05); }
void unicode_name(std::string &result) const { return read_string(result, 0x05, m_length - 0x05); }
- std::size_t total_length() const { return m_length; }
- static std::size_t minimum_length() { return 0x05; }
+ std::size_t total_length() const noexcept { return m_length; }
+ static constexpr std::size_t minimum_length() { return 0x05; }
private:
std::size_t m_length;
@@ -580,17 +641,17 @@ private:
class ntfs_tag_reader : private reader_base
{
public:
- ntfs_tag_reader(void const *buf, std::size_t len) : reader_base(buf), m_length(len) { }
+ ntfs_tag_reader(void const *buf, std::size_t len) noexcept : reader_base(buf), m_length(len) { }
- std::uint16_t tag() const { return read_word(0x00); }
- std::uint16_t size() const { return read_word(0x02); }
- void const * data() const { return m_buffer + 0x04; }
- ntfs_tag_reader next() const { return ntfs_tag_reader(m_buffer + total_length(), m_length - total_length()); }
+ std::uint16_t tag() const noexcept { return read_word(0x00); }
+ std::uint16_t size() const noexcept { return read_word(0x02); }
+ void const * data() const noexcept { return m_buffer + 0x04; }
+ ntfs_tag_reader next() const noexcept { return ntfs_tag_reader(m_buffer + total_length(), m_length - total_length()); }
- bool length_sufficient() const { return (m_length >= minimum_length()) && (m_length >= total_length()); }
+ bool length_sufficient() const noexcept { return (m_length >= minimum_length()) && (m_length >= total_length()); }
- std::size_t total_length() const { return minimum_length() + size(); }
- static std::size_t minimum_length() { return 0x04; }
+ std::size_t total_length() const noexcept { return minimum_length() + size(); }
+ static constexpr std::size_t minimum_length() { return 0x04; }
private:
std::size_t m_length;
@@ -600,13 +661,13 @@ private:
class ntfs_reader : private reader_base
{
public:
- ntfs_reader(extra_field_reader const &field) : reader_base(field.data()), m_length(field.data_size()) { }
+ ntfs_reader(extra_field_reader const &field) noexcept : reader_base(field.data()), m_length(field.data_size()) { }
- std::uint32_t reserved() const { return read_dword(0x00); }
- ntfs_tag_reader tag1() const { return ntfs_tag_reader(m_buffer + 0x04, m_length - 4); }
+ std::uint32_t reserved() const noexcept { return read_dword(0x00); }
+ ntfs_tag_reader tag1() const noexcept { return ntfs_tag_reader(m_buffer + 0x04, m_length - 4); }
- std::size_t total_length() const { return m_length; }
- static std::size_t minimum_length() { return 0x08; }
+ std::size_t total_length() const noexcept { return m_length; }
+ static constexpr std::size_t minimum_length() { return 0x08; }
private:
std::size_t m_length;
@@ -616,14 +677,14 @@ private:
class ntfs_times_reader : private reader_base
{
public:
- ntfs_times_reader(ntfs_tag_reader const &tag) : reader_base(tag.data()) { }
+ ntfs_times_reader(ntfs_tag_reader const &tag) noexcept : reader_base(tag.data()) { }
- std::uint64_t mtime() const { return read_qword(0x00); }
- std::uint64_t atime() const { return read_qword(0x08); }
- std::uint64_t ctime() const { return read_qword(0x10); }
+ std::uint64_t mtime() const noexcept { return read_qword(0x00); }
+ std::uint64_t atime() const noexcept { return read_qword(0x08); }
+ std::uint64_t ctime() const noexcept { return read_qword(0x10); }
- std::size_t total_length() const { return minimum_length(); }
- static std::size_t minimum_length() { return 0x18; }
+ std::size_t total_length() const noexcept { return minimum_length(); }
+ static constexpr std::size_t minimum_length() { return 0x18; }
};
@@ -632,16 +693,16 @@ class general_flag_reader
public:
general_flag_reader(std::uint16_t val) : m_value(val) { }
- bool encrypted() const { return bool(m_value & 0x0001); }
- bool implode_8k_dict() const { return bool(m_value & 0x0002); }
- bool implode_3_trees() const { return bool(m_value & 0x0004); }
- unsigned deflate_option() const { return unsigned((m_value >> 1) & 0x0003); }
- bool lzma_eos_mark() const { return bool(m_value & 0x0002); }
- bool use_descriptor() const { return bool(m_value & 0x0008); }
- bool patch_data() const { return bool(m_value & 0x0020); }
- bool strong_encryption() const { return bool(m_value & 0x0040); }
- bool utf8_encoding() const { return bool(m_value & 0x0800); }
- bool directory_encryption() const { return bool(m_value & 0x2000); }
+ bool encrypted() const noexcept { return bool(m_value & 0x0001); }
+ bool implode_8k_dict() const noexcept { return bool(m_value & 0x0002); }
+ bool implode_3_trees() const noexcept { return bool(m_value & 0x0004); }
+ unsigned deflate_option() const noexcept { return unsigned((m_value >> 1) & 0x0003); }
+ bool lzma_eos_mark() const noexcept { return bool(m_value & 0x0002); }
+ bool use_descriptor() const noexcept { return bool(m_value & 0x0008); }
+ bool patch_data() const noexcept { return bool(m_value & 0x0020); }
+ bool strong_encryption() const noexcept { return bool(m_value & 0x0040); }
+ bool utf8_encoding() const noexcept { return bool(m_value & 0x0800); }
+ bool directory_encryption() const noexcept { return bool(m_value & 0x2000); }
private:
std::uint16_t m_value;
@@ -653,6 +714,8 @@ private:
GLOBAL VARIABLES
***************************************************************************/
+archive_category_impl const f_archive_category_instance;
+
std::array<zip_file_impl::ptr, zip_file_impl::CACHE_SIZE> zip_file_impl::s_cache;
std::mutex zip_file_impl::s_cache_mutex;
@@ -663,33 +726,38 @@ std::mutex zip_file_impl::s_cache_mutex;
to the cache
-------------------------------------------------*/
-void zip_file_impl::close(ptr &&zip)
+void zip_file_impl::close(ptr &&zip) noexcept
{
- if (!zip) return;
+ // if the filename isn't empty, the cached directory can be reused
+ if (zip && !zip->m_filename.empty())
+ {
+ // close the open files
+ osd_printf_verbose("unzip: closing archive file %s and sending to cache\n", zip->m_filename);
+ zip->m_file.reset();
- // close the open files
- osd_printf_verbose("unzip: closing archive file %s and sending to cache\n", zip->m_filename);
- zip->m_file.reset();
+ // find the first nullptr entry in the cache
+ std::lock_guard<std::mutex> guard(s_cache_mutex);
+ std::size_t cachenum;
+ for (cachenum = 0; cachenum < s_cache.size(); cachenum++)
+ if (!s_cache[cachenum])
+ break;
- // find the first nullptr entry in the cache
- std::lock_guard<std::mutex> guard(s_cache_mutex);
- std::size_t cachenum;
- for (cachenum = 0; cachenum < s_cache.size(); cachenum++)
- if (!s_cache[cachenum])
- break;
+ // if no room left in the cache, free the bottommost entry
+ if (cachenum == s_cache.size())
+ {
+ cachenum--;
+ osd_printf_verbose("unzip: removing %s from cache to make space\n", s_cache[cachenum]->m_filename);
+ s_cache[cachenum].reset();
+ }
- // if no room left in the cache, free the bottommost entry
- if (cachenum == s_cache.size())
- {
- cachenum--;
- osd_printf_verbose("unzip: removing %s from cache to make space\n", s_cache[cachenum]->m_filename);
- s_cache[cachenum].reset();
+ // move everyone else down and place us at the top
+ for ( ; cachenum > 0; cachenum--)
+ s_cache[cachenum] = std::move(s_cache[cachenum - 1]);
+ s_cache[0] = std::move(zip);
}
- // move everyone else down and place us at the top
- for ( ; cachenum > 0; cachenum--)
- s_cache[cachenum] = std::move(s_cache[cachenum - 1]);
- s_cache[0] = std::move(zip);
+ // make sure it's cleaned up
+ zip.reset();
}
@@ -702,7 +770,7 @@ void zip_file_impl::close(ptr &&zip)
entry in the ZIP
-------------------------------------------------*/
-int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname, bool partialpath)
+int zip_file_impl::search(std::uint32_t search_crc, std::string_view search_filename, bool matchcrc, bool matchname, bool partialpath) noexcept
{
// if we're at or past the end, we're done
while ((m_cd_pos + central_dir_entry_reader::minimum_length()) <= m_ecd.cd_size)
@@ -712,98 +780,123 @@ int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_fi
if (!reader.signature_correct() || ((m_cd_pos + reader.total_length()) > m_ecd.cd_size))
break;
- // extract file header info
- m_header.version_created = reader.version_created();
- m_header.version_needed = reader.version_needed();
- m_header.bit_flag = reader.general_flag();
- m_header.compression = reader.compression_method();
- m_header.crc = reader.crc32();
- m_header.compressed_length = reader.compressed_size();
- m_header.uncompressed_length = reader.uncompressed_size();
- m_header.start_disk_number = reader.start_disk();
- m_header.local_header_offset = reader.header_offset();
-
- // don't immediately decode DOS timestamp - it's expensive
- m_header.modified_date = reader.modified_date();
- m_header.modified_time = reader.modified_time();
- m_header.modified_cached = false;
-
- // advance the position
- m_cd_pos += reader.total_length();
-
- // copy the filename
- bool is_utf8(general_flag_reader(m_header.bit_flag).utf8_encoding());
- reader.file_name(m_header.file_name);
-
- // walk the extra data
- for (auto extra = reader.extra_field(); extra.length_sufficient(); extra = extra.next())
+ // setting std::string can raise allocation exceptions
+ try
{
- // look for ZIP64 extended info
- if ((extra.header_id() == 0x0001) && (extra.data_size() >= zip64_ext_info_reader::minimum_length()))
+ // extract file header info
+ file_header header;
+ header.version_created = reader.version_created();
+ header.version_needed = reader.version_needed();
+ header.bit_flag = reader.general_flag();
+ header.compression = reader.compression_method();
+ header.crc = reader.crc32();
+ header.compressed_length = reader.compressed_size();
+ header.uncompressed_length = reader.uncompressed_size();
+ header.start_disk_number = reader.start_disk();
+ header.local_header_offset = reader.header_offset();
+
+ // don't immediately decode DOS timestamp - it's expensive
+ header.modified_date = reader.modified_date();
+ header.modified_time = reader.modified_time();
+ header.modified_cached = false;
+
+ // copy the filename
+ bool is_utf8(general_flag_reader(header.bit_flag).utf8_encoding());
+ reader.file_name(header.file_name);
+
+ // walk the extra data
+ for (auto extra = reader.extra_field(); extra.length_sufficient(); extra = extra.next())
{
- zip64_ext_info_reader const ext64(reader, extra);
- if (extra.data_size() >= ext64.total_length())
+ // look for ZIP64 extended info
+ if ((extra.header_id() == 0x0001) && (extra.data_size() >= zip64_ext_info_reader::minimum_length()))
{
- m_header.compressed_length = ext64.compressed_size();
- m_header.uncompressed_length = ext64.uncompressed_size();
- m_header.start_disk_number = ext64.start_disk();
- m_header.local_header_offset = ext64.header_offset();
+ zip64_ext_info_reader const ext64(reader, extra);
+ if (extra.data_size() >= ext64.total_length())
+ {
+ header.compressed_length = ext64.compressed_size();
+ header.uncompressed_length = ext64.uncompressed_size();
+ header.start_disk_number = ext64.start_disk();
+ header.local_header_offset = ext64.header_offset();
+ }
}
- }
- // look for Info-ZIP UTF-8 path
- if (!is_utf8 && (extra.header_id() == 0x7075) && (extra.data_size() >= utf8_path_reader::minimum_length()))
- {
- utf8_path_reader const utf8path(extra);
- if (utf8path.version() == 1)
+ // look for Info-ZIP UTF-8 path
+ if (!is_utf8 && (extra.header_id() == 0x7075) && (extra.data_size() >= utf8_path_reader::minimum_length()))
{
- auto const addr(m_header.file_name.empty() ? nullptr : &m_header.file_name[0]);
- auto const length(m_header.file_name.empty() ? 0 : m_header.file_name.length() * sizeof(m_header.file_name[0]));
- auto const crc(crc32_creator::simple(addr, length));
- if (utf8path.name_crc32() == crc.m_raw)
+ utf8_path_reader const utf8path(extra);
+ if (utf8path.version() == 1)
{
- utf8path.unicode_name(m_header.file_name);
- is_utf8 = true;
+ auto const addr(header.file_name.empty() ? nullptr : &header.file_name[0]);
+ auto const length(header.file_name.empty() ? 0 : header.file_name.length() * sizeof(header.file_name[0]));
+ auto const crc(crc32_creator::simple(addr, length));
+ if (utf8path.name_crc32() == crc.m_raw)
+ {
+ utf8path.unicode_name(header.file_name);
+ is_utf8 = true;
+ }
}
}
- }
- // look for NTFS extra field
- if ((extra.header_id() == 0x000a) && (extra.data_size() >= ntfs_reader::minimum_length()))
- {
- ntfs_reader const ntfs(extra);
- for (auto tag = ntfs.tag1(); tag.length_sufficient(); tag = tag.next())
+ // look for NTFS extra field
+ if ((extra.header_id() == 0x000a) && (extra.data_size() >= ntfs_reader::minimum_length()))
{
- if ((tag.tag() == 0x0001) && (tag.size() >= ntfs_times_reader::minimum_length()))
+ ntfs_reader const ntfs(extra);
+ for (auto tag = ntfs.tag1(); tag.length_sufficient(); tag = tag.next())
{
- ntfs_times_reader const times(tag);
- ntfs_duration const ticks(times.mtime());
- m_header.modified = system_clock_time_point_from_ntfs_duration(ticks);
- m_header.modified_cached = true;
+ if ((tag.tag() == 0x0001) && (tag.size() >= ntfs_times_reader::minimum_length()))
+ {
+ ntfs_times_reader const times(tag);
+ ntfs_duration const ticks(times.mtime());
+ try
+ {
+ header.modified = system_clock_time_point_from_ntfs_duration(ticks);
+ header.modified_cached = true;
+ }
+ catch (...)
+ {
+ // out-of-range exception - let it fall back to DOS-style timestamp
+ }
+ }
}
}
}
- }
- // FIXME: if (!is_utf8) convert filename to UTF8 (assume CP437 or something)
+ // FIXME: if (!is_utf8) convert filename to UTF8 (assume CP437 or something)
- // chop off trailing slash for directory entries
- bool const is_dir(!m_header.file_name.empty() && (m_header.file_name.back() == '/'));
- if (is_dir) m_header.file_name.resize(m_header.file_name.length() - 1);
+ // chop off trailing slash for directory entries
+ bool const is_dir(!header.file_name.empty() && (header.file_name.back() == '/'));
+ if (is_dir)
+ header.file_name.resize(header.file_name.length() - 1);
- // check to see if it matches query
- bool const crcmatch(search_crc == m_header.crc);
- auto const partialoffset(m_header.file_name.length() - search_filename.length());
- bool const partialpossible((m_header.file_name.length() > search_filename.length()) && (m_header.file_name[partialoffset - 1] == '/'));
- const bool namematch(
- !core_stricmp(search_filename.c_str(), m_header.file_name.c_str()) ||
- (partialpath && partialpossible && !core_stricmp(search_filename.c_str(), m_header.file_name.c_str() + partialoffset)));
+ // advance the position
+ m_header = std::move(header);
+ m_curr_is_dir = is_dir;
+ m_cd_pos += reader.total_length();
+ }
+ catch (...)
+ {
+ break;
+ }
- bool const found = ((!matchcrc && !matchname) || !is_dir) && (!matchcrc || crcmatch) && (!matchname || namematch);
- if (found)
+ // quick return if not required to match on name
+ if (!matchname)
{
- m_curr_is_dir = is_dir;
- return 0;
+ if (!matchcrc || ((search_crc == m_header.crc) && !m_curr_is_dir))
+ return 0;
+ }
+ else if (!m_curr_is_dir)
+ {
+ // check to see if it matches query
+ auto const partialoffset = m_header.file_name.length() - search_filename.length();
+ const bool namematch =
+ (search_filename.length() == m_header.file_name.length()) &&
+ (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_header.file_name[0], search_filename.length()));
+ bool const partialmatch =
+ partialpath &&
+ ((m_header.file_name.length() > search_filename.length()) && (m_header.file_name[partialoffset - 1] == '/')) &&
+ (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_header.file_name[partialoffset], search_filename.length()));
+ if ((!matchcrc || (search_crc == m_header.crc)) && (namematch || partialmatch))
+ return 0;
}
}
return -1;
@@ -815,11 +908,8 @@ int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_fi
from a ZIP into the target buffer
-------------------------------------------------*/
-archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length)
+std::error_condition zip_file_impl::decompress(void *buffer, std::size_t length) noexcept
{
- archive_file::error ziperr;
- std::uint64_t offset;
-
// if we don't have enough buffer, error
if (length < m_header.uncompressed_length)
{
@@ -835,33 +925,29 @@ archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length
}
// get the compressed data offset
- ziperr = get_compressed_data_offset(offset);
- if (ziperr != archive_file::error::NONE)
+ std::uint64_t offset;
+ auto const ziperr = get_compressed_data_offset(offset);
+ if (ziperr)
return ziperr;
// handle compression types
switch (m_header.compression)
{
case 0:
- ziperr = decompress_data_type_0(offset, buffer, length);
- break;
+ return decompress_data_type_0(offset, buffer, length);
case 8:
- ziperr = decompress_data_type_8(offset, buffer, length);
- break;
+ return decompress_data_type_8(offset, buffer, length);
case 14:
- ziperr = decompress_data_type_14(offset, buffer, length);
- break;
+ return decompress_data_type_14(offset, buffer, length);
default:
osd_printf_error(
"unzip: %s in %s uses unsupported compression method %u\n",
- m_header.file_name.c_str(), m_filename.c_str(), m_header.compression);
- ziperr = archive_file::error::UNSUPPORTED;
- break;
+ m_header.file_name, m_filename, m_header.compression);
+ return archive_file::error::UNSUPPORTED;
}
- return ziperr;
}
@@ -874,16 +960,16 @@ archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length
read_ecd - read the ECD data
-------------------------------------------------*/
-archive_file::error zip_file_impl::read_ecd()
+std::error_condition zip_file_impl::read_ecd() noexcept
{
// make sure the file handle is open
auto const ziperr = reopen();
- if (ziperr != archive_file::error::NONE)
+ if (ziperr)
return ziperr;
// we may need multiple tries
- osd_file::error error;
- std::uint32_t read_length;
+ std::error_condition filerr;
+ std::size_t read_length;
std::uint32_t buflen = 1024;
while (buflen < 65536)
{
@@ -893,19 +979,26 @@ archive_file::error zip_file_impl::read_ecd()
// allocate buffer
std::unique_ptr<std::uint8_t []> buffer;
- try { buffer.reset(new std::uint8_t[buflen + 1]); }
- catch (...)
+ buffer.reset(new (std::nothrow) std::uint8_t[buflen + 1]);
+ if (!buffer)
{
osd_printf_error("unzip: %s failed to allocate memory for ECD search\n", m_filename);
- return archive_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
// read in one buffers' worth of data
- error = m_file->read(&buffer[0], m_length - buflen, buflen, read_length);
- if ((error != osd_file::error::NONE) || (read_length != buflen))
+ filerr = m_file->read_at(m_length - buflen, &buffer[0], buflen, read_length);
+ if (filerr)
+ {
+ osd_printf_error(
+ "unzip: error reading %s to search for ECD (%s:%d %s)\n",
+ m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
+ }
+ if (read_length != buflen)
{
- osd_printf_error("unzip: %s error reading file to search for ECD (%d)\n", m_filename, int(error));
- return archive_file::error::FILE_ERROR;
+ osd_printf_error("unzip: unexpectedly reached end-of-file while reading %s to search for ECD\n", m_filename);
+ return archive_file::error::FILE_TRUNCATED;
}
// find the ECD signature
@@ -935,19 +1028,26 @@ archive_file::error zip_file_impl::read_ecd()
if ((m_length - buflen + offset) < ecd64_locator_reader::minimum_length())
{
osd_printf_verbose("unzip: %s too small to contain ZIP64 ECD locator\n", m_filename);
- return archive_file::error::NONE;
+ return std::error_condition();
}
// try to read the ZIP64 ECD locator
- error = m_file->read(
- &buffer[0],
+ filerr = m_file->read_at(
m_length - buflen + offset - ecd64_locator_reader::minimum_length(),
+ &buffer[0],
ecd64_locator_reader::minimum_length(),
read_length);
- if ((error != osd_file::error::NONE) || (read_length != ecd64_locator_reader::minimum_length()))
+ if (filerr)
+ {
+ osd_printf_error(
+ "unzip: error reading %s to search for ZIP64 ECD locator (%s:%d %s)\n",
+ m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
+ }
+ if (read_length != ecd64_locator_reader::minimum_length())
{
- osd_printf_error("unzip: error reading %s to search for ZIP64 ECD locator (%d)\n", m_filename, int(error));
- return archive_file::error::FILE_ERROR;
+ osd_printf_error("unzip: unexpectedly reached end-of-file while reading %s to search for ZIP64 ECD locator\n", m_filename);
+ return archive_file::error::FILE_TRUNCATED;
}
// if the signature isn't correct, it's not a ZIP64 archive
@@ -955,7 +1055,7 @@ archive_file::error zip_file_impl::read_ecd()
if (!ecd64_loc_rd.signature_correct())
{
osd_printf_verbose("unzip: %s has no ZIP64 ECD locator\n", m_filename);
- return archive_file::error::NONE;
+ return std::error_condition();
}
// check that the ZIP64 ECD is in this segment (assuming this segment is the last segment)
@@ -966,11 +1066,13 @@ archive_file::error zip_file_impl::read_ecd()
}
// try to read the ZIP64 ECD
- error = m_file->read(&buffer[0], ecd64_loc_rd.ecd64_offset(), ecd64_reader::minimum_length(), read_length);
- if (error != osd_file::error::NONE)
+ filerr = m_file->read_at(ecd64_loc_rd.ecd64_offset(), &buffer[0], ecd64_reader::minimum_length(), read_length);
+ if (filerr)
{
- osd_printf_error("unzip: error reading %s ZIP64 ECD (%d)\n", m_filename, int(error));
- return archive_file::error::FILE_ERROR;
+ osd_printf_error(
+ "unzip: error reading %s ZIP64 ECD (%s:%d %s)\n",
+ m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
if (read_length != ecd64_reader::minimum_length())
{
@@ -983,8 +1085,8 @@ archive_file::error zip_file_impl::read_ecd()
if (!ecd64_rd.signature_correct())
{
osd_printf_error(
- "unzip: %s ZIP64 ECD has incorrect signature 0x%08lx\n",
- m_filename.c_str(), long(ecd64_rd.signature()));
+ "unzip: %s ZIP64 ECD has incorrect signature 0x%08x\n",
+ m_filename, ecd64_rd.signature());
return archive_file::error::BAD_SIGNATURE;
}
if (ecd64_rd.total_length() < ecd64_reader::minimum_length())
@@ -996,7 +1098,7 @@ archive_file::error zip_file_impl::read_ecd()
{
osd_printf_error(
"unzip: %s ZIP64 ECD requires unsupported version %u.%u\n",
- m_filename.c_str(), unsigned(ecd64_rd.version_needed() / 10), unsigned(ecd64_rd.version_needed() % 10));
+ m_filename, ecd64_rd.version_needed() / 10, ecd64_rd.version_needed() % 10);
return archive_file::error::UNSUPPORTED;
}
osd_printf_verbose("unzip: found %s ZIP64 ECD\n", m_filename);
@@ -1009,7 +1111,7 @@ archive_file::error zip_file_impl::read_ecd()
m_ecd.cd_size = ecd64_rd.dir_size();
m_ecd.cd_start_disk_offset = ecd64_rd.dir_offset();
- return archive_file::error::NONE;
+ return std::error_condition();
}
// didn't find it; free this buffer and expand our search
@@ -1024,7 +1126,7 @@ archive_file::error zip_file_impl::read_ecd()
}
}
osd_printf_error("unzip: %s couldn't find ECD in last 64KiB\n", m_filename);
- return archive_file::error::OUT_OF_MEMORY;
+ return archive_file::error::UNSUPPORTED; // TODO: revisit this error code
}
@@ -1033,7 +1135,7 @@ archive_file::error zip_file_impl::read_ecd()
offset of the compressed data
-------------------------------------------------*/
-archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &offset)
+std::error_condition zip_file_impl::get_compressed_data_offset(std::uint64_t &offset) noexcept
{
// don't support a number of features
general_flag_reader const flags(m_header.bit_flag);
@@ -1046,7 +1148,7 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off
{
osd_printf_error(
"unzip: %s in %s requires unsupported version %u.%u\n",
- m_header.file_name.c_str(), m_filename.c_str(), unsigned(m_header.version_needed / 10), unsigned(m_header.version_needed % 10));
+ m_header.file_name, m_filename, m_header.version_needed / 10, m_header.version_needed % 10);
return archive_file::error::UNSUPPORTED;
}
if (flags.encrypted() || flags.strong_encryption())
@@ -1062,24 +1164,24 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off
// make sure the file handle is open
auto const ziperr = reopen();
- if (ziperr != archive_file::error::NONE)
+ if (ziperr)
return ziperr;
// now go read the fixed-sized part of the local file header
- std::uint32_t read_length;
- auto const error = m_file->read(&m_buffer[0], m_header.local_header_offset, local_file_header_reader::minimum_length(), read_length);
- if (error != osd_file::error::NONE)
+ std::size_t read_length;
+ std::error_condition const filerr = m_file->read_at(m_header.local_header_offset, &m_buffer[0], local_file_header_reader::minimum_length(), read_length);
+ if (filerr)
{
osd_printf_error(
- "unzip: error reading local file header for %s in %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(error));
- return archive_file::error::FILE_ERROR;
+ "unzip: error reading local file header for %s in %s (%s:%d %s)\n",
+ m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
if (read_length != local_file_header_reader::minimum_length())
{
osd_printf_error(
"unzip: unexpectedly reached end-of-file while reading local file header for %s in %s\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::FILE_TRUNCATED;
}
@@ -1088,13 +1190,13 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off
if (!reader.signature_correct())
{
osd_printf_error(
- "unzip: local file header for %s in %s has incorrect signature %04lx\n",
- m_header.file_name.c_str(), m_filename.c_str(), long(reader.signature()));
+ "unzip: local file header for %s in %s has incorrect signature %04x\n",
+ m_header.file_name, m_filename, reader.signature());
return archive_file::error::BAD_SIGNATURE;
}
offset = m_header.local_header_offset + reader.total_length();
- return archive_file::error::NONE;
+ return std::error_condition();
}
@@ -1108,24 +1210,28 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off
type 0 data (which is uncompressed)
-------------------------------------------------*/
-archive_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length)
+std::error_condition zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::size_t length) noexcept
{
// the data is uncompressed; just read it
- std::uint32_t read_length(0);
- auto const filerr = m_file->read(buffer, offset, m_header.compressed_length, read_length);
- if (filerr != osd_file::error::NONE)
+ std::size_t read_length(0);
+ std::error_condition const filerr = m_file->read_at(offset, buffer, m_header.compressed_length, read_length);
+ if (filerr)
{
- osd_printf_error("unzip: error reading %s from %s (%d)\n", m_header.file_name, m_filename, int(filerr));
- return archive_file::error::FILE_ERROR;
+ osd_printf_error(
+ "unzip: error reading %s from %s (%s:%d %s)\n",
+ m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
else if (read_length != m_header.compressed_length)
{
- osd_printf_error("unzip: unexpectedly reached end-of-file while reading %s from %s\n", m_header.file_name, m_filename);
+ osd_printf_error(
+ "unzip: unexpectedly reached end-of-file while reading %s from %s\n",
+ m_header.file_name, m_filename);
return archive_file::error::FILE_TRUNCATED;
}
else
{
- return archive_file::error::NONE;
+ return std::error_condition();
}
}
@@ -1135,8 +1241,23 @@ archive_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset,
type 8 data (which is deflated)
-------------------------------------------------*/
-archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length)
+std::error_condition zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::size_t length) noexcept
{
+ auto const convert_zerr =
+ [] (int e) -> std::error_condition
+ {
+ switch (e)
+ {
+ case Z_OK:
+ return std::error_condition();
+ case Z_ERRNO:
+ return std::error_condition(errno, std::generic_category());
+ case Z_MEM_ERROR:
+ return std::errc::not_enough_memory;
+ default:
+ return archive_file::error::DECOMPRESS_ERROR;
+ }
+ };
std::uint64_t input_remaining = m_header.compressed_length;
int zerr;
@@ -1153,38 +1274,39 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset,
zerr = inflateInit2(&stream, -MAX_WBITS);
if (zerr != Z_OK)
{
+ auto result = convert_zerr(zerr);
osd_printf_error(
"unzip: error allocating zlib stream to inflate %s from %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), zerr);
- return archive_file::error::DECOMPRESS_ERROR;
+ m_header.file_name, m_filename, zerr);
+ return result;
}
// loop until we're done
while (true)
{
// read in the next chunk of data
- std::uint32_t read_length(0);
- auto const filerr = m_file->read(
- &m_buffer[0],
+ std::size_t read_length(0);
+ auto const filerr = m_file->read_at(
offset,
- std::uint32_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())),
+ &m_buffer[0],
+ std::size_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())),
read_length);
- if (filerr != osd_file::error::NONE)
+ if (filerr)
{
osd_printf_error(
- "unzip: error reading compressed data for %s in %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(filerr));
+ "unzip: error reading compressed data for %s in %s (%s:%d %s)\n",
+ m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message());
inflateEnd(&stream);
- return archive_file::error::FILE_ERROR;
+ return filerr;
}
offset += read_length;
// if we read nothing, but still have data left, the file is truncated
- if ((read_length == 0) && (input_remaining > 0))
+ if (!read_length && input_remaining)
{
osd_printf_error(
"unzip: unexpectedly reached end-of-file while reading compressed data for %s in %s\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
inflateEnd(&stream);
return archive_file::error::FILE_TRUNCATED;
}
@@ -1206,9 +1328,12 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset,
}
else if (zerr != Z_OK)
{
- osd_printf_error("unzip: error inflating %s from %s (%d)\n", m_header.file_name, m_filename, zerr);
+ auto result = convert_zerr(zerr);
+ osd_printf_error(
+ "unzip: error inflating %s from %s (%d)\n",
+ m_header.file_name, m_filename, zerr);
inflateEnd(&stream);
- return archive_file::error::DECOMPRESS_ERROR;
+ return result;
}
}
@@ -1216,20 +1341,23 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset,
zerr = inflateEnd(&stream);
if (zerr != Z_OK)
{
- osd_printf_error("unzip: error finishing inflation of %s from %s (%d)\n", m_header.file_name, m_filename, zerr);
- return archive_file::error::DECOMPRESS_ERROR;
+ auto result = convert_zerr(zerr);
+ osd_printf_error(
+ "unzip: error finishing inflation of %s from %s (%d)\n",
+ m_header.file_name, m_filename, zerr);
+ return result;
}
// if anything looks funny, report an error
- if ((stream.avail_out > 0) || (input_remaining > 0))
+ if (stream.avail_out || input_remaining)
{
osd_printf_error(
"unzip: inflation of %s from %s doesn't appear to have completed correctly\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::DECOMPRESS_ERROR;
}
- return archive_file::error::NONE;
+ return std::error_condition();
}
@@ -1238,7 +1366,7 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset,
type 14 data (LZMA)
-------------------------------------------------*/
-archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, void *buffer, std::uint32_t length)
+std::error_condition zip_file_impl::decompress_data_type_14(std::uint64_t offset, void *buffer, std::size_t length) noexcept
{
// two-byte version
// two-byte properties size (little-endian)
@@ -1253,15 +1381,15 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
SizeT output_remaining(length);
std::uint64_t input_remaining(m_header.compressed_length);
- std::uint32_t read_length;
- osd_file::error filerr;
+ std::size_t read_length;
+ std::error_condition filerr;
SRes lzerr;
ELzmaStatus lzstatus(LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK);
// reset the stream
ISzAlloc alloc_imp;
- alloc_imp.Alloc = [](void *p, std::size_t size) -> void * { return (size == 0) ? nullptr : std::malloc(size); };
- alloc_imp.Free = [](void *p, void *address) -> void { std::free(address); };
+ alloc_imp.Alloc = [] (void *p, std::size_t size) -> void * { return size ? std::malloc(size) : nullptr; };
+ alloc_imp.Free = [] (void *p, void *address) -> void { std::free(address); };
CLzmaDec stream;
LzmaDec_Construct(&stream);
@@ -1270,16 +1398,16 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
{
osd_printf_error(
"unzip:compressed data for %s in %s is too small to hold LZMA properties header\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::DECOMPRESS_ERROR;
}
- filerr = m_file->read(&m_buffer[0], offset, 4, read_length);
- if (filerr != osd_file::error::NONE)
+ filerr = m_file->read_at(offset, &m_buffer[0], 4, read_length);
+ if (filerr)
{
osd_printf_error(
- "unzip: error reading LZMA properties header for %s in %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(filerr));
- return archive_file::error::FILE_ERROR;
+ "unzip: error reading LZMA properties header for %s in %s (%s:%d %s)\n",
+ m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
offset += read_length;
input_remaining -= read_length;
@@ -1287,7 +1415,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
{
osd_printf_error(
"unzip: unexpectedly reached end-of-file while reading LZMA properties header for %s in %s\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::FILE_TRUNCATED;
}
std::uint16_t const props_size((std::uint16_t(m_buffer[3]) << 8) | std::uint16_t(m_buffer[2]));
@@ -1295,23 +1423,23 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
{
osd_printf_error(
"unzip: %s in %s has excessively large LZMA properties\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::UNSUPPORTED;
}
else if (props_size > input_remaining)
{
osd_printf_error(
"unzip:compressed data for %s in %s is too small to hold LZMA properties\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::DECOMPRESS_ERROR;
}
- filerr = m_file->read(&m_buffer[0], offset, props_size, read_length);
- if (filerr != osd_file::error::NONE)
+ filerr = m_file->read_at(offset, &m_buffer[0], props_size, read_length);
+ if (filerr)
{
osd_printf_error(
- "unzip: error reading LZMA properties for %s in %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(filerr));
- return archive_file::error::FILE_ERROR;
+ "unzip: error reading LZMA properties for %s in %s (%s:%d %s)\n",
+ m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
}
offset += read_length;
input_remaining -= read_length;
@@ -1319,7 +1447,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
{
osd_printf_error(
"unzip: unexpectedly reached end-of-file while reading LZMA properties for %s in %s\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
return archive_file::error::FILE_TRUNCATED;
}
@@ -1329,14 +1457,21 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
{
osd_printf_error(
"unzip: memory error allocating LZMA decoder to decompress %s from %s\n",
- m_header.file_name.c_str(), m_filename.c_str());
- return archive_file::error::OUT_OF_MEMORY;
+ m_header.file_name, m_filename);
+ return std::errc::not_enough_memory;
+ }
+ else if (SZ_ERROR_UNSUPPORTED)
+ {
+ osd_printf_error(
+ "unzip: LZMA decoder does not support properties for %s in %s\n",
+ m_header.file_name, m_filename);
+ return archive_file::error::UNSUPPORTED;
}
else if (SZ_OK != lzerr)
{
osd_printf_error(
"unzip: error allocating LZMA decoder to decompress %s from %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(lzerr));
+ m_header.file_name, m_filename, int(lzerr));
return archive_file::error::DECOMPRESS_ERROR;
}
LzmaDec_Init(&stream);
@@ -1345,28 +1480,28 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
while (0 < input_remaining)
{
// read in the next chunk of data
- filerr = m_file->read(
- &m_buffer[0],
+ filerr = m_file->read_at(
offset,
- std::uint32_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())),
+ &m_buffer[0],
+ std::size_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())),
read_length);
- if (filerr != osd_file::error::NONE)
+ if (filerr)
{
osd_printf_error(
- "unzip: error reading compressed data for %s in %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(filerr));
+ "unzip: error reading compressed data for %s in %s (%s)\n",
+ m_header.file_name, m_filename);
LzmaDec_Free(&stream, &alloc_imp);
- return archive_file::error::FILE_ERROR;
+ return filerr;
}
offset += read_length;
input_remaining -= read_length;
// if we read nothing, but still have data left, the file is truncated
- if ((0 == read_length) && (0 < input_remaining))
+ if (!read_length && input_remaining)
{
osd_printf_error(
"unzip: unexpectedly reached end-of-file while reading compressed data for %s in %s\n",
- m_header.file_name.c_str(), m_filename.c_str());
+ m_header.file_name, m_filename);
LzmaDec_Free(&stream, &alloc_imp);
return archive_file::error::FILE_TRUNCATED;
}
@@ -1381,7 +1516,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
&output_remaining,
reinterpret_cast<Byte const *>(&m_buffer[0]),
&len,
- ((0 == input_remaining) && eos_mark) ? LZMA_FINISH_END : LZMA_FINISH_ANY,
+ (!input_remaining && eos_mark) ? LZMA_FINISH_END : LZMA_FINISH_ANY,
&lzstatus);
if (SZ_OK != lzerr)
{
@@ -1397,25 +1532,25 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
// if anything looks funny, report an error
if (LZMA_STATUS_FINISHED_WITH_MARK == lzstatus)
{
- return archive_file::error::NONE;
+ return std::error_condition();
}
else if (eos_mark)
{
osd_printf_error(
"unzip: LZMA end mark not found for %s in %s (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(lzstatus));
+ m_header.file_name, m_filename, int(lzstatus));
return archive_file::error::DECOMPRESS_ERROR;
}
else if (LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK != lzstatus)
{
osd_printf_error(
"unzip: LZMA decompression of %s from %s doesn't appear to have completed correctly (%d)\n",
- m_header.file_name.c_str(), m_filename.c_str(), int(lzstatus));
+ m_header.file_name, m_filename, int(lzstatus));
return archive_file::error::DECOMPRESS_ERROR;
}
else
{
- return archive_file::error::NONE;
+ return std::error_condition();
}
}
@@ -1427,7 +1562,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset,
un7z.cpp TRAMPOLINES
***************************************************************************/
-void m7z_file_cache_clear();
+void m7z_file_cache_clear() noexcept;
@@ -1439,7 +1574,7 @@ void m7z_file_cache_clear();
zip_file_open - opens a ZIP file for reading
-------------------------------------------------*/
-archive_file::error archive_file::open_zip(const std::string &filename, ptr &result)
+std::error_condition archive_file::open_zip(std::string_view filename, ptr &result) noexcept
{
// ensure we start with a nullptr result
result.reset();
@@ -1450,21 +1585,49 @@ archive_file::error archive_file::open_zip(const std::string &filename, ptr &res
if (!newimpl)
{
// allocate memory for the zip_file structure
- try { newimpl = std::make_unique<zip_file_impl>(filename); }
- catch (...) { return error::OUT_OF_MEMORY; }
- auto const ziperr = newimpl->initialize();
- if (ziperr != error::NONE) return ziperr;
+ try { newimpl = std::make_unique<zip_file_impl>(std::string(filename)); }
+ catch (...) { return std::errc::not_enough_memory; }
+ auto const err = newimpl->initialize();
+ if (err)
+ return err;
+ }
+
+ // allocate the archive API wrapper
+ result.reset(new (std::nothrow) zip_file_wrapper(std::move(newimpl)));
+ if (result)
+ {
+ return std::error_condition();
+ }
+ else
+ {
+ zip_file_impl::close(std::move(newimpl));
+ return std::errc::not_enough_memory;
}
+}
- try
+std::error_condition archive_file::open_zip(random_read::ptr &&file, ptr &result) noexcept
+{
+ // ensure we start with a nullptr result
+ result.reset();
+
+ // allocate memory for the zip_file structure
+ zip_file_impl::ptr newimpl(new (std::nothrow) zip_file_impl(std::move(file)));
+ if (!newimpl)
+ return std::errc::not_enough_memory;
+ auto const err = newimpl->initialize();
+ if (err)
+ return err;
+
+ // allocate the archive API wrapper
+ result.reset(new (std::nothrow) zip_file_wrapper(std::move(newimpl)));
+ if (result)
{
- result = std::make_unique<zip_file_wrapper>(std::move(newimpl));
- return error::NONE;
+ return std::error_condition();
}
- catch (...)
+ else
{
zip_file_impl::close(std::move(newimpl));
- return error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -1474,7 +1637,7 @@ archive_file::error archive_file::open_zip(const std::string &filename, ptr &res
cache and free all memory
-------------------------------------------------*/
-void archive_file::cache_clear()
+void archive_file::cache_clear() noexcept
{
zip_file_impl::cache_clear();
m7z_file_cache_clear();
@@ -1485,4 +1648,15 @@ archive_file::~archive_file()
{
}
+
+/*-------------------------------------------------
+ archive_category - gets the archive error
+ category instance
+-------------------------------------------------*/
+
+std::error_category const &archive_category() noexcept
+{
+ return f_archive_category_instance;
+}
+
} // namespace util
diff --git a/src/lib/util/unzip.h b/src/lib/util/unzip.h
index b1ddb7a27d1..2108eadee28 100644
--- a/src/lib/util/unzip.h
+++ b/src/lib/util/unzip.h
@@ -7,19 +7,24 @@
archive file management.
***************************************************************************/
+#ifndef MAME_LIB_UTIL_UNZIP_H
+#define MAME_LIB_UTIL_UNZIP_H
#pragma once
-#ifndef MAME_LIB_UTIL_UNZIP_H
-#define MAME_LIB_UTIL_UNZIP_H
+#include "utilfwd.h"
#include <chrono>
#include <cstdint>
#include <memory>
#include <string>
+#include <string_view>
+#include <system_error>
+#include <type_traits>
namespace util {
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -30,12 +35,9 @@ class archive_file
public:
// Error types
- enum class error
+ enum class error : int
{
- NONE = 0,
- OUT_OF_MEMORY,
- FILE_ERROR,
- BAD_SIGNATURE,
+ BAD_SIGNATURE = 1,
DECOMPRESS_ERROR,
FILE_TRUNCATED,
FILE_CORRUPT,
@@ -49,40 +51,54 @@ public:
/* ----- archive file access ----- */
// open a ZIP file and parse its central directory
- static error open_zip(const std::string &filename, ptr &zip);
+ static std::error_condition open_zip(std::string_view filename, ptr &result) noexcept;
+ static std::error_condition open_zip(std::unique_ptr<random_read> &&file, ptr &result) noexcept;
// open a 7Z file and parse its central directory
- static error open_7z(const std::string &filename, ptr &result);
+ static std::error_condition open_7z(std::string_view filename, ptr &result) noexcept;
+ static std::error_condition open_7z(std::unique_ptr<random_read> &&file, ptr &result) noexcept;
// close an archive file (may actually be left open due to caching)
virtual ~archive_file();
// clear out all open files from the cache
- static void cache_clear();
+ static void cache_clear() noexcept;
/* ----- contained file access ----- */
// iterating over files - returns negative on reaching end
- virtual int first_file() = 0;
- virtual int next_file() = 0;
+ virtual int first_file() noexcept = 0;
+ virtual int next_file() noexcept = 0;
// find a file index by crc, filename or both - returns non-negative on match
- virtual int search(std::uint32_t crc) = 0;
- virtual int search(const std::string &filename, bool partialpath) = 0;
- virtual int search(std::uint32_t crc, const std::string &filename, bool partialpath) = 0;
+ virtual int search(std::uint32_t crc) noexcept = 0;
+ virtual int search(std::string_view filename, bool partialpath) noexcept = 0;
+ virtual int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept = 0;
// information on most recently found file
- virtual bool current_is_directory() const = 0;
- virtual const std::string &current_name() const = 0;
- virtual std::uint64_t current_uncompressed_length() const = 0;
- virtual std::chrono::system_clock::time_point current_last_modified() const = 0;
- virtual std::uint32_t current_crc() const = 0;
+ virtual bool current_is_directory() const noexcept = 0;
+ virtual const std::string &current_name() const noexcept = 0;
+ virtual std::uint64_t current_uncompressed_length() const noexcept = 0;
+ virtual std::chrono::system_clock::time_point current_last_modified() const noexcept = 0;
+ virtual std::uint32_t current_crc() const noexcept = 0;
// decompress the most recently found file in the ZIP
- virtual error decompress(void *buffer, std::uint32_t length) = 0;
+ virtual std::error_condition decompress(void *buffer, std::size_t length) noexcept = 0;
};
+
+// error category for archive errors
+std::error_category const &archive_category() noexcept;
+inline std::error_condition make_error_condition(archive_file::error err) noexcept { return std::error_condition(int(err), archive_category()); }
+
} // namespace util
+
+namespace std {
+
+template <> struct is_error_condition_enum<util::archive_file::error> : public std::true_type { };
+
+} // namespace std
+
#endif // MAME_LIB_UTIL_UNZIP_H
diff --git a/src/lib/util/utilfwd.h b/src/lib/util/utilfwd.h
new file mode 100644
index 00000000000..fefe0631c68
--- /dev/null
+++ b/src/lib/util/utilfwd.h
@@ -0,0 +1,45 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/**********************************************************************
+
+ utilfwd.h
+
+ Forward declarations of types
+
+**********************************************************************/
+#ifndef MAME_LIB_UTIL_UTILFWD_H
+#define MAME_LIB_UTIL_UTILFWD_H
+
+// chd.h
+class chd_file;
+
+
+namespace util {
+
+// corefile.h
+class core_file;
+
+// ioprocs.h
+class read_stream;
+class write_stream;
+class read_write_stream;
+class random_access;
+class random_read;
+class random_write;
+class random_read_write;
+
+// unzip.h
+class archive_file;
+
+} // namespace util
+
+
+namespace util::xml {
+
+// xmlfile.h
+class data_node;
+class file;
+
+} // namespace util::xml
+
+#endif // MAME_LIB_UTIL_UTILFWD_H
diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp
index 023484010b8..f317319c8c3 100644
--- a/src/lib/util/zippath.cpp
+++ b/src/lib/util/zippath.cpp
@@ -9,13 +9,13 @@
***************************************************************************/
#include "zippath.h"
-#include "unzip.h"
-#include "corestr.h"
-#include <cstdlib>
+#include "corestr.h"
+#include "unzip.h"
#include <cassert>
#include <cctype>
+#include <cstdlib>
#include <forward_list>
#include <new>
@@ -192,7 +192,7 @@ int zippath_find_sub_path(archive_file &zipfile, std::string_view subpath, osd::
// true path and ZIP entry components
// -------------------------------------------------
-osd_file::error zippath_resolve(std::string_view path, osd::directory::entry::entry_type &entry_type, archive_file::ptr &zipfile, std::string &newpath)
+std::error_condition zippath_resolve(std::string_view path, osd::directory::entry::entry_type &entry_type, archive_file::ptr &zipfile, std::string &newpath)
{
newpath.clear();
@@ -238,13 +238,13 @@ osd_file::error zippath_resolve(std::string_view path, osd::directory::entry::en
if (current_entry_type == osd::directory::entry::entry_type::NONE)
{
entry_type = osd::directory::entry::entry_type::NONE;
- return osd_file::error::NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
// is this file a ZIP file?
if ((current_entry_type == osd::directory::entry::entry_type::FILE) &&
- ((is_zip_file(apath_trimmed) && (archive_file::open_zip(apath_trimmed, zipfile) == archive_file::error::NONE)) ||
- (is_7z_file(apath_trimmed) && (archive_file::open_7z(apath_trimmed, zipfile) == archive_file::error::NONE))))
+ ((is_zip_file(apath_trimmed) && !archive_file::open_zip(apath_trimmed, zipfile)) ||
+ (is_7z_file(apath_trimmed) && !archive_file::open_7z(apath_trimmed, zipfile))))
{
auto i = path.length() - apath.length();
while ((i > 0) && is_zip_path_separator(path[apath.length() + i - 1]))
@@ -254,53 +254,20 @@ osd_file::error zippath_resolve(std::string_view path, osd::directory::entry::en
// this was a true ZIP path - attempt to identify the type of path
zippath_find_sub_path(*zipfile, newpath, current_entry_type);
if (current_entry_type == osd::directory::entry::entry_type::NONE)
- return osd_file::error::NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
else
{
// this was a normal path
if (went_up)
- return osd_file::error::NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
newpath = path;
}
// success!
entry_type = current_entry_type;
- return osd_file::error::NONE;
-}
-
-
-// -------------------------------------------------
-// file_error_from_zip_error - translates a
-// osd_file::error to a zip_error
-// -------------------------------------------------
-
-osd_file::error file_error_from_zip_error(archive_file::error ziperr)
-{
- osd_file::error filerr;
- switch(ziperr)
- {
- case archive_file::error::NONE:
- filerr = osd_file::error::NONE;
- break;
- case archive_file::error::OUT_OF_MEMORY:
- filerr = osd_file::error::OUT_OF_MEMORY;
- break;
- case archive_file::error::BAD_SIGNATURE:
- case archive_file::error::DECOMPRESS_ERROR:
- case archive_file::error::FILE_TRUNCATED:
- case archive_file::error::FILE_CORRUPT:
- case archive_file::error::UNSUPPORTED:
- case archive_file::error::FILE_ERROR:
- filerr = osd_file::error::INVALID_DATA;
- break;
- case archive_file::error::BUFFER_TOO_SMALL:
- default:
- filerr = osd_file::error::FAILURE;
- break;
- }
- return filerr;
+ return std::error_condition();
}
@@ -309,27 +276,24 @@ osd_file::error file_error_from_zip_error(archive_file::error ziperr)
// from a zip file entry
// -------------------------------------------------
-osd_file::error create_core_file_from_zip(archive_file &zip, util::core_file::ptr &file)
+std::error_condition create_core_file_from_zip(archive_file &zip, util::core_file::ptr &file)
{
- osd_file::error filerr;
- archive_file::error ziperr;
+ // TODO: would be more efficient if we could open a memory-based core_file with uninitialised contents and decompress into it
+ std::error_condition filerr;
void *ptr = malloc(zip.current_uncompressed_length());
if (!ptr)
{
- filerr = osd_file::error::OUT_OF_MEMORY;
+ filerr = std::errc::not_enough_memory;
goto done;
}
- ziperr = zip.decompress(ptr, zip.current_uncompressed_length());
- if (ziperr != archive_file::error::NONE)
- {
- filerr = file_error_from_zip_error(ziperr);
+ filerr = zip.decompress(ptr, zip.current_uncompressed_length());
+ if (filerr)
goto done;
- }
filerr = util::core_file::open_ram_copy(ptr, zip.current_uncompressed_length(), OPEN_FLAG_READ, file);
- if (filerr != osd_file::error::NONE)
+ if (filerr)
goto done;
done:
@@ -545,7 +509,7 @@ private:
// zippath_directory::open - opens a directory
// -------------------------------------------------
-osd_file::error zippath_directory::open(std::string_view path, ptr &directory)
+std::error_condition zippath_directory::open(std::string_view path, ptr &directory)
{
try
{
@@ -553,34 +517,34 @@ osd_file::error zippath_directory::open(std::string_view path, ptr &directory)
osd::directory::entry::entry_type entry_type;
archive_file::ptr zipfile;
std::string zipprefix;
- osd_file::error const err = zippath_resolve(path, entry_type, zipfile, zipprefix);
- if (osd_file::error::NONE != err)
+ std::error_condition const err = zippath_resolve(path, entry_type, zipfile, zipprefix);
+ if (err)
return err;
// we have to be a directory
if (osd::directory::entry::entry_type::DIR != entry_type)
- return osd_file::error::NOT_FOUND;
+ return std::errc::not_a_directory;
// was the result a ZIP?
if (zipfile)
{
directory = std::make_unique<archive_directory_impl>(std::move(zipfile), std::move(zipprefix));
- return osd_file::error::NONE;
+ return std::error_condition();
}
else
{
// a conventional directory
std::unique_ptr<filesystem_directory_impl> result(new filesystem_directory_impl(path));
if (!*result)
- return osd_file::error::FAILURE;
+ return std::errc::io_error; // TODO: any way to give a better error here?
directory = std::move(result);
- return osd_file::error::NONE;
+ return std::error_condition();
}
}
catch (std::bad_alloc const &)
{
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -681,7 +645,7 @@ std::string zippath_combine(const std::string &path1, const std::string &path2)
// -------------------------------------------------
/**
- * @fn osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path)
+ * @fn std::error_condition zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path)
*
* @brief Zippath fopen.
*
@@ -693,38 +657,35 @@ std::string zippath_combine(const std::string &path1, const std::string &path2)
* @return A osd_file::error.
*/
-osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path)
+std::error_condition zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path)
{
- osd_file::error filerr = osd_file::error::NOT_FOUND;
- archive_file::error ziperr;
+ std::error_condition filerr = std::errc::no_such_file_or_directory;
archive_file::ptr zip;
- int header;
- osd::directory::entry::entry_type entry_type;
- int len;
- /* first, set up the two types of paths */
+ // first, set up the two types of paths
std::string mainpath(filename);
std::string subpath;
file = nullptr;
- /* loop through */
- while((file == nullptr) && (mainpath.length() > 0)
- && ((openflags == OPEN_FLAG_READ) || subpath.empty()))
+ // loop through
+ while (!file && !mainpath.empty() && ((openflags == OPEN_FLAG_READ) || subpath.empty()))
{
- /* is the mainpath a ZIP path? */
+ // is the mainpath a ZIP path?
if (is_zip_file(mainpath) || is_7z_file(mainpath))
{
- /* this file might be a zip file - lets take a look */
- ziperr = is_zip_file(mainpath) ? archive_file::open_zip(mainpath, zip) : archive_file::open_7z(mainpath, zip);
- if (ziperr == archive_file::error::NONE)
+ // this file might be a zip file - lets take a look
+ std::error_condition const ziperr = is_zip_file(mainpath) ? archive_file::open_zip(mainpath, zip) : archive_file::open_7z(mainpath, zip);
+ if (!ziperr)
{
- /* it is a zip file - error if we're not opening for reading */
+ // it is a zip file - error if we're not opening for reading
if (openflags != OPEN_FLAG_READ)
{
- filerr = osd_file::error::ACCESS_DENIED;
+ filerr = std::errc::permission_denied;
goto done;
}
+ osd::directory::entry::entry_type entry_type;
+ int header;
if (!subpath.empty())
header = zippath_find_sub_path(*zip, subpath, entry_type);
else
@@ -732,20 +693,20 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti
if (header < 0)
{
- filerr = osd_file::error::NOT_FOUND;
+ filerr = std::errc::no_such_file_or_directory;
goto done;
}
- /* attempt to read the file */
+ // attempt to read the file
filerr = create_core_file_from_zip(*zip, file);
- if (filerr != osd_file::error::NONE)
+ if (filerr)
goto done;
- /* update subpath, if appropriate */
+ // update subpath, if appropriate
if (subpath.empty())
subpath.assign(zip->current_name());
- /* we're done */
+ // we're done
goto done;
}
}
@@ -753,15 +714,15 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti
if (subpath.empty())
filerr = util::core_file::open(std::string(filename), openflags, file);
else
- filerr = osd_file::error::NOT_FOUND;
+ filerr = std::errc::no_such_file_or_directory;
- /* if we errored, then go up a directory */
- if (filerr != osd_file::error::NONE)
+ // if we errored, then go up a directory
+ if (filerr)
{
- /* go up a directory */
+ // go up a directory
auto temp = zippath_parent(mainpath);
- /* append to the sub path */
+ // append to the sub path
if (!subpath.empty())
{
std::string temp2;
@@ -774,8 +735,8 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti
mainpath = mainpath.substr(temp.length());
subpath.assign(mainpath);
}
- /* get the new main path, truncating path separators */
- len = temp.length();
+ // get the new main path, truncating path separators
+ auto len = temp.length();
while (len > 0 && is_zip_file_separator(temp[len - 1]))
len--;
temp = temp.substr(0, len);
@@ -784,14 +745,14 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti
}
done:
- /* store the revised path */
+ // store the revised path
revised_path.clear();
- if (filerr == osd_file::error::NONE)
+ if (!filerr)
{
- /* canonicalize mainpath */
+ // canonicalize mainpath
std::string alloc_fullpath;
filerr = osd_get_full_path(alloc_fullpath, mainpath);
- if (filerr == osd_file::error::NONE)
+ if (!filerr)
{
revised_path = alloc_fullpath;
if (!subpath.empty())
diff --git a/src/lib/util/zippath.h b/src/lib/util/zippath.h
index 1eb92aa1c1d..955c75cfc8f 100644
--- a/src/lib/util/zippath.h
+++ b/src/lib/util/zippath.h
@@ -18,6 +18,7 @@
#include <string>
#include <string_view>
+#include <system_error>
namespace util {
@@ -32,7 +33,7 @@ public:
typedef std::unique_ptr<zippath_directory> ptr;
// opens a directory
- static osd_file::error open(std::string_view path, ptr &directory);
+ static std::error_condition open(std::string_view path, ptr &directory);
// closes a directory
virtual ~zippath_directory();
@@ -63,7 +64,7 @@ std::string zippath_combine(const std::string &path1, const std::string &path2);
// ----- file operations -----
// opens a zip path file
-osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path);
+std::error_condition zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path);
} // namespace util