summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util')
-rw-r--r--src/lib/util/aviio.cpp3369
-rw-r--r--src/lib/util/aviio.h188
-rw-r--r--src/lib/util/cdrom.cpp4
-rw-r--r--src/lib/util/chd.cpp16
-rw-r--r--src/lib/util/chdcd.cpp55
-rw-r--r--src/lib/util/corefile.cpp168
-rw-r--r--src/lib/util/corefile.h25
-rw-r--r--src/lib/util/un7z.cpp693
-rw-r--r--src/lib/util/un7z.h152
-rw-r--r--src/lib/util/unzip.cpp794
-rw-r--r--src/lib/util/unzip.h187
-rw-r--r--src/lib/util/zippath.cpp175
-rw-r--r--src/lib/util/zippath.h4
13 files changed, 2813 insertions, 3017 deletions
diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp
index a448128070b..8483adb24f6 100644
--- a/src/lib/util/aviio.cpp
+++ b/src/lib/util/aviio.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
aviio.c
@@ -8,8 +8,10 @@
***************************************************************************/
-#include <stdlib.h>
-#include <assert.h>
+#include <array>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
#include "aviio.h"
@@ -45,7 +47,7 @@
* @brief A macro that defines four gigabytes.
*/
-#define FOUR_GB ((UINT64)1 << 32)
+#define FOUR_GB (std::uint64_t(1) << 32)
/**
* @def MAX_SOUND_CHANNELS
@@ -222,7 +224,7 @@
#define HUFFYUV_PREDICT_DECORR 0x40
-
+namespace {
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -235,14 +237,12 @@
struct avi_chunk
{
- /** @brief The offset. */
- UINT64 offset; /* file offset of chunk header */
- /** @brief The size. */
- UINT64 size; /* size of this chunk */
- /** @brief The type. */
- UINT32 type; /* type of this chunk */
- /** @brief The listtype. */
- UINT32 listtype; /* type of this list (if we are a list) */
+ avi_chunk() : offset(0), size(0), type(0), listtype(0) { }
+
+ std::uint64_t offset; /* file offset of chunk header */
+ std::uint64_t size; /* size of this chunk */
+ std::uint32_t type; /* type of this chunk */
+ std::uint32_t listtype; /* type of this list (if we are a list) */
};
/**
@@ -253,211 +253,297 @@ struct avi_chunk
struct avi_chunk_list
{
- /** @brief The offset. */
- UINT64 offset; /* offset in the file of header */
- /** @brief The length. */
- UINT32 length; /* length of the chunk including header */
+ std::uint64_t offset; /* offset in the file of header */
+ std::uint32_t length; /* length of the chunk including header */
};
/**
- * @struct huffyuv_table
+ * @struct avi_stream
*
- * @brief A huffyuv table.
+ * @brief An avi stream.
*/
-struct huffyuv_table
-{
- /** @brief The shift[ 256]. */
- UINT8 shift[256]; /* bit shift amounts */
- /** @brief The bits[ 256]. */
- UINT32 bits[256]; /* bit match values */
- /** @brief The mask[ 256]. */
- UINT32 mask[256]; /* bit mask values */
- /** @brief The baselookup[ 65536]. */
- UINT16 baselookup[65536]; /* base lookup table */
- /** @brief The extralookup. */
- UINT16 * extralookup; /* extra lookup tables */
-};
+class avi_stream
+{
+public:
+ avi_stream()
+ : m_type(0)
+ , m_format(0)
+ , m_rate(0)
+ , m_scale(0)
+ , m_samples(0)
+ , m_chunks()
+ , m_width(0)
+ , m_height(0)
+ , m_depth(0)
+ , m_interlace(0)
+ , m_huffyuv()
+ , m_channels(0)
+ , m_samplebits(0)
+ , m_samplerate(0)
+ , m_saved_strh_offset(0)
+ , m_saved_indx_offset(0)
+ {
+ }
-/**
- * @struct huffyuv_data
- *
- * @brief A huffyuv data.
- */
+ void initialize_video(avi_file::movie_info const &info)
+ {
+ m_type = STREAMTYPE_VIDS;
+ m_format = info.video_format;
+ m_rate = info.video_timescale;
+ m_scale = info.video_sampletime;
+ m_width = info.video_width;
+ m_height = info.video_height;
+ m_depth = info.video_depth;
+ }
-struct huffyuv_data
-{
- /** @brief The predictor. */
- UINT8 predictor; /* predictor */
- /** @brief The table[ 3]. */
- huffyuv_table table[3]; /* array of tables */
-};
+ void initialize_audio(avi_file::movie_info const &info)
+ {
+ m_type = STREAMTYPE_AUDS;
+ m_format = info.audio_format;
+ m_rate = info.audio_timescale;
+ m_scale = info.audio_sampletime;
+ m_channels = info.audio_channels;
+ m_samplebits = info.audio_samplebits;
+ m_samplerate = info.audio_samplerate;
+ }
-/**
- * @struct avi_stream
- *
- * @brief An avi stream.
- */
+ std::uint32_t type() const { return m_type; }
+ std::uint32_t format() const { return m_format; }
+
+ std::uint32_t rate() const { return m_rate; }
+ std::uint32_t scale() const { return m_scale; }
+ std::uint32_t samples() const { return m_samples; }
+ void set_samples(std::uint32_t value) { m_samples = value; }
+ std::uint32_t add_samples(std::uint32_t value) { return m_samples += value; }
+
+ std::uint32_t chunks() const { return m_chunks.size(); }
+ avi_chunk_list const &chunk(std::uint32_t index) const { assert(index < m_chunks.size()); return m_chunks[index]; }
+ avi_chunk_list &chunk(std::uint32_t index) { assert(index < m_chunks.size()); return m_chunks[index]; }
+ avi_file::error set_chunk_info(std::uint32_t index, std::uint64_t offset, std::uint32_t length);
+ void set_chunks(std::uint32_t count) { assert(count <= m_chunks.size()); m_chunks.resize(count); }
+
+ std::uint32_t width() const { return m_width; }
+ std::uint32_t height() const { return m_height; }
+ std::uint32_t depth() const { return m_depth; }
+
+ std::uint16_t channels() const { return m_channels; }
+ std::uint16_t samplebits() const { return m_samplebits; }
+ std::uint32_t samplerate() const { return m_samplerate; }
+ std::uint32_t bytes_per_sample() const { return (m_samplebits / 8) * m_channels; }
+
+ avi_file::error set_strh_data(std::uint8_t const *data, std::uint32_t size);
+ avi_file::error set_strf_data(std::uint8_t const *data, std::uint32_t size);
+
+ std::uint64_t &saved_strh_offset() { return m_saved_strh_offset; }
+ std::uint64_t &saved_indx_offset() { return m_saved_indx_offset; }
+
+ // RGB helpers
+ avi_file::error rgb32_compress_to_rgb(const bitmap_rgb32 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const;
+
+ // YUY helpers
+ avi_file::error yuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const;
+ avi_file::error yuy16_compress_to_yuy(const bitmap_yuy16 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const;
+
+ // HuffYUV helpers
+ avi_file::error huffyuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const;
+
+private:
+ struct huffyuv_table
+ {
+ std::uint8_t shift[256]; /* bit shift amounts */
+ std::uint32_t bits[256]; /* bit match values */
+ std::uint32_t mask[256]; /* bit mask values */
+ std::uint16_t baselookup[65536]; /* base lookup table */
+ std::vector<std::uint16_t> extralookup; /* extra lookup tables */
+ };
+
+ struct huffyuv_data
+ {
+ std::uint8_t predictor; /* predictor */
+ huffyuv_table table[3]; /* array of tables */
+ };
-struct avi_stream
-{
- /** @brief The type. */
- UINT32 type; /* subtype of stream */
- /** @brief Describes the format to use. */
- UINT32 format; /* format of stream data */
-
- /** @brief The rate. */
- UINT32 rate; /* timescale for stream */
- /** @brief The scale. */
- UINT32 scale; /* duration of one sample in the stream */
- /** @brief The samples. */
- UINT32 samples; /* number of samples */
-
- /** @brief The chunk. */
- avi_chunk_list * chunk; /* list of chunks */
- /** @brief The chunks. */
- UINT32 chunks; /* chunks currently known */
- /** @brief The chunksalloc. */
- UINT32 chunksalloc; /* number of chunks allocated */
-
- /** @brief The width. */
- UINT32 width; /* width of video */
- /** @brief The height. */
- UINT32 height; /* height of video */
- /** @brief The depth. */
- UINT32 depth; /* depth of video */
- /** @brief The interlace. */
- UINT8 interlace; /* interlace parameters */
- /** @brief The huffyuv. */
- huffyuv_data * huffyuv; /* huffyuv decompression data */
-
- /** @brief The channels. */
- UINT16 channels; /* audio channels */
- /** @brief The samplebits. */
- UINT16 samplebits; /* audio bits per sample */
- /** @brief The samplerate. */
- UINT32 samplerate; /* audio sample rate */
+ avi_file::error huffyuv_extract_tables(const std::uint8_t *chunkdata, std::uint32_t size);
+
+ std::uint32_t m_type; /* subtype of stream */
+ std::uint32_t m_format; /* format of stream data */
+
+ std::uint32_t m_rate; /* timescale for stream */
+ std::uint32_t m_scale; /* duration of one sample in the stream */
+ std::uint32_t m_samples; /* number of samples */
+
+ std::vector<avi_chunk_list> m_chunks; /* list of chunks */
+
+ std::uint32_t m_width; /* width of video */
+ std::uint32_t m_height; /* height of video */
+ std::uint32_t m_depth; /* depth of video */
+ std::uint8_t m_interlace; /* interlace parameters */
+ std::unique_ptr<huffyuv_data const> m_huffyuv; /* huffyuv decompression data */
+
+ std::uint16_t m_channels; /* audio channels */
+ std::uint16_t m_samplebits; /* audio bits per sample */
+ std::uint32_t m_samplerate; /* audio sample rate */
/* only used when creating */
- /** @brief The saved strh offset. */
- UINT64 saved_strh_offset; /* writeoffset of strh chunk */
- /** @brief The saved indx offset. */
- UINT64 saved_indx_offset; /* writeoffset of indx chunk */
+ std::uint64_t m_saved_strh_offset; /* writeoffset of strh chunk */
+ std::uint64_t m_saved_indx_offset; /* writeoffset of indx chunk */
};
/**
- * @struct avi_file
+ * @class avi_file_impl
*
* @brief An avi file.
*/
-struct avi_file
+class avi_file_impl : public avi_file
{
- /* shared data */
- /** @brief The file. */
- osd_file * file; /* pointer to open file */
- /** @brief The type. */
- int type; /* type of access (read/create) */
- /** @brief The information. */
- avi_movie_info info; /* movie info structure */
- /** @brief The tempbuffer. */
- UINT8 * tempbuffer; /* temporary buffer */
- /** @brief The tempbuffersize. */
- UINT32 tempbuffersize; /* size of the temporary buffer */
-
- /* only used when reading */
- /** @brief The streams. */
- int streams; /* number of streams */
- /** @brief The stream. */
- avi_stream * stream; /* allocated array of stream information */
- /** @brief The rootchunk. */
- avi_chunk rootchunk; /* dummy root chunk that wraps the whole file */
-
- /* only used when creating */
- /** @brief The writeoffs. */
- UINT64 writeoffs; /* current file write offset */
- /** @brief The riffbase. */
- UINT64 riffbase; /* base of the current RIFF */
-
- /** @brief The chunkstack[ 8]. */
- avi_chunk chunkstack[8]; /* stack of chunks we are writing */
- /** @brief The chunksp. */
- int chunksp; /* stack pointer for the current chunk */
-
- /** @brief The saved movi offset. */
- UINT64 saved_movi_offset; /* writeoffset of movi list */
- /** @brief The saved avih offset. */
- UINT64 saved_avih_offset; /* writeoffset of avih chunk */
-
- /** @brief The soundbuf. */
- INT16 * soundbuf; /* buffer for sound data */
- /** @brief The soundbuf samples. */
- UINT32 soundbuf_samples; /* length of sound buffer in samples */
- /** @brief The soundbuf chansamples[ maximum sound channels]. */
- UINT32 soundbuf_chansamples[MAX_SOUND_CHANNELS]; /* samples in buffer for each channel */
- /** @brief The soundbuf chunks. */
- UINT32 soundbuf_chunks; /* number of chunks completed so far */
- /** @brief The soundbuf frames. */
- UINT32 soundbuf_frames; /* number of frames ahead of the video */
-};
-
+public:
+ avi_file_impl(osd_file::ptr &&file, std::uint64_t length) : avi_file_impl()
+ {
+ m_file = std::move(file);
+ m_type = FILETYPE_READ;
+
+ // make a root atom
+ m_rootchunk.offset = 0;
+ m_rootchunk.size = length;
+ m_rootchunk.type = 0;
+ m_rootchunk.listtype = 0;
+ }
+ avi_file_impl(osd_file::ptr &&file, movie_info const &info) : avi_file_impl()
+ {
+ m_file = std::move(file);
+ m_type = FILETYPE_CREATE;
-/***************************************************************************
- PROTOTYPES
-***************************************************************************/
+ // copy the movie info
+ m_info = info;
+ m_info.video_numsamples = 0;
+ m_info.audio_numsamples = 0;
-/* stream helpers */
+ // initialize the video track
+ m_streams.emplace_back();
+ m_streams.back().initialize_video(m_info);
-/* core chunk read routines */
-static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk);
-static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk);
-static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result);
-static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result);
-static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset);
-static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer);
+ // initialize the audio track
+ if (m_info.audio_channels > 0)
+ {
+ m_streams.emplace_back();
+ m_streams.back().initialize_audio(m_info);
+ }
+ }
-/* chunk read helpers */
-static avi_error read_movie_data(avi_file *file);
-static avi_error extract_movie_info(avi_file *file);
-static avi_error parse_avih_chunk(avi_file *file, avi_chunk *avih);
-static avi_error parse_strh_chunk(avi_file *file, avi_stream *stream, avi_chunk *strh);
-static avi_error parse_strf_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf);
-static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf);
-static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1);
+ virtual ~avi_file_impl() override;
+
+ virtual void printf_chunks() override;
+
+ virtual movie_info const &get_movie_info() const override;
+ virtual std::uint32_t first_sample_in_frame(std::uint32_t framenum) const override;
+
+ virtual error read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap) override;
+ virtual error read_sound_samples(int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output) override;
+
+ virtual error append_video_frame(bitmap_yuy16 &bitmap) override;
+ virtual error append_video_frame(bitmap_rgb32 &bitmap) override;
+ virtual error append_sound_samples(int channel, std::int16_t const *samples, std::uint32_t numsamples, std::uint32_t sampleskip) override;
+
+ error read_movie_data();
+ error write_initial_headers();
+ error soundbuf_initialize();
+
+private:
+ avi_file_impl()
+ : m_file()
+ , m_type(0)
+ , m_info({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })
+ , m_tempbuffer()
+ , m_streams()
+ , m_rootchunk()
+ , m_writeoffs(0)
+ , m_riffbase(0)
+ , m_chunkstack()
+ , m_chunksp(0)
+ , m_saved_movi_offset(0)
+ , m_saved_avih_offset(0)
+ , m_soundbuf()
+ , m_soundbuf_samples(0)
+ , m_soundbuf_chansamples{ 0 }
+ , m_soundbuf_chunks(0)
+ , m_soundbuf_frames(0)
+ {
+ }
-/* core chunk write routines */
-static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength);
-static avi_error chunk_close(avi_file *file);
-static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length);
-static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write);
+ avi_stream *get_video_stream();
+ avi_stream *get_audio_stream(int channel, int &offset);
+ std::uint32_t compute_idx1_size() const;
+ std::uint32_t get_chunkid_for_stream(const avi_stream *stream) const;
+ std::uint32_t framenum_to_samplenum(std::uint32_t framenum) const;
+ error expand_tempbuffer(std::uint32_t length);
+
+ // core chunk read routines
+ error get_first_chunk(avi_chunk const *parent, avi_chunk &newchunk);
+ error get_next_chunk(avi_chunk const *parent, avi_chunk &newchunk);
+ error find_first_chunk(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error find_next_chunk(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error find_first_list(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error find_next_list(std::uint32_t findme, avi_chunk const *container, avi_chunk &result);
+ error get_next_chunk_internal(avi_chunk const *parent, avi_chunk &newchunk, std::uint64_t offset);
+ error read_chunk_data(avi_chunk const &chunk, std::unique_ptr<std::uint8_t []> &buffer);
+
+ // chunk read helpers
+ error extract_movie_info();
+ error parse_avih_chunk(avi_chunk const &avih);
+ error parse_strh_chunk(avi_stream &stream, avi_chunk const &strh);
+ error parse_strf_chunk(avi_stream &stream, avi_chunk const &strf);
+ error parse_indx_chunk(avi_stream &stream, avi_chunk const &strf);
+ error parse_idx1_chunk(std::uint64_t baseoffset, avi_chunk const &idx1);
+
+ // core chunk write routines
+ error chunk_open(std::uint32_t type, std::uint32_t listtype, std::uint32_t estlength);
+ error chunk_close();
+ error chunk_write(std::uint32_t type, const void *data, std::uint32_t length);
+ error chunk_overwrite(std::uint32_t type, const void *data, std::uint32_t length, std::uint64_t &offset, bool initial_write);
+
+ // chunk write helpers
+ error write_avih_chunk(bool initial_write);
+ error write_strh_chunk(avi_stream &stream, bool initial_write);
+ error write_strf_chunk(avi_stream const &stream);
+ error write_indx_chunk(avi_stream &stream, bool initial_write);
+ error write_idx1_chunk();
+
+ // sound buffering helpers
+ error soundbuf_write_chunk(std::uint32_t framenum);
+ error soundbuf_flush(bool only_flush_full);
+
+ // debugging
+ void printf_chunk_recursive(avi_chunk const *chunk, int indent);
-/* chunk write helpers */
-static avi_error write_initial_headers(avi_file *file);
-static avi_error write_avih_chunk(avi_file *file, int initial_write);
-static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initial_write);
-static avi_error write_strf_chunk(avi_file *file, avi_stream *stream);
-static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initial_write);
-static avi_error write_idx1_chunk(avi_file *file);
+ /* shared data */
+ osd_file::ptr m_file; /* pointer to open file */
+ int m_type; /* type of access (read/create) */
+ movie_info m_info; /* movie info structure */
+ std::vector<std::uint8_t> m_tempbuffer; /* temporary buffer */
-/* sound buffering helpers */
-static avi_error soundbuf_initialize(avi_file *file);
-static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum);
-static avi_error soundbuf_flush(avi_file *file, int only_flush_full);
+ /* only used when reading */
+ std::vector<avi_stream> m_streams; /* allocated array of stream information */
+ avi_chunk m_rootchunk; /* dummy root chunk that wraps the whole file */
-/* RGB helpers */
-static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, UINT8 *data, UINT32 numbytes);
+ /* only used when creating */
+ std::uint64_t m_writeoffs; /* current file write offset */
+ std::uint64_t m_riffbase; /* base of the current RIFF */
-/* YUY helpers */
-static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap);
-static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, UINT8 *data, UINT32 numbytes);
+ std::array<avi_chunk, 8> m_chunkstack; /* stack of chunks we are writing */
+ int m_chunksp; /* stack pointer for the current chunk */
-/* HuffYUV helpers */
-static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size);
-static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap);
+ std::uint64_t m_saved_movi_offset; /* writeoffset of movi list */
+ std::uint64_t m_saved_avih_offset; /* writeoffset of avih chunk */
-/* debugging */
-static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent);
+ std::vector<std::int16_t> m_soundbuf; /* buffer for sound data */
+ std::uint32_t m_soundbuf_samples; /* length of sound buffer in samples */
+ std::uint32_t m_soundbuf_chansamples[MAX_SOUND_CHANNELS]; /* samples in buffer for each channel */
+ std::uint32_t m_soundbuf_chunks; /* number of chunks completed so far */
+ std::uint32_t m_soundbuf_frames; /* number of frames ahead of the video */
+};
@@ -471,7 +557,7 @@ static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent)
-------------------------------------------------*/
/**
- * @fn static inline UINT16 fetch_16bits(const UINT8 *data)
+ * @fn static inline std::uint16_t fetch_16bits(const std::uint8_t *data)
*
* @brief Fetches the 16bits.
*
@@ -480,7 +566,7 @@ static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent)
* @return The 16bits.
*/
-static inline UINT16 fetch_16bits(const UINT8 *data)
+inline std::uint16_t fetch_16bits(const std::uint8_t *data)
{
return data[0] | (data[1] << 8);
}
@@ -492,7 +578,7 @@ static inline UINT16 fetch_16bits(const UINT8 *data)
-------------------------------------------------*/
/**
- * @fn static inline UINT32 fetch_32bits(const UINT8 *data)
+ * @fn static inline std::uint32_t fetch_32bits(const std::uint8_t *data)
*
* @brief Fetches the 32bits.
*
@@ -501,7 +587,7 @@ static inline UINT16 fetch_16bits(const UINT8 *data)
* @return The 32bits.
*/
-static inline UINT32 fetch_32bits(const UINT8 *data)
+inline std::uint32_t fetch_32bits(const std::uint8_t *data)
{
return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
}
@@ -513,7 +599,7 @@ static inline UINT32 fetch_32bits(const UINT8 *data)
-------------------------------------------------*/
/**
- * @fn static inline UINT64 fetch_64bits(const UINT8 *data)
+ * @fn static inline std::uint64_t fetch_64bits(const std::uint8_t *data)
*
* @brief Fetches the 64bits.
*
@@ -522,12 +608,12 @@ static inline UINT32 fetch_32bits(const UINT8 *data)
* @return The 64bits.
*/
-static inline UINT64 fetch_64bits(const UINT8 *data)
+inline std::uint64_t fetch_64bits(const std::uint8_t *data)
{
- return (UINT64)data[0] | ((UINT64)data[1] << 8) |
- ((UINT64)data[2] << 16) | ((UINT64)data[3] << 24) |
- ((UINT64)data[4] << 32) | ((UINT64)data[5] << 40) |
- ((UINT64)data[6] << 48) | ((UINT64)data[7] << 56);
+ return std::uint64_t(data[0]) | (std::uint64_t(data[1]) << 8) |
+ (std::uint64_t(data[2]) << 16) | (std::uint64_t(data[3]) << 24) |
+ (std::uint64_t(data[4]) << 32) | (std::uint64_t(data[5]) << 40) |
+ (std::uint64_t(data[6]) << 48) | (std::uint64_t(data[7]) << 56);
}
@@ -537,7 +623,7 @@ static inline UINT64 fetch_64bits(const UINT8 *data)
-------------------------------------------------*/
/**
- * @fn static inline void put_16bits(UINT8 *data, UINT16 value)
+ * @fn static inline void put_16bits(std::uint8_t *data, std::uint16_t value)
*
* @brief Puts the 16bits.
*
@@ -545,7 +631,7 @@ static inline UINT64 fetch_64bits(const UINT8 *data)
* @param value The value.
*/
-static inline void put_16bits(UINT8 *data, UINT16 value)
+inline void put_16bits(std::uint8_t *data, std::uint16_t value)
{
data[0] = value >> 0;
data[1] = value >> 8;
@@ -558,7 +644,7 @@ static inline void put_16bits(UINT8 *data, UINT16 value)
-------------------------------------------------*/
/**
- * @fn static inline void put_32bits(UINT8 *data, UINT32 value)
+ * @fn static inline void put_32bits(std::uint8_t *data, std::uint32_t value)
*
* @brief Puts the 32bits.
*
@@ -566,7 +652,7 @@ static inline void put_16bits(UINT8 *data, UINT16 value)
* @param value The value.
*/
-static inline void put_32bits(UINT8 *data, UINT32 value)
+inline void put_32bits(std::uint8_t *data, std::uint32_t value)
{
data[0] = value >> 0;
data[1] = value >> 8;
@@ -581,7 +667,7 @@ static inline void put_32bits(UINT8 *data, UINT32 value)
-------------------------------------------------*/
/**
- * @fn static inline void put_64bits(UINT8 *data, UINT64 value)
+ * @fn static inline void put_64bits(std::uint8_t *data, std::uint64_t value)
*
* @brief Puts the 64bits.
*
@@ -589,7 +675,7 @@ static inline void put_32bits(UINT8 *data, UINT32 value)
* @param value The value.
*/
-static inline void put_64bits(UINT8 *data, UINT64 value)
+inline void put_64bits(std::uint8_t *data, std::uint64_t value)
{
data[0] = value >> 0;
data[1] = value >> 8;
@@ -602,29 +688,120 @@ static inline void put_64bits(UINT8 *data, UINT64 value)
}
+/**
+ * @fn static void u64toa(std::uint64_t val, char *output)
+ *
+ * @brief 64toas.
+ *
+ * @param val The value.
+ * @param [in,out] output If non-null, the output.
+ */
+
+inline void u64toa(std::uint64_t val, char *output)
+{
+ std::uint32_t lo = std::uint32_t(val & 0xffffffff);
+ std::uint32_t hi = std::uint32_t(val >> 32);
+ if (hi != 0)
+ sprintf(output, "%X%08X", hi, lo);
+ else
+ sprintf(output, "%X", lo);
+}
+
+
+/*-------------------------------------------------
+ set_stream_chunk_info - set the chunk info
+ for a given chunk within a stream
+-------------------------------------------------*/
+
+/**
+ * @fn static inline avi_error set_stream_chunk_info(avi_stream *stream, std::uint32_t index, std::uint64_t offset, std::uint32_t length)
+ *
+ * @brief Sets stream chunk information.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param index Zero-based index of the.
+ * @param offset The offset.
+ * @param length The length.
+ *
+ * @return An avi_error.
+ */
+
+inline avi_file::error avi_stream::set_chunk_info(std::uint32_t index, std::uint64_t offset, std::uint32_t length)
+{
+ /* if we need to allocate more, allocate more */
+ if (index >= m_chunks.capacity())
+ {
+ try { m_chunks.reserve((std::max<std::size_t>)(index, m_chunks.capacity() + 1000)); }
+ catch (...) { return avi_file::error::NO_MEMORY; }
+ }
+
+ /* update the number of chunks */
+ m_chunks.resize((std::max<std::size_t>)(m_chunks.size(), index + 1));
+
+ /* set the data */
+ m_chunks[index].offset = offset;
+ m_chunks[index].length = length;
+
+ return avi_file::error::NONE;
+}
+
+
+inline avi_file::error avi_stream::set_strh_data(std::uint8_t const *data, std::uint32_t size)
+{
+ m_type = fetch_32bits(&data[0]);
+ m_scale = fetch_32bits(&data[20]);
+ m_rate = fetch_32bits(&data[24]);
+ m_samples = fetch_32bits(&data[32]);
+ return avi_file::error::NONE;
+}
+
+
+inline avi_file::error avi_stream::set_strf_data(std::uint8_t const *data, std::uint32_t size)
+{
+ /* audio and video streams have differing headers */
+ if (m_type == STREAMTYPE_VIDS)
+ {
+ m_width = fetch_32bits(&data[4]);
+ m_height = fetch_32bits(&data[8]);
+ m_depth = fetch_16bits(&data[14]);
+ m_format = fetch_32bits(&data[16]);
+
+ /* extra extraction for HuffYUV data */
+ if ((m_format == FORMAT_HFYU) && (size >= 56))
+ {
+ avi_file::error const avierr = huffyuv_extract_tables(data, size);
+ if (avierr != avi_file::error::NONE)
+ return avierr;
+ }
+ }
+ else if (m_type == STREAMTYPE_AUDS)
+ {
+ m_channels = fetch_16bits(&data[2]);
+ m_samplebits = fetch_16bits(&data[14]);
+ m_samplerate = fetch_32bits(&data[4]);
+ }
+ return avi_file::error::NONE;
+}
+
+
/*-------------------------------------------------
get_video_stream - return a pointer to the
video stream
-------------------------------------------------*/
/**
- * @fn static inline avi_stream *get_video_stream(avi_file *file)
+ * @fn static inline avi_stream *get_video_stream()
*
* @brief Gets video stream.
*
- * @param [in,out] file If non-null, the file.
- *
* @return null if it fails, else the video stream.
*/
-static inline avi_stream *get_video_stream(avi_file *file)
+inline avi_stream *avi_file_impl::get_video_stream()
{
- int streamnum;
-
- /* find the video stream */
- for (streamnum = 0; streamnum < file->streams; streamnum++)
- if (file->stream[streamnum].type == STREAMTYPE_VIDS)
- return &file->stream[streamnum];
+ for (int streamnum = 0; streamnum < m_streams.size(); streamnum++)
+ if (m_streams[streamnum].type() == STREAMTYPE_VIDS)
+ return &m_streams[streamnum];
return nullptr;
}
@@ -647,21 +824,18 @@ static inline avi_stream *get_video_stream(avi_file *file)
* @return null if it fails, else the audio stream.
*/
-static inline avi_stream *get_audio_stream(avi_file *file, int channel, int *offset)
+inline avi_stream *avi_file_impl::get_audio_stream(int channel, int &offset)
{
- int streamnum;
-
/* find the audios stream */
- for (streamnum = 0; streamnum < file->streams; streamnum++)
- if (file->stream[streamnum].type == STREAMTYPE_AUDS)
+ for (int streamnum = 0; streamnum < m_streams.size(); streamnum++)
+ if (m_streams[streamnum].type() == STREAMTYPE_AUDS)
{
- if (channel < file->stream[streamnum].channels)
+ if (channel < m_streams[streamnum].channels())
{
- if (offset != nullptr)
- *offset = channel;
- return &file->stream[streamnum];
+ offset = channel;
+ return &m_streams[streamnum];
}
- channel -= file->stream[streamnum].channels;
+ channel -= m_streams[streamnum].channels();
}
return nullptr;
@@ -669,58 +843,12 @@ static inline avi_stream *get_audio_stream(avi_file *file, int channel, int *off
/*-------------------------------------------------
- set_stream_chunk_info - set the chunk info
- for a given chunk within a stream
--------------------------------------------------*/
-
-/**
- * @fn static inline avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index, UINT64 offset, UINT32 length)
- *
- * @brief Sets stream chunk information.
- *
- * @param [in,out] stream If non-null, the stream.
- * @param index Zero-based index of the.
- * @param offset The offset.
- * @param length The length.
- *
- * @return An avi_error.
- */
-
-static inline avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index, UINT64 offset, UINT32 length)
-{
- /* if we need to allocate more, allocate more */
- if (index >= stream->chunksalloc)
- {
- UINT32 newcount = MAX(index, stream->chunksalloc + 1000);
- avi_chunk_list *newchunks = (avi_chunk_list *)malloc(newcount * sizeof(stream->chunk[0]));
- if (newchunks == nullptr)
- return AVIERR_NO_MEMORY;
- if (stream->chunk != nullptr)
- {
- memcpy(newchunks, stream->chunk, stream->chunksalloc * sizeof(stream->chunk[0]));
- free(stream->chunk);
- }
- stream->chunk = newchunks;
- stream->chunksalloc = newcount;
- }
-
- /* set the data */
- stream->chunk[index].offset = offset;
- stream->chunk[index].length = length;
-
- /* update the number of chunks */
- stream->chunks = MAX(stream->chunks, index + 1);
- return AVIERR_NONE;
-}
-
-
-/*-------------------------------------------------
compute_idx1_size - compute the size of the
idx1 chunk
-------------------------------------------------*/
/**
- * @fn static inline UINT32 compute_idx1_size(avi_file *file)
+ * @fn static inline std::uint32_t compute_idx1_size(avi_file *file)
*
* @brief Calculates the index 1 size.
*
@@ -729,14 +857,13 @@ static inline avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index,
* @return The calculated index 1 size.
*/
-static inline UINT32 compute_idx1_size(avi_file *file)
+inline std::uint32_t avi_file_impl::compute_idx1_size() const
{
int chunks = 0;
- int strnum;
/* count chunks in streams */
- for (strnum = 0; strnum < file->streams; strnum++)
- chunks += file->stream[strnum].chunks;
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
+ chunks += m_streams[strnum].chunks();
return chunks * 16 + 8;
}
@@ -748,7 +875,7 @@ static inline UINT32 compute_idx1_size(avi_file *file)
-------------------------------------------------*/
/**
- * @fn static inline UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
+ * @fn static inline std::uint32_t get_chunkid_for_stream(avi_file *file, avi_stream *stream)
*
* @brief Gets chunkid for stream.
*
@@ -758,14 +885,14 @@ static inline UINT32 compute_idx1_size(avi_file *file)
* @return The chunkid for stream.
*/
-static inline UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
+inline std::uint32_t avi_file_impl::get_chunkid_for_stream(const avi_stream *stream) const
{
- UINT32 chunkid;
+ std::uint32_t chunkid;
- chunkid = AVI_FOURCC('0' + (stream - file->stream) / 10, '0' + (stream - file->stream) % 10, 0, 0);
- if (stream->type == STREAMTYPE_VIDS)
- chunkid |= (stream->format == 0) ? CHUNKTYPE_XXDB : CHUNKTYPE_XXDC;
- else if (stream->type == STREAMTYPE_AUDS)
+ chunkid = AVI_FOURCC('0' + (stream - &m_streams[0]) / 10, '0' + (stream - &m_streams[0]) % 10, 0, 0);
+ if (stream->type() == STREAMTYPE_VIDS)
+ chunkid |= (stream->format() == 0) ? CHUNKTYPE_XXDB : CHUNKTYPE_XXDC;
+ else if (stream->type() == STREAMTYPE_AUDS)
chunkid |= CHUNKTYPE_XXWB;
return chunkid;
@@ -778,19 +905,19 @@ static inline UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
-------------------------------------------------*/
/**
- * @fn static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
+ * @fn static inline std::uint32_t framenum_to_samplenum(avi_file *file, std::uint32_t framenum)
*
* @brief Framenum to samplenum.
*
* @param [in,out] file If non-null, the file.
* @param framenum The framenum.
*
- * @return An UINT32.
+ * @return An std::uint32_t.
*/
-static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
+inline std::uint32_t avi_file_impl::framenum_to_samplenum(std::uint32_t framenum) const
{
- return ((UINT64)file->info.audio_samplerate * (UINT64)framenum * (UINT64)file->info.video_sampletime + file->info.video_timescale - 1) / (UINT64)file->info.video_timescale;
+ return (std::uint64_t(m_info.audio_samplerate) * std::uint64_t(framenum) * std::uint64_t(m_info.video_sampletime) + m_info.video_timescale - 1) / std::uint64_t(m_info.video_timescale);
}
@@ -801,7 +928,7 @@ static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
-------------------------------------------------*/
/**
- * @fn static inline avi_error expand_tempbuffer(avi_file *file, UINT32 length)
+ * @fn static inline avi_error expand_tempbuffer(avi_file *file, std::uint32_t length)
*
* @brief Expand tempbuffer.
*
@@ -811,207 +938,532 @@ static inline UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
* @return An avi_error.
*/
-static inline avi_error expand_tempbuffer(avi_file *file, UINT32 length)
+inline avi_file::error avi_file_impl::expand_tempbuffer(std::uint32_t length)
{
/* expand the tempbuffer to hold the data if necessary */
- if (length > file->tempbuffersize)
+ if (length > m_tempbuffer.size())
{
- file->tempbuffersize = 2 * length;
- UINT8 *newbuffer = (UINT8 *)malloc(file->tempbuffersize);
- if (newbuffer == nullptr)
- return AVIERR_NO_MEMORY;
- if (file->tempbuffer != nullptr)
- free(file->tempbuffer);
- file->tempbuffer = newbuffer;
+ try { m_tempbuffer.resize(2 * length); }
+ catch (...) { return error::NO_MEMORY; }
}
- return AVIERR_NONE;
+ return error::NONE;
}
+/*-------------------------------------------------
+ rgb32_compress_to_rgb - "compress" an RGB32
+ bitmap to an RGB encoded frame
+-------------------------------------------------*/
+
+/**
+ * @fn static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, std::uint8_t *data, std::uint32_t numbytes)
+ *
+ * @brief RGB 32 compress to RGB.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param bitmap The bitmap.
+ * @param [in,out] data If non-null, the data.
+ * @param numbytes The numbytes.
+ *
+ * @return An avi_error.
+ */
+
+avi_file::error avi_stream::rgb32_compress_to_rgb(const bitmap_rgb32 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const
+{
+ int const height = (std::min<int>)(m_height, bitmap.height());
+ int const width = (std::min<int>)(m_width, bitmap.width());
+ std::uint8_t *const dataend = data + numbytes;
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < height; y++)
+ {
+ const std::uint32_t *source = &bitmap.pix32(y);
+ std::uint8_t *dest = data + (m_height - 1 - y) * m_width * 3;
+
+ for (x = 0; x < width && dest < dataend; x++)
+ {
+ rgb_t pix = *source++;
+ *dest++ = pix.b();
+ *dest++ = pix.g();
+ *dest++ = pix.r();
+ }
+
+ /* fill in any blank space on the right */
+ for ( ; x < m_width && dest < dataend; x++)
+ {
+ *dest++ = 0;
+ *dest++ = 0;
+ *dest++ = 0;
+ }
+ }
+
+ /* fill in any blank space on the bottom */
+ for ( ; y < m_height; y++)
+ {
+ std::uint8_t *dest = data + (m_height - 1 - y) * m_width * 3;
+ for (x = 0; x < m_width && dest < dataend; x++)
+ {
+ *dest++ = 0;
+ *dest++ = 0;
+ *dest++ = 0;
+ }
+ }
+
+ return avi_file::error::NONE;
+}
-/***************************************************************************
- IMPLEMENTATION
-***************************************************************************/
/*-------------------------------------------------
- avi_open - open an AVI movie file for read
+ yuv_decompress_to_yuy16 - decompress a YUV
+ encoded frame to a YUY16 bitmap
-------------------------------------------------*/
/**
- * @fn avi_error avi_open(const char *filename, avi_file **file)
+ * @fn static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap)
*
- * @brief Queries if a given avi open.
+ * @brief Yuv decompress to yuy 16.
*
- * @param filename Filename of the file.
- * @param [in,out] file If non-null, the file.
+ * @param [in,out] stream If non-null, the stream.
+ * @param data The data.
+ * @param numbytes The numbytes.
+ * @param [in,out] bitmap The bitmap.
*
* @return An avi_error.
*/
-avi_error avi_open(const char *filename, avi_file **file)
+avi_file::error avi_stream::yuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const
{
- avi_file *newfile = nullptr;
- file_error filerr;
- avi_error avierr;
- UINT64 length;
-
- /* allocate the file */
- newfile = (avi_file *)malloc(sizeof(*newfile));
- if (newfile == nullptr)
- return AVIERR_NO_MEMORY;
- memset(newfile, 0, sizeof(*newfile));
- newfile->type = FILETYPE_READ;
+ std::uint16_t const *const dataend = reinterpret_cast<const std::uint16_t *>(data + numbytes);
+ int x, y;
- /* open the file */
- filerr = osd_open(filename, OPEN_FLAG_READ, &newfile->file, &length);
- if (filerr != FILERR_NONE)
+ /* compressed video */
+ for (y = 0; y < m_height; y++)
{
- avierr = AVIERR_CANT_OPEN_FILE;
- goto error;
+ const std::uint16_t *source = reinterpret_cast<const std::uint16_t *>(data) + y * m_width;
+ std::uint16_t *dest = &bitmap.pix16(y);
+
+ /* switch off the compression */
+ switch (m_format)
+ {
+ case FORMAT_UYVY:
+ for (x = 0; x < m_width && source < dataend; x++)
+ *dest++ = *source++;
+ break;
+
+ case FORMAT_VYUY:
+ case FORMAT_YUY2:
+ for (x = 0; x < m_width && source < dataend; x++)
+ {
+ std::uint16_t pix = *source++;
+ *dest++ = (pix >> 8) | (pix << 8);
+ }
+ break;
+ }
}
- /* make a root atom */
- newfile->rootchunk.offset = 0;
- newfile->rootchunk.size = length;
- newfile->rootchunk.type = 0;
- newfile->rootchunk.listtype = 0;
+ return avi_file::error::NONE;
+}
- /* parse the data */
- avierr = read_movie_data(newfile);
- if (avierr != AVIERR_NONE)
- goto error;
- *file = newfile;
- return AVIERR_NONE;
+/*-------------------------------------------------
+ yuy16_compress_to_yuy - "compress" a YUY16
+ bitmap to a YUV encoded frame
+-------------------------------------------------*/
-error:
- /* clean up after an error */
- if (newfile != nullptr)
+/**
+ * @fn static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, std::uint8_t *data, std::uint32_t numbytes)
+ *
+ * @brief Yuy 16 compress to yuy.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param bitmap The bitmap.
+ * @param [in,out] data If non-null, the data.
+ * @param numbytes The numbytes.
+ *
+ * @return An avi_error.
+ */
+
+avi_file::error avi_stream::yuy16_compress_to_yuy(const bitmap_yuy16 &bitmap, std::uint8_t *data, std::uint32_t numbytes) const
+{
+ std::uint16_t *const dataend = reinterpret_cast<std::uint16_t *>(data + numbytes);
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < m_height; y++)
{
- if (newfile->file != nullptr)
- osd_close(newfile->file);
- free(newfile);
+ const std::uint16_t *source = &bitmap.pix16(y);
+ std::uint16_t *dest = reinterpret_cast<std::uint16_t *>(data) + y * m_width;
+
+ /* switch off the compression */
+ switch (m_format)
+ {
+ case FORMAT_UYVY:
+ for (x = 0; x < m_width && dest < dataend; x++)
+ *dest++ = *source++;
+ break;
+
+ case FORMAT_VYUY:
+ case FORMAT_YUY2:
+ for (x = 0; x < m_width && dest < dataend; x++)
+ {
+ std::uint16_t pix = *source++;
+ *dest++ = (pix >> 8) | (pix << 8);
+ }
+ break;
+ }
}
- return avierr;
+
+ return avi_file::error::NONE;
}
/*-------------------------------------------------
- avi_create - create a new AVI movie file
+ huffyuv_extract_tables - extract HuffYUV
+ tables
-------------------------------------------------*/
/**
- * @fn avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
+ * @fn static avi_error huffyuv_extract_tables(avi_stream *stream, const std::uint8_t *chunkdata, std::uint32_t size)
*
- * @brief Avi create.
+ * @brief Huffyuv extract tables.
*
- * @param filename Filename of the file.
- * @param info The information.
- * @param [in,out] file If non-null, the file.
+ * @param [in,out] stream If non-null, the stream.
+ * @param chunkdata The chunkdata.
+ * @param size The size.
*
* @return An avi_error.
*/
-avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
+avi_file::error avi_stream::huffyuv_extract_tables(const std::uint8_t *chunkdata, std::uint32_t size)
{
- avi_file *newfile = nullptr;
- file_error filerr;
- avi_stream *stream;
- avi_error avierr;
- UINT64 length;
+ const std::uint8_t *const chunkend = chunkdata + size;
- /* validate video info */
- if ((info->video_format != 0 && info->video_format != FORMAT_UYVY && info->video_format != FORMAT_VYUY && info->video_format != FORMAT_YUY2) ||
- info->video_width == 0 ||
- info->video_height == 0 ||
- info->video_depth == 0 || info->video_depth % 8 != 0)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ /* allocate memory for the data */
+ std::unique_ptr<huffyuv_data> huffyuv;
+ try { huffyuv = std::make_unique<huffyuv_data>(); }
+ catch (...) { return avi_file::error::NO_MEMORY; }
- /* validate audio info */
- if (info->audio_format != 0 ||
- info->audio_channels > MAX_SOUND_CHANNELS ||
- info->audio_samplebits != 16)
- return AVIERR_UNSUPPORTED_AUDIO_FORMAT;
+ /* extract predictor information */
+ if (&chunkdata[40] >= chunkend)
+ return avi_file::error::INVALID_DATA;
+ huffyuv->predictor = chunkdata[40];
- /* allocate the file */
- newfile = (avi_file *)malloc(sizeof(*newfile));
- if (newfile == nullptr)
- return AVIERR_NO_MEMORY;
- memset(newfile, 0, sizeof(*newfile));
- newfile->type = FILETYPE_CREATE;
+ /* make sure it's the left predictor */
+ if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) != HUFFYUV_PREDICT_LEFT)
+ return avi_file::error::UNSUPPORTED_VIDEO_FORMAT;
- /* open the file */
- filerr = osd_open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &newfile->file, &length);
- if (filerr != FILERR_NONE)
+ /* make sure it's 16bpp YUV data */
+ if (chunkdata[41] != 16)
+ return avi_file::error::UNSUPPORTED_VIDEO_FORMAT;
+ chunkdata += 44;
+
+ /* loop over tables */
+ for (int tabnum = 0; tabnum < 3; tabnum++)
{
- avierr = AVIERR_CANT_OPEN_FILE;
- goto error;
+ huffyuv_table &table = huffyuv->table[tabnum];
+ std::uint32_t curbits, bitadd;
+ std::uint16_t bitsat16 = 0;
+ int offset = 0, bits;
+
+ /* loop until we populate the whole table */
+ while (offset < 256)
+ {
+ int data, shift, count, i;
+
+ /* extract the next run */
+ if (chunkdata >= chunkend)
+ return avi_file::error::INVALID_DATA;
+ data = *chunkdata++;
+ shift = data & 0x1f;
+ count = data >> 5;
+
+ /* zero count means next whole byte is a count */
+ if (count == 0)
+ {
+ if (chunkdata >= chunkend)
+ return avi_file::error::INVALID_DATA;
+ count = *chunkdata++;
+ }
+ for (i = 0; i < count; i++)
+ table.shift[offset++] = shift;
+ }
+
+ /* now determine bit patterns and masks */
+ curbits = 0;
+ for (bits = 31; bits >= 0; bits--)
+ {
+ bitadd = 1 << (32 - bits);
+
+ /* make sure we've cleared out all the bits below */
+ if ((curbits & (bitadd - 1)) != 0)
+ return avi_file::error::INVALID_DATA;
+
+ /* find all entries with this shift count and assign them */
+ for (offset = 0; offset < 256; offset++)
+ if (table.shift[offset] == bits)
+ {
+ table.bits[offset] = curbits;
+ table.mask[offset] = ~(bitadd - 1);
+ curbits += bitadd;
+ }
+
+ /* remember the bit pattern when we complete all the 17-bit codes */
+ if (bits == 17)
+ bitsat16 = curbits >> 16;
+ }
+
+ /* allocate the number of extra lookup tables we need */
+ if (bitsat16 > 0)
+ {
+ try { table.extralookup.resize(bitsat16 * 65536); }
+ catch (...) { return avi_file::error::NO_MEMORY; }
+ for (offset = 0; offset < bitsat16; offset++)
+ table.baselookup[offset] = (offset << 8) | 0;
+ }
+
+ /* then create lookup tables */
+ for (offset = 0; offset < 256; offset++)
+ if (table.shift[offset] > 16)
+ {
+ std::uint16_t *tablebase = &table.extralookup[(table.bits[offset] >> 16) * 65536];
+ std::uint32_t start = table.bits[offset] & 0xffff;
+ std::uint32_t end = start + ((1 << (32 - table.shift[offset])) - 1);
+ while (start <= end)
+ tablebase[start++] = (offset << 8) | (table.shift[offset] - 16);
+ }
+ else if (table.shift[offset] > 0)
+ {
+ std::uint32_t start = table.bits[offset] >> 16;
+ std::uint32_t end = start + ((1 << (16 - table.shift[offset])) - 1);
+ while (start <= end)
+ table.baselookup[start++] = (offset << 8) | table.shift[offset];
+ }
}
- /* copy the movie info */
- newfile->info = *info;
- newfile->info.video_numsamples = 0;
- newfile->info.audio_numsamples = 0;
+ m_huffyuv = std::move(huffyuv);
+ return avi_file::error::NONE;
+}
+
- /* allocate two streams */
- newfile->stream = (avi_stream *)malloc(2 * sizeof(newfile->stream[0]));
- if (newfile->stream == nullptr)
+/*-------------------------------------------------
+ huffyuv_decompress_to_yuy16 - decompress a
+ HuffYUV-encoded frame to a YUY16 bitmap
+-------------------------------------------------*/
+
+/**
+ * @fn static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap)
+ *
+ * @brief Huffyuv decompress to yuy 16.
+ *
+ * @param [in,out] stream If non-null, the stream.
+ * @param data The data.
+ * @param numbytes The numbytes.
+ * @param [in,out] bitmap The bitmap.
+ *
+ * @return An avi_error.
+ */
+
+avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data, std::uint32_t numbytes, bitmap_yuy16 &bitmap) const
+{
+ int prevlines = (m_height > 288) ? 2 : 1;
+ std::uint8_t lastprevy = 0, lastprevcb = 0, lastprevcr = 0;
+ std::uint8_t lasty = 0, lastcb = 0, lastcr = 0;
+ std::uint8_t bitsinbuffer = 0;
+ std::uint32_t bitbuffer = 0;
+ std::uint32_t dataoffs = 0;
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < m_height; y++)
{
- avierr = AVIERR_NO_MEMORY;
- goto error;
+ std::uint16_t *dest = &bitmap.pix16(y);
+
+ /* handle the first four bytes independently */
+ x = 0;
+ if (y == 0)
+ {
+ /* first DWORD is stored as YUY2 */
+ lasty = data[dataoffs++];
+ lastcb = data[dataoffs++];
+ *dest++ = (lasty << 8) | lastcb;
+ lasty = data[dataoffs++];
+ lastcr = data[dataoffs++];
+ *dest++ = (lasty << 8) | lastcr;
+ x = 2;
+ }
+
+ /* loop over pixels */
+ for ( ; x < m_width; x++)
+ {
+ huffyuv_table const &ytable = m_huffyuv->table[0];
+ huffyuv_table const &ctable = m_huffyuv->table[1 + (x & 1)];
+ std::uint16_t huffdata;
+ int shift;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ /* look up the Y component */
+ huffdata = ytable.baselookup[bitbuffer >> 16];
+ shift = huffdata & 0xff;
+ if (shift == 0)
+ {
+ bitsinbuffer -= 16;
+ bitbuffer <<= 16;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ huffdata = ytable.extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
+ shift = huffdata & 0xff;
+ }
+ bitsinbuffer -= shift;
+ bitbuffer <<= shift;
+ std::uint16_t const pixel = huffdata & 0xff00;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ /* look up the Cb/Cr component */
+ huffdata = ctable.baselookup[bitbuffer >> 16];
+ shift = huffdata & 0xff;
+ if (shift == 0)
+ {
+ bitsinbuffer -= 16;
+ bitbuffer <<= 16;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ huffdata = ctable.extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
+ shift = huffdata & 0xff;
+ }
+ bitsinbuffer -= shift;
+ bitbuffer <<= shift;
+ *dest++ = pixel | (huffdata >> 8);
+ }
}
- memset(newfile->stream, 0, 2 * sizeof(newfile->stream[0]));
-
- /* initialize the video track */
- stream = &newfile->stream[newfile->streams++];
- stream->type = STREAMTYPE_VIDS;
- stream->format = newfile->info.video_format;
- stream->rate = newfile->info.video_timescale;
- stream->scale = newfile->info.video_sampletime;
- stream->width = newfile->info.video_width;
- stream->height = newfile->info.video_height;
- stream->depth = newfile->info.video_depth;
-
- /* initialize the audio track */
- if (newfile->info.audio_channels > 0)
+
+ /* apply deltas */
+ lastprevy = lastprevcb = lastprevcr = 0;
+ for (y = 0; y < m_height; y++)
{
- stream = &newfile->stream[newfile->streams++];
- stream->type = STREAMTYPE_AUDS;
- stream->format = newfile->info.audio_format;
- stream->rate = newfile->info.audio_timescale;
- stream->scale = newfile->info.audio_sampletime;
- stream->channels = newfile->info.audio_channels;
- stream->samplebits = newfile->info.audio_samplebits;
- stream->samplerate = newfile->info.audio_samplerate;
-
- /* initialize the sound buffering */
- avierr = soundbuf_initialize(newfile);
- if (avierr != AVIERR_NONE)
- goto error;
- }
+ std::uint16_t *prevrow = &bitmap.pix16(y - prevlines);
+ std::uint16_t *dest = &bitmap.pix16(y);
- /* write the initial headers */
- avierr = write_initial_headers(newfile);
- if (avierr != AVIERR_NONE)
- goto error;
+ /* handle the first four bytes independently */
+ x = 0;
+ if (y == 0)
+ {
+ /* lasty, lastcr, lastcb are set up previously */
+ x = 2;
+ }
- *file = newfile;
- return AVIERR_NONE;
+ /* left predict or gradient predict */
+ if ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_LEFT ||
+ ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT))
+ {
+ /* first do left deltas */
+ for ( ; x < m_width; x += 2)
+ {
+ std::uint16_t pixel0 = dest[x + 0];
+ std::uint16_t pixel1 = dest[x + 1];
-error:
- /* clean up after an error */
- if (newfile != nullptr)
- {
- if (newfile->stream != nullptr)
- free(newfile->stream);
- if (newfile->file != nullptr)
+ lasty += pixel0 >> 8;
+ lastcb += pixel0;
+ dest[x + 0] = (lasty << 8) | lastcb;
+
+ lasty += pixel1 >> 8;
+ lastcr += pixel1;
+ dest[x + 1] = (lasty << 8) | lastcr;
+ }
+
+ /* for gradient, we then add in the previous row */
+ if ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT && y >= prevlines)
+ for (x = 0; x < m_width; x++)
+ {
+ std::uint16_t curpix = dest[x];
+ std::uint16_t prevpix = prevrow[x];
+ std::uint8_t ysum = (curpix >> 8) + (prevpix >> 8);
+ std::uint8_t csum = curpix + prevpix;
+ dest[x] = (ysum << 8) | csum;
+ }
+ }
+
+ /* median predict on rows > 0 */
+ else if ((m_huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_MEDIAN && y >= prevlines)
{
- osd_close(newfile->file);
- osd_rmfile(filename);
+ for ( ; x < m_width; x += 2)
+ {
+ std::uint16_t prevpixel0 = prevrow[x + 0];
+ std::uint16_t prevpixel1 = prevrow[x + 1];
+ std::uint16_t pixel0 = dest[x + 0];
+ std::uint16_t pixel1 = dest[x + 1];
+ std::uint8_t a, b, c;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lasty;
+ b = prevpixel0 >> 8;
+ c = lastprevy;
+ lastprevy = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lasty = (pixel0 >> 8) + b;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lastcb;
+ b = prevpixel0 & 0xff;
+ c = lastprevcb;
+ lastprevcb = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lastcb = (pixel0 & 0xff) + b;
+ dest[x + 0] = (lasty << 8) | lastcb;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lasty;
+ b = prevpixel1 >> 8;
+ c = lastprevy;
+ lastprevy = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lasty = (pixel1 >> 8) + b;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lastcr;
+ b = prevpixel1 & 0xff;
+ c = lastprevcr;
+ lastprevcr = b;
+ if (a > b) { std::uint8_t tmp = a; a = b; b = tmp; }
+ if (a > c) { std::uint8_t tmp = a; a = c; c = tmp; }
+ if (b > c) { std::uint8_t tmp = b; b = c; c = tmp; }
+ lastcr = (pixel1 & 0xff) + b;
+ dest[x + 1] = (lasty << 8) | lastcr;
+ }
}
- free(newfile);
}
- return avierr;
+
+ return avi_file::error::NONE;
}
@@ -1029,73 +1481,46 @@ error:
* @return An avi_error.
*/
-avi_error avi_close(avi_file *file)
+avi_file_impl::~avi_file_impl()
{
- avi_error avierr = AVIERR_NONE;
- int strnum;
+ error avierr = error::NONE;
/* if we're creating a new file, finalize it by writing out the non-media chunks */
- if (file->type == FILETYPE_CREATE)
+ if (m_type == FILETYPE_CREATE)
{
/* flush any pending sound data */
- avierr = soundbuf_flush(file, FALSE);
+ avierr = soundbuf_flush(false);
/* close the movi chunk */
- if (avierr == AVIERR_NONE)
- avierr = chunk_close(file);
+ if (avierr == error::NONE)
+ avierr = chunk_close();
/* if this is the first RIFF chunk, write an idx1 */
- if (avierr == AVIERR_NONE && file->riffbase == 0)
- avierr = write_idx1_chunk(file);
+ if (avierr == error::NONE && m_riffbase == 0)
+ avierr = write_idx1_chunk();
/* update the strh and indx chunks for each stream */
- for (strnum = 0; strnum < file->streams; strnum++)
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
{
- if (avierr == AVIERR_NONE)
- avierr = write_strh_chunk(file, &file->stream[strnum], FALSE);
- if (avierr == AVIERR_NONE)
- avierr = write_indx_chunk(file, &file->stream[strnum], FALSE);
+ if (avierr == error::NONE)
+ avierr = write_strh_chunk(m_streams[strnum], false);
+ if (avierr == error::NONE)
+ avierr = write_indx_chunk(m_streams[strnum], false);
}
/* update the avih chunk */
- if (avierr == AVIERR_NONE)
- avierr = write_avih_chunk(file, FALSE);
+ if (avierr == error::NONE)
+ avierr = write_avih_chunk(false);
/* close the RIFF chunk */
- if (avierr == AVIERR_NONE)
- avierr = chunk_close(file);
+ if (avierr == error::NONE)
+ avierr = chunk_close();
}
/* close the file */
- osd_close(file->file);
-
- /* free the stream-specific data */
- for (strnum = 0; strnum < file->streams; strnum++)
- {
- avi_stream *stream = &file->stream[strnum];
- if (stream->huffyuv != nullptr)
- {
- huffyuv_data *huffyuv = stream->huffyuv;
- int table;
+ m_file.reset();
- for (table = 0; table < ARRAY_LENGTH(huffyuv->table); table++)
- if (huffyuv->table[table].extralookup != nullptr)
- free(huffyuv->table[table].extralookup);
- free(huffyuv);
- }
- if (stream->chunk != nullptr)
- free(stream->chunk);
- }
-
- /* free the file itself */
- if (file->soundbuf != nullptr)
- free(file->soundbuf);
- if (file->stream != nullptr)
- free(file->stream);
- if (file->tempbuffer != nullptr)
- free(file->tempbuffer);
- free(file);
- return avierr;
+ //return avierr;
}
@@ -1111,55 +1536,14 @@ avi_error avi_close(avi_file *file)
* @param [in,out] file If non-null, the file.
*/
-void avi_printf_chunks(avi_file *file)
-{
- printf_chunk_recursive(file, &file->rootchunk, 0);
-}
-
-
-/*-------------------------------------------------
- avi_error_string - get the error string for
- an avi_error
--------------------------------------------------*/
-
-/**
- * @fn const char *avi_error_string(avi_error err)
- *
- * @brief Avi error string.
- *
- * @param err The error.
- *
- * @return null if it fails, else a char*.
- */
-
-const char *avi_error_string(avi_error err)
+void avi_file_impl::printf_chunks()
{
- switch (err)
- {
- case AVIERR_NONE: return "success";
- case AVIERR_END: return "hit end of file";
- case AVIERR_INVALID_DATA: return "invalid data";
- case AVIERR_NO_MEMORY: return "out of memory";
- case AVIERR_READ_ERROR: return "read error";
- case AVIERR_WRITE_ERROR: return "write error";
- case AVIERR_STACK_TOO_DEEP: return "stack overflow";
- case AVIERR_UNSUPPORTED_FEATURE: return "unsupported feature";
- case AVIERR_CANT_OPEN_FILE: return "unable to open file";
- case AVIERR_INCOMPATIBLE_AUDIO_STREAMS: return "found incompatible audio streams";
- case AVIERR_INVALID_SAMPLERATE: return "found invalid sample rate";
- case AVIERR_INVALID_STREAM: return "invalid stream";
- case AVIERR_INVALID_FRAME: return "invalid frame index";
- case AVIERR_INVALID_BITMAP: return "invalid bitmap";
- case AVIERR_UNSUPPORTED_VIDEO_FORMAT: return "unsupported video format";
- case AVIERR_UNSUPPORTED_AUDIO_FORMAT: return "unsupported audio format";
- case AVIERR_EXCEEDED_SOUND_BUFFER: return "sound buffer overflow";
- default: return "undocumented error";
- }
+ printf_chunk_recursive(&m_rootchunk, 0);
}
/*-------------------------------------------------
- avi_get_movie_info - return a pointer to the
+ get_movie_info - return a pointer to the
movie info
-------------------------------------------------*/
@@ -1173,9 +1557,9 @@ const char *avi_error_string(avi_error err)
* @return null if it fails, else an avi_movie_info*.
*/
-const avi_movie_info *avi_get_movie_info(avi_file *file)
+avi_file::movie_info const &avi_file_impl::get_movie_info() const
{
- return &file->info;
+ return m_info;
}
@@ -1185,19 +1569,19 @@ const avi_movie_info *avi_get_movie_info(avi_file *file)
-------------------------------------------------*/
/**
- * @fn UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
+ * @fn std::uint32_t avi_first_sample_in_frame(avi_file *file, std::uint32_t framenum)
*
* @brief Avi first sample in frame.
*
* @param [in,out] file If non-null, the file.
* @param framenum The framenum.
*
- * @return An UINT32.
+ * @return An std::uint32_t.
*/
-UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
+std::uint32_t avi_file_impl::first_sample_in_frame(std::uint32_t framenum) const
{
- return framenum_to_samplenum(file, framenum);
+ return framenum_to_samplenum(framenum);
}
@@ -1208,7 +1592,7 @@ UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
-------------------------------------------------*/
/**
- * @fn avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bitmap)
+ * @fn avi_error avi_read_video_frame(avi_file *file, std::uint32_t framenum, bitmap_yuy16 &bitmap)
*
* @brief Avi read video frame.
*
@@ -1219,54 +1603,51 @@ UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
* @return An avi_error.
*/
-avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bitmap)
+avi_file::error avi_file_impl::read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap)
{
- avi_error avierr = AVIERR_NONE;
- UINT32 bytes_read, chunkid;
- file_error filerr;
- avi_stream *stream;
-
/* get the video stream */
- stream = get_video_stream(file);
- if (stream == nullptr)
- return AVIERR_INVALID_STREAM;
+ avi_stream *const stream = get_video_stream();
+ if (!stream)
+ return error::INVALID_STREAM;
/* validate our ability to handle the data */
- if (stream->format != FORMAT_UYVY && stream->format != FORMAT_VYUY && stream->format != FORMAT_YUY2 && stream->format != FORMAT_HFYU)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->format() != FORMAT_UYVY && stream->format() != FORMAT_VYUY && stream->format() != FORMAT_YUY2 && stream->format() != FORMAT_HFYU)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* assume one chunk == one frame */
- if (framenum >= stream->chunks)
- return AVIERR_INVALID_FRAME;
+ if (framenum >= stream->chunks())
+ return error::INVALID_FRAME;
/* we only support YUY-style bitmaps (16bpp) */
- if (bitmap.width() < stream->width || bitmap.height() < stream->height)
- return AVIERR_INVALID_BITMAP;
+ if (bitmap.width() < stream->width() || bitmap.height() < stream->height())
+ return error::INVALID_BITMAP;
/* expand the tempbuffer to hold the data if necessary */
- avierr = expand_tempbuffer(file, stream->chunk[framenum].length);
- if (avierr != AVIERR_NONE)
+ error avierr = error::NONE;
+ avierr = expand_tempbuffer(stream->chunk(framenum).length);
+ if (avierr != error::NONE)
return avierr;
/* read in the data */
- filerr = osd_read(file->file, file->tempbuffer, stream->chunk[framenum].offset, stream->chunk[framenum].length, &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != stream->chunk[framenum].length)
- return AVIERR_READ_ERROR;
+ 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)
+ return error::READ_ERROR;
/* validate this is good data */
- chunkid = fetch_32bits(&file->tempbuffer[0]);
- if (chunkid == get_chunkid_for_stream(file, stream))
+ std::uint32_t const chunkid = fetch_32bits(&m_tempbuffer[0]);
+ if (chunkid == get_chunkid_for_stream(stream))
{
/* HuffYUV-compressed */
- if (stream->format == FORMAT_HFYU)
- avierr = huffyuv_decompress_to_yuy16(stream, file->tempbuffer + 8, stream->chunk[framenum].length - 8, bitmap);
+ if (stream->format() == FORMAT_HFYU)
+ avierr = stream->huffyuv_decompress_to_yuy16(&m_tempbuffer[8], stream->chunk(framenum).length - 8, bitmap);
/* other YUV-compressed */
else
- avierr = yuv_decompress_to_yuy16(stream, file->tempbuffer + 8, stream->chunk[framenum].length - 8, bitmap);
+ avierr = stream->yuv_decompress_to_yuy16(&m_tempbuffer[8], stream->chunk(framenum).length - 8, bitmap);
}
else
- avierr = AVIERR_INVALID_DATA;
+ avierr = error::INVALID_DATA;
return avierr;
}
@@ -1278,7 +1659,7 @@ avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bi
-------------------------------------------------*/
/**
- * @fn avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output)
+ * @fn avi_error avi_read_sound_samples(avi_file *file, int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output)
*
* @brief Avi read sound samples.
*
@@ -1291,95 +1672,90 @@ avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bi
* @return An avi_error.
*/
-avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output)
+avi_file::error avi_file_impl::read_sound_samples(int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output)
{
- avi_error avierr = AVIERR_NONE;
- UINT32 bytes_per_sample;
- file_error filerr;
- avi_stream *stream;
- int offset = 0;
-
/* get the audio stream */
- stream = get_audio_stream(file, channel, &offset);
- if (stream == nullptr)
- return AVIERR_INVALID_STREAM;
+ int offset = 0;
+ avi_stream *const stream = get_audio_stream(channel, offset);
+ if (!stream)
+ return error::INVALID_STREAM;
/* validate our ability to handle the data */
- if (stream->format != 0 || (stream->samplebits != 8 && stream->samplebits != 16))
- return AVIERR_UNSUPPORTED_AUDIO_FORMAT;
+ if (stream->format() != 0 || (stream->samplebits() != 8 && stream->samplebits() != 16))
+ return error::UNSUPPORTED_AUDIO_FORMAT;
/* verify we are in range */
- if (firstsample >= stream->samples)
- return AVIERR_INVALID_FRAME;
- if (firstsample + numsamples > stream->samples)
- numsamples = stream->samples - firstsample;
+ if (firstsample >= stream->samples())
+ return error::INVALID_FRAME;
+ if (firstsample + numsamples > stream->samples())
+ numsamples = stream->samples() - firstsample;
/* determine bytes per sample */
- bytes_per_sample = (stream->samplebits / 8) * stream->channels;
+ std::uint32_t const bytes_per_sample = stream->bytes_per_sample();
/* loop until all samples have been extracted */
while (numsamples > 0)
{
- UINT32 chunkbase = 0, chunkend = 0, chunkid;
- UINT32 bytes_read, samples_this_chunk;
+ std::uint32_t chunkbase = 0, chunkend = 0, chunkid;
+ std::uint32_t bytes_read, samples_this_chunk;
int chunknum, sampnum;
/* locate the chunk with the first sample */
- for (chunknum = 0; chunknum < stream->chunks; chunknum++)
+ for (chunknum = 0; chunknum < stream->chunks(); chunknum++)
{
- chunkend = chunkbase + (stream->chunk[chunknum].length - 8) / bytes_per_sample;
+ chunkend = chunkbase + (stream->chunk(chunknum).length - 8) / bytes_per_sample;
if (firstsample < chunkend)
break;
chunkbase = chunkend;
}
/* if we hit the end, fill the rest with silence */
- if (chunknum == stream->chunks)
+ if (chunknum == stream->chunks())
{
- memset(output, 0, numsamples * 2);
+ std::memset(output, 0, numsamples * 2);
break;
}
/* expand the tempbuffer to hold the data if necessary */
- avierr = expand_tempbuffer(file, stream->chunk[chunknum].length);
- if (avierr != AVIERR_NONE)
+ error avierr = expand_tempbuffer(stream->chunk(chunknum).length);
+ if (avierr != error::NONE)
return avierr;
/* read in the data */
- filerr = osd_read(file->file, file->tempbuffer, stream->chunk[chunknum].offset, stream->chunk[chunknum].length, &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != stream->chunk[chunknum].length)
- return AVIERR_READ_ERROR;
+ 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)
+ return error::READ_ERROR;
/* validate this is good data */
- chunkid = fetch_32bits(&file->tempbuffer[0]);
- if (chunkid != get_chunkid_for_stream(file, stream))
- return AVIERR_INVALID_DATA;
+ chunkid = fetch_32bits(&m_tempbuffer[0]);
+ if (chunkid != get_chunkid_for_stream(stream))
+ return error::INVALID_DATA;
/* determine how many samples to copy */
samples_this_chunk = chunkend - firstsample;
- samples_this_chunk = MIN(samples_this_chunk, numsamples);
+ samples_this_chunk = (std::min)(samples_this_chunk, numsamples);
/* extract 16-bit samples from the chunk */
- if (stream->samplebits == 16)
+ if (stream->samplebits() == 16)
{
- const INT16 *base = (const INT16 *)(file->tempbuffer + 8);
- base += stream->channels * (firstsample - chunkbase) + offset;
+ const std::int16_t *base = reinterpret_cast<const std::int16_t *>(&m_tempbuffer[8]);
+ base += stream->channels() * (firstsample - chunkbase) + offset;
for (sampnum = 0; sampnum < samples_this_chunk; sampnum++)
{
*output++ = LITTLE_ENDIANIZE_INT16(*base);
- base += stream->channels;
+ base += stream->channels();
}
}
/* extract 8-bit samples from the chunk */
- else if (stream->samplebits == 8)
+ else if (stream->samplebits() == 8)
{
- const UINT8 *base = (const UINT8 *)(file->tempbuffer + 8);
- base += stream->channels * (firstsample - chunkbase) + offset;
+ const std::uint8_t *base = &m_tempbuffer[8];
+ base += stream->channels() * (firstsample - chunkbase) + offset;
for (sampnum = 0; sampnum < samples_this_chunk; sampnum++)
{
*output++ = (*base << 8) - 0x8000;
- base += stream->channels;
+ base += stream->channels();
}
}
@@ -1388,7 +1764,7 @@ avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample
numsamples -= samples_this_chunk;
}
- return avierr;
+ return error::NONE;
}
@@ -1408,45 +1784,45 @@ avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample
* @return An avi_error.
*/
-avi_error avi_append_video_frame(avi_file *file, bitmap_yuy16 &bitmap)
+avi_file::error avi_file_impl::append_video_frame(bitmap_yuy16 &bitmap)
{
- avi_stream *stream = get_video_stream(file);
- avi_error avierr;
- UINT32 maxlength;
+ avi_stream *const stream = get_video_stream();
+ error avierr;
+ std::uint32_t maxlength;
/* validate our ability to handle the data */
- if (stream->format != FORMAT_UYVY && stream->format != FORMAT_VYUY && stream->format != FORMAT_YUY2 && stream->format != FORMAT_HFYU)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->format() != FORMAT_UYVY && stream->format() != FORMAT_VYUY && stream->format() != FORMAT_YUY2 && stream->format() != FORMAT_HFYU)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* write out any sound data first */
- avierr = soundbuf_write_chunk(file, stream->chunks);
- if (avierr != AVIERR_NONE)
+ avierr = soundbuf_write_chunk(stream->chunks());
+ if (avierr != error::NONE)
return avierr;
/* make sure we have enough room */
- maxlength = 2 * stream->width * stream->height;
- avierr = expand_tempbuffer(file, maxlength);
- if (avierr != AVIERR_NONE)
+ maxlength = 2 * stream->width() * stream->height();
+ avierr = expand_tempbuffer(maxlength);
+ if (avierr != error::NONE)
return avierr;
/* now compress the data */
- avierr = yuy16_compress_to_yuy(stream, bitmap, file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = stream->yuy16_compress_to_yuy(bitmap, &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* write the data */
- avierr = chunk_write(file, get_chunkid_for_stream(file, stream), file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_write(get_chunkid_for_stream(stream), &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* set the info for this new chunk */
- avierr = set_stream_chunk_info(stream, stream->chunks, file->writeoffs - maxlength - 8, maxlength + 8);
- if (avierr != AVIERR_NONE)
+ avierr = stream->set_chunk_info(stream->chunks(), m_writeoffs - maxlength - 8, maxlength + 8);
+ if (avierr != error::NONE)
return avierr;
- stream->samples = file->info.video_numsamples = stream->chunks;
+ stream->set_samples(m_info.video_numsamples = stream->chunks());
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1466,49 +1842,49 @@ avi_error avi_append_video_frame(avi_file *file, bitmap_yuy16 &bitmap)
* @return An avi_error.
*/
-avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap)
+avi_file::error avi_file_impl::append_video_frame(bitmap_rgb32 &bitmap)
{
- avi_stream *stream = get_video_stream(file);
- avi_error avierr;
- UINT32 maxlength;
+ avi_stream *const stream = get_video_stream();
+ error avierr;
+ std::uint32_t maxlength;
/* validate our ability to handle the data */
- if (stream->format != 0)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->format() != 0)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* depth must be 24 */
- if (stream->depth != 24)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ if (stream->depth() != 24)
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* write out any sound data first */
- avierr = soundbuf_write_chunk(file, stream->chunks);
- if (avierr != AVIERR_NONE)
+ avierr = soundbuf_write_chunk(stream->chunks());
+ if (avierr != error::NONE)
return avierr;
/* make sure we have enough room */
- maxlength = 3 * stream->width * stream->height;
- avierr = expand_tempbuffer(file, maxlength);
- if (avierr != AVIERR_NONE)
+ maxlength = 3 * stream->width() * stream->height();
+ avierr = expand_tempbuffer(maxlength);
+ if (avierr != error::NONE)
return avierr;
/* copy the RGB data to the destination */
- avierr = rgb32_compress_to_rgb(stream, bitmap, file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = stream->rgb32_compress_to_rgb(bitmap, &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* write the data */
- avierr = chunk_write(file, get_chunkid_for_stream(file, stream), file->tempbuffer, maxlength);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_write(get_chunkid_for_stream(stream), &m_tempbuffer[0], maxlength);
+ if (avierr != error::NONE)
return avierr;
/* set the info for this new chunk */
- avierr = set_stream_chunk_info(stream, stream->chunks, file->writeoffs - maxlength - 8, maxlength + 8);
- if (avierr != AVIERR_NONE)
+ avierr = stream->set_chunk_info(stream->chunks(), m_writeoffs - maxlength - 8, maxlength + 8);
+ if (avierr != error::NONE)
return avierr;
- stream->samples = file->info.video_numsamples = stream->chunks;
+ stream->set_samples(m_info.video_numsamples = stream->chunks());
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1518,7 +1894,7 @@ avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap)
-------------------------------------------------*/
/**
- * @fn avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples, UINT32 sampleskip)
+ * @fn avi_error avi_append_sound_samples(avi_file *file, int channel, const std::int16_t *samples, std::uint32_t numsamples, std::uint32_t sampleskip)
*
* @brief Avi append sound samples.
*
@@ -1531,27 +1907,27 @@ avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap)
* @return An avi_error.
*/
-avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples, UINT32 sampleskip)
+avi_file::error avi_file_impl::append_sound_samples(int channel, const std::int16_t *samples, std::uint32_t numsamples, std::uint32_t sampleskip)
{
- UINT32 sampoffset = file->soundbuf_chansamples[channel];
- UINT32 sampnum;
+ std::uint32_t sampoffset = m_soundbuf_chansamples[channel];
+ std::uint32_t sampnum;
/* see if we have enough room in the buffer */
- if (sampoffset + numsamples > file->soundbuf_samples)
- return AVIERR_EXCEEDED_SOUND_BUFFER;
+ if (sampoffset + numsamples > m_soundbuf_samples)
+ return error::EXCEEDED_SOUND_BUFFER;
/* append samples to the buffer in little-endian format */
for (sampnum = 0; sampnum < numsamples; sampnum++)
{
- INT16 data = *samples++;
+ std::int16_t data = *samples++;
samples += sampleskip;
data = LITTLE_ENDIANIZE_INT16(data);
- file->soundbuf[sampoffset++ * file->info.audio_channels + channel] = data;
+ m_soundbuf[sampoffset++ * m_info.audio_channels + channel] = data;
}
- file->soundbuf_chansamples[channel] = sampoffset;
+ m_soundbuf_chansamples[channel] = sampoffset;
/* flush any full sound chunks to disk */
- return soundbuf_flush(file, TRUE);
+ return soundbuf_flush(TRUE);
}
@@ -1561,7 +1937,7 @@ avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *sam
-------------------------------------------------*/
/**
- * @fn static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer)
+ * @fn static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, std::uint8_t **buffer)
*
* @brief Reads chunk data.
*
@@ -1572,26 +1948,22 @@ avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *sam
* @return The chunk data.
*/
-static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer)
+avi_file::error avi_file_impl::read_chunk_data(avi_chunk const &chunk, std::unique_ptr<std::uint8_t []> &buffer)
{
- file_error filerr;
- UINT32 bytes_read;
-
/* allocate memory for the data */
- *buffer = (UINT8 *)malloc(chunk->size);
- if (*buffer == nullptr)
- return AVIERR_NO_MEMORY;
+ try { buffer.reset(new std::uint8_t[chunk.size]); }
+ catch (...) { return error::NO_MEMORY; }
/* read from the file */
- filerr = osd_read(file->file, *buffer, chunk->offset + 8, chunk->size, &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != chunk->size)
+ 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)
{
- free(*buffer);
- *buffer = nullptr;
- return AVIERR_READ_ERROR;
+ buffer.reset();
+ return error::READ_ERROR;
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1612,12 +1984,12 @@ static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 *
* @return The first chunk.
*/
-static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk)
+avi_file::error avi_file_impl::get_first_chunk(avi_chunk const *parent, avi_chunk &newchunk)
{
- UINT64 startoffset = (parent != nullptr && parent->type != 0) ? parent->offset + 12 : 0;
+ std::uint64_t startoffset = (parent != nullptr && parent->type != 0) ? parent->offset + 12 : 0;
if (parent != nullptr && parent->type != CHUNKTYPE_LIST && parent->type != CHUNKTYPE_RIFF && parent->type != 0)
- return AVIERR_INVALID_DATA;
- return get_next_chunk_internal(file, parent, newchunk, startoffset);
+ return error::INVALID_DATA;
+ return get_next_chunk_internal(parent, newchunk, startoffset);
}
@@ -1638,10 +2010,10 @@ static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_ch
* @return The next chunk.
*/
-static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk)
+avi_file::error avi_file_impl::get_next_chunk(avi_chunk const *parent, avi_chunk &newchunk)
{
- UINT64 nextoffset = newchunk->offset + 8 + newchunk->size + (newchunk->size & 1);
- return get_next_chunk_internal(file, parent, newchunk, nextoffset);
+ std::uint64_t nextoffset = newchunk.offset + 8 + newchunk.size + (newchunk.size & 1);
+ return get_next_chunk_internal(parent, newchunk, nextoffset);
}
@@ -1651,7 +2023,7 @@ static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chu
-------------------------------------------------*/
/**
- * @fn static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_first_chunk(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the first chunk.
*
@@ -1663,13 +2035,13 @@ static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chu
* @return The found chunk.
*/
-static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_first_chunk(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = get_first_chunk(file, container, result); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, result))
- if (result->type == findme)
- return AVIERR_NONE;
+ for (avierr = get_first_chunk(container, result); avierr == error::NONE; avierr = get_next_chunk(container, result))
+ if (result.type == findme)
+ return error::NONE;
return avierr;
}
@@ -1681,7 +2053,7 @@ static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk
-------------------------------------------------*/
/**
- * @fn static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_next_chunk(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the next chunk.
*
@@ -1693,13 +2065,13 @@ static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk
* @return The found chunk.
*/
-static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_next_chunk(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = get_next_chunk(file, container, result); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, result))
- if (result->type == findme)
- return AVIERR_NONE;
+ for (avierr = get_next_chunk(container, result); avierr == error::NONE; avierr = get_next_chunk(container, result))
+ if (result.type == findme)
+ return error::NONE;
return avierr;
}
@@ -1711,7 +2083,7 @@ static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk
-------------------------------------------------*/
/**
- * @fn static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_first_list(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the first list.
*
@@ -1723,13 +2095,13 @@ static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk
* @return The found list.
*/
-static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_first_list(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = find_first_chunk(file, CHUNKTYPE_LIST, container, result); avierr == AVIERR_NONE; avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result))
- if (result->listtype == findme)
- return AVIERR_NONE;
+ for (avierr = find_first_chunk(CHUNKTYPE_LIST, container, result); avierr == error::NONE; avierr = find_next_chunk(CHUNKTYPE_LIST, container, result))
+ if (result.listtype == findme)
+ return error::NONE;
return avierr;
}
@@ -1741,7 +2113,7 @@ static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk
-------------------------------------------------*/
/**
- * @fn static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+ * @fn static avi_error find_next_list(avi_file *file, std::uint32_t findme, const avi_chunk *container, avi_chunk *result)
*
* @brief Searches for the next list.
*
@@ -1753,13 +2125,13 @@ static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk
* @return The found list.
*/
-static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+avi_file::error avi_file_impl::find_next_list(std::uint32_t findme, const avi_chunk *container, avi_chunk &result)
{
- avi_error avierr;
+ error avierr;
- for (avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result); avierr == AVIERR_NONE; avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result))
- if (result->listtype == findme)
- return AVIERR_NONE;
+ for (avierr = find_next_chunk(CHUNKTYPE_LIST, container, result); avierr == error::NONE; avierr = find_next_chunk(CHUNKTYPE_LIST, container, result))
+ if (result.listtype == findme)
+ return error::NONE;
return avierr;
}
@@ -1771,7 +2143,7 @@ static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *
-------------------------------------------------*/
/**
- * @fn static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset)
+ * @fn static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, std::uint64_t offset)
*
* @brief Gets the next chunk internal.
*
@@ -1783,42 +2155,42 @@ static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *
* @return The next chunk internal.
*/
-static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset)
+avi_file::error avi_file_impl::get_next_chunk_internal(const avi_chunk *parent, avi_chunk &newchunk, std::uint64_t offset)
{
- file_error filerr;
- UINT8 buffer[12];
- UINT32 bytesread;
+ osd_file::error filerr;
+ std::uint8_t buffer[12];
+ std::uint32_t bytesread;
/* NULL parent implies the root */
if (parent == nullptr)
- parent = &file->rootchunk;
+ parent = &m_rootchunk;
/* start at the current offset */
- newchunk->offset = offset;
+ newchunk.offset = offset;
/* if we're past the bounds of the parent, bail */
- if (newchunk->offset + 8 >= parent->offset + 8 + parent->size)
- return AVIERR_END;
+ if (newchunk.offset + 8 >= parent->offset + 8 + parent->size)
+ return error::END;
/* read the header */
- filerr = osd_read(file->file, buffer, newchunk->offset, 8, &bytesread);
- if (filerr != FILERR_NONE || bytesread != 8)
- return AVIERR_INVALID_DATA;
+ filerr = m_file->read(buffer, newchunk.offset, 8, bytesread);
+ if (filerr != osd_file::error::NONE || bytesread != 8)
+ return error::INVALID_DATA;
/* fill in the new chunk */
- newchunk->type = fetch_32bits(&buffer[0]);
- newchunk->size = fetch_32bits(&buffer[4]);
+ newchunk.type = fetch_32bits(&buffer[0]);
+ newchunk.size = fetch_32bits(&buffer[4]);
/* if we are a list, fetch the list type */
- if (newchunk->type == CHUNKTYPE_LIST || newchunk->type == CHUNKTYPE_RIFF)
+ if (newchunk.type == CHUNKTYPE_LIST || newchunk.type == CHUNKTYPE_RIFF)
{
- filerr = osd_read(file->file, &buffer[8], newchunk->offset + 8, 4, &bytesread);
- if (filerr != FILERR_NONE || bytesread != 4)
- return AVIERR_INVALID_DATA;
- newchunk->listtype = fetch_32bits(&buffer[8]);
+ filerr = m_file->read(&buffer[8], newchunk.offset + 8, 4, bytesread);
+ if (filerr != osd_file::error::NONE || bytesread != 4)
+ return error::INVALID_DATA;
+ newchunk.listtype = fetch_32bits(&buffer[8]);
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -1836,98 +2208,95 @@ static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent
* @return The movie data.
*/
-static avi_error read_movie_data(avi_file *file)
+avi_file::error avi_file_impl::read_movie_data()
{
avi_chunk riff, hdrl, avih, strl, strh, strf, indx, movi, idx1;
- avi_error avierr;
- int strindex;
+ error avierr;
/* find the RIFF chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_RIFF, nullptr, &riff);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_RIFF, nullptr, riff);
+ if (avierr != error::NONE)
+ return avierr;
/* verify that the RIFF type is AVI */
if (riff.listtype != LISTTYPE_AVI)
{
- avierr = AVIERR_INVALID_DATA;
- goto error;
+ avierr = error::INVALID_DATA;
+ return avierr;
}
/* find the hdrl LIST chunk within the RIFF */
- avierr = find_first_list(file, LISTTYPE_HDRL, &riff, &hdrl);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_list(LISTTYPE_HDRL, &riff, hdrl);
+ if (avierr != error::NONE)
+ return avierr;
/* find the avih chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_AVIH, &hdrl, &avih);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_AVIH, &hdrl, avih);
+ if (avierr != error::NONE)
+ return avierr;
/* parse the avih chunk */
- avierr = parse_avih_chunk(file, &avih);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = parse_avih_chunk(avih);
+ if (avierr != error::NONE)
+ return avierr;
/* loop over strl LIST chunks */
- strindex = 0;
- for (avierr = find_first_list(file, LISTTYPE_STRL, &hdrl, &strl); avierr == AVIERR_NONE; avierr = find_next_list(file, LISTTYPE_STRL, &hdrl, &strl))
+ int strindex = 0;
+ for (avierr = find_first_list(LISTTYPE_STRL, &hdrl, strl); avierr == error::NONE; avierr = find_next_list(LISTTYPE_STRL, &hdrl, strl))
{
/* if we have too many, it's a bad file */
- if (strindex >= file->streams)
- goto error;
+ if (strindex >= m_streams.size())
+ return avierr;
/* find the strh chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_STRH, &strl, &strh);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_STRH, &strl, strh);
+ if (avierr != error::NONE)
+ return avierr;
/* parse the data */
- avierr = parse_strh_chunk(file, &file->stream[strindex], &strh);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = parse_strh_chunk(m_streams[strindex], strh);
+ if (avierr != error::NONE)
+ return avierr;
/* find the strf chunk */
- avierr = find_first_chunk(file, CHUNKTYPE_STRF, &strl, &strf);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_STRF, &strl, strf);
+ if (avierr != error::NONE)
+ return avierr;
/* parse the data */
- avierr = parse_strf_chunk(file, &file->stream[strindex], &strf);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = parse_strf_chunk(m_streams[strindex], strf);
+ if (avierr != error::NONE)
+ return avierr;
/* find the indx chunk, if present */
- avierr = find_first_chunk(file, CHUNKTYPE_INDX, &strl, &indx);
- if (avierr == AVIERR_NONE)
- avierr = parse_indx_chunk(file, &file->stream[strindex], &indx);
+ avierr = find_first_chunk(CHUNKTYPE_INDX, &strl, indx);
+ if (avierr == error::NONE)
+ avierr = parse_indx_chunk(m_streams[strindex], indx);
/* next stream */
strindex++;
}
/* normalize the error after parsing the stream headers */
- if (avierr == AVIERR_END)
- avierr = AVIERR_NONE;
- if (avierr != AVIERR_NONE)
- goto error;
+ if (avierr == error::END)
+ avierr = error::NONE;
+ if (avierr != error::NONE)
+ return avierr;
/* find the base of the movi data */
- avierr = find_first_list(file, LISTTYPE_MOVI, &riff, &movi);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_list(LISTTYPE_MOVI, &riff, movi);
+ if (avierr != error::NONE)
+ return avierr;
/* find and parse the idx1 chunk within the RIFF (if present) */
- avierr = find_first_chunk(file, CHUNKTYPE_IDX1, &riff, &idx1);
- if (avierr == AVIERR_NONE)
- avierr = parse_idx1_chunk(file, movi.offset + 8, &idx1);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = find_first_chunk(CHUNKTYPE_IDX1, &riff, idx1);
+ if (avierr == error::NONE)
+ avierr = parse_idx1_chunk(movi.offset + 8, idx1);
+ if (avierr != error::NONE)
+ return avierr;
/* now extract the movie info */
- avierr = extract_movie_info(file);
-
-error:
+ avierr = extract_movie_info();
return avierr;
}
@@ -1947,59 +2316,55 @@ error:
* @return The extracted movie information.
*/
-static avi_error extract_movie_info(avi_file *file)
+avi_file::error avi_file_impl::extract_movie_info()
{
- //avi_stream *audiostream;
avi_stream *stream;
+ int offset;
/* get the video stream */
- stream = get_video_stream(file);
+ stream = get_video_stream();
if (stream != nullptr)
{
/* fill in the info */
- file->info.video_format = stream->format;
- file->info.video_timescale = stream->rate;
- file->info.video_sampletime = stream->scale;
- file->info.video_numsamples = stream->samples;
- file->info.video_width = stream->width;
- file->info.video_height = stream->height;
+ m_info.video_format = stream->format();
+ m_info.video_timescale = stream->rate();
+ m_info.video_sampletime = stream->scale();
+ m_info.video_numsamples = stream->samples();
+ m_info.video_width = stream->width();
+ m_info.video_height = stream->height();
}
/* get the first audio stream */
- stream = get_audio_stream(file, 0, nullptr);
+ stream = get_audio_stream(0, offset);
if (stream != nullptr)
{
/* fill in the info */
- file->info.audio_format = stream->format;
- file->info.audio_timescale = stream->rate;
- file->info.audio_sampletime = stream->scale;
- file->info.audio_numsamples = stream->samples;
- file->info.audio_channels = 1;
- file->info.audio_samplebits = stream->samplebits;
- file->info.audio_samplerate = stream->samplerate;
+ m_info.audio_format = stream->format();
+ m_info.audio_timescale = stream->rate();
+ m_info.audio_sampletime = stream->scale();
+ m_info.audio_numsamples = stream->samples();
+ m_info.audio_channels = 1;
+ m_info.audio_samplebits = stream->samplebits();
+ m_info.audio_samplerate = stream->samplerate();
}
/* now make sure all other audio streams are valid */
- //audiostream = stream;
- while (1)
+ while (nullptr != (stream = get_audio_stream(m_info.audio_channels, offset)))
{
/* get the stream info */
- stream = get_audio_stream(file, file->info.audio_channels, nullptr);
- if (stream == nullptr)
- break;
- file->info.audio_channels++;
+ m_info.audio_channels++;
/* verify compatibility */
- if (file->info.audio_format != stream->format ||
- file->info.audio_timescale != stream->rate ||
- file->info.audio_sampletime != stream->scale ||
- file->info.audio_numsamples != stream->samples ||
- file->info.audio_samplebits != stream->samplebits ||
- file->info.audio_samplerate != stream->samplerate)
- return AVIERR_INCOMPATIBLE_AUDIO_STREAMS;
+ if (m_info.audio_format != stream->format() ||
+ m_info.audio_timescale != stream->rate() ||
+ m_info.audio_sampletime != stream->scale() ||
+ m_info.audio_numsamples != stream->samples() ||
+ m_info.audio_samplebits != stream->samplebits() ||
+ m_info.audio_samplerate != stream->samplerate())
+ return error::INCOMPATIBLE_AUDIO_STREAMS;
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -2019,28 +2384,21 @@ static avi_error extract_movie_info(avi_file *file)
* @return An avi_error.
*/
-static avi_error parse_avih_chunk(avi_file *file, avi_chunk *avih)
+avi_file::error avi_file_impl::parse_avih_chunk(avi_chunk const &avih)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
-
/* read the data */
- avierr = read_chunk_data(file, avih, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ error avierr = read_chunk_data(avih, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* extract the data */
- file->streams = fetch_32bits(&chunkdata[24]);
+ std::uint32_t const streams = fetch_32bits(&chunkdata[24]);
/* allocate memory for the streams */
- file->stream = (avi_stream *)malloc(sizeof(*file->stream) * file->streams);
- if (file->stream == nullptr)
- goto error;
- memset(file->stream, 0, sizeof(*file->stream) * file->streams);
+ m_streams.clear();
+ m_streams.resize(streams);
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
return avierr;
}
@@ -2062,26 +2420,16 @@ error:
* @return An avi_error.
*/
-static avi_error parse_strh_chunk(avi_file *file, avi_stream *stream, avi_chunk *strh)
+avi_file::error avi_file_impl::parse_strh_chunk(avi_stream &stream, avi_chunk const &strh)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
-
/* read the data */
- avierr = read_chunk_data(file, strh, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ error const avierr = read_chunk_data(strh, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* extract the data */
- stream->type = fetch_32bits(&chunkdata[0]);
- stream->scale = fetch_32bits(&chunkdata[20]);
- stream->rate = fetch_32bits(&chunkdata[24]);
- stream->samples = fetch_32bits(&chunkdata[32]);
-
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
- return avierr;
+ return stream.set_strh_data(&chunkdata[0], strh.size);
}
@@ -2102,43 +2450,17 @@ error:
* @return An avi_error.
*/
-static avi_error parse_strf_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf)
+avi_file::error avi_file_impl::parse_strf_chunk(avi_stream &stream, avi_chunk const &strf)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
+ error avierr;
/* read the data */
- avierr = read_chunk_data(file, strf, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
-
- /* audio and video streams have differing headers */
- if (stream->type == STREAMTYPE_VIDS)
- {
- stream->width = fetch_32bits(&chunkdata[4]);
- stream->height = fetch_32bits(&chunkdata[8]);
- stream->depth = fetch_16bits(&chunkdata[14]);
- stream->format = fetch_32bits(&chunkdata[16]);
-
- /* extra extraction for HuffYUV data */
- if (stream->format == FORMAT_HFYU && strf->size >= 56)
- {
- avierr = huffyuv_extract_tables(stream, chunkdata, strf->size);
- if (avierr != AVIERR_NONE)
- goto error;
- }
- }
- else if (stream->type == STREAMTYPE_AUDS)
- {
- stream->channels = fetch_16bits(&chunkdata[2]);
- stream->samplebits = fetch_16bits(&chunkdata[14]);
- stream->samplerate = fetch_32bits(&chunkdata[4]);
- }
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ avierr = read_chunk_data(strf, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
- return avierr;
+ return stream.set_strf_data(&chunkdata[0], strf.size);
}
@@ -2158,50 +2480,46 @@ error:
* @return An avi_error.
*/
-static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf)
+avi_file::error avi_file_impl::parse_indx_chunk(avi_stream &stream, avi_chunk const &strf)
{
- UINT32 entries, entry;
- UINT8 *chunkdata = nullptr;
- UINT16 longs_per_entry;
- UINT8 type;
- UINT64 baseoffset;
- avi_error avierr;
+ error avierr;
/* read the data */
- avierr = read_chunk_data(file, strf, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ avierr = read_chunk_data(strf, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* extract the data */
- longs_per_entry = fetch_16bits(&chunkdata[0]);
+ std::uint16_t const longs_per_entry = fetch_16bits(&chunkdata[0]);
//subtype = chunkdata[2];
- type = chunkdata[3];
- entries = fetch_32bits(&chunkdata[4]);
+ std::uint8_t const type = chunkdata[3];
+ std::uint32_t const entries = fetch_32bits(&chunkdata[4]);
//id = fetch_32bits(&chunkdata[8]);
- baseoffset = fetch_64bits(&chunkdata[12]);
+ std::uint64_t const baseoffset = fetch_64bits(&chunkdata[12]);
/* if this is a superindex, loop over entries and call ourselves recursively */
if (type == AVI_INDEX_OF_INDEXES)
{
/* validate the size of each entry */
if (longs_per_entry != 4)
- return AVIERR_INVALID_DATA;
+ return error::INVALID_DATA;
/* loop over entries and create subchunks for each */
- for (entry = 0; entry < entries; entry++)
+ for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const UINT8 *base = &chunkdata[24 + entry * 16];
- file_error filerr;
+ const std::uint8_t *base = &chunkdata[24 + entry * 16];
+ osd_file::error filerr;
avi_chunk subchunk;
- UINT32 bytes_read;
- UINT8 buffer[8];
+ std::uint32_t bytes_read;
+ std::uint8_t buffer[8];
/* go read the subchunk */
subchunk.offset = fetch_64bits(&base[0]);
- filerr = osd_read(file->file, buffer, subchunk.offset, sizeof(buffer), &bytes_read);
- if (filerr != FILERR_NONE || bytes_read != sizeof(buffer))
+ filerr = m_file->read(buffer, subchunk.offset, sizeof(buffer), bytes_read);
+ if (filerr != osd_file::error::NONE || bytes_read != sizeof(buffer))
{
- avierr = AVIERR_READ_ERROR;
+ avierr = error::READ_ERROR;
break;
}
@@ -2210,8 +2528,8 @@ static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk
subchunk.size = fetch_32bits(&buffer[4]);
/* recursively parse each referenced chunk; stop if we hit an error */
- avierr = parse_indx_chunk(file, stream, &subchunk);
- if (avierr != AVIERR_NONE)
+ avierr = parse_indx_chunk(stream, subchunk);
+ if (avierr != error::NONE)
break;
}
}
@@ -2221,25 +2539,22 @@ static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk
{
/* validate the size of each entry */
if (longs_per_entry != 2 && longs_per_entry != 3)
- return AVIERR_INVALID_DATA;
+ return error::INVALID_DATA;
/* loop over entries and parse out the data */
- for (entry = 0; entry < entries; entry++)
+ for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const UINT8 *base = &chunkdata[24 + entry * 4 * longs_per_entry];
- UINT32 offset = fetch_32bits(&base[0]);
- UINT32 size = fetch_32bits(&base[4]) & 0x7fffffff; // bit 31 == NOT a keyframe
+ const std::uint8_t *base = &chunkdata[24 + entry * 4 * longs_per_entry];
+ std::uint32_t offset = fetch_32bits(&base[0]);
+ std::uint32_t size = fetch_32bits(&base[4]) & 0x7fffffff; // bit 31 == NOT a keyframe
/* set the info for this chunk and advance */
- avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset - 8, size + 8);
- if (avierr != AVIERR_NONE)
+ avierr = stream.set_chunk_info(stream.chunks(), baseoffset + offset - 8, size + 8);
+ if (avierr != error::NONE)
break;
}
}
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
return avierr;
}
@@ -2249,7 +2564,7 @@ error:
-------------------------------------------------*/
/**
- * @fn static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1)
+ * @fn static avi_error parse_idx1_chunk(avi_file *file, std::uint64_t baseoffset, avi_chunk *idx1)
*
* @brief Parse index 1 chunk.
*
@@ -2260,48 +2575,39 @@ error:
* @return An avi_error.
*/
-static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1)
+avi_file::error avi_file_impl::parse_idx1_chunk(std::uint64_t baseoffset, avi_chunk const &idx1)
{
- UINT8 *chunkdata = nullptr;
- avi_error avierr;
- UINT32 entries;
- UINT32 entry;
+ error avierr;
/* read the data */
- avierr = read_chunk_data(file, idx1, &chunkdata);
- if (avierr != AVIERR_NONE)
- goto error;
+ std::unique_ptr<std::uint8_t []> chunkdata;
+ avierr = read_chunk_data(idx1, chunkdata);
+ if (avierr != error::NONE)
+ return avierr;
/* loop over entries */
- entries = idx1->size / 16;
- for (entry = 0; entry < entries; entry++)
+ std::uint32_t const entries = idx1.size / 16;
+ for (std::uint32_t entry = 0; entry < entries; entry++)
{
- const UINT8 *base = &chunkdata[entry * 16];
- UINT32 chunkid = fetch_32bits(&base[0]);
- UINT32 offset = fetch_32bits(&base[8]);
- UINT32 size = fetch_32bits(&base[12]);
- avi_stream *stream;
+ std::uint8_t const *const base = &chunkdata[entry * 16];
+ std::uint32_t const chunkid = fetch_32bits(&base[0]);
+ std::uint32_t const offset = fetch_32bits(&base[8]);
+ std::uint32_t const size = fetch_32bits(&base[12]);
int streamnum;
/* determine the stream index */
streamnum = ((chunkid >> 8) & 0xff) - '0';
streamnum += 10 * ((chunkid & 0xff) - '0');
- if (streamnum >= file->streams)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
- stream = &file->stream[streamnum];
+ if (streamnum >= m_streams.size())
+ return error::INVALID_DATA;
+ avi_stream &stream = m_streams[streamnum];
/* set the appropriate entry */
- avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset, size + 8);
- if (avierr != AVIERR_NONE)
- goto error;
+ avierr = stream.set_chunk_info(stream.chunks(), baseoffset + offset, size + 8);
+ if (avierr != error::NONE)
+ return avierr;
}
-error:
- if (chunkdata != nullptr)
- free(chunkdata);
return avierr;
}
@@ -2311,7 +2617,7 @@ error:
-------------------------------------------------*/
/**
- * @fn static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength)
+ * @fn static avi_error chunk_open(avi_file *file, std::uint32_t type, std::uint32_t listtype, std::uint32_t estlength)
*
* @brief Queries if a given chunk open.
*
@@ -2323,57 +2629,55 @@ error:
* @return An avi_error.
*/
-static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength)
+avi_file::error avi_file_impl::chunk_open(std::uint32_t type, std::uint32_t listtype, std::uint32_t estlength)
{
- file_error filerr;
- avi_chunk *chunk;
- UINT32 written;
-
/* if we're out of stack entries, bail */
- if (file->chunksp >= ARRAY_LENGTH(file->chunkstack))
- return AVIERR_STACK_TOO_DEEP;
- chunk = &file->chunkstack[file->chunksp++];
+ if (m_chunksp >= m_chunkstack.size())
+ return error::STACK_TOO_DEEP;
+ avi_chunk &chunk = m_chunkstack[m_chunksp++];
/* set up the chunk information */
- chunk->offset = file->writeoffs;
- chunk->size = estlength;
- chunk->type = type;
- chunk->listtype = listtype;
+ chunk.offset = m_writeoffs;
+ chunk.size = estlength;
+ chunk.type = type;
+ chunk.listtype = listtype;
/* non-list types */
if (type != CHUNKTYPE_RIFF && type != CHUNKTYPE_LIST)
{
- UINT8 buffer[8];
+ std::uint8_t buffer[8];
/* populate the header */
- put_32bits(&buffer[0], chunk->type);
- put_32bits(&buffer[4], chunk->size);
+ put_32bits(&buffer[0], chunk.type);
+ put_32bits(&buffer[4], chunk.size);
/* write the header */
- filerr = osd_write(file->file, buffer, file->writeoffs, sizeof(buffer), &written);
- if (filerr != FILERR_NONE || written != sizeof(buffer))
- return AVIERR_WRITE_ERROR;
- file->writeoffs += written;
+ 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))
+ return error::WRITE_ERROR;
+ m_writeoffs += written;
}
/* list types */
else
{
- UINT8 buffer[12];
+ std::uint8_t buffer[12];
/* populate the header */
- put_32bits(&buffer[0], chunk->type);
- put_32bits(&buffer[4], chunk->size);
- put_32bits(&buffer[8], chunk->listtype);
+ put_32bits(&buffer[0], chunk.type);
+ put_32bits(&buffer[4], chunk.size);
+ put_32bits(&buffer[8], chunk.listtype);
/* write the header */
- filerr = osd_write(file->file, buffer, file->writeoffs, sizeof(buffer), &written);
- if (filerr != FILERR_NONE || written != sizeof(buffer))
- return AVIERR_WRITE_ERROR;
- file->writeoffs += written;
+ 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))
+ return error::WRITE_ERROR;
+ m_writeoffs += written;
}
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -2391,32 +2695,31 @@ static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32
* @return An avi_error.
*/
-static avi_error chunk_close(avi_file *file)
+avi_file::error avi_file_impl::chunk_close()
{
- avi_chunk *chunk = &file->chunkstack[--file->chunksp];
- UINT64 chunksize = file->writeoffs - (chunk->offset + 8);
- UINT32 written;
+ avi_chunk const &chunk = m_chunkstack[--m_chunksp];
+ std::uint64_t const chunksize = m_writeoffs - (chunk.offset + 8);
/* error if we don't fit into 32 bits */
- if (chunksize != (UINT32)chunksize)
- return AVIERR_INVALID_DATA;
+ if (chunksize != std::uint32_t(chunksize))
+ return error::INVALID_DATA;
/* write the final size if it is different from the guess */
- if (chunk->size != chunksize)
+ if (chunk.size != chunksize)
{
- file_error filerr;
- UINT8 buffer[4];
+ std::uint8_t buffer[4];
- put_32bits(&buffer[0], (UINT32)chunksize);
- filerr = osd_write(file->file, buffer, chunk->offset + 4, sizeof(buffer), &written);
- if (filerr != FILERR_NONE || written != sizeof(buffer))
- return AVIERR_WRITE_ERROR;
+ 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))
+ return error::WRITE_ERROR;
}
/* round up to the next word */
- file->writeoffs += chunksize & 1;
+ m_writeoffs += chunksize & 1;
- return AVIERR_NONE;
+ return error::NONE;
}
@@ -2425,7 +2728,7 @@ static avi_error chunk_close(avi_file *file)
-------------------------------------------------*/
/**
- * @fn static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length)
+ * @fn static avi_error chunk_write(avi_file *file, std::uint32_t type, const void *data, std::uint32_t length)
*
* @brief Chunk write.
*
@@ -2437,67 +2740,63 @@ static avi_error chunk_close(avi_file *file)
* @return An avi_error.
*/
-static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length)
+avi_file::error avi_file_impl::chunk_write(std::uint32_t type, const void *data, std::uint32_t length)
{
- file_error filerr;
- avi_error avierr;
- UINT32 idxreserve;
- UINT32 written;
+ error avierr;
/* if we are the first RIFF, we must reserve enough space for the IDX chunk */
- idxreserve = 0;
- if (file->riffbase == 0 && type != CHUNKTYPE_IDX1)
- idxreserve = compute_idx1_size(file);
+ std::uint32_t const idxreserve = (m_riffbase == 0 && type != CHUNKTYPE_IDX1) ? compute_idx1_size() : 0;
/* if we are getting too big, split the RIFF */
/* note that we ignore writes before the current RIFF base, as those are assumed to be
overwrites of a chunk from the previous RIFF */
- if (file->writeoffs >= file->riffbase && file->writeoffs + length + idxreserve - file->riffbase >= MAX_RIFF_SIZE)
+ if ((m_writeoffs >= m_riffbase) && ((m_writeoffs + length + idxreserve - m_riffbase) >= MAX_RIFF_SIZE))
{
/* close the movi list */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
/* write the idx1 chunk if this is the first */
- if (file->riffbase == 0)
+ if (m_riffbase == 0)
{
- avierr = write_idx1_chunk(file);
- if (avierr != AVIERR_NONE)
+ avierr = write_idx1_chunk();
+ if (avierr != error::NONE)
return avierr;
}
/* close the RIFF */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
/* open a new RIFF */
- file->riffbase = file->writeoffs;
- avierr = chunk_open(file, CHUNKTYPE_RIFF, LISTTYPE_AVIX, 0);
- if (avierr != AVIERR_NONE)
+ m_riffbase = m_writeoffs;
+ avierr = chunk_open(CHUNKTYPE_RIFF, LISTTYPE_AVIX, 0);
+ if (avierr != error::NONE)
return avierr;
/* open a nested movi list */
- file->saved_movi_offset = file->writeoffs;
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
- if (avierr != AVIERR_NONE)
+ m_saved_movi_offset = m_writeoffs;
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
+ if (avierr != error::NONE)
return avierr;
}
/* open the chunk */
- avierr = chunk_open(file, type, 0, length);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(type, 0, length);
+ if (avierr != error::NONE)
return avierr;
/* write the data */
- filerr = osd_write(file->file, data, file->writeoffs, length, &written);
- if (filerr != FILERR_NONE || written != length)
- return AVIERR_WRITE_ERROR;
- file->writeoffs += written;
+ 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)
+ return error::WRITE_ERROR;
+ m_writeoffs += written;
/* close the chunk */
- return chunk_close(file);
+ return chunk_close();
}
@@ -2509,7 +2808,7 @@ static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT
-------------------------------------------------*/
/**
- * @fn static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write)
+ * @fn static avi_error chunk_overwrite(avi_file *file, std::uint32_t type, const void *data, std::uint32_t length, std::uint64_t *offset, int initial_write)
*
* @brief Chunk overwrite.
*
@@ -2523,28 +2822,27 @@ static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT
* @return An avi_error.
*/
-static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write)
+avi_file::error avi_file_impl::chunk_overwrite(std::uint32_t type, const void *data, std::uint32_t length, std::uint64_t &offset, bool initial_write)
{
- UINT64 savedoffset = 0;
- avi_error avierr;
+ std::uint64_t savedoffset = 0;
/* if this is our initial write, save the offset */
if (initial_write)
- *offset = file->writeoffs;
+ offset = m_writeoffs;
/* otherwise, remember the current write offset and replace it with the original */
else
{
- savedoffset = file->writeoffs;
- file->writeoffs = *offset;
+ savedoffset = m_writeoffs;
+ m_writeoffs = offset;
}
/* write the chunk */
- avierr = chunk_write(file, type, data, length);
+ error const avierr = chunk_write(type, data, length);
/* if this isn't the initial write, restore the previous offset */
if (!initial_write)
- file->writeoffs = savedoffset;
+ m_writeoffs = savedoffset;
return avierr;
}
@@ -2565,67 +2863,66 @@ static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data,
* @return An avi_error.
*/
-static avi_error write_initial_headers(avi_file *file)
+avi_file::error avi_file_impl::write_initial_headers()
{
- avi_error avierr;
- int strnum;
+ error avierr;
/* reset the write pointer */
- file->writeoffs = 0;
+ m_writeoffs = 0;
/* open a RIFF chunk */
- avierr = chunk_open(file, CHUNKTYPE_RIFF, LISTTYPE_AVI, 0);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(CHUNKTYPE_RIFF, LISTTYPE_AVI, 0);
+ if (avierr != error::NONE)
return avierr;
/* open a hdlr LIST */
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_HDRL, 0);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_HDRL, 0);
+ if (avierr != error::NONE)
return avierr;
/* write an avih chunk */
- avierr = write_avih_chunk(file, TRUE);
- if (avierr != AVIERR_NONE)
+ avierr = write_avih_chunk(true);
+ if (avierr != error::NONE)
return avierr;
/* for each stream, write a strl LIST */
- for (strnum = 0; strnum < file->streams; strnum++)
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
{
/* open a strl LIST */
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_STRL, 0);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_STRL, 0);
+ if (avierr != error::NONE)
return avierr;
/* write the strh chunk */
- avierr = write_strh_chunk(file, &file->stream[strnum], TRUE);
- if (avierr != AVIERR_NONE)
+ avierr = write_strh_chunk(m_streams[strnum], true);
+ if (avierr != error::NONE)
return avierr;
/* write the strf chunk */
- avierr = write_strf_chunk(file, &file->stream[strnum]);
- if (avierr != AVIERR_NONE)
+ avierr = write_strf_chunk(m_streams[strnum]);
+ if (avierr != error::NONE)
return avierr;
/* write the indx chunk */
- avierr = write_indx_chunk(file, &file->stream[strnum], TRUE);
- if (avierr != AVIERR_NONE)
+ avierr = write_indx_chunk(m_streams[strnum], true);
+ if (avierr != error::NONE)
return avierr;
/* close the strl LIST */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
}
/* close the hdlr LIST */
- avierr = chunk_close(file);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_close();
+ if (avierr != error::NONE)
return avierr;
/* open a movi LIST */
- file->saved_movi_offset = file->writeoffs;
- avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
- if (avierr != AVIERR_NONE)
+ m_saved_movi_offset = m_writeoffs;
+ avierr = chunk_open(CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
+ if (avierr != error::NONE)
return avierr;
return avierr;
@@ -2648,23 +2945,23 @@ static avi_error write_initial_headers(avi_file *file)
* @return An avi_error.
*/
-static avi_error write_avih_chunk(avi_file *file, int initial_write)
+avi_file::error avi_file_impl::write_avih_chunk(bool initial_write)
{
- avi_stream *video = get_video_stream(file);
- UINT8 buffer[56];
+ avi_stream *video = get_video_stream();
+ std::uint8_t buffer[56];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
- put_32bits(&buffer[0], 1000000 * (INT64)video->scale / video->rate); /* dwMicroSecPerFrame */
+ put_32bits(&buffer[0], 1000000 * std::int64_t(video->scale()) / video->rate()); /* dwMicroSecPerFrame */
put_32bits(&buffer[12], AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* dwFlags */
- put_32bits(&buffer[16], video->samples); /* dwTotalFrames */
- put_32bits(&buffer[24], file->streams); /* dwStreams */
- put_32bits(&buffer[32], video->width); /* dwWidth */
- put_32bits(&buffer[36], video->height); /* dwHeight */
+ put_32bits(&buffer[16], video->samples()); /* dwTotalFrames */
+ put_32bits(&buffer[24], m_streams.size()); /* dwStreams */
+ put_32bits(&buffer[32], video->width()); /* dwWidth */
+ put_32bits(&buffer[36], video->height()); /* dwHeight */
/* (over)write the chunk */
- return chunk_overwrite(file, CHUNKTYPE_AVIH, buffer, sizeof(buffer), &file->saved_avih_offset, initial_write);
+ return chunk_overwrite(CHUNKTYPE_AVIH, buffer, sizeof(buffer), m_saved_avih_offset, initial_write);
}
@@ -2685,41 +2982,41 @@ static avi_error write_avih_chunk(avi_file *file, int initial_write)
* @return An avi_error.
*/
-static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initial_write)
+avi_file::error avi_file_impl::write_strh_chunk(avi_stream &stream, bool initial_write)
{
- UINT8 buffer[56];
+ std::uint8_t buffer[56];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
- put_32bits(&buffer[0], stream->type); /* fccType */
- put_32bits(&buffer[20], stream->scale); /* dwScale */
- put_32bits(&buffer[24], stream->rate); /* dwRate */
- put_32bits(&buffer[32], stream->samples); /* dwLength */
+ put_32bits(&buffer[0], stream.type()); /* fccType */
+ put_32bits(&buffer[20], stream.scale()); /* dwScale */
+ put_32bits(&buffer[24], stream.rate()); /* dwRate */
+ put_32bits(&buffer[32], stream.samples()); /* dwLength */
put_32bits(&buffer[40], 10000); /* dwQuality */
/* video-stream specific data */
- if (stream->type == STREAMTYPE_VIDS)
+ if (stream.type() == STREAMTYPE_VIDS)
{
put_32bits(&buffer[4], /* fccHandler */
- (stream->format == FORMAT_HFYU) ? HANDLER_HFYU : HANDLER_DIB);
+ (stream.format() == FORMAT_HFYU) ? HANDLER_HFYU : HANDLER_DIB);
put_32bits(&buffer[36], /* dwSuggestedBufferSize */
- stream->width * stream->height * 4);
- put_16bits(&buffer[52], stream->width); /* rcFrame.right */
- put_16bits(&buffer[54], stream->height); /* rcFrame.bottom */
+ stream.width() * stream.height() * 4);
+ put_16bits(&buffer[52], stream.width()); /* rcFrame.right */
+ put_16bits(&buffer[54], stream.height()); /* rcFrame.bottom */
}
/* audio-stream specific data */
- if (stream->type == STREAMTYPE_AUDS)
+ if (stream.type() == STREAMTYPE_AUDS)
{
put_32bits(&buffer[36], /* dwSuggestedBufferSize */
- stream->samplerate * stream->channels * (stream->samplebits / 8));
+ stream.samplerate() * stream.bytes_per_sample());
put_32bits(&buffer[44], /* dwSampleSize */
- stream->channels * (stream->samplebits / 8));
+ stream.bytes_per_sample());
}
/* write the chunk */
- return chunk_overwrite(file, CHUNKTYPE_STRH, buffer, sizeof(buffer), &stream->saved_strh_offset, initial_write);
+ return chunk_overwrite(CHUNKTYPE_STRH, buffer, sizeof(buffer), stream.saved_strh_offset(), initial_write);
}
@@ -2739,51 +3036,51 @@ static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initia
* @return An avi_error.
*/
-static avi_error write_strf_chunk(avi_file *file, avi_stream *stream)
+avi_file::error avi_file_impl::write_strf_chunk(avi_stream const &stream)
{
/* video stream */
- if (stream->type == STREAMTYPE_VIDS)
+ if (stream.type() == STREAMTYPE_VIDS)
{
- UINT8 buffer[40];
+ std::uint8_t buffer[40];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
put_32bits(&buffer[0], sizeof(buffer)); /* biSize */
- put_32bits(&buffer[4], stream->width); /* biWidth */
- put_32bits(&buffer[8], stream->height); /* biHeight */
+ put_32bits(&buffer[4], stream.width()); /* biWidth */
+ put_32bits(&buffer[8], stream.height()); /* biHeight */
put_16bits(&buffer[12], 1); /* biPlanes */
- put_16bits(&buffer[14], stream->depth); /* biBitCount */
- put_32bits(&buffer[16], stream->format); /* biCompression */
+ put_16bits(&buffer[14], stream.depth()); /* biBitCount */
+ put_32bits(&buffer[16], stream.format()); /* biCompression */
put_32bits(&buffer[20], /* biSizeImage */
- stream->width * stream->height * (stream->depth + 7) / 8);
+ stream.width() * stream.height() * (stream.depth() + 7) / 8);
/* write the chunk */
- return chunk_write(file, CHUNKTYPE_STRF, buffer, sizeof(buffer));
+ return chunk_write(CHUNKTYPE_STRF, buffer, sizeof(buffer));
}
/* audio stream */
- if (stream->type == STREAMTYPE_AUDS)
+ if (stream.type() == STREAMTYPE_AUDS)
{
- UINT8 buffer[16];
+ std::uint8_t buffer[16];
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
put_16bits(&buffer[0], 1); /* wFormatTag */
- put_16bits(&buffer[2], stream->channels); /* nChannels */
- put_32bits(&buffer[4], stream->samplerate); /* nSamplesPerSec */
+ put_16bits(&buffer[2], stream.channels()); /* nChannels */
+ put_32bits(&buffer[4], stream.samplerate()); /* nSamplesPerSec */
put_32bits(&buffer[8], /* nAvgBytesPerSec */
- stream->samplerate * stream->channels * (stream->samplebits / 8));
+ stream.samplerate() * stream.bytes_per_sample());
put_16bits(&buffer[12], /* nBlockAlign */
- stream->channels * (stream->samplebits / 8));
- put_16bits(&buffer[14], stream->samplebits); /* wBitsPerSample */
+ stream.bytes_per_sample());
+ put_16bits(&buffer[14], stream.samplebits()); /* wBitsPerSample */
/* write the chunk */
- return chunk_write(file, CHUNKTYPE_STRF, buffer, sizeof(buffer));
+ return chunk_write(CHUNKTYPE_STRF, buffer, sizeof(buffer));
}
- return AVIERR_INVALID_DATA;
+ return error::INVALID_DATA;
}
@@ -2804,35 +3101,30 @@ static avi_error write_strf_chunk(avi_file *file, avi_stream *stream)
* @return An avi_error.
*/
-static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initial_write)
+avi_file::error avi_file_impl::write_indx_chunk(avi_stream &stream, bool initial_write)
{
- UINT8 buffer[24 + 16 * MAX_AVI_SIZE_IN_GB / 4];
- UINT32 chunkid, indexchunkid;
- UINT32 master_entries = 0;
+ std::uint8_t buffer[24 + 16 * MAX_AVI_SIZE_IN_GB / 4];
+ std::uint32_t master_entries = 0;
/* reset the buffer */
- memset(buffer, 0, sizeof(buffer));
+ std::memset(buffer, 0, sizeof(buffer));
/* construct the chunk ID and index chunk ID */
- chunkid = get_chunkid_for_stream(file, stream);
- indexchunkid = AVI_FOURCC('i', 'x', '0' + (stream - file->stream) / 10, '0' + (stream - file->stream) % 10);
+ std::uint32_t const chunkid = get_chunkid_for_stream(&stream);
+ std::uint32_t const indexchunkid = AVI_FOURCC('i', 'x', '0' + (&stream - &m_streams[0]) / 10, '0' + (&stream - &m_streams[0]) % 10);
/* loop over chunks of 4GB and write out indexes for them first */
- if (!initial_write && file->riffbase != 0)
+ if (!initial_write && m_riffbase != 0)
{
- UINT64 currentbase;
- for (currentbase = 0; currentbase < file->writeoffs; currentbase += FOUR_GB)
+ for (std::uint64_t currentbase = 0; currentbase < m_writeoffs; currentbase += FOUR_GB)
{
- UINT64 currentend = currentbase + FOUR_GB;
- UINT32 chunks_this_index = 0;
- UINT32 bytes_this_index = 0;
- avi_error avierr;
- UINT32 chunknum;
- UINT8 *tempbuf;
+ std::uint64_t const currentend = currentbase + FOUR_GB;
+ std::uint32_t chunks_this_index = 0;
+ std::uint32_t bytes_this_index = 0;
/* count chunks that are in this region */
- for (chunknum = 0; chunknum < stream->chunks; chunknum++)
- if (stream->chunk[chunknum].offset >= currentbase && stream->chunk[chunknum].offset < currentend)
+ for (std::uint32_t chunknum = 0; chunknum < stream.chunks(); chunknum++)
+ if (stream.chunk(chunknum).offset >= currentbase && stream.chunk(chunknum).offset < currentend)
chunks_this_index++;
/* if no chunks, skip */
@@ -2840,10 +3132,10 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
continue;
/* allocate memory */
- tempbuf = (UINT8 *)malloc(24 + 8 * chunks_this_index);
- if (tempbuf == nullptr)
- return AVIERR_NO_MEMORY;
- memset(tempbuf, 0, 24 + 8 * chunks_this_index);
+ std::unique_ptr<std::uint8_t []> tempbuf;
+ try { tempbuf.reset(new std::uint8_t[24 + 8 * chunks_this_index]); }
+ catch (...) { return error::NO_MEMORY; }
+ std::memset(&tempbuf[0], 0, 24 + 8 * chunks_this_index);
/* make a regular index */
put_16bits(&tempbuf[0], 2); /* wLongsPerEntry */
@@ -2855,28 +3147,27 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
/* now fill in the indexes */
chunks_this_index = 0;
- for (chunknum = 0; chunknum < stream->chunks; chunknum++)
- if (stream->chunk[chunknum].offset >= currentbase && stream->chunk[chunknum].offset < currentend)
+ for (std::uint32_t chunknum = 0; chunknum < stream.chunks(); chunknum++)
+ if (stream.chunk(chunknum).offset >= currentbase && stream.chunk(chunknum).offset < currentend)
{
- put_32bits(&tempbuf[24 + 8 * chunks_this_index + 0], stream->chunk[chunknum].offset + 8 - currentbase);
- put_32bits(&tempbuf[24 + 8 * chunks_this_index + 4], stream->chunk[chunknum].length - 8);
- bytes_this_index += stream->chunk[chunknum].length;
+ put_32bits(&tempbuf[24 + 8 * chunks_this_index + 0], stream.chunk(chunknum).offset + 8 - currentbase);
+ put_32bits(&tempbuf[24 + 8 * chunks_this_index + 4], stream.chunk(chunknum).length - 8);
+ bytes_this_index += stream.chunk(chunknum).length;
chunks_this_index++;
}
/* write the offset of this index to the master table */
- put_64bits(&buffer[24 + 16 * master_entries + 0], file->writeoffs);
+ put_64bits(&buffer[24 + 16 * master_entries + 0], m_writeoffs);
put_32bits(&buffer[24 + 16 * master_entries + 8], 24 + 8 * chunks_this_index + 8);
- if (stream->type == STREAMTYPE_VIDS)
+ if (stream.type() == STREAMTYPE_VIDS)
put_32bits(&buffer[24 + 16 * master_entries + 12], chunks_this_index);
- else if (stream->type == STREAMTYPE_AUDS)
- put_32bits(&buffer[24 + 16 * master_entries + 12], bytes_this_index / ((stream->samplebits / 8) * stream->channels));
+ else if (stream.type() == STREAMTYPE_AUDS)
+ put_32bits(&buffer[24 + 16 * master_entries + 12], bytes_this_index / stream.bytes_per_sample());
master_entries++;
/* write the index */
- avierr = chunk_write(file, indexchunkid, tempbuf, 24 + 8 * chunks_this_index);
- free(tempbuf);
- if (avierr != AVIERR_NONE)
+ error const avierr = chunk_write(indexchunkid, &tempbuf[0], 24 + 8 * chunks_this_index);
+ if (avierr != error::NONE)
return avierr;
}
}
@@ -2892,7 +3183,7 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
}
/* (over)write the chunk */
- return chunk_overwrite(file, (master_entries == 0) ? CHUNKTYPE_JUNK : CHUNKTYPE_INDX, buffer, sizeof(buffer), &stream->saved_indx_offset, initial_write);
+ return chunk_overwrite((master_entries == 0) ? CHUNKTYPE_JUNK : CHUNKTYPE_INDX, buffer, sizeof(buffer), stream.saved_indx_offset(), initial_write);
}
@@ -2910,47 +3201,42 @@ static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initia
* @return An avi_error.
*/
-static avi_error write_idx1_chunk(avi_file *file)
+avi_file::error avi_file_impl::write_idx1_chunk()
{
- UINT32 tempbuflength = compute_idx1_size(file) - 8;
- UINT32 curchunk[2] = { 0 };
- UINT32 curoffset;
- avi_error avierr;
- UINT8 *tempbuf;
+ std::uint32_t const tempbuflength = compute_idx1_size() - 8;
+ std::uint32_t curchunk[2] = { 0 };
/* allocate a temporary buffer */
- tempbuf = (UINT8 *)malloc(tempbuflength);
- if (tempbuf == nullptr)
- return AVIERR_NO_MEMORY;
+ std::unique_ptr<std::uint8_t []> tempbuf;
+ try { tempbuf.reset(new std::uint8_t[tempbuflength]); }
+ catch (...) { return error::NO_MEMORY; }
/* fill it in */
- for (curoffset = 0; curoffset < tempbuflength; curoffset += 16)
+ for (std::uint32_t curoffset = 0; curoffset < tempbuflength; curoffset += 16)
{
- UINT64 minoffset = ~(UINT64)0;
- int strnum, minstr = 0;
+ std::uint64_t minoffset = ~std::uint64_t(0);
+ int minstr = 0;
/* determine which stream has the next chunk */
- for (strnum = 0; strnum < file->streams; strnum++)
- if (curchunk[strnum] < file->stream[strnum].chunks && file->stream[strnum].chunk[curchunk[strnum]].offset < minoffset)
+ for (int strnum = 0; strnum < m_streams.size(); strnum++)
+ if (curchunk[strnum] < m_streams[strnum].chunks() && m_streams[strnum].chunk(curchunk[strnum]).offset < minoffset)
{
- minoffset = file->stream[strnum].chunk[curchunk[strnum]].offset;
+ minoffset = m_streams[strnum].chunk(curchunk[strnum]).offset;
minstr = strnum;
}
/* make an entry for this index */
- put_32bits(&tempbuf[curoffset + 0], get_chunkid_for_stream(file, &file->stream[minstr]));
+ put_32bits(&tempbuf[curoffset + 0], get_chunkid_for_stream(&m_streams[minstr]));
put_32bits(&tempbuf[curoffset + 4], 0x0010 /* AVIIF_KEYFRAME */);
- put_32bits(&tempbuf[curoffset + 8], minoffset - (file->saved_movi_offset + 8));
- put_32bits(&tempbuf[curoffset + 12], file->stream[minstr].chunk[curchunk[minstr]].length - 8);
+ put_32bits(&tempbuf[curoffset + 8], minoffset - (m_saved_movi_offset + 8));
+ put_32bits(&tempbuf[curoffset + 12], m_streams[minstr].chunk(curchunk[minstr]).length - 8);
/* advance the chunk counter for this stream */
curchunk[minstr]++;
}
/* write the chunk */
- avierr = chunk_write(file, CHUNKTYPE_IDX1, tempbuf, tempbuflength);
- free(tempbuf);
- return avierr;
+ return chunk_write(CHUNKTYPE_IDX1, &tempbuf[0], tempbuflength);
}
@@ -2969,31 +3255,31 @@ static avi_error write_idx1_chunk(avi_file *file)
* @return An avi_error.
*/
-static avi_error soundbuf_initialize(avi_file *file)
+avi_file::error avi_file_impl::soundbuf_initialize()
{
- avi_stream *audio = get_audio_stream(file, 0, nullptr);
- avi_stream *video = get_video_stream(file);
+ int offset;
+ avi_stream *const audio = get_audio_stream(0, offset);
+ avi_stream *const video = get_video_stream();
/* we require a video stream */
if (video == nullptr)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ return error::UNSUPPORTED_VIDEO_FORMAT;
/* skip if no audio stream */
if (audio == nullptr)
- return AVIERR_NONE;
+ return error::NONE;
/* determine the number of samples we want in our buffer; 2 seconds should be enough */
- file->soundbuf_samples = file->info.audio_samplerate * SOUND_BUFFER_MSEC / 1000;
+ m_soundbuf_samples = m_info.audio_samplerate * SOUND_BUFFER_MSEC / 1000;
/* allocate a buffer */
- file->soundbuf = (INT16 *)malloc(file->soundbuf_samples * file->info.audio_channels * sizeof(file->soundbuf[0]));
- if (file->soundbuf == nullptr)
- return AVIERR_NO_MEMORY;
- memset(file->soundbuf, 0, file->soundbuf_samples * file->info.audio_channels * sizeof(file->soundbuf[0]));
+ m_soundbuf.clear();
+ try { m_soundbuf.resize(m_soundbuf_samples * m_info.audio_channels, 0); }
+ catch (...) { return error::NO_MEMORY; }
/* determine the number of frames to be ahead (0.75secs) */
- file->soundbuf_frames = ((UINT64)video->rate * 75) / ((UINT64)video->scale * 100) + 1;
- return AVIERR_NONE;
+ m_soundbuf_frames = (std::uint64_t(video->rate()) * 75) / (std::uint64_t(video->scale()) * 100) + 1;
+ return error::NONE;
}
@@ -3003,7 +3289,7 @@ static avi_error soundbuf_initialize(avi_file *file)
-------------------------------------------------*/
/**
- * @fn static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
+ * @fn static avi_error soundbuf_write_chunk(avi_file *file, std::uint32_t framenum)
*
* @brief Soundbuf write chunk.
*
@@ -3013,30 +3299,30 @@ static avi_error soundbuf_initialize(avi_file *file)
* @return An avi_error.
*/
-static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
+avi_file::error avi_file_impl::soundbuf_write_chunk(std::uint32_t framenum)
{
- avi_stream *stream = get_audio_stream(file, 0, nullptr);
- avi_error avierr;
- UINT32 length;
+ int offset;
+ avi_stream *const stream = get_audio_stream(0, offset);
+ std::uint32_t length;
/* skip if no audio stream */
if (stream == nullptr)
- return AVIERR_NONE;
+ return error::NONE;
/* determine the length of this chunk */
if (framenum == 0)
- length = framenum_to_samplenum(file, file->soundbuf_frames);
+ length = framenum_to_samplenum(m_soundbuf_frames);
else
- length = framenum_to_samplenum(file, framenum + 1 + file->soundbuf_frames) - framenum_to_samplenum(file, framenum + file->soundbuf_frames);
- length *= stream->channels * sizeof(INT16);
+ length = framenum_to_samplenum(framenum + 1 + m_soundbuf_frames) - framenum_to_samplenum(framenum + m_soundbuf_frames);
+ length *= stream->channels() * sizeof(std::int16_t);
/* then do the initial write */
- avierr = chunk_write(file, get_chunkid_for_stream(file, stream), file->soundbuf, length);
- if (avierr != AVIERR_NONE)
+ error const avierr = chunk_write(get_chunkid_for_stream(stream), &m_soundbuf[0], length);
+ if (avierr != error::NONE)
return avierr;
/* set the info for this new chunk */
- return set_stream_chunk_info(stream, stream->chunks, file->writeoffs - length - 8, length + 8);
+ return stream->set_chunk_info(stream->chunks(), m_writeoffs - length - 8, length + 8);
}
@@ -3056,36 +3342,35 @@ static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
* @return An avi_error.
*/
-static avi_error soundbuf_flush(avi_file *file, int only_flush_full)
+avi_file::error avi_file_impl::soundbuf_flush(bool only_flush_full)
{
- avi_stream *stream = get_audio_stream(file, 0, nullptr);
- INT32 channelsamples = file->soundbuf_samples;
- INT32 processedsamples = 0;
- UINT32 bytes_per_sample;
- UINT32 finalchunks;
- avi_error avierr;
- UINT32 chunknum;
- UINT32 chunkid;
- int channel;
+ int offset;
+ avi_stream *const stream = get_audio_stream(0, offset);
+ std::int32_t channelsamples = m_soundbuf_samples;
+ std::int32_t processedsamples = 0;
+ std::uint32_t finalchunks;
+ error avierr;
+ std::uint32_t chunknum;
+ std::uint32_t chunkid;
/* skip if no stream */
if (stream == nullptr)
- return AVIERR_NONE;
+ return error::NONE;
/* get the chunk ID for this stream */
- chunkid = get_chunkid_for_stream(file, stream);
- bytes_per_sample = stream->channels * sizeof(INT16);
- finalchunks = stream->chunks;
+ chunkid = get_chunkid_for_stream(stream);
+ std::uint32_t const bytes_per_sample = stream->channels() * sizeof(std::int16_t);
+ finalchunks = stream->chunks();
/* find out how many samples we've accumulated */
- for (channel = 0; channel < stream->channels; channel++)
- channelsamples = MIN(channelsamples, file->soundbuf_chansamples[channel]);
+ for (int channel = 0; channel < stream->channels(); channel++)
+ channelsamples = (std::min<std::int32_t>)(channelsamples, m_soundbuf_chansamples[channel]);
/* loop over pending sound chunks */
- for (chunknum = file->soundbuf_chunks; chunknum < stream->chunks; chunknum++)
+ for (chunknum = m_soundbuf_chunks; chunknum < stream->chunks(); chunknum++)
{
- avi_chunk_list *chunk = &stream->chunk[chunknum];
- UINT32 chunksamples = (chunk->length - 8) / bytes_per_sample;
+ avi_chunk_list &chunk = stream->chunk(chunknum);
+ std::uint32_t const chunksamples = (chunk.length - 8) / bytes_per_sample;
/* stop if we don't have enough to satisfy this chunk */
if (only_flush_full && channelsamples < chunksamples)
@@ -3094,696 +3379,300 @@ static avi_error soundbuf_flush(avi_file *file, int only_flush_full)
/* if we don't have all the samples we need, pad with 0's */
if (channelsamples > 0 && channelsamples < chunksamples)
{
- if (processedsamples + chunksamples > file->soundbuf_samples)
- return AVIERR_EXCEEDED_SOUND_BUFFER;
- memset(&file->soundbuf[(processedsamples + channelsamples) * stream->channels], 0, (chunksamples - channelsamples) * bytes_per_sample);
+ if (processedsamples + chunksamples > m_soundbuf_samples)
+ return error::EXCEEDED_SOUND_BUFFER;
+ std::memset(&m_soundbuf[(processedsamples + channelsamples) * stream->channels()], 0, (chunksamples - channelsamples) * bytes_per_sample);
}
/* if we're completely out of samples, clear the buffer entirely and use the end */
else if (channelsamples <= 0)
{
- processedsamples = file->soundbuf_samples - chunksamples;
- memset(&file->soundbuf[processedsamples * stream->channels], 0, chunksamples * bytes_per_sample);
+ processedsamples = m_soundbuf_samples - chunksamples;
+ std::memset(&m_soundbuf[processedsamples * stream->channels()], 0, chunksamples * bytes_per_sample);
chunkid = CHUNKTYPE_JUNK;
finalchunks--;
}
/* copy the sample data in */
- avierr = chunk_overwrite(file, chunkid, &file->soundbuf[processedsamples * stream->channels], chunk->length - 8, &chunk->offset, FALSE);
- if (avierr != AVIERR_NONE)
+ avierr = chunk_overwrite(chunkid, &m_soundbuf[processedsamples * stream->channels()], chunk.length - 8, chunk.offset, false);
+ if (avierr != error::NONE)
return avierr;
/* add up the samples */
if (channelsamples > chunksamples)
- file->info.audio_numsamples = stream->samples += chunksamples;
+ m_info.audio_numsamples = stream->add_samples(chunksamples);
else if (channelsamples > 0)
- file->info.audio_numsamples = stream->samples += channelsamples;
+ m_info.audio_numsamples = stream->add_samples(channelsamples);
/* advance past those */
processedsamples += chunksamples;
channelsamples -= chunksamples;
- channelsamples = MAX(0, channelsamples);
+ channelsamples = (std::max)(0, channelsamples);
}
/* if we have a non-zero offset, shift everything down */
if (processedsamples > 0)
{
/* first account for the samples we processed */
- memmove(&file->soundbuf[0], &file->soundbuf[processedsamples * stream->channels], (file->soundbuf_samples - processedsamples) * bytes_per_sample);
- for (channel = 0; channel < stream->channels; channel++)
- file->soundbuf_chansamples[channel] -= processedsamples;
+ std::memmove(&m_soundbuf[0], &m_soundbuf[processedsamples * stream->channels()], (m_soundbuf_samples - processedsamples) * bytes_per_sample);
+ for (int channel = 0; channel < stream->channels(); channel++)
+ m_soundbuf_chansamples[channel] -= processedsamples;
}
/* update the final chunk count */
if (!only_flush_full)
- stream->chunks = finalchunks;
+ stream->set_chunks(finalchunks);
/* account for flushed chunks */
- file->soundbuf_chunks = chunknum;
- return AVIERR_NONE;
+ m_soundbuf_chunks = chunknum;
+ return error::NONE;
}
/*-------------------------------------------------
- rgb32_compress_to_rgb - "compress" an RGB32
- bitmap to an RGB encoded frame
+ printf_chunk_recursive - print information
+ about a chunk recursively
-------------------------------------------------*/
/**
- * @fn static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, UINT8 *data, UINT32 numbytes)
- *
- * @brief RGB 32 compress to RGB.
+ * @fn static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
*
- * @param [in,out] stream If non-null, the stream.
- * @param bitmap The bitmap.
- * @param [in,out] data If non-null, the data.
- * @param numbytes The numbytes.
+ * @brief Printf chunk recursive.
*
- * @return An avi_error.
+ * @param [in,out] file If non-null, the file.
+ * @param [in,out] container If non-null, the container.
+ * @param indent The indent.
*/
-static avi_error rgb32_compress_to_rgb(avi_stream *stream, const bitmap_rgb32 &bitmap, UINT8 *data, UINT32 numbytes)
+void avi_file_impl::printf_chunk_recursive(avi_chunk const *container, int indent)
{
- int height = MIN(stream->height, bitmap.height());
- int width = MIN(stream->width, bitmap.width());
- UINT8 *dataend = data + numbytes;
- int x, y;
+ char size[20], offset[20];
+ avi_chunk curchunk;
+ error avierr;
- /* compressed video */
- for (y = 0; y < height; y++)
+ /* iterate over chunks in this container */
+ for (avierr = get_first_chunk(container, curchunk); avierr == error::NONE; avierr = get_next_chunk(container, curchunk))
{
- const UINT32 *source = &bitmap.pix32(y);
- UINT8 *dest = data + (stream->height - 1 - y) * stream->width * 3;
-
- for (x = 0; x < width && dest < dataend; x++)
- {
- rgb_t pix = *source++;
- *dest++ = pix.b();
- *dest++ = pix.g();
- *dest++ = pix.r();
- }
+ std::uint32_t chunksize = curchunk.size;
+ bool recurse = false;
- /* fill in any blank space on the right */
- for ( ; x < stream->width && dest < dataend; x++)
- {
- *dest++ = 0;
- *dest++ = 0;
- *dest++ = 0;
- }
- }
+ u64toa(curchunk.size, size);
+ u64toa(curchunk.offset, offset);
+ printf("%*schunk = %c%c%c%c, size=%s (%s)\n", indent, "",
+ std::uint8_t(curchunk.type >> 0),
+ std::uint8_t(curchunk.type >> 8),
+ std::uint8_t(curchunk.type >> 16),
+ std::uint8_t(curchunk.type >> 24),
+ size, offset);
- /* fill in any blank space on the bottom */
- for ( ; y < stream->height; y++)
- {
- UINT8 *dest = data + (stream->height - 1 - y) * stream->width * 3;
- for (x = 0; x < stream->width && dest < dataend; x++)
+ /* certain chunks are just containers; recurse into them */
+ switch (curchunk.type)
{
- *dest++ = 0;
- *dest++ = 0;
- *dest++ = 0;
+ /* basic containers */
+ case CHUNKTYPE_RIFF:
+ case CHUNKTYPE_LIST:
+ printf("%*stype = %c%c%c%c\n", indent, "",
+ std::uint8_t(curchunk.listtype >> 0),
+ std::uint8_t(curchunk.listtype >> 8),
+ std::uint8_t(curchunk.listtype >> 16),
+ std::uint8_t(curchunk.listtype >> 24));
+ recurse = true;
+ chunksize = 0;
+ break;
}
- }
-
- return AVIERR_NONE;
-}
-
-
-/*-------------------------------------------------
- yuv_decompress_to_yuy16 - decompress a YUV
- encoded frame to a YUY16 bitmap
--------------------------------------------------*/
-
-/**
- * @fn static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
- *
- * @brief Yuv decompress to yuy 16.
- *
- * @param [in,out] stream If non-null, the stream.
- * @param data The data.
- * @param numbytes The numbytes.
- * @param [in,out] bitmap The bitmap.
- *
- * @return An avi_error.
- */
-static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
-{
- const UINT16 *dataend = (const UINT16 *)(data + numbytes);
- int x, y;
-
- /* compressed video */
- for (y = 0; y < stream->height; y++)
- {
- const UINT16 *source = (const UINT16 *)data + y * stream->width;
- UINT16 *dest = &bitmap.pix16(y);
-
- /* switch off the compression */
- switch (stream->format)
+ /* print data within the chunk */
+ if (chunksize > 0 && curchunk.size < 1024 * 1024)
{
- case FORMAT_UYVY:
- for (x = 0; x < stream->width && source < dataend; x++)
- *dest++ = *source++;
- break;
+ std::unique_ptr<std::uint8_t []> data;
- case FORMAT_VYUY:
- case FORMAT_YUY2:
- for (x = 0; x < stream->width && source < dataend; x++)
+ /* read the data for a chunk */
+ avierr = read_chunk_data(curchunk, data);
+ if (avierr == error::NONE)
+ {
+ std::uint32_t const bytes = (std::min)(std::uint32_t(512), chunksize);
+ for (std::uint32_t i = 0; i < bytes; i++)
{
- UINT16 pix = *source++;
- *dest++ = (pix >> 8) | (pix << 8);
+ if (i % 16 == 0) printf("%*s ", indent, "");
+ printf("%02X ", data[i]);
+ if (i % 16 == 15) printf("\n");
}
- break;
+ if (chunksize % 16 != 0) printf("\n");
+ }
}
+
+ /* if we're recursing, dive down */
+ if (recurse)
+ printf_chunk_recursive(&curchunk, indent + 4);
}
- return AVIERR_NONE;
+ /* if we didn't get a legitimate error, indicate that */
+ if (avierr != error::END)
+ printf("[chunk error %d]\n", int(avierr));
}
+} // anonymous namespace
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
/*-------------------------------------------------
- yuy16_compress_to_yuy - "compress" a YUY16
- bitmap to a YUV encoded frame
+ avi_open - open an AVI movie file for read
-------------------------------------------------*/
/**
- * @fn static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, UINT8 *data, UINT32 numbytes)
+ * @fn avi_error avi_open(const char *filename, avi_file **file)
*
- * @brief Yuy 16 compress to yuy.
+ * @brief Queries if a given avi open.
*
- * @param [in,out] stream If non-null, the stream.
- * @param bitmap The bitmap.
- * @param [in,out] data If non-null, the data.
- * @param numbytes The numbytes.
+ * @param filename Filename of the file.
+ * @param [in,out] file If non-null, the file.
*
* @return An avi_error.
*/
-static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_yuy16 &bitmap, UINT8 *data, UINT32 numbytes)
+avi_file::error avi_file::open(std::string const &filename, ptr &file)
{
- const UINT16 *dataend = (const UINT16 *)(data + numbytes);
- int x, y;
-
- /* compressed video */
- for (y = 0; y < stream->height; y++)
- {
- const UINT16 *source = &bitmap.pix16(y);
- UINT16 *dest = (UINT16 *)data + y * stream->width;
+ /* 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)
+ return error::CANT_OPEN_FILE;
- /* switch off the compression */
- switch (stream->format)
- {
- case FORMAT_UYVY:
- for (x = 0; x < stream->width && dest < dataend; x++)
- *dest++ = *source++;
- break;
+ /* allocate the file */
+ std::unique_ptr<avi_file_impl> newfile;
+ try { newfile = std::make_unique<avi_file_impl>(std::move(f), length); }
+ catch (...) { return error::NO_MEMORY; }
- case FORMAT_VYUY:
- case FORMAT_YUY2:
- for (x = 0; x < stream->width && dest < dataend; x++)
- {
- UINT16 pix = *source++;
- *dest++ = (pix >> 8) | (pix << 8);
- }
- break;
- }
- }
+ /* parse the data */
+ error const avierr = newfile->read_movie_data();
+ if (avierr != error::NONE)
+ return avierr;
- return AVIERR_NONE;
+ file = std::move(newfile);
+ return error::NONE;
}
/*-------------------------------------------------
- huffyuv_extract_tables - extract HuffYUV
- tables
+ avi_create - create a new AVI movie file
-------------------------------------------------*/
/**
- * @fn static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size)
+ * @fn avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
*
- * @brief Huffyuv extract tables.
+ * @brief Avi create.
*
- * @param [in,out] stream If non-null, the stream.
- * @param chunkdata The chunkdata.
- * @param size The size.
+ * @param filename Filename of the file.
+ * @param info The information.
+ * @param [in,out] file If non-null, the file.
*
* @return An avi_error.
*/
-static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size)
+avi_file::error avi_file::create(std::string const &filename, movie_info const &info, ptr &file)
{
- const UINT8 *chunkend = chunkdata + size;
- avi_error avierr = AVIERR_NONE;
- int tabnum;
-
- /* allocate memory for the data */
- stream->huffyuv = (huffyuv_data *)malloc(sizeof(*stream->huffyuv));
- if (stream->huffyuv == nullptr)
- {
- avierr = AVIERR_NO_MEMORY;
- goto error;
- }
-
- /* extract predictor information */
- if (&chunkdata[40] >= chunkend)
- return AVIERR_INVALID_DATA;
- stream->huffyuv->predictor = chunkdata[40];
+ /* validate video info */
+ if ((info.video_format != 0 && info.video_format != FORMAT_UYVY && info.video_format != FORMAT_VYUY && info.video_format != FORMAT_YUY2) ||
+ (info.video_width == 0) ||
+ (info.video_height == 0) ||
+ (info.video_depth == 0) ||
+ (info.video_depth % 8 != 0))
+ return error::UNSUPPORTED_VIDEO_FORMAT;
- /* make sure it's the left predictor */
- if ((stream->huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) != HUFFYUV_PREDICT_LEFT)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ /* validate audio info */
+ if (info.audio_format != 0 ||
+ info.audio_channels > MAX_SOUND_CHANNELS ||
+ info.audio_samplebits != 16)
+ return error::UNSUPPORTED_AUDIO_FORMAT;
- /* make sure it's 16bpp YUV data */
- if (chunkdata[41] != 16)
- return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
- chunkdata += 44;
+ /* 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)
+ return error::CANT_OPEN_FILE;
- /* loop over tables */
- for (tabnum = 0; tabnum < 3; tabnum++)
+ /* allocate the file */
+ error avierr;
+ std::unique_ptr<avi_file_impl> newfile;
+ try { newfile = std::make_unique<avi_file_impl>(std::move(f), info); }
+ catch (...)
{
- huffyuv_table *table = &stream->huffyuv->table[tabnum];
- UINT32 curbits, bitadd;
- UINT16 bitsat16 = 0;
- int offset = 0, bits;
-
- /* loop until we populate the whole table */
- while (offset < 256)
- {
- int data, shift, count, i;
-
- /* extract the next run */
- if (chunkdata >= chunkend)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
- data = *chunkdata++;
- shift = data & 0x1f;
- count = data >> 5;
-
- /* zero count means next whole byte is a count */
- if (count == 0)
- {
- if (chunkdata >= chunkend)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
- count = *chunkdata++;
- }
- for (i = 0; i < count; i++)
- table->shift[offset++] = shift;
- }
-
- /* now determine bit patterns and masks */
- curbits = 0;
- for (bits = 31; bits >= 0; bits--)
- {
- bitadd = 1 << (32 - bits);
-
- /* make sure we've cleared out all the bits below */
- if ((curbits & (bitadd - 1)) != 0)
- {
- avierr = AVIERR_INVALID_DATA;
- goto error;
- }
-
- /* find all entries with this shift count and assign them */
- for (offset = 0; offset < 256; offset++)
- if (table->shift[offset] == bits)
- {
- table->bits[offset] = curbits;
- table->mask[offset] = ~(bitadd - 1);
- curbits += bitadd;
- }
+ avierr = error::NO_MEMORY;
+ goto error;
+ }
- /* remember the bit pattern when we complete all the 17-bit codes */
- if (bits == 17)
- bitsat16 = curbits >> 16;
- }
+ /* initialize the sound buffering */
+ avierr = newfile->soundbuf_initialize();
+ if (avierr != error::NONE)
+ goto error;
- /* allocate the number of extra lookup tables we need */
- if (bitsat16 > 0)
- {
- table->extralookup = (UINT16 *)malloc(bitsat16 * 65536 * sizeof(table->extralookup[0]));
- if (table->extralookup == nullptr)
- {
- avierr = AVIERR_NO_MEMORY;
- goto error;
- }
- for (offset = 0; offset < bitsat16; offset++)
- table->baselookup[offset] = (offset << 8) | 0;
- }
+ /* write the initial headers */
+ avierr = newfile->write_initial_headers();
+ if (avierr != error::NONE)
+ goto error;
- /* then create lookup tables */
- for (offset = 0; offset < 256; offset++)
- if (table->shift[offset] > 16)
- {
- UINT16 *tablebase = table->extralookup + (table->bits[offset] >> 16) * 65536;
- UINT32 start = table->bits[offset] & 0xffff;
- UINT32 end = start + ((1 << (32 - table->shift[offset])) - 1);
- while (start <= end)
- tablebase[start++] = (offset << 8) | (table->shift[offset] - 16);
- }
- else if (table->shift[offset] > 0)
- {
- UINT32 start = table->bits[offset] >> 16;
- UINT32 end = start + ((1 << (16 - table->shift[offset])) - 1);
- while (start <= end)
- table->baselookup[start++] = (offset << 8) | table->shift[offset];
- }
- }
+ file = std::move(newfile);
+ return error::NONE;
error:
- if (avierr != AVIERR_NONE && stream->huffyuv != nullptr)
- {
- free(stream->huffyuv);
- stream->huffyuv = nullptr;
- }
+ f.reset();
+ newfile.reset();
+ osd_file::remove(filename);
return avierr;
}
/*-------------------------------------------------
- huffyuv_decompress_to_yuy16 - decompress a
- HuffYUV-encoded frame to a YUY16 bitmap
+ avi_error_string - get the error string for
+ an avi_error
-------------------------------------------------*/
/**
- * @fn static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
+ * @fn const char *avi_error_string(avi_error err)
*
- * @brief Huffyuv decompress to yuy 16.
+ * @brief Avi error string.
*
- * @param [in,out] stream If non-null, the stream.
- * @param data The data.
- * @param numbytes The numbytes.
- * @param [in,out] bitmap The bitmap.
+ * @param err The error.
*
- * @return An avi_error.
+ * @return null if it fails, else a char*.
*/
-static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_yuy16 &bitmap)
+const char *avi_file::error_string(error err)
{
- huffyuv_data *huffyuv = stream->huffyuv;
- int prevlines = (stream->height > 288) ? 2 : 1;
- UINT8 lastprevy = 0, lastprevcb = 0, lastprevcr = 0;
- UINT8 lasty = 0, lastcb = 0, lastcr = 0;
- UINT8 bitsinbuffer = 0;
- UINT32 bitbuffer = 0;
- UINT32 dataoffs = 0;
- int x, y;
-
- /* compressed video */
- for (y = 0; y < stream->height; y++)
- {
- UINT16 *dest = &bitmap.pix16(y);
-
- /* handle the first four bytes independently */
- x = 0;
- if (y == 0)
- {
- /* first DWORD is stored as YUY2 */
- lasty = data[dataoffs++];
- lastcb = data[dataoffs++];
- *dest++ = (lasty << 8) | lastcb;
- lasty = data[dataoffs++];
- lastcr = data[dataoffs++];
- *dest++ = (lasty << 8) | lastcr;
- x = 2;
- }
-
- /* loop over pixels */
- for ( ; x < stream->width; x++)
- {
- huffyuv_table *ytable = &huffyuv->table[0];
- huffyuv_table *ctable = &huffyuv->table[1 + (x & 1)];
- UINT16 pixel, huffdata;
- int shift;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- /* look up the Y component */
- huffdata = ytable->baselookup[bitbuffer >> 16];
- shift = huffdata & 0xff;
- if (shift == 0)
- {
- bitsinbuffer -= 16;
- bitbuffer <<= 16;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- huffdata = ytable->extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
- shift = huffdata & 0xff;
- }
- bitsinbuffer -= shift;
- bitbuffer <<= shift;
- pixel = huffdata & 0xff00;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- /* look up the Cb/Cr component */
- huffdata = ctable->baselookup[bitbuffer >> 16];
- shift = huffdata & 0xff;
- if (shift == 0)
- {
- bitsinbuffer -= 16;
- bitbuffer <<= 16;
-
- /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
- while (bitsinbuffer <= 24 && dataoffs < numbytes)
- {
- bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
- bitsinbuffer += 8;
- }
-
- huffdata = ctable->extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
- shift = huffdata & 0xff;
- }
- bitsinbuffer -= shift;
- bitbuffer <<= shift;
- *dest++ = pixel | (huffdata >> 8);
- }
- }
-
- /* apply deltas */
- lastprevy = lastprevcb = lastprevcr = 0;
- for (y = 0; y < stream->height; y++)
+ switch (err)
{
- UINT16 *prevrow = &bitmap.pix16(y - prevlines);
- UINT16 *dest = &bitmap.pix16(y);
-
- /* handle the first four bytes independently */
- x = 0;
- if (y == 0)
- {
- /* lasty, lastcr, lastcb are set up previously */
- x = 2;
- }
-
- /* left predict or gradient predict */
- if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_LEFT ||
- ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT))
- {
- /* first do left deltas */
- for ( ; x < stream->width; x += 2)
- {
- UINT16 pixel0 = dest[x + 0];
- UINT16 pixel1 = dest[x + 1];
-
- lasty += pixel0 >> 8;
- lastcb += pixel0;
- dest[x + 0] = (lasty << 8) | lastcb;
-
- lasty += pixel1 >> 8;
- lastcr += pixel1;
- dest[x + 1] = (lasty << 8) | lastcr;
- }
-
- /* for gradient, we then add in the previous row */
- if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT && y >= prevlines)
- for (x = 0; x < stream->width; x++)
- {
- UINT16 curpix = dest[x];
- UINT16 prevpix = prevrow[x];
- UINT8 ysum = (curpix >> 8) + (prevpix >> 8);
- UINT8 csum = curpix + prevpix;
- dest[x] = (ysum << 8) | csum;
- }
- }
-
- /* median predict on rows > 0 */
- else if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_MEDIAN && y >= prevlines)
- {
- for ( ; x < stream->width; x += 2)
- {
- UINT16 prevpixel0 = prevrow[x + 0];
- UINT16 prevpixel1 = prevrow[x + 1];
- UINT16 pixel0 = dest[x + 0];
- UINT16 pixel1 = dest[x + 1];
- UINT8 a, b, c;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lasty;
- b = prevpixel0 >> 8;
- c = lastprevy;
- lastprevy = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lasty = (pixel0 >> 8) + b;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lastcb;
- b = prevpixel0 & 0xff;
- c = lastprevcb;
- lastprevcb = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lastcb = (pixel0 & 0xff) + b;
- dest[x + 0] = (lasty << 8) | lastcb;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lasty;
- b = prevpixel1 >> 8;
- c = lastprevy;
- lastprevy = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lasty = (pixel1 >> 8) + b;
-
- /* compute previous, above, and (prev + above - above-left) */
- a = lastcr;
- b = prevpixel1 & 0xff;
- c = lastprevcr;
- lastprevcr = b;
- if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
- if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
- if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
- lastcr = (pixel1 & 0xff) + b;
- dest[x + 1] = (lasty << 8) | lastcr;
- }
- }
+ case error::NONE: return "success";
+ case error::END: return "hit end of file";
+ case error::INVALID_DATA: return "invalid data";
+ case error::NO_MEMORY: return "out of memory";
+ case error::READ_ERROR: return "read error";
+ case error::WRITE_ERROR: return "write error";
+ case error::STACK_TOO_DEEP: return "stack overflow";
+ case error::UNSUPPORTED_FEATURE: return "unsupported feature";
+ case error::CANT_OPEN_FILE: return "unable to open file";
+ case error::INCOMPATIBLE_AUDIO_STREAMS: return "found incompatible audio streams";
+ case error::INVALID_SAMPLERATE: return "found invalid sample rate";
+ case error::INVALID_STREAM: return "invalid stream";
+ case error::INVALID_FRAME: return "invalid frame index";
+ case error::INVALID_BITMAP: return "invalid bitmap";
+ case error::UNSUPPORTED_VIDEO_FORMAT: return "unsupported video format";
+ case error::UNSUPPORTED_AUDIO_FORMAT: return "unsupported audio format";
+ case error::EXCEEDED_SOUND_BUFFER: return "sound buffer overflow";
+ default: return "undocumented error";
}
-
- return AVIERR_NONE;
}
-/**
- * @fn static void u64toa(UINT64 val, char *output)
- *
- * @brief 64toas.
- *
- * @param val The value.
- * @param [in,out] output If non-null, the output.
- */
-static void u64toa(UINT64 val, char *output)
+avi_file::avi_file()
{
- UINT32 lo = (UINT32)(val & 0xffffffff);
- UINT32 hi = (UINT32)(val >> 32);
- if (hi != 0)
- sprintf(output, "%X%08X", hi, lo);
- else
- sprintf(output, "%X", lo);
}
-/*-------------------------------------------------
- printf_chunk_recursive - print information
- about a chunk recursively
--------------------------------------------------*/
-
-/**
- * @fn static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
- *
- * @brief Printf chunk recursive.
- *
- * @param [in,out] file If non-null, the file.
- * @param [in,out] container If non-null, the container.
- * @param indent The indent.
- */
-
-static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
+avi_file::~avi_file()
{
- char size[20], offset[20];
- avi_chunk curchunk;
- int avierr;
-
- /* iterate over chunks in this container */
- for (avierr = get_first_chunk(file, container, &curchunk); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, &curchunk))
- {
- UINT32 chunksize = curchunk.size;
- int recurse = FALSE;
-
- u64toa(curchunk.size, size);
- u64toa(curchunk.offset, offset);
- printf("%*schunk = %c%c%c%c, size=%s (%s)\n", indent, "",
- (UINT8)(curchunk.type >> 0),
- (UINT8)(curchunk.type >> 8),
- (UINT8)(curchunk.type >> 16),
- (UINT8)(curchunk.type >> 24),
- size, offset);
-
- /* certain chunks are just containers; recurse into them */
- switch (curchunk.type)
- {
- /* basic containers */
- case CHUNKTYPE_RIFF:
- case CHUNKTYPE_LIST:
- printf("%*stype = %c%c%c%c\n", indent, "",
- (UINT8)(curchunk.listtype >> 0),
- (UINT8)(curchunk.listtype >> 8),
- (UINT8)(curchunk.listtype >> 16),
- (UINT8)(curchunk.listtype >> 24));
- recurse = TRUE;
- chunksize = 0;
- break;
- }
-
- /* print data within the chunk */
- if (chunksize > 0 && curchunk.size < 1024 * 1024)
- {
- UINT8 *data = nullptr;
- int i;
-
- /* read the data for a chunk */
- avierr = read_chunk_data(file, &curchunk, &data);
- if (avierr == AVIERR_NONE)
- {
- int bytes = MIN(512, chunksize);
- for (i = 0; i < bytes; i++)
- {
- if (i % 16 == 0) printf("%*s ", indent, "");
- printf("%02X ", data[i]);
- if (i % 16 == 15) printf("\n");
- }
- if (chunksize % 16 != 0) printf("\n");
- free(data);
- }
- }
-
- /* if we're recursing, dive down */
- if (recurse)
- printf_chunk_recursive(file, &curchunk, indent + 4);
- }
-
- /* if we didn't get a legitimate error, indicate that */
- if (avierr != AVIERR_END)
- printf("[chunk error %d]\n", avierr);
}
diff --git a/src/lib/util/aviio.h b/src/lib/util/aviio.h
index 86e2fd19cd2..c6d547903fe 100644
--- a/src/lib/util/aviio.h
+++ b/src/lib/util/aviio.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
aviio.h
@@ -8,52 +8,15 @@
***************************************************************************/
-#ifndef __AVIIO_H__
-#define __AVIIO_H__
+#ifndef MAME_LIB_UTIL_AVIIO_H
+#define MAME_LIB_UTIL_AVIIO_H
#include "osdcore.h"
#include "bitmap.h"
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-enum avi_error
-{
- AVIERR_NONE = 0,
- AVIERR_END,
- AVIERR_INVALID_DATA,
- AVIERR_NO_MEMORY,
- AVIERR_READ_ERROR,
- AVIERR_WRITE_ERROR,
- AVIERR_STACK_TOO_DEEP,
- AVIERR_UNSUPPORTED_FEATURE,
- AVIERR_CANT_OPEN_FILE,
- AVIERR_INCOMPATIBLE_AUDIO_STREAMS,
- AVIERR_INVALID_SAMPLERATE,
- AVIERR_INVALID_STREAM,
- AVIERR_INVALID_FRAME,
- AVIERR_INVALID_BITMAP,
- AVIERR_UNSUPPORTED_VIDEO_FORMAT,
- AVIERR_UNSUPPORTED_AUDIO_FORMAT,
- AVIERR_EXCEEDED_SOUND_BUFFER
-};
-
-
-enum avi_datatype
-{
- AVIDATA_VIDEO,
- AVIDATA_AUDIO_CHAN0,
- AVIDATA_AUDIO_CHAN1,
- AVIDATA_AUDIO_CHAN2,
- AVIDATA_AUDIO_CHAN3,
- AVIDATA_AUDIO_CHAN4,
- AVIDATA_AUDIO_CHAN5,
- AVIDATA_AUDIO_CHAN6,
- AVIDATA_AUDIO_CHAN7
-};
-
+#include <cstdint>
+#include <memory>
+#include <string>
/***************************************************************************
@@ -69,53 +32,98 @@ enum avi_datatype
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-struct avi_file;
-
-
-struct avi_movie_info
+class avi_file
{
- UINT32 video_format; /* format of video data */
- UINT32 video_timescale; /* timescale for video data */
- UINT32 video_sampletime; /* duration of a single video sample (frame) */
- UINT32 video_numsamples; /* total number of video samples */
- UINT32 video_width; /* width of the video */
- UINT32 video_height; /* height of the video */
- UINT32 video_depth; /* depth of the video */
-
- UINT32 audio_format; /* format of audio data */
- UINT32 audio_timescale; /* timescale for audio data */
- UINT32 audio_sampletime; /* duration of a single audio sample */
- UINT32 audio_numsamples; /* total number of audio samples */
- UINT32 audio_channels; /* number of audio channels */
- UINT32 audio_samplebits; /* number of bits per channel */
- UINT32 audio_samplerate; /* sample rate of audio */
+public:
+
+ /***********************************************************************
+ CONSTANTS
+ ***********************************************************************/
+
+ enum class error
+ {
+ NONE = 0,
+ END,
+ INVALID_DATA,
+ NO_MEMORY,
+ READ_ERROR,
+ WRITE_ERROR,
+ STACK_TOO_DEEP,
+ UNSUPPORTED_FEATURE,
+ CANT_OPEN_FILE,
+ INCOMPATIBLE_AUDIO_STREAMS,
+ INVALID_SAMPLERATE,
+ INVALID_STREAM,
+ INVALID_FRAME,
+ INVALID_BITMAP,
+ UNSUPPORTED_VIDEO_FORMAT,
+ UNSUPPORTED_AUDIO_FORMAT,
+ EXCEEDED_SOUND_BUFFER
+ };
+
+ enum class datatype
+ {
+ VIDEO,
+ AUDIO_CHAN0,
+ AUDIO_CHAN1,
+ AUDIO_CHAN2,
+ AUDIO_CHAN3,
+ AUDIO_CHAN4,
+ AUDIO_CHAN5,
+ AUDIO_CHAN6,
+ AUDIO_CHAN7
+ };
+
+
+ /***********************************************************************
+ TYPE DEFINITIONS
+ ***********************************************************************/
+
+ struct movie_info
+ {
+ std::uint32_t video_format; // format of video data
+ std::uint32_t video_timescale; // timescale for video data
+ std::uint32_t video_sampletime; // duration of a single video sample (frame)
+ std::uint32_t video_numsamples; // total number of video samples
+ std::uint32_t video_width; // width of the video
+ std::uint32_t video_height; // height of the video
+ std::uint32_t video_depth; // depth of the video
+
+ std::uint32_t audio_format; // format of audio data
+ std::uint32_t audio_timescale; // timescale for audio data
+ std::uint32_t audio_sampletime; // duration of a single audio sample
+ std::uint32_t audio_numsamples; // total number of audio samples
+ std::uint32_t audio_channels; // number of audio channels
+ std::uint32_t audio_samplebits; // number of bits per channel
+ std::uint32_t audio_samplerate; // sample rate of audio
+ };
+
+ typedef std::unique_ptr<avi_file> ptr;
+
+
+ /***********************************************************************
+ PROTOTYPES
+ ***********************************************************************/
+
+ static error open(std::string const &filename, ptr &file);
+ static error create(std::string const &filename, movie_info const &info, ptr &file);
+ virtual ~avi_file();
+
+ virtual void printf_chunks() = 0;
+ static const char *error_string(error err);
+
+ virtual movie_info const &get_movie_info() const = 0;
+ virtual std::uint32_t first_sample_in_frame(std::uint32_t framenum) const = 0;
+
+ virtual error read_video_frame(std::uint32_t framenum, bitmap_yuy16 &bitmap) = 0;
+ virtual error read_sound_samples(int channel, std::uint32_t firstsample, std::uint32_t numsamples, std::int16_t *output) = 0;
+
+ virtual error append_video_frame(bitmap_yuy16 &bitmap) = 0;
+ virtual error append_video_frame(bitmap_rgb32 &bitmap) = 0;
+ virtual error append_sound_samples(int channel, std::int16_t const *samples, std::uint32_t numsamples, std::uint32_t sampleskip) = 0;
+
+protected:
+ avi_file();
};
-
-
-/***************************************************************************
- PROTOTYPES
-***************************************************************************/
-
-avi_error avi_open(const char *filename, avi_file **file);
-avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file);
-avi_error avi_close(avi_file *file);
-
-void avi_printf_chunks(avi_file *file);
-const char *avi_error_string(avi_error err);
-
-const avi_movie_info *avi_get_movie_info(avi_file *file);
-UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum);
-
-avi_error avi_read_video_frame(avi_file *file, UINT32 framenum, bitmap_yuy16 &bitmap);
-avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output);
-
-avi_error avi_append_video_frame(avi_file *file, bitmap_yuy16 &bitmap);
-avi_error avi_append_video_frame(avi_file *file, bitmap_rgb32 &bitmap);
-avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples, UINT32 sampleskip);
-
-#endif
+#endif // MAME_LIB_UTIL_AVIIO_H
diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp
index 8bdf4af6c0f..bd48a73d8d8 100644
--- a/src/lib/util/cdrom.cpp
+++ b/src/lib/util/cdrom.cpp
@@ -244,8 +244,8 @@ cdrom_file *cdrom_open(const char *inputfile)
for (i = 0; i < file->cdtoc.numtrks; i++)
{
- file_error filerr = util::core_file::open(file->track_info.track[i].fname.c_str(), OPEN_FLAG_READ, file->fhandle[i]);
- if (filerr != FILERR_NONE)
+ osd_file::error filerr = util::core_file::open(file->track_info.track[i].fname.c_str(), OPEN_FLAG_READ, file->fhandle[i]);
+ if (filerr != osd_file::error::NONE)
{
fprintf(stderr, "Unable to open file: %s\n", file->track_info.track[i].fname.c_str());
cdrom_close(file);
diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp
index 93a1b34ba29..3a97c6ce0fe 100644
--- a/src/lib/util/chd.cpp
+++ b/src/lib/util/chd.cpp
@@ -660,8 +660,8 @@ chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hun
// create the new file
util::core_file::ptr file;
- const file_error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
- if (filerr != FILERR_NONE)
+ 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;
// create the file normally, then claim the file
@@ -672,7 +672,7 @@ chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hun
if (chderr != CHDERR_NONE)
{
file.reset();
- osd_rmfile(filename);
+ osd_file::remove(filename);
}
else
{
@@ -705,8 +705,8 @@ chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hun
// create the new file
util::core_file::ptr file;
- const file_error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file);
- if (filerr != FILERR_NONE)
+ 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;
// create the file normally, then claim the file
@@ -717,7 +717,7 @@ chd_error chd_file::create(const char *filename, UINT64 logicalbytes, UINT32 hun
if (chderr != CHDERR_NONE)
{
file.reset();
- osd_rmfile(filename);
+ osd_file::remove(filename);
}
else
{
@@ -749,8 +749,8 @@ chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent)
// open the file
const UINT32 openflags = writeable ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_READ;
util::core_file::ptr file;
- const file_error filerr = util::core_file::open(filename, openflags, file);
- if (filerr != FILERR_NONE)
+ const osd_file::error filerr = util::core_file::open(filename, openflags, file);
+ if (filerr != osd_file::error::NONE)
return CHDERR_FILE_NOT_FOUND;
// now open the CHD
diff --git a/src/lib/util/chdcd.cpp b/src/lib/util/chdcd.cpp
index eeb196d242f..0e8b32b1ed6 100644
--- a/src/lib/util/chdcd.cpp
+++ b/src/lib/util/chdcd.cpp
@@ -87,13 +87,10 @@ static std::string get_file_path(std::string &path)
static UINT64 get_file_size(const char *filename)
{
- osd_file *file;
- UINT64 filesize = 0;
- file_error filerr;
+ osd_file::ptr file;
+ std::uint64_t filesize = 0;
- filerr = osd_open(filename, OPEN_FLAG_READ, &file, &filesize);
- if (filerr == FILERR_NONE)
- osd_close(file);
+ osd_file::open(filename, OPEN_FLAG_READ, file, filesize);
return filesize;
}
@@ -215,57 +212,51 @@ static UINT32 parse_wav_sample(const char *filename, UINT32 *dataoffs)
UINT32 length, rate, filesize;
UINT16 bits, temp16;
char buf[32];
- osd_file *file;
- file_error filerr;
+ osd_file::ptr file;
UINT64 fsize = 0;
- UINT32 actual;
+ std::uint32_t actual;
- filerr = osd_open(filename, OPEN_FLAG_READ, &file, &fsize);
- if (filerr != FILERR_NONE)
+ osd_file::error filerr = osd_file::open(filename, OPEN_FLAG_READ, file, fsize);
+ if (filerr != osd_file::error::NONE)
{
printf("ERROR: could not open (%s)\n", filename);
return 0;
}
/* read the core header and make sure it's a WAVE file */
- osd_read(file, buf, 0, 4, &actual);
+ file->read(buf, 0, 4, actual);
offset += actual;
if (offset < 4)
{
- osd_close(file);
printf("ERROR: unexpected RIFF offset %lu (%s)\n", offset, filename);
return 0;
}
if (memcmp(&buf[0], "RIFF", 4) != 0)
{
- osd_close(file);
printf("ERROR: could not find RIFF header (%s)\n", filename);
return 0;
}
/* get the total size */
- osd_read(file, &filesize, offset, 4, &actual);
+ file->read(&filesize, offset, 4, actual);
offset += actual;
if (offset < 8)
{
- osd_close(file);
printf("ERROR: unexpected size offset %lu (%s)\n", offset, filename);
return 0;
}
filesize = LITTLE_ENDIANIZE_INT32(filesize);
/* read the RIFF file type and make sure it's a WAVE file */
- osd_read(file, buf, offset, 4, &actual);
+ file->read(buf, offset, 4, actual);
offset += actual;
if (offset < 12)
{
- osd_close(file);
printf("ERROR: unexpected WAVE offset %lu (%s)\n", offset, filename);
return 0;
}
if (memcmp(&buf[0], "WAVE", 4) != 0)
{
- osd_close(file);
printf("ERROR: could not find WAVE header (%s)\n", filename);
return 0;
}
@@ -273,9 +264,9 @@ static UINT32 parse_wav_sample(const char *filename, UINT32 *dataoffs)
/* seek until we find a format tag */
while (1)
{
- osd_read(file, buf, offset, 4, &actual);
+ file->read(buf, offset, 4, actual);
offset += actual;
- osd_read(file, &length, offset, 4, &actual);
+ file->read(&length, offset, 4, actual);
offset += actual;
length = LITTLE_ENDIANIZE_INT32(length);
if (memcmp(&buf[0], "fmt ", 4) == 0)
@@ -285,56 +276,51 @@ static UINT32 parse_wav_sample(const char *filename, UINT32 *dataoffs)
offset += length;
if (offset >= filesize)
{
- osd_close(file);
printf("ERROR: could not find fmt tag (%s)\n", filename);
return 0;
}
}
/* read the format -- make sure it is PCM */
- osd_read(file, &temp16, offset, 2, &actual);
+ file->read(&temp16, offset, 2, actual);
offset += actual;
temp16 = LITTLE_ENDIANIZE_INT16(temp16);
if (temp16 != 1)
{
- osd_close(file);
printf("ERROR: unsupported format %u - only PCM is supported (%s)\n", temp16, filename);
return 0;
}
/* number of channels -- only stereo is supported */
- osd_read(file, &temp16, offset, 2, &actual);
+ file->read(&temp16, offset, 2, actual);
offset += actual;
temp16 = LITTLE_ENDIANIZE_INT16(temp16);
if (temp16 != 2)
{
- osd_close(file);
printf("ERROR: unsupported number of channels %u - only stereo is supported (%s)\n", temp16, filename);
return 0;
}
/* sample rate */
- osd_read(file, &rate, offset, 4, &actual);
+ file->read(&rate, offset, 4, actual);
offset += actual;
rate = LITTLE_ENDIANIZE_INT32(rate);
if (rate != 44100)
{
- osd_close(file);
printf("ERROR: unsupported samplerate %u - only 44100 is supported (%s)\n", rate, filename);
return 0;
}
/* bytes/second and block alignment are ignored */
- osd_read(file, buf, offset, 6, &actual);
+ file->read(buf, offset, 6, actual);
offset += actual;
/* bits/sample */
- osd_read(file, &bits, offset, 2, &actual);
+ file->read(&bits, offset, 2, actual);
offset += actual;
bits = LITTLE_ENDIANIZE_INT16(bits);
if (bits != 16)
{
- osd_close(file);
printf("ERROR: unsupported bits/sample %u - only 16 is supported (%s)\n", bits, filename);
return 0;
}
@@ -345,9 +331,9 @@ static UINT32 parse_wav_sample(const char *filename, UINT32 *dataoffs)
/* seek until we find a data tag */
while (1)
{
- osd_read(file, buf, offset, 4, &actual);
+ file->read(buf, offset, 4, actual);
offset += actual;
- osd_read(file, &length, offset, 4, &actual);
+ file->read(&length, offset, 4, actual);
offset += actual;
length = LITTLE_ENDIANIZE_INT32(length);
if (memcmp(&buf[0], "data", 4) == 0)
@@ -357,14 +343,11 @@ static UINT32 parse_wav_sample(const char *filename, UINT32 *dataoffs)
offset += length;
if (offset >= filesize)
{
- osd_close(file);
printf("ERROR: could not find data tag (%s)\n", filename);
return 0;
}
}
- osd_close(file);
-
/* if there was a 0 length data block, we're done */
if (length == 0)
{
diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp
index 64169a606fc..ec1e25340e3 100644
--- a/src/lib/util/corefile.cpp
+++ b/src/lib/util/corefile.cpp
@@ -23,9 +23,7 @@
namespace util {
-
namespace {
-
/***************************************************************************
VALIDATION
***************************************************************************/
@@ -143,7 +141,7 @@ class core_proxy_file : public core_file
public:
core_proxy_file(core_file &file) : m_file(file) { }
virtual ~core_proxy_file() override { }
- virtual file_error compress(int level) override { return m_file.compress(level); }
+ 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(); }
@@ -159,9 +157,9 @@ public:
virtual std::uint32_t write(const void *buffer, std::uint32_t length) override { return m_file.write(buffer, length); }
virtual int puts(const char *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 file_error truncate(std::uint64_t offset) override { return m_file.truncate(offset); }
+ virtual osd_file::error truncate(std::uint64_t offset) override { return m_file.truncate(offset); }
- virtual file_error flush() override { return m_file.flush(); }
+ virtual osd_file::error flush() override { return m_file.flush(); }
private:
core_file &m_file;
@@ -232,7 +230,7 @@ public:
}
~core_in_memory_file() override { purge(); }
- virtual file_error compress(int level) override { return FILERR_INVALID_ACCESS; }
+ 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; }
@@ -243,8 +241,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 file_error truncate(std::uint64_t offset) override;
- virtual file_error flush() override { clear_putback(); return FILERR_NONE; }
+ virtual osd_file::error truncate(std::uint64_t offset) override;
+ virtual osd_file::error flush() override { clear_putback(); return osd_file::error::NONE; }
protected:
core_in_memory_file(std::uint32_t openflags, std::uint64_t length)
@@ -295,9 +293,9 @@ private:
class core_osd_file : public core_in_memory_file
{
public:
- core_osd_file(std::uint32_t openmode, osd_file *file, std::uint64_t length)
+ core_osd_file(std::uint32_t openmode, osd_file::ptr &&file, std::uint64_t length)
: core_in_memory_file(openmode, length)
- , m_file(file)
+ , m_file(std::move(file))
, m_zdata()
, m_bufferbase(0)
, m_bufferbytes(0)
@@ -305,7 +303,7 @@ public:
}
~core_osd_file() override;
- virtual file_error compress(int level) override;
+ virtual osd_file::error compress(int level) override;
virtual int seek(std::int64_t offset, int whence) override;
@@ -313,8 +311,8 @@ public:
virtual void const *buffer() override;
virtual std::uint32_t write(void const *buffer, std::uint32_t length) override;
- virtual file_error truncate(std::uint64_t offset) override;
- virtual file_error flush() override;
+ virtual osd_file::error truncate(std::uint64_t offset) override;
+ virtual osd_file::error flush() override;
protected:
@@ -323,10 +321,10 @@ protected:
private:
static constexpr std::size_t FILE_BUFFER_SIZE = 512;
- file_error osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual);
- file_error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual);
+ 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 * m_file; // OSD file handle
+ 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
@@ -688,14 +686,14 @@ std::uint32_t core_in_memory_file::read(void *buffer, std::uint32_t length)
truncate - truncate a file
-------------------------------------------------*/
-file_error core_in_memory_file::truncate(std::uint64_t offset)
+osd_file::error core_in_memory_file::truncate(std::uint64_t offset)
{
if (m_length < offset)
- return FILERR_FAILURE;
+ return osd_file::error::FAILURE;
// adjust to new length and offset
set_length(offset);
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
@@ -736,8 +734,6 @@ core_osd_file::~core_osd_file()
// close files and free memory
if (m_zdata)
compress(FCOMPRESS_NONE);
- if (m_file)
- osd_close(m_file);
}
@@ -747,13 +743,13 @@ core_osd_file::~core_osd_file()
compression, or up to 9 for max compression
-------------------------------------------------*/
-file_error core_osd_file::compress(int level)
+osd_file::error core_osd_file::compress(int level)
{
- file_error result = FILERR_NONE;
+ 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 FILERR_INVALID_ACCESS;
+ return osd_file::error::INVALID_ACCESS;
// if we have been compressing, flush and free the data
if (m_zdata && (level == FCOMPRESS_NONE))
@@ -767,7 +763,7 @@ file_error core_osd_file::compress(int level)
zerr = m_zdata->finalise();
if ((zerr != Z_STREAM_END) && (zerr != Z_OK))
{
- result = FILERR_INVALID_DATA;
+ result = osd_file::error::INVALID_DATA;
break;
}
@@ -775,8 +771,8 @@ file_error core_osd_file::compress(int level)
if (m_zdata->has_output())
{
std::uint32_t actualdata;
- auto const filerr = osd_write(m_file, m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), &actualdata);
- if (filerr != FILERR_NONE)
+ 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();
@@ -800,7 +796,7 @@ file_error core_osd_file::compress(int level)
// on error, return an error
if (zerr != Z_OK)
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
// flush buffers
m_bufferbytes = 0;
@@ -888,13 +884,12 @@ void const *core_osd_file::buffer()
// read the file
std::uint32_t read_length = 0;
auto const filerr = osd_or_zlib_read(buf, 0, length(), read_length);
- if ((filerr != FILERR_NONE) || (read_length != length()))
+ if ((filerr != osd_file::error::NONE) || (read_length != length()))
purge();
else
{
// close the file because we don't need it anymore
- osd_close(m_file);
- m_file = nullptr;
+ m_file.reset();
}
}
return core_in_memory_file::buffer();
@@ -931,19 +926,19 @@ std::uint32_t core_osd_file::write(void const *buffer, std::uint32_t length)
truncate - truncate a file
-------------------------------------------------*/
-file_error core_osd_file::truncate(std::uint64_t offset)
+osd_file::error core_osd_file::truncate(std::uint64_t offset)
{
if (is_loaded())
return core_in_memory_file::truncate(offset);
// truncate file
- auto const err = osd_truncate(m_file, offset);
- if (err != FILERR_NONE)
+ auto const err = m_file->truncate(offset);
+ if (err != osd_file::error::NONE)
return err;
// and adjust to new length and offset
set_length(offset);
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
@@ -951,7 +946,7 @@ file_error core_osd_file::truncate(std::uint64_t offset)
flush - flush file buffers
-------------------------------------------------*/
-file_error core_osd_file::flush()
+osd_file::error core_osd_file::flush()
{
if (is_loaded())
return core_in_memory_file::flush();
@@ -962,7 +957,7 @@ file_error core_osd_file::flush()
// invalidate any buffered data
m_bufferbytes = 0;
- return osd_fflush(m_file);
+ return m_file->flush();
}
@@ -971,18 +966,18 @@ file_error core_osd_file::flush()
handles zlib-compressed data
-------------------------------------------------*/
-file_error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual)
+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 osd_read(m_file, buffer, offset, length, &actual);
+ 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 FILERR_INVALID_ACCESS;
+ return osd_file::error::INVALID_ACCESS;
// set up the destination
- file_error filerr = FILERR_NONE;
+ osd_file::error filerr = osd_file::error::NONE;
m_zdata->set_output(buffer, length);
while (!m_zdata->output_full())
{
@@ -992,7 +987,7 @@ file_error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, s
auto const zerr = m_zdata->decompress();
if (Z_OK != zerr)
{
- if (Z_STREAM_END != zerr) filerr = FILERR_INVALID_DATA;
+ if (Z_STREAM_END != zerr) filerr = osd_file::error::INVALID_DATA;
break;
}
}
@@ -1001,8 +996,8 @@ file_error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, s
if (!m_zdata->has_input())
{
std::uint32_t actualdata = 0;
- filerr = osd_read(m_file, m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->buffer_size(), &actualdata);
- if (filerr != FILERR_NONE) break;
+ 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;
@@ -1022,7 +1017,7 @@ file_error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, s
-------------------------------------------------*/
/**
- * @fn file_error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t actual)
+ * @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.
*
@@ -1031,18 +1026,18 @@ file_error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, s
* @param length The length.
* @param [in,out] actual The actual.
*
- * @return A file_error.
+ * @return A osd_file::error.
*/
-file_error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual)
+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 osd_write(m_file, buffer, offset, length, &actual);
+ 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 FILERR_INVALID_ACCESS;
+ return osd_file::error::INVALID_ACCESS;
// set up the source
m_zdata->set_input(buffer, length);
@@ -1054,15 +1049,15 @@ file_error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t of
{
actual = length - m_zdata->input_size();
m_zdata->add_nextoffset(actual);
- return FILERR_INVALID_DATA;
+ 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 = osd_write(m_file, m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), &actualdata);
- if (filerr != FILERR_NONE)
+ 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();
@@ -1072,7 +1067,7 @@ file_error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t of
// we wrote everything
actual = length;
m_zdata->add_nextoffset(actual);
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
} // anonymous namespace
@@ -1088,24 +1083,23 @@ file_error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t of
return an error code
-------------------------------------------------*/
-file_error core_file::open(char const *filename, std::uint32_t openflags, ptr &file)
+osd_file::error core_file::open(char const *filename, std::uint32_t openflags, ptr &file)
{
- // attempt to open the file
- osd_file *f = nullptr;
- std::uint64_t length = 0;
- auto const filerr = osd_open(filename, openflags, &f, &length);
- if (filerr != FILERR_NONE)
- return filerr;
-
try
{
- file = std::make_unique<core_osd_file>(openflags, f, length);
- return FILERR_NONE;
+ // 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)
+ return filerr;
+
+ file = std::make_unique<core_osd_file>(openflags, std::move(f), length);
+ return osd_file::error::NONE;
}
catch (...)
{
- osd_close(f);
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
}
}
@@ -1115,20 +1109,20 @@ file_error core_file::open(char const *filename, std::uint32_t openflags, ptr &f
like access and return an error code
-------------------------------------------------*/
-file_error core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
+osd_file::error 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 FILERR_INVALID_ACCESS;
+ return osd_file::error::INVALID_ACCESS;
try
{
file.reset(new core_in_memory_file(openflags, data, length, false));
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
catch (...)
{
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
}
}
@@ -1139,24 +1133,24 @@ file_error core_file::open_ram(void const *data, std::size_t length, std::uint32
error code
-------------------------------------------------*/
-file_error core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file)
+osd_file::error 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 FILERR_INVALID_ACCESS;
+ return osd_file::error::INVALID_ACCESS;
try
{
ptr result(new core_in_memory_file(openflags, data, length, true));
if (!result->buffer())
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
file = std::move(result);
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
catch (...)
{
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
}
}
@@ -1166,16 +1160,16 @@ file_error core_file::open_ram_copy(void const *data, std::size_t length, std::u
object and return an error code
-------------------------------------------------*/
-file_error core_file::open_proxy(core_file &file, ptr &proxy)
+osd_file::error core_file::open_proxy(core_file &file, ptr &proxy)
{
try
{
proxy = std::make_unique<core_proxy_file>(file);
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
catch (...)
{
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
}
}
@@ -1195,19 +1189,19 @@ core_file::~core_file()
pointer
-------------------------------------------------*/
-file_error core_file::load(char const *filename, void **data, std::uint32_t &length)
+osd_file::error core_file::load(char const *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 != FILERR_NONE)
+ if (err != osd_file::error::NONE)
return err;
// get the size
auto const size = file->size();
if (std::uint32_t(size) != size)
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
// allocate memory
*data = osd_malloc(size);
@@ -1217,26 +1211,26 @@ file_error core_file::load(char const *filename, void **data, std::uint32_t &len
if (file->read(*data, size) != size)
{
free(*data);
- return FILERR_FAILURE;
+ return osd_file::error::FAILURE;
}
// close the file and return data
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
-file_error core_file::load(char const *filename, dynamic_buffer &data)
+osd_file::error core_file::load(char const *filename, dynamic_buffer &data)
{
ptr file;
// attempt to open the file
auto const err = open(filename, OPEN_FLAG_READ, file);
- if (err != FILERR_NONE)
+ if (err != osd_file::error::NONE)
return err;
// get the size
auto const size = file->size();
if (std::uint32_t(size) != size)
- return FILERR_OUT_OF_MEMORY;
+ return osd_file::error::OUT_OF_MEMORY;
// allocate memory
data.resize(size);
@@ -1245,11 +1239,11 @@ file_error core_file::load(char const *filename, dynamic_buffer &data)
if (file->read(&data[0], size) != size)
{
data.clear();
- return FILERR_FAILURE;
+ return osd_file::error::FAILURE;
}
// close the file and return data
- return FILERR_NONE;
+ return osd_file::error::NONE;
}
diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h
index 7ec76af7cb5..e66545440c2 100644
--- a/src/lib/util/corefile.h
+++ b/src/lib/util/corefile.h
@@ -10,8 +10,8 @@
#pragma once
-#ifndef __COREFILE_H__
-#define __COREFILE_H__
+#ifndef MAME_LIB_UTIL_COREFILE_H
+#define MAME_LIB_UTIL_COREFILE_H
#include "corestr.h"
#include "coretmpl.h"
@@ -23,7 +23,6 @@
namespace util {
-
/***************************************************************************
ADDITIONAL OPEN FLAGS
***************************************************************************/
@@ -49,22 +48,22 @@ public:
// ----- file open/close -----
// open a file with the specified filename
- static file_error open(const char *filename, std::uint32_t openflags, ptr &file);
+ static osd_file::error open(const char *filename, std::uint32_t openflags, ptr &file);
// open a RAM-based "file" using the given data and length (read-only)
- static file_error open_ram(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
+ static osd_file::error 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 file_error open_ram_copy(const void *data, std::size_t length, std::uint32_t openflags, ptr &file);
+ static osd_file::error 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 file_error open_proxy(core_file &file, ptr &proxy);
+ static osd_file::error 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 file_error compress(int level) = 0;
+ virtual osd_file::error compress(int level) = 0;
// ----- file positioning -----
@@ -101,8 +100,8 @@ public:
virtual const void *buffer() = 0;
// open a file with the specified filename, read it into memory, and return a pointer
- static file_error load(const char *filename, void **data, std::uint32_t &length);
- static file_error load(const char *filename, dynamic_buffer &data);
+ static osd_file::error load(const char *filename, void **data, std::uint32_t &length);
+ static osd_file::error load(const char *filename, dynamic_buffer &data);
// ----- file write -----
@@ -121,10 +120,10 @@ public:
}
// file truncation
- virtual file_error truncate(std::uint64_t offset) = 0;
+ virtual osd_file::error truncate(std::uint64_t offset) = 0;
// flush file buffers
- virtual file_error flush() = 0;
+ virtual osd_file::error flush() = 0;
protected:
@@ -147,4 +146,4 @@ std::string core_filename_extract_base(const char *name, bool strip_extension =
int core_filename_ends_with(const char *filename, const char *extension);
-#endif /* __COREFILE_H__ */
+#endif // MAME_LIB_UTIL_COREFILE_H
diff --git a/src/lib/util/un7z.cpp b/src/lib/util/un7z.cpp
index b9cfa13eafe..80c0a6bcba6 100644
--- a/src/lib/util/un7z.cpp
+++ b/src/lib/util/un7z.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
un7z.c
@@ -10,364 +10,285 @@
// this is based on unzip.c, with modifications needed to use the 7zip library
-#include "osdcore.h"
#include "un7z.h"
-#include <ctype.h>
-#include <stdlib.h>
-#include <zlib.h>
+#include "corestr.h"
+#include "unicode.h"
+#include "lzma/C/7z.h"
+#include "lzma/C/7zCrc.h"
+#include "lzma/C/7zVersion.h"
+
+#include <array>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <utility>
+#include <vector>
+
+
+namespace {
/***************************************************************************
- 7Zip Memory / File handling (adapted from 7zfile.c/.h and 7zalloc.c/.h)
+ TYPE DEFINITIONS
***************************************************************************/
-void *SZipAlloc(void *p, size_t size)
+struct CSzFile
{
- if (size == 0)
- return nullptr;
+ CSzFile() : currfpos(0), length(0), osdfile() {}
- return malloc(size);
-}
+ long currfpos;
+ std::uint64_t length;
+ osd_file::ptr osdfile;
-void SZipFree(void *p, void *address)
-{
- free(address);
-}
+ WRes read(void *data, std::size_t &size)
+ {
+ if (!osdfile)
+ {
+ std::printf("un7z.c: called File_Read without file\n");
+ return 1;
+ }
+ if (!size) return 0;
+ size_t originalSize = size;
+ std::uint32_t read_length;
+ //osd_file::error err =
+ osdfile->read(data, currfpos, originalSize, read_length);
+ size = read_length;
+ currfpos += read_length;
-void File_Construct(CSzFile *p)
-{
- p->_7z_osdfile = nullptr;
-}
+ if (size == originalSize)
+ return 0;
-static WRes File_Open(CSzFile *p, const char *name, int writeMode)
-{
- /* we handle this ourselves ... */
- if (!p->_7z_osdfile) return 1;
- else return 0;
-}
+ return 0;
+ }
+
+ WRes seek(Int64 &pos, ESzSeek origin)
+ {
+ if (origin == 0) currfpos = pos;
+ if (origin == 1) currfpos = currfpos + pos;
+ if (origin == 2) currfpos = length -pos;
-WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
-WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
+ pos = currfpos;
+ return 0;
+ }
+};
-WRes File_Close(CSzFile *p)
+struct CFileInStream : public ISeekInStream, public CSzFile
{
- /* we handle this ourselves ... */
- return 0;
-}
+ CFileInStream();
+};
-WRes File_Read(CSzFile *p, void *data, size_t *size)
+
+class m7z_file_impl
{
-// file_error err;
- UINT32 read_length;
+public:
+ typedef std::unique_ptr<m7z_file_impl> ptr;
- if (!p->_7z_osdfile)
+ m7z_file_impl(const std::string &filename);
+ ~m7z_file_impl()
{
- printf("un7z.c: called File_Read without file\n");
- return 1;
+ if (m_out_buffer)
+ IAlloc_Free(&m_alloc_imp, m_out_buffer);
+ if (m_inited)
+ SzArEx_Free(&m_db, &m_alloc_imp);
}
- size_t originalSize = *size;
- if (originalSize == 0)
- return 0;
+ static ptr find_cached(const std::string &filename)
+ {
+ for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++)
+ {
+ // 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))
+ {
+ ptr result;
+ std::swap(s_cache[cachenum], result);
+ return result;
+ }
+ }
+ return ptr();
+ }
+ static void close(ptr &&archive);
+ static void cache_clear()
+ {
+ // clear call cache entries
+ for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { }
+ }
-// err =
- osd_read( p->_7z_osdfile, data, p->_7z_currfpos, originalSize, &read_length );
- *size = read_length;
- p->_7z_currfpos += read_length;
+ _7z_file::error initialize();
- if (*size == originalSize)
- return 0;
+ int first_file() { return search(0, 0, std::string(), false, false); }
+ int next_file() { return (m_curr_file_idx < 0) ? -1 : search(m_curr_file_idx + 1, 0, std::string(), false, false); }
- return 0;
-}
+ int search(std::uint32_t crc) { return search(0, crc, std::string(), true, false); }
+ int search(const std::string &filename) { return search(0, 0, filename, false, true); }
+ int search(std::uint32_t crc, const std::string &filename) { return search(0, crc, filename, true, true); }
-WRes File_Write(CSzFile *p, const void *data, size_t *size)
-{
- return 0;
-}
+ const std::string &current_name() const { return m_curr_name; }
+ std::uint64_t current_uncompressed_length() const { return m_curr_length; }
+ std::uint32_t current_crc() const { return m_curr_crc; }
-WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
-{
- if (origin==0) p->_7z_currfpos = *pos;
- if (origin==1) p->_7z_currfpos = p->_7z_currfpos + *pos;
- if (origin==2) p->_7z_currfpos = p->_7z_length - *pos;
+ _7z_file::error decompress(void *buffer, std::uint32_t length);
- *pos = p->_7z_currfpos;
+private:
+ m7z_file_impl(const m7z_file_impl &) = delete;
+ m7z_file_impl(m7z_file_impl &&) = delete;
+ m7z_file_impl &operator=(const m7z_file_impl &) = delete;
+ m7z_file_impl &operator=(m7z_file_impl &&) = delete;
- return 0;
-}
+ int search(int i, std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname);
+ void make_utf8_name(int index);
-WRes File_GetLength(CSzFile *p, UInt64 *length)
-{
- *length = p->_7z_length;
- return 0;
-}
+ static constexpr std::size_t CACHE_SIZE = 8;
+ static std::array<ptr, CACHE_SIZE> s_cache;
-/* ---------- FileSeqInStream ---------- */
+ const std::string m_filename; // copy of _7Z filename (for caching)
-static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
-{
- CFileSeqInStream *p = (CFileSeqInStream *)pp;
- return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
-}
+ int m_curr_file_idx; // current file index
+ std::string m_curr_name; // current file name
+ std::uint64_t m_curr_length; // current file uncompressed length
+ std::uint32_t m_curr_crc; // current file crc
-void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
-{
- p->s.Read = FileSeqInStream_Read;
-}
+ std::vector<UInt16> m_utf16_buf;
+ std::vector<unicode_char> m_uchar_buf;
+ std::vector<char> m_utf8_buf;
+ CFileInStream m_archive_stream;
+ CLookToRead m_look_stream;
+ CSzArEx m_db;
+ ISzAlloc m_alloc_imp;
+ ISzAlloc m_alloc_temp_imp;
+ bool m_inited;
-/* ---------- FileInStream ---------- */
+ // cached stuff for solid blocks
+ UInt32 m_block_index;
+ Byte * m_out_buffer;
+ std::size_t m_out_buffer_size;
-static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
-{
- CFileInStream *p = (CFileInStream *)pp;
- return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
-}
+};
-static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
-{
- CFileInStream *p = (CFileInStream *)pp;
- return File_Seek(&p->file, pos, origin);
-}
-void FileInStream_CreateVTable(CFileInStream *p)
+class m7z_file_wrapper : public _7z_file
{
- p->s.Read = FileInStream_Read;
- p->s.Seek = FileInStream_Seek;
-}
+public:
+ m7z_file_wrapper(m7z_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); }
+ virtual ~m7z_file_wrapper() override { m7z_file_impl::close(std::move(m_impl)); }
-/* ---------- FileOutStream ---------- */
+ virtual int first_file() override { return m_impl->first_file(); }
+ virtual int next_file() override { return m_impl->next_file(); }
-static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
-{
- CFileOutStream *p = (CFileOutStream *)pp;
- File_Write(&p->file, data, &size);
- return size;
-}
+ virtual int search(std::uint32_t crc) override { return m_impl->search(crc); }
+ virtual int search(const std::string &filename) override { return m_impl->search(filename); }
+ virtual int search(std::uint32_t crc, const std::string &filename) override { return m_impl->search(crc, filename); }
-void FileOutStream_CreateVTable(CFileOutStream *p)
-{
- p->s.Write = FileOutStream_Write;
-}
+ 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::uint32_t current_crc() const override { return m_impl->current_crc(); }
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
+ virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); }
+
+private:
+ m7z_file_impl::ptr m_impl;
+};
-/* number of open files to cache */
-#define _7Z_CACHE_SIZE 8
/***************************************************************************
GLOBAL VARIABLES
***************************************************************************/
-static _7z_file *_7z_cache[_7Z_CACHE_SIZE];
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+std::array<m7z_file_impl::ptr, m7z_file_impl::CACHE_SIZE> m7z_file_impl::s_cache;
-/* cache management */
-static void free__7z_file(_7z_file *_7z);
/***************************************************************************
- _7Z FILE ACCESS
+ 7Zip Memory / File handling (adapted from 7zfile.c/.h and 7zalloc.c/.h)
***************************************************************************/
-/*-------------------------------------------------
- _7z_file_open - opens a _7Z file for reading
--------------------------------------------------*/
-
-int _7z_search_crc_match(_7z_file *new_7z, UINT32 search_crc, const char* search_filename, int search_filename_length, bool matchcrc, bool matchname)
-{
- UInt16 *temp = nullptr;
- size_t tempSize = 0;
-
- for (int i = 0; i < new_7z->db.db.NumFiles; i++)
- {
- const CSzFileItem *f = new_7z->db.db.Files + i;
- size_t len;
-
- len = SzArEx_GetFileNameUtf16(&new_7z->db, i, nullptr);
-
- // if it's a directory entry we don't care about it..
- if (f->IsDir)
- continue;
-
- if (len > tempSize)
- {
- SZipFree(nullptr, temp);
- tempSize = len;
- temp = (UInt16 *)SZipAlloc(nullptr, tempSize * sizeof(temp[0]));
- if (temp == nullptr)
- {
- return -1; // memory error
- }
- }
-
- bool crcmatch = false;
- bool namematch = false;
-
- UINT64 size = f->Size;
- UINT32 crc = f->Crc;
-
- /* Check for a name match */
- SzArEx_GetFileNameUtf16(&new_7z->db, i, temp);
-
- if (len == search_filename_length+1)
- {
- int j;
- for (j=0;j<search_filename_length;j++)
- {
- UINT8 sn = search_filename[j];
- UINT16 zn = temp[j]; // these are utf16
-
- // MAME filenames are always lowercase so be case insensitive
- if ((zn>=0x41) && (zn<=0x5a)) zn+=0x20;
-
- if (sn != zn) break;
- }
- if (j==search_filename_length) namematch = true;
- }
-
-
- /* Check for a CRC match */
- if (crc==search_crc) crcmatch = true;
-
- bool found = false;
-
- if (matchcrc && matchname)
- {
- if (crcmatch && namematch)
- found = true;
- }
- else if (matchcrc)
- {
- if (crcmatch)
- found = true;
- }
- else if (matchname)
- {
- if (namematch)
- found = true;
- }
+/* ---------- FileInStream ---------- */
- if (found)
- {
- // printf("found %S %d %08x %08x %08x %s %d\n", temp, len, crc, search_crc, size, search_filename, search_filename_length);
- new_7z->curr_file_idx = i;
- new_7z->uncompressed_length = size;
- new_7z->crc = crc;
+extern "C" {
- SZipFree(nullptr, temp);
- return i;
- }
- }
+static void *SZipAlloc(void *p, std::size_t size)
+{
+ return (size == 0) ? nullptr : std::malloc(size);
+}
- SZipFree(nullptr, temp);
- return -1;
+static void SZipFree(void *p, void *address)
+{
+ std::free(address);
}
-_7z_error _7z_file_open(const char *filename, _7z_file **_7z)
+static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
{
- file_error err;
- _7z_error _7zerr = _7ZERR_NONE;
-
+ return (reinterpret_cast<CFileInStream *>(pp)->read(buf, *size) == 0) ? SZ_OK : SZ_ERROR_READ;
+}
- _7z_file *new_7z;
- char *string;
- int cachenum;
+static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ return reinterpret_cast<CFileInStream *>(pp)->seek(*pos, origin);
+}
- SRes res;
+} // extern "C"
- /* ensure we start with a NULL result */
- *_7z = nullptr;
- /* see if we are in the cache, and reopen if so */
- for (cachenum = 0; cachenum < ARRAY_LENGTH(_7z_cache); cachenum++)
- {
- _7z_file *cached = _7z_cache[cachenum];
+CFileInStream::CFileInStream()
+{
+ Read = &FileInStream_Read;
+ Seek = &FileInStream_Seek;
+}
- /* if we have a valid entry and it matches our filename, use it and remove from the cache */
- if (cached != nullptr && cached->filename != nullptr && strcmp(filename, cached->filename) == 0)
- {
- *_7z = cached;
- _7z_cache[cachenum] = nullptr;
- return _7ZERR_NONE;
- }
- }
- /* allocate memory for the _7z_file structure */
- new_7z = (_7z_file *)malloc(sizeof(*new_7z));
- if (new_7z == nullptr)
- return _7ZERR_OUT_OF_MEMORY;
- memset(new_7z, 0, sizeof(*new_7z));
- new_7z->inited = false;
- new_7z->archiveStream.file._7z_currfpos = 0;
- err = osd_open(filename, OPEN_FLAG_READ, &new_7z->archiveStream.file._7z_osdfile, &new_7z->archiveStream.file._7z_length);
- if (err != FILERR_NONE)
- {
- _7zerr = _7ZERR_FILE_ERROR;
- goto error;
- }
+/***************************************************************************
+ CACHE MANAGEMENT
+***************************************************************************/
- new_7z->allocImp.Alloc = SZipAlloc;
- new_7z->allocImp.Free = SZipFree;
+m7z_file_impl::m7z_file_impl(const std::string &filename)
+ : m_filename(filename)
+ , m_curr_file_idx(-1)
+ , m_curr_name()
+ , m_curr_length(0)
+ , m_curr_crc(0)
+ , m_utf16_buf(128)
+ , m_uchar_buf(128)
+ , m_utf8_buf(512)
+ , m_inited(false)
+ , m_block_index(0xffffffff) // it can have any value before first call (if outBuffer = 0)
+ , m_out_buffer(nullptr) // it must be 0 before first call for each new archive
+ , m_out_buffer_size(0) // it can have any value before first call (if outBuffer = 0)
+{
+ m_alloc_imp.Alloc = SZipAlloc;
+ m_alloc_imp.Free = SZipFree;
- new_7z->allocTempImp.Alloc = SZipAlloc;
- new_7z->allocTempImp.Free = SZipFree;
+ m_alloc_temp_imp.Alloc = SZipAlloc;
+ m_alloc_temp_imp.Free = SZipFree;
+}
- if (InFile_Open(&new_7z->archiveStream.file, filename))
- {
- _7zerr = _7ZERR_FILE_ERROR;
- goto error;
- }
- FileInStream_CreateVTable(&new_7z->archiveStream);
- LookToRead_CreateVTable(&new_7z->lookStream, False);
+_7z_file::error m7z_file_impl::initialize()
+{
+ 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 _7z_file::error::FILE_ERROR;
- new_7z->lookStream.realStream = &new_7z->archiveStream.s;
- LookToRead_Init(&new_7z->lookStream);
+ LookToRead_CreateVTable(&m_look_stream, False);
+ m_look_stream.realStream = &m_archive_stream;
+ LookToRead_Init(&m_look_stream);
CrcGenerateTable();
- SzArEx_Init(&new_7z->db);
- new_7z->inited = true;
+ SzArEx_Init(&m_db);
+ m_inited = true;
- res = SzArEx_Open(&new_7z->db, &new_7z->lookStream.s, &new_7z->allocImp, &new_7z->allocTempImp);
+ SRes const res = SzArEx_Open(&m_db, &m_look_stream.s, &m_alloc_imp, &m_alloc_temp_imp);
if (res != SZ_OK)
- {
- _7zerr = _7ZERR_FILE_ERROR;
- goto error;
- }
-
- new_7z->blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
- new_7z->outBuffer = nullptr; /* it must be 0 before first call for each new archive. */
- new_7z->outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
+ return _7z_file::error::FILE_ERROR;
- /* make a copy of the filename for caching purposes */
- string = (char *)malloc(strlen(filename) + 1);
- if (string == nullptr)
- {
- _7zerr = _7ZERR_OUT_OF_MEMORY;
- goto error;
- }
- strcpy(string, filename);
- new_7z->filename = string;
- *_7z = new_7z;
- return _7ZERR_NONE;
-
-error:
- free__7z_file(new_7z);
- return _7zerr;
+ return _7z_file::error::NONE;
}
@@ -376,119 +297,187 @@ error:
to the cache
-------------------------------------------------*/
-void _7z_file_close(_7z_file *_7z)
+void m7z_file_impl::close(ptr &&archive)
{
- int cachenum;
+ if (!archive) return;
- /* close the open files */
- if (_7z->archiveStream.file._7z_osdfile != nullptr)
- osd_close(_7z->archiveStream.file._7z_osdfile);
- _7z->archiveStream.file._7z_osdfile = nullptr;
+ // close the open files
+ archive->m_archive_stream.osdfile.reset();
- /* find the first NULL entry in the cache */
- for (cachenum = 0; cachenum < ARRAY_LENGTH(_7z_cache); cachenum++)
- if (_7z_cache[cachenum] == nullptr)
+ // find the first NULL entry in the cache
+ 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 == ARRAY_LENGTH(_7z_cache))
- free__7z_file(_7z_cache[--cachenum]);
+ // if no room left in the cache, free the bottommost entry
+ if (cachenum == s_cache.size())
+ s_cache[--cachenum].reset();
- /* move everyone else down and place us at the top */
- if (cachenum != 0)
- memmove(&_7z_cache[1], &_7z_cache[0], cachenum * sizeof(_7z_cache[0]));
- _7z_cache[0] = _7z;
+ // 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);
}
-/*-------------------------------------------------
- _7z_file_cache_clear - clear the _7Z file
- cache and free all memory
--------------------------------------------------*/
-
-void _7z_file_cache_clear(void)
-{
- int cachenum;
-
- /* clear call cache entries */
- for (cachenum = 0; cachenum < ARRAY_LENGTH(_7z_cache); cachenum++)
- if (_7z_cache[cachenum] != nullptr)
- {
- free__7z_file(_7z_cache[cachenum]);
- _7z_cache[cachenum] = nullptr;
- }
-}
+/***************************************************************************
+ 7Z FILE ACCESS
+***************************************************************************/
/*-------------------------------------------------
_7z_file_decompress - decompress a file
from a _7Z into the target buffer
-------------------------------------------------*/
-_7z_error _7z_file_decompress(_7z_file *new_7z, void *buffer, UINT32 length)
+_7z_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length)
{
- file_error err;
- SRes res;
- int index = new_7z->curr_file_idx;
-
- /* make sure the file is open.. */
- if (new_7z->archiveStream.file._7z_osdfile==nullptr)
+ // make sure the file is open..
+ if (!m_archive_stream.osdfile)
{
- new_7z->archiveStream.file._7z_currfpos = 0;
- err = osd_open(new_7z->filename, OPEN_FLAG_READ, &new_7z->archiveStream.file._7z_osdfile, &new_7z->archiveStream.file._7z_length);
- if (err != FILERR_NONE)
- return _7ZERR_FILE_ERROR;
+ 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)
+ return _7z_file::error::FILE_ERROR;
}
size_t offset = 0;
- size_t outSizeProcessed = 0;
+ size_t out_size_processed = 0;
- res = SzArEx_Extract(&new_7z->db, &new_7z->lookStream.s, index,
- &new_7z->blockIndex, &new_7z->outBuffer, &new_7z->outBufferSize,
- &offset, &outSizeProcessed,
- &new_7z->allocImp, &new_7z->allocTempImp);
+ SRes const res = SzArEx_Extract(
+ &m_db, &m_look_stream.s, m_curr_file_idx,
+ &m_block_index,
+ &m_out_buffer, &m_out_buffer_size,
+ &offset, &out_size_processed,
+ &m_alloc_imp, &m_alloc_temp_imp);
if (res != SZ_OK)
- return _7ZERR_FILE_ERROR;
+ return _7z_file::error::FILE_ERROR;
- memcpy(buffer, new_7z->outBuffer + offset, length);
+ std::memcpy(buffer, m_out_buffer + offset, length);
- return _7ZERR_NONE;
+ return _7z_file::error::NONE;
}
+int m7z_file_impl::search(int i, std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname)
+{
+ for ( ; i < m_db.db.NumFiles; i++)
+ {
+ const CSzFileItem &f(m_db.db.Files[i]);
-/***************************************************************************
- CACHE MANAGEMENT
-***************************************************************************/
+ // if it's a directory entry we don't care about it..
+ if (!f.IsDir)
+ {
+ make_utf8_name(i);
+ const std::uint64_t size(f.Size);
+ const std::uint32_t crc(f.Crc);
+ const bool crcmatch(crc == search_crc);
+ const bool namematch(core_stricmp(search_filename.c_str(), &m_utf8_buf[0]) == 0);
+
+ const bool found = (!matchcrc || crcmatch) && (!matchname || namematch);
+ if (found)
+ {
+ m_curr_file_idx = i;
+ m_curr_name = &m_utf8_buf[0];
+ m_curr_length = size;
+ m_curr_crc = crc;
-/*-------------------------------------------------
- free__7z_file - free all the data for a
- _7z_file
--------------------------------------------------*/
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
-/**
- * @fn static void free__7z_file(_7z_file *_7z)
- *
- * @brief Free 7z file.
- *
- * @param [in,out] _7z If non-null, the 7z.
- */
-static void free__7z_file(_7z_file *_7z)
+void m7z_file_impl::make_utf8_name(int index)
{
- if (_7z != nullptr)
+ 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));
+ SzArEx_GetFileNameUtf16(&m_db, index, &m_utf16_buf[0]);
+
+ 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], &m_utf16_buf[in_pos], len - in_pos);
+ if (used < 0)
+ {
+ in_pos++;
+ m_uchar_buf[out_pos++] = 0x00fffd; // Unicode REPLACEMENT CHARACTER
+ }
+ else
+ {
+ assert(used > 0);
+ in_pos += used;
+ out_pos++;
+ }
+ }
+ len = out_pos;
+
+ m_utf8_buf.resize((std::max<std::size_t>)(m_utf8_buf.size(), 4 * len + 1));
+ out_pos = 0;
+ for (std::size_t in_pos = 0; in_pos < len; in_pos++)
{
- if (_7z->archiveStream.file._7z_osdfile != nullptr)
- osd_close(_7z->archiveStream.file._7z_osdfile);
- if (_7z->filename != nullptr)
- free((void *)_7z->filename);
+ int produced = utf8_from_uchar(&m_utf8_buf[out_pos], m_utf8_buf.size() - out_pos, m_uchar_buf[in_pos]);
+ if (produced < 0)
+ produced = utf8_from_uchar(&m_utf8_buf[out_pos], m_utf8_buf.size() - out_pos, 0x00fffd);
+ if (produced >= 0)
+ out_pos += produced;
+ assert(out_pos < m_utf8_buf.size());
+ }
+ m_utf16_buf[out_pos++] = '\0';
+}
+
+} // anonymous namespace
+
+
+_7z_file::~_7z_file()
+{
+}
+
+_7z_file::error _7z_file::open(const std::string &filename, ptr &result)
+{
+ // ensure we start with a NULL result
+ result.reset();
- if (_7z->outBuffer) IAlloc_Free(&_7z->allocImp, _7z->outBuffer);
- if (_7z->inited) SzArEx_Free(&_7z->db, &_7z->allocImp);
+ // see if we are in the cache, and reopen if so
+ m7z_file_impl::ptr newimpl(m7z_file_impl::find_cached(filename));
+ 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;
+ }
- free(_7z);
+ try
+ {
+ result = std::make_unique<m7z_file_wrapper>(std::move(newimpl));
+ return error::NONE;
+ }
+ catch (...)
+ {
+ m7z_file_impl::close(std::move(newimpl));
+ return error::OUT_OF_MEMORY;
}
}
+
+
+/*-------------------------------------------------
+ _7z_file_cache_clear - clear the _7Z file
+ cache and free all memory
+-------------------------------------------------*/
+
+void _7z_file::cache_clear()
+{
+ m7z_file_impl::cache_clear();
+}
diff --git a/src/lib/util/un7z.h b/src/lib/util/un7z.h
index d2c0c9f098a..d2d2e18e25f 100644
--- a/src/lib/util/un7z.h
+++ b/src/lib/util/un7z.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
un7z.h
@@ -12,132 +12,72 @@
#pragma once
-#ifndef __UN_7Z_H__
-#define __UN_7Z_H__
+#ifndef MAME_LIB_UTIL_UN7Z_H
+#define MAME_LIB_UTIL_UN7Z_H
#include "osdcore.h"
-#include "lzma/C/7z.h"
-#include "lzma/C/7zCrc.h"
-#include "lzma/C/7zVersion.h"
-
-
-void *SZipAlloc(void *p, size_t size);
-void SZipFree(void *p, void *address);
-void *SZipAllocTemp(void *p, size_t size);
-void SZipFreeTemp(void *p, void *address);
-
-struct CSzFile
-{
- long _7z_currfpos;
- UINT64 _7z_length;
- osd_file * _7z_osdfile; /* OSD file handle */
-
-};
-
-
-struct CFileSeqInStream
-{
- ISeqInStream s;
- CSzFile file;
-};
-
-void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
-
-
-struct CFileInStream
-{
- ISeekInStream s;
- CSzFile file;
-};
-
-void FileInStream_CreateVTable(CFileInStream *p);
-
-
-struct CFileOutStream
-{
- ISeqOutStream s;
- CSzFile file;
-} ;
-
-void FileOutStream_CreateVTable(CFileOutStream *p);
-
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-
-/* Error types */
-enum _7z_error
-{
- _7ZERR_NONE = 0,
- _7ZERR_OUT_OF_MEMORY,
- _7ZERR_FILE_ERROR,
- _7ZERR_BAD_SIGNATURE,
- _7ZERR_DECOMPRESS_ERROR,
- _7ZERR_FILE_TRUNCATED,
- _7ZERR_FILE_CORRUPT,
- _7ZERR_UNSUPPORTED,
- _7ZERR_BUFFER_TOO_SMALL
-};
-
+#include <cstdint>
+#include <memory>
+#include <string>
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
-/* describes an open _7Z file */
-struct _7z_file
+// describes an open _7Z file
+class _7z_file
{
- const char * filename; /* copy of _7Z filename (for caching) */
-
- int curr_file_idx; /* current file index */
- UINT64 uncompressed_length; /* current file uncompressed length */
- UINT64 crc; /* current file crc */
-
- CFileInStream archiveStream;
- CLookToRead lookStream;
- CSzArEx db;
- SRes res;
- ISzAlloc allocImp;
- ISzAlloc allocTempImp;
- bool inited;
-
- // cached stuff for solid blocks
- UInt32 blockIndex;// = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
- Byte *outBuffer;// = 0; /* it must be 0 before first call for each new archive. */
- size_t outBufferSize;// = 0; /* it can have any value before first call (if outBuffer = 0) */
-};
+public:
+ // Error types
+ enum class error
+ {
+ NONE = 0,
+ OUT_OF_MEMORY,
+ FILE_ERROR,
+ BAD_SIGNATURE,
+ DECOMPRESS_ERROR,
+ FILE_TRUNCATED,
+ FILE_CORRUPT,
+ UNSUPPORTED,
+ BUFFER_TOO_SMALL
+ };
+ typedef std::unique_ptr<_7z_file> ptr;
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+ virtual ~_7z_file();
-/* ----- _7Z file access ----- */
+ /* ----- 7Z file access ----- */
-/* open a _7Z file and parse its central directory */
-_7z_error _7z_file_open(const char *filename, _7z_file **_7z);
+ // open a 7Z file and parse its central directory
+ static error open(const std::string &filename, ptr &result);
-/* close a _7Z file (may actually be left open due to caching) */
-void _7z_file_close(_7z_file *_7z);
+ // clear out all open 7Z files from the cache
+ static void cache_clear();
-/* clear out all open _7Z files from the cache */
-void _7z_file_cache_clear(void);
+ /* ----- contained file access ----- */
-/* ----- contained file access ----- */
+ // iterating over files
+ virtual int first_file() = 0;
+ virtual int next_file() = 0;
-/* find a file index by crc, filename or both */
-int _7z_search_crc_match(_7z_file *new_7z, UINT32 crc, const char *search_filename, int search_filename_length, bool matchcrc, bool matchname);
+ // find a file index by crc, filename or both
+ virtual int search(std::uint32_t crc) = 0;
+ virtual int search(const std::string &filename) = 0;
+ virtual int search(std::uint32_t crc, const std::string &filename) = 0;
-/* decompress the most recently found file in the _7Z */
-_7z_error _7z_file_decompress(_7z_file *_7z, void *buffer, UINT32 length);
+ // information on most recently found file
+ virtual const std::string &current_name() const = 0;
+ virtual std::uint64_t current_uncompressed_length() const = 0;
+ virtual std::uint32_t current_crc() const = 0;
+ // decompress the most recently found file in the _7Z
+ virtual error decompress(void *buffer, std::uint32_t length) = 0;
+
+};
-#endif /* __UN_7Z_H__ */
+#endif // MAME_LIB_UTIL_UN7Z_H
diff --git a/src/lib/util/unzip.cpp b/src/lib/util/unzip.cpp
index 876d8ae90c5..321f4e0b69f 100644
--- a/src/lib/util/unzip.cpp
+++ b/src/lib/util/unzip.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
unzip.c
@@ -11,19 +11,23 @@
#include "osdcore.h"
#include "unzip.h"
-#include <ctype.h>
-#include <stdlib.h>
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstring>
+#include <cstdlib>
+#include <utility>
+#include <vector>
+
#include <zlib.h>
+namespace {
/***************************************************************************
CONSTANTS
***************************************************************************/
-/* number of open files to cache */
-#define ZIP_CACHE_SIZE 8
-
/* offsets in end of central directory structure */
#define ZIPESIG 0x00
#define ZIPEDSK 0x04
@@ -95,6 +99,162 @@
/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+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_buffer()
+ {
+ std::memset(&m_header, 0, sizeof(m_header));
+ std::fill(m_buffer.begin(), m_buffer.end(), 0);
+ }
+
+ static ptr find_cached(const std::string &filename)
+ {
+ for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++)
+ {
+ // 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))
+ {
+ ptr result;
+ std::swap(s_cache[cachenum], result);
+ return result;
+ }
+ }
+ return ptr();
+ }
+ static void close(ptr &&zip);
+ static void cache_clear()
+ {
+ // clear call cache entries
+ for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { }
+ }
+
+ zip_file::error initialize()
+ {
+ // read ecd data
+ auto const ziperr = read_ecd();
+ if (ziperr != zip_file::error::NONE)
+ return ziperr;
+
+ // verify that we can work with this zipfile (no disk spanning allowed)
+ if ((m_ecd.disk_number != m_ecd.cd_start_disk_number) || (m_ecd.cd_disk_entries != m_ecd.cd_total_entries))
+ return zip_file::error::UNSUPPORTED;
+
+ // allocate memory for the central directory
+ try { m_cd.resize(m_ecd.cd_size + 1); }
+ catch (...) { return zip_file::error::OUT_OF_MEMORY; }
+
+ // read the central directory
+ std::uint32_t read_length;
+ auto const filerr = m_file->read(&m_cd[0], m_ecd.cd_start_disk_offset, m_ecd.cd_size, read_length);
+ if ((filerr != osd_file::error::NONE) || (read_length != m_ecd.cd_size))
+ return (filerr == osd_file::error::NONE) ? zip_file::error::FILE_TRUNCATED : zip_file::error::FILE_ERROR;
+
+ return zip_file::error::NONE;
+ }
+
+ // contained file access
+ const zip_file::file_header *first_file();
+ const zip_file::file_header *next_file();
+ zip_file::error decompress(void *buffer, std::uint32_t length);
+
+private:
+ zip_file_impl(const zip_file_impl &) = delete;
+ zip_file_impl(zip_file_impl &&) = delete;
+ zip_file_impl &operator=(const zip_file_impl &) = delete;
+ zip_file_impl &operator=(zip_file_impl &&) = delete;
+
+ zip_file::error reopen()
+ {
+ if (!m_file)
+ {
+ auto const filerr = osd_file::open(m_filename, OPEN_FLAG_READ, m_file, m_length);
+ if (filerr != osd_file::error::NONE)
+ return zip_file::error::FILE_ERROR;
+ }
+ return zip_file::error::NONE;
+ }
+
+ // ZIP file parsing
+ zip_file::error read_ecd();
+ zip_file::error get_compressed_data_offset(std::uint64_t &offset);
+
+ // decompression interfaces
+ zip_file::error decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length);
+ zip_file::error decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length);
+
+ struct file_header_int : zip_file::file_header
+ {
+ std::uint8_t * raw; // pointer to the raw data
+ std::uint32_t rawlength; // length of the raw data
+ std::uint8_t saved; // saved byte from after filename
+ };
+
+ // contains extracted end of central directory information
+ struct ecd
+ {
+ std::uint32_t signature; // end of central dir signature
+ std::uint16_t disk_number; // number of this disk
+ std::uint16_t cd_start_disk_number; // number of the disk with the start of the central directory
+ std::uint16_t cd_disk_entries; // total number of entries in the central directory on this disk
+ std::uint16_t cd_total_entries; // total number of entries in the central directory
+ std::uint32_t cd_size; // size of the central directory
+ std::uint32_t cd_start_disk_offset; // offset of start of central directory with respect to the starting disk number
+ std::uint16_t comment_length; // .ZIP file comment length
+ const char * comment; // .ZIP file comment
+
+ std::unique_ptr<std::uint8_t []> raw; // pointer to the raw data
+ std::uint32_t rawlength; // length of the raw data
+ };
+
+ static constexpr std::size_t DECOMPRESS_BUFSIZE = 16384;
+ static constexpr std::size_t CACHE_SIZE = 8; // number of open files to cache
+ static std::array<ptr, CACHE_SIZE> s_cache;
+
+ 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
+
+ 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
+ file_header_int m_header; // current file header
+
+ std::array<std::uint8_t, DECOMPRESS_BUFSIZE> m_buffer; // buffer for decompression
+};
+
+
+class zip_file_wrapper : public zip_file
+{
+public:
+ zip_file_wrapper(zip_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); }
+ virtual ~zip_file_wrapper() { zip_file_impl::close(std::move(m_impl)); }
+
+ virtual const file_header *first_file() override { return m_impl->first_file(); }
+ virtual const file_header *next_file() override { return m_impl->next_file(); }
+ virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); }
+
+private:
+ zip_file_impl::ptr m_impl;
+};
+
+
+
+/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
@@ -108,7 +268,7 @@
* @return The word.
*/
-static inline UINT16 read_word(UINT8 *buf)
+inline UINT16 read_word(UINT8 *buf)
{
return (buf[1] << 8) | buf[0];
}
@@ -123,7 +283,7 @@ static inline UINT16 read_word(UINT8 *buf)
* @return The double word.
*/
-static inline UINT32 read_dword(UINT8 *buf)
+inline UINT32 read_dword(UINT8 *buf)
{
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
}
@@ -135,130 +295,8 @@ static inline UINT32 read_dword(UINT8 *buf)
***************************************************************************/
/** @brief The zip cache[ zip cache size]. */
-static zip_file *zip_cache[ZIP_CACHE_SIZE];
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-/* cache management */
-static void free_zip_file(zip_file *zip);
+std::array<zip_file_impl::ptr, zip_file_impl::CACHE_SIZE> zip_file_impl::s_cache;
-/* ZIP file parsing */
-static zip_error read_ecd(zip_file *zip);
-static zip_error get_compressed_data_offset(zip_file *zip, UINT64 *offset);
-
-/* decompression interfaces */
-static zip_error decompress_data_type_0(zip_file *zip, UINT64 offset, void *buffer, UINT32 length);
-static zip_error decompress_data_type_8(zip_file *zip, UINT64 offset, void *buffer, UINT32 length);
-
-
-
-/***************************************************************************
- ZIP FILE ACCESS
-***************************************************************************/
-
-/*-------------------------------------------------
- zip_file_open - opens a ZIP file for reading
--------------------------------------------------*/
-
-/**
- * @fn zip_error zip_file_open(const char *filename, zip_file **zip)
- *
- * @brief Queries if a given zip file open.
- *
- * @param filename Filename of the file.
- * @param [in,out] zip If non-null, the zip.
- *
- * @return A zip_error.
- */
-
-zip_error zip_file_open(const char *filename, zip_file **zip)
-{
- zip_error ziperr = ZIPERR_NONE;
- file_error filerr;
- UINT32 read_length;
- zip_file *newzip;
- char *string;
- int cachenum;
-
- /* ensure we start with a NULL result */
- *zip = nullptr;
-
- /* see if we are in the cache, and reopen if so */
- for (cachenum = 0; cachenum < ARRAY_LENGTH(zip_cache); cachenum++)
- {
- zip_file *cached = zip_cache[cachenum];
-
- /* if we have a valid entry and it matches our filename, use it and remove from the cache */
- if (cached != nullptr && cached->filename != nullptr && strcmp(filename, cached->filename) == 0)
- {
- *zip = cached;
- zip_cache[cachenum] = nullptr;
- return ZIPERR_NONE;
- }
- }
-
- /* allocate memory for the zip_file structure */
- newzip = (zip_file *)malloc(sizeof(*newzip));
- if (newzip == nullptr)
- return ZIPERR_OUT_OF_MEMORY;
- memset(newzip, 0, sizeof(*newzip));
-
- /* open the file */
- filerr = osd_open(filename, OPEN_FLAG_READ, &newzip->file, &newzip->length);
- if (filerr != FILERR_NONE)
- {
- ziperr = ZIPERR_FILE_ERROR;
- goto error;
- }
-
- /* read ecd data */
- ziperr = read_ecd(newzip);
- if (ziperr != ZIPERR_NONE)
- goto error;
-
- /* verify that we can work with this zipfile (no disk spanning allowed) */
- if (newzip->ecd.disk_number != newzip->ecd.cd_start_disk_number || newzip->ecd.cd_disk_entries != newzip->ecd.cd_total_entries)
- {
- ziperr = ZIPERR_UNSUPPORTED;
- goto error;
- }
-
- /* allocate memory for the central directory */
- newzip->cd = (UINT8 *)malloc(newzip->ecd.cd_size + 1);
- if (newzip->cd == nullptr)
- {
- ziperr = ZIPERR_OUT_OF_MEMORY;
- goto error;
- }
-
- /* read the central directory */
- filerr = osd_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset, newzip->ecd.cd_size, &read_length);
- if (filerr != FILERR_NONE || read_length != newzip->ecd.cd_size)
- {
- ziperr = (filerr == FILERR_NONE) ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR;
- goto error;
- }
-
- /* make a copy of the filename for caching purposes */
- string = (char *)malloc(strlen(filename) + 1);
- if (string == nullptr)
- {
- ziperr = ZIPERR_OUT_OF_MEMORY;
- goto error;
- }
- strcpy(string, filename);
- newzip->filename = string;
- *zip = newzip;
- return ZIPERR_NONE;
-
-error:
- free_zip_file(newzip);
- return ziperr;
-}
/*-------------------------------------------------
@@ -274,57 +312,30 @@ error:
* @param [in,out] zip If non-null, the zip.
*/
-void zip_file_close(zip_file *zip)
+void zip_file_impl::close(ptr &&zip)
{
- int cachenum;
+ if (!zip) return;
- /* close the open files */
- if (zip->file != nullptr)
- osd_close(zip->file);
- zip->file = nullptr;
+ // close the open files
+ zip->m_file.reset();
- /* find the first NULL entry in the cache */
- for (cachenum = 0; cachenum < ARRAY_LENGTH(zip_cache); cachenum++)
- if (zip_cache[cachenum] == nullptr)
+ // find the first NULL entry in the cache
+ 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 == ARRAY_LENGTH(zip_cache))
- free_zip_file(zip_cache[--cachenum]);
-
- /* move everyone else down and place us at the top */
- if (cachenum != 0)
- memmove(&zip_cache[1], &zip_cache[0], cachenum * sizeof(zip_cache[0]));
- zip_cache[0] = zip;
-}
-
-
-/*-------------------------------------------------
- zip_file_cache_clear - clear the ZIP file
- cache and free all memory
--------------------------------------------------*/
-
-/**
- * @fn void zip_file_cache_clear(void)
- *
- * @brief Zip file cache clear.
- */
-
-void zip_file_cache_clear(void)
-{
- int cachenum;
+ // if no room left in the cache, free the bottommost entry
+ if (cachenum == s_cache.size())
+ s_cache[--cachenum].reset();
- /* clear call cache entries */
- for (cachenum = 0; cachenum < ARRAY_LENGTH(zip_cache); cachenum++)
- if (zip_cache[cachenum] != nullptr)
- {
- free_zip_file(zip_cache[cachenum]);
- zip_cache[cachenum] = nullptr;
- }
+ // 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);
}
-
/***************************************************************************
CONTAINED FILE ACCESS
***************************************************************************/
@@ -344,11 +355,11 @@ void zip_file_cache_clear(void)
* @return null if it fails, else a zip_file_header*.
*/
-const zip_file_header *zip_file_first_file(zip_file *zip)
+const zip_file::file_header *zip_file_impl::first_file()
{
/* reset the position and go from there */
- zip->cd_pos = 0;
- return zip_file_next_file(zip);
+ m_cd_pos = 0;
+ return next_file();
}
@@ -367,55 +378,55 @@ const zip_file_header *zip_file_first_file(zip_file *zip)
* @return null if it fails, else a zip_file_header*.
*/
-const zip_file_header *zip_file_next_file(zip_file *zip)
+const zip_file::file_header *zip_file_impl::next_file()
{
- /* fix up any modified data */
- if (zip->header.raw != nullptr)
+ // fix up any modified data
+ if (m_header.raw)
{
- zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved;
- zip->header.raw = nullptr;
+ m_header.raw[ZIPCFN + m_header.filename_length] = m_header.saved;
+ m_header.raw = nullptr;
}
- /* if we're at or past the end, we're done */
- if (zip->cd_pos >= zip->ecd.cd_size)
+ // if we're at or past the end, we're done
+ if (m_cd_pos >= m_ecd.cd_size)
return nullptr;
- /* extract file header info */
- zip->header.raw = zip->cd + zip->cd_pos;
- zip->header.rawlength = ZIPCFN;
- zip->header.signature = read_dword(zip->header.raw + ZIPCENSIG);
- zip->header.version_created = read_word (zip->header.raw + ZIPCVER);
- zip->header.version_needed = read_word (zip->header.raw + ZIPCVXT);
- zip->header.bit_flag = read_word (zip->header.raw + ZIPCFLG);
- zip->header.compression = read_word (zip->header.raw + ZIPCMTHD);
- zip->header.file_time = read_word (zip->header.raw + ZIPCTIM);
- zip->header.file_date = read_word (zip->header.raw + ZIPCDAT);
- zip->header.crc = read_dword(zip->header.raw + ZIPCCRC);
- zip->header.compressed_length = read_dword(zip->header.raw + ZIPCSIZ);
- zip->header.uncompressed_length = read_dword(zip->header.raw + ZIPCUNC);
- zip->header.filename_length = read_word (zip->header.raw + ZIPCFNL);
- zip->header.extra_field_length = read_word (zip->header.raw + ZIPCXTL);
- zip->header.file_comment_length = read_word (zip->header.raw + ZIPCCML);
- zip->header.start_disk_number = read_word (zip->header.raw + ZIPDSK);
- zip->header.internal_attributes = read_word (zip->header.raw + ZIPINT);
- zip->header.external_attributes = read_dword(zip->header.raw + ZIPEXT);
- zip->header.local_header_offset = read_dword(zip->header.raw + ZIPOFST);
- zip->header.filename = (char *)zip->header.raw + ZIPCFN;
-
- /* make sure we have enough data */
- zip->header.rawlength += zip->header.filename_length;
- zip->header.rawlength += zip->header.extra_field_length;
- zip->header.rawlength += zip->header.file_comment_length;
- if (zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size)
+ // extract file header info
+ m_header.raw = &m_cd[0] + m_cd_pos;
+ m_header.rawlength = ZIPCFN;
+ m_header.signature = read_dword(m_header.raw + ZIPCENSIG);
+ m_header.version_created = read_word (m_header.raw + ZIPCVER);
+ m_header.version_needed = read_word (m_header.raw + ZIPCVXT);
+ m_header.bit_flag = read_word (m_header.raw + ZIPCFLG);
+ m_header.compression = read_word (m_header.raw + ZIPCMTHD);
+ m_header.file_time = read_word (m_header.raw + ZIPCTIM);
+ m_header.file_date = read_word (m_header.raw + ZIPCDAT);
+ m_header.crc = read_dword(m_header.raw + ZIPCCRC);
+ m_header.compressed_length = read_dword(m_header.raw + ZIPCSIZ);
+ m_header.uncompressed_length = read_dword(m_header.raw + ZIPCUNC);
+ m_header.filename_length = read_word (m_header.raw + ZIPCFNL);
+ m_header.extra_field_length = read_word (m_header.raw + ZIPCXTL);
+ m_header.file_comment_length = read_word (m_header.raw + ZIPCCML);
+ m_header.start_disk_number = read_word (m_header.raw + ZIPDSK);
+ m_header.internal_attributes = read_word (m_header.raw + ZIPINT);
+ m_header.external_attributes = read_dword(m_header.raw + ZIPEXT);
+ m_header.local_header_offset = read_dword(m_header.raw + ZIPOFST);
+ m_header.filename = reinterpret_cast<const char *>(m_header.raw + ZIPCFN);
+
+ // make sure we have enough data
+ m_header.rawlength += m_header.filename_length;
+ m_header.rawlength += m_header.extra_field_length;
+ m_header.rawlength += m_header.file_comment_length;
+ if (m_cd_pos + m_header.rawlength > m_ecd.cd_size)
return nullptr;
- /* NULL terminate the filename */
- zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length];
- zip->header.raw[ZIPCFN + zip->header.filename_length] = 0;
+ // NULL terminate the filename
+ m_header.saved = m_header.raw[ZIPCFN + m_header.filename_length];
+ m_header.raw[ZIPCFN + m_header.filename_length] = 0;
- /* advance the position */
- zip->cd_pos += zip->header.rawlength;
- return &zip->header;
+ // advance the position
+ m_cd_pos += m_header.rawlength;
+ return &m_header;
}
@@ -436,38 +447,38 @@ const zip_file_header *zip_file_next_file(zip_file *zip)
* @return A zip_error.
*/
-zip_error zip_file_decompress(zip_file *zip, void *buffer, UINT32 length)
+zip_file::error zip_file_impl::decompress(void *buffer, UINT32 length)
{
- zip_error ziperr;
- UINT64 offset;
+ zip_file::error ziperr;
+ std::uint64_t offset;
- /* if we don't have enough buffer, error */
- if (length < zip->header.uncompressed_length)
- return ZIPERR_BUFFER_TOO_SMALL;
+ // if we don't have enough buffer, error
+ if (length < m_header.uncompressed_length)
+ return zip_file::error::BUFFER_TOO_SMALL;
- /* make sure the info in the header aligns with what we know */
- if (zip->header.start_disk_number != zip->ecd.disk_number)
- return ZIPERR_UNSUPPORTED;
+ // make sure the info in the header aligns with what we know
+ if (m_header.start_disk_number != m_ecd.disk_number)
+ return zip_file::error::UNSUPPORTED;
- /* get the compressed data offset */
- ziperr = get_compressed_data_offset(zip, &offset);
- if (ziperr != ZIPERR_NONE)
+ // get the compressed data offset
+ ziperr = get_compressed_data_offset(offset);
+ if (ziperr != zip_file::error::NONE)
return ziperr;
- /* handle compression types */
- switch (zip->header.compression)
+ // handle compression types
+ switch (m_header.compression)
{
- case 0:
- ziperr = decompress_data_type_0(zip, offset, buffer, length);
- break;
+ case 0:
+ ziperr = decompress_data_type_0(offset, buffer, length);
+ break;
- case 8:
- ziperr = decompress_data_type_8(zip, offset, buffer, length);
- break;
+ case 8:
+ ziperr = decompress_data_type_8(offset, buffer, length);
+ break;
- default:
- ziperr = ZIPERR_UNSUPPORTED;
- break;
+ default:
+ ziperr = zip_file::error::UNSUPPORTED;
+ break;
}
return ziperr;
}
@@ -475,41 +486,6 @@ zip_error zip_file_decompress(zip_file *zip, void *buffer, UINT32 length)
/***************************************************************************
- CACHE MANAGEMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- free_zip_file - free all the data for a
- zip_file
--------------------------------------------------*/
-
-/**
- * @fn static void free_zip_file(zip_file *zip)
- *
- * @brief Free zip file.
- *
- * @param [in,out] zip If non-null, the zip.
- */
-
-static void free_zip_file(zip_file *zip)
-{
- if (zip != nullptr)
- {
- if (zip->file != nullptr)
- osd_close(zip->file);
- if (zip->filename != nullptr)
- free((void *)zip->filename);
- if (zip->ecd.raw != nullptr)
- free(zip->ecd.raw);
- if (zip->cd != nullptr)
- free(zip->cd);
- free(zip);
- }
-}
-
-
-
-/***************************************************************************
ZIP FILE PARSING
***************************************************************************/
@@ -527,72 +503,69 @@ static void free_zip_file(zip_file *zip)
* @return The ecd.
*/
-static zip_error read_ecd(zip_file *zip)
+zip_file::error zip_file_impl::read_ecd()
{
- UINT32 buflen = 1024;
- UINT8 *buffer;
+ // make sure the file handle is open
+ auto const ziperr = reopen();
+ if (ziperr != zip_file::error::NONE)
+ return ziperr;
- /* we may need multiple tries */
+ // we may need multiple tries
+ std::uint32_t buflen = 1024;
while (buflen < 65536)
{
- file_error error;
- UINT32 read_length;
- INT32 offset;
-
- /* max out the buffer length at the size of the file */
- if (buflen > zip->length)
- buflen = zip->length;
-
- /* allocate buffer */
- buffer = (UINT8 *)malloc(buflen + 1);
- if (buffer == nullptr)
- return ZIPERR_OUT_OF_MEMORY;
-
- /* read in one buffers' worth of data */
- error = osd_read(zip->file, buffer, zip->length - buflen, buflen, &read_length);
- if (error != FILERR_NONE || read_length != buflen)
- {
- free(buffer);
- return ZIPERR_FILE_ERROR;
- }
-
- /* find the ECD signature */
+ // max out the buffer length at the size of the file
+ if (buflen > m_length)
+ buflen = m_length;
+
+ // allocate buffer
+ std::unique_ptr<std::uint8_t []> buffer;
+ try { buffer.reset(new std::uint8_t[buflen + 1]); }
+ catch (...) { return zip_file::error::OUT_OF_MEMORY; }
+
+ // read in one buffers' worth of data
+ std::uint32_t read_length;
+ auto const error = m_file->read(&buffer[0], m_length - buflen, buflen, read_length);
+ if (error != osd_file::error::NONE || read_length != buflen)
+ return zip_file::error::FILE_ERROR;
+
+ // find the ECD signature
+ std::int32_t offset;
for (offset = buflen - 22; offset >= 0; offset--)
if (buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' && buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06)
break;
- /* if we found it, fill out the data */
+ // if we found it, fill out the data
if (offset >= 0)
{
- /* reuse the buffer as our ECD buffer */
- zip->ecd.raw = buffer;
- zip->ecd.rawlength = buflen - offset;
+ // reuse the buffer as our ECD buffer
+ m_ecd.raw = std::move(buffer);
+ m_ecd.rawlength = buflen - offset;
/* append a NULL terminator to the comment */
- memmove(&buffer[0], &buffer[offset], zip->ecd.rawlength);
- zip->ecd.raw[zip->ecd.rawlength] = 0;
+ memmove(&m_ecd.raw[0], &m_ecd.raw[offset], m_ecd.rawlength);
+ m_ecd.raw[m_ecd.rawlength] = 0;
/* extract ecd info */
- zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG);
- zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK);
- zip->ecd.cd_start_disk_number = read_word (zip->ecd.raw + ZIPECEN);
- zip->ecd.cd_disk_entries = read_word (zip->ecd.raw + ZIPENUM);
- zip->ecd.cd_total_entries = read_word (zip->ecd.raw + ZIPECENN);
- zip->ecd.cd_size = read_dword(zip->ecd.raw + ZIPECSZ);
- zip->ecd.cd_start_disk_offset = read_dword(zip->ecd.raw + ZIPEOFST);
- zip->ecd.comment_length = read_word (zip->ecd.raw + ZIPECOML);
- zip->ecd.comment = (const char *)(zip->ecd.raw + ZIPECOM);
- return ZIPERR_NONE;
+ m_ecd.signature = read_dword(&m_ecd.raw[ZIPESIG]);
+ m_ecd.disk_number = read_word (&m_ecd.raw[ZIPEDSK]);
+ m_ecd.cd_start_disk_number = read_word (&m_ecd.raw[ZIPECEN]);
+ m_ecd.cd_disk_entries = read_word (&m_ecd.raw[ZIPENUM]);
+ m_ecd.cd_total_entries = read_word (&m_ecd.raw[ZIPECENN]);
+ m_ecd.cd_size = read_dword(&m_ecd.raw[ZIPECSZ]);
+ m_ecd.cd_start_disk_offset = read_dword(&m_ecd.raw[ZIPEOFST]);
+ m_ecd.comment_length = read_word (&m_ecd.raw[ZIPECOML]);
+ m_ecd.comment = reinterpret_cast<const char *>(&m_ecd.raw[ZIPECOM]);
+ return zip_file::error::NONE;
}
- /* didn't find it; free this buffer and expand our search */
- free(buffer);
- if (buflen < zip->length)
+ // didn't find it; free this buffer and expand our search
+ if (buflen < m_length)
buflen *= 2;
else
- return ZIPERR_BAD_SIGNATURE;
+ return zip_file::error::BAD_SIGNATURE;
}
- return ZIPERR_OUT_OF_MEMORY;
+ return zip_file::error::OUT_OF_MEMORY;
}
@@ -612,30 +585,25 @@ static zip_error read_ecd(zip_file *zip)
* @return The compressed data offset.
*/
-static zip_error get_compressed_data_offset(zip_file *zip, UINT64 *offset)
+zip_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &offset)
{
- file_error error;
- UINT32 read_length;
-
- /* make sure the file handle is open */
- if (zip->file == nullptr)
- {
- int filerr = osd_open(zip->filename, OPEN_FLAG_READ, &zip->file, &zip->length);
- if (filerr != FILERR_NONE)
- return ZIPERR_FILE_ERROR;
- }
+ // make sure the file handle is open
+ auto const ziperr = reopen();
+ if (ziperr != zip_file::error::NONE)
+ return ziperr;
- /* now go read the fixed-sized part of the local file header */
- error = osd_read(zip->file, zip->buffer, zip->header.local_header_offset, ZIPNAME, &read_length);
- if (error != FILERR_NONE || read_length != ZIPNAME)
- return (error == FILERR_NONE) ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR;
+ // 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, ZIPNAME, read_length);
+ if (error != osd_file::error::NONE || read_length != ZIPNAME)
+ return (error == osd_file::error::NONE) ? zip_file::error::FILE_TRUNCATED : zip_file::error::FILE_ERROR;
/* compute the final offset */
- *offset = zip->header.local_header_offset + ZIPNAME;
- *offset += read_word(zip->buffer + ZIPFNLN);
- *offset += read_word(zip->buffer + ZIPXTRALN);
+ offset = m_header.local_header_offset + ZIPNAME;
+ offset += read_word(&m_buffer[ZIPFNLN]);
+ offset += read_word(&m_buffer[ZIPXTRALN]);
- return ZIPERR_NONE;
+ return zip_file::error::NONE;
}
@@ -662,19 +630,18 @@ static zip_error get_compressed_data_offset(zip_file *zip, UINT64 *offset)
* @return A zip_error.
*/
-static zip_error decompress_data_type_0(zip_file *zip, UINT64 offset, void *buffer, UINT32 length)
+zip_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length)
{
- file_error filerr;
- UINT32 read_length;
-
- /* the data is uncompressed; just read it */
- filerr = osd_read(zip->file, buffer, offset, zip->header.compressed_length, &read_length);
- if (filerr != FILERR_NONE)
- return ZIPERR_FILE_ERROR;
- else if (read_length != zip->header.compressed_length)
- return ZIPERR_FILE_TRUNCATED;
+ std::uint32_t read_length;
+
+ // the data is uncompressed; just read it
+ auto const filerr = m_file->read(buffer, offset, m_header.compressed_length, read_length);
+ if (filerr != osd_file::error::NONE)
+ return zip_file::error::FILE_ERROR;
+ else if (read_length != m_header.compressed_length)
+ return zip_file::error::FILE_TRUNCATED;
else
- return ZIPERR_NONE;
+ return zip_file::error::NONE;
}
@@ -696,75 +663,148 @@ static zip_error decompress_data_type_0(zip_file *zip, UINT64 offset, void *buff
* @return A zip_error.
*/
-static zip_error decompress_data_type_8(zip_file *zip, UINT64 offset, void *buffer, UINT32 length)
+zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length)
{
- UINT32 input_remaining = zip->header.compressed_length;
- UINT32 read_length;
- z_stream stream;
- int filerr;
+ std::uint32_t input_remaining = m_header.compressed_length;
int zerr;
- /* make sure we don't need a newer mechanism */
- if (zip->header.version_needed > 0x14)
- return ZIPERR_UNSUPPORTED;
+ // make sure we don't need a newer mechanism
+ if (m_header.version_needed > 0x14)
+ return zip_file::error::UNSUPPORTED;
/* reset the stream */
+ z_stream stream;
memset(&stream, 0, sizeof(stream));
stream.next_out = (Bytef *)buffer;
stream.avail_out = length;
- /* initialize the decompressor */
+ // initialize the decompressor
zerr = inflateInit2(&stream, -MAX_WBITS);
if (zerr != Z_OK)
- return ZIPERR_DECOMPRESS_ERROR;
+ return zip_file::error::DECOMPRESS_ERROR;
- /* loop until we're done */
+ // loop until we're done
while (1)
{
- /* read in the next chunk of data */
- filerr = osd_read(zip->file, zip->buffer, offset, MIN(input_remaining, sizeof(zip->buffer)), &read_length);
- if (filerr != FILERR_NONE)
+ // read in the next chunk of data
+ std::uint32_t read_length;
+ auto const filerr = m_file->read(&m_buffer[0], offset, (std::min<std::uint32_t>)(input_remaining, m_buffer.size()), read_length);
+ if (filerr != osd_file::error::NONE)
{
inflateEnd(&stream);
- return ZIPERR_FILE_ERROR;
+ return zip_file::error::FILE_ERROR;
}
offset += read_length;
- /* if we read nothing, but still have data left, the file is truncated */
+ // if we read nothing, but still have data left, the file is truncated
if (read_length == 0 && input_remaining > 0)
{
inflateEnd(&stream);
- return ZIPERR_FILE_TRUNCATED;
+ return zip_file::error::FILE_TRUNCATED;
}
- /* fill out the input data */
- stream.next_in = zip->buffer;
+ // fill out the input data
+ stream.next_in = &m_buffer[0];
stream.avail_in = read_length;
input_remaining -= read_length;
- /* add a dummy byte at end of compressed data */
+ // add a dummy byte at end of compressed data
if (input_remaining == 0)
stream.avail_in++;
- /* now inflate */
+ // now inflate
zerr = inflate(&stream, Z_NO_FLUSH);
if (zerr == Z_STREAM_END)
break;
if (zerr != Z_OK)
{
inflateEnd(&stream);
- return ZIPERR_DECOMPRESS_ERROR;
+ return zip_file::error::DECOMPRESS_ERROR;
}
}
- /* finish decompression */
+ // finish decompression
zerr = inflateEnd(&stream);
if (zerr != Z_OK)
- return ZIPERR_DECOMPRESS_ERROR;
+ return zip_file::error::DECOMPRESS_ERROR;
/* if anything looks funny, report an error */
if (stream.avail_out > 0 || input_remaining > 0)
- return ZIPERR_DECOMPRESS_ERROR;
+ return zip_file::error::DECOMPRESS_ERROR;
+
+ return zip_file::error::NONE;
+}
- return ZIPERR_NONE;
+} // anonymous namespace
+
+
+
+/***************************************************************************
+ ZIP FILE ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ zip_file_open - opens a ZIP file for reading
+-------------------------------------------------*/
+
+/**
+ * @fn zip_error zip_file_open(const char *filename, zip_file **zip)
+ *
+ * @brief Queries if a given zip file open.
+ *
+ * @param filename Filename of the file.
+ * @param [in,out] zip If non-null, the zip.
+ *
+ * @return A zip_error.
+ */
+
+zip_file::error zip_file::open(const std::string &filename, ptr &zip)
+{
+ // ensure we start with a NULL result
+ zip.reset();
+
+ // see if we are in the cache, and reopen if so
+ zip_file_impl::ptr newimpl(zip_file_impl::find_cached(filename));
+
+ 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
+ {
+ zip = std::make_unique<zip_file_wrapper>(std::move(newimpl));
+ return error::NONE;
+ }
+ catch (...)
+ {
+ zip_file_impl::close(std::move(newimpl));
+ return error::OUT_OF_MEMORY;
+ }
+}
+
+
+/*-------------------------------------------------
+ zip_file_cache_clear - clear the ZIP file
+ cache and free all memory
+-------------------------------------------------*/
+
+/**
+ * @fn void zip_file_cache_clear(void)
+ *
+ * @brief Zip file cache clear.
+ */
+
+void zip_file::cache_clear()
+{
+ zip_file_impl::cache_clear();
+}
+
+
+zip_file::~zip_file()
+{
}
diff --git a/src/lib/util/unzip.h b/src/lib/util/unzip.h
index fa3956be8c3..2882cda0fc3 100644
--- a/src/lib/util/unzip.h
+++ b/src/lib/util/unzip.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
unzip.h
@@ -10,129 +10,88 @@
#pragma once
-#ifndef __UNZIP_H__
-#define __UNZIP_H__
+#ifndef MAME_LIB_UTIL_UNZIP_H
+#define MAME_LIB_UTIL_UNZIP_H
#include "osdcore.h"
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define ZIP_DECOMPRESS_BUFSIZE 16384
-
-/* Error types */
-enum zip_error
-{
- ZIPERR_NONE = 0,
- ZIPERR_OUT_OF_MEMORY,
- ZIPERR_FILE_ERROR,
- ZIPERR_BAD_SIGNATURE,
- ZIPERR_DECOMPRESS_ERROR,
- ZIPERR_FILE_TRUNCATED,
- ZIPERR_FILE_CORRUPT,
- ZIPERR_UNSUPPORTED,
- ZIPERR_BUFFER_TOO_SMALL
-};
-
+#include <cstdint>
+#include <memory>
+#include <string>
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
-/* contains extracted file header information */
-struct zip_file_header
+// describes an open ZIP file
+class zip_file
{
- UINT32 signature; /* central file header signature */
- UINT16 version_created; /* version made by */
- UINT16 version_needed; /* version needed to extract */
- UINT16 bit_flag; /* general purpose bit flag */
- UINT16 compression; /* compression method */
- UINT16 file_time; /* last mod file time */
- UINT16 file_date; /* last mod file date */
- UINT32 crc; /* crc-32 */
- UINT32 compressed_length; /* compressed size */
- UINT32 uncompressed_length; /* uncompressed size */
- UINT16 filename_length; /* filename length */
- UINT16 extra_field_length; /* extra field length */
- UINT16 file_comment_length; /* file comment length */
- UINT16 start_disk_number; /* disk number start */
- UINT16 internal_attributes; /* internal file attributes */
- UINT32 external_attributes; /* external file attributes */
- UINT32 local_header_offset; /* relative offset of local header */
- const char * filename; /* filename */
-
- UINT8 * raw; /* pointer to the raw data */
- UINT32 rawlength; /* length of the raw data */
- UINT8 saved; /* saved byte from after filename */
-};
-
-
-/* contains extracted end of central directory information */
-struct zip_ecd
-{
- UINT32 signature; /* end of central dir signature */
- UINT16 disk_number; /* number of this disk */
- UINT16 cd_start_disk_number; /* number of the disk with the start of the central directory */
- UINT16 cd_disk_entries; /* total number of entries in the central directory on this disk */
- UINT16 cd_total_entries; /* total number of entries in the central directory */
- UINT32 cd_size; /* size of the central directory */
- UINT32 cd_start_disk_offset; /* offset of start of central directory with respect to the starting disk number */
- UINT16 comment_length; /* .ZIP file comment length */
- const char * comment; /* .ZIP file comment */
-
- UINT8 * raw; /* pointer to the raw data */
- UINT32 rawlength; /* length of the raw data */
-};
-
-
-/* describes an open ZIP file */
-struct zip_file
-{
- const char * filename; /* copy of ZIP filename (for caching) */
- osd_file * file; /* OSD file handle */
- UINT64 length; /* length of zip file */
-
- zip_ecd ecd; /* end of central directory */
-
- UINT8 * cd; /* central directory raw data */
- UINT32 cd_pos; /* position in central directory */
- zip_file_header header; /* current file header */
-
- UINT8 buffer[ZIP_DECOMPRESS_BUFSIZE]; /* buffer for decompression */
+public:
+
+ // Error types
+ enum class error
+ {
+ NONE = 0,
+ OUT_OF_MEMORY,
+ FILE_ERROR,
+ BAD_SIGNATURE,
+ DECOMPRESS_ERROR,
+ FILE_TRUNCATED,
+ FILE_CORRUPT,
+ UNSUPPORTED,
+ BUFFER_TOO_SMALL
+ };
+
+ // contains extracted file header information
+ struct file_header
+ {
+ std::uint32_t signature; // central file header signature
+ 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
+ std::uint16_t compression; // compression method
+ std::uint16_t file_time; // last mod file time
+ std::uint16_t file_date; // last mod file date
+ std::uint32_t crc; // crc-32
+ std::uint32_t compressed_length; // compressed size
+ std::uint32_t uncompressed_length; // uncompressed size
+ std::uint16_t filename_length; // filename length
+ std::uint16_t extra_field_length; // extra field length
+ std::uint16_t file_comment_length; // file comment length
+ std::uint16_t start_disk_number; // disk number start
+ std::uint16_t internal_attributes; // internal file attributes
+ std::uint32_t external_attributes; // external file attributes
+ std::uint32_t local_header_offset; // relative offset of local header
+ const char * filename; // filename
+ };
+
+ typedef std::unique_ptr<zip_file> ptr;
+
+
+ /* ----- ZIP file access ----- */
+
+ // open a ZIP file and parse its central directory
+ static error open(const std::string &filename, ptr &zip);
+
+ // close a ZIP file (may actually be left open due to caching)
+ virtual ~zip_file();
+
+ // clear out all open ZIP files from the cache
+ static void cache_clear();
+
+
+ /* ----- contained file access ----- */
+
+ // find the first file in the ZIP
+ virtual const file_header *first_file() = 0;
+
+ // find the next file in the ZIP
+ virtual const file_header *next_file() = 0;
+
+ // decompress the most recently found file in the ZIP
+ virtual error decompress(void *buffer, std::uint32_t length) = 0;
};
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-
-/* ----- ZIP file access ----- */
-
-/* open a ZIP file and parse its central directory */
-zip_error zip_file_open(const char *filename, zip_file **zip);
-
-/* close a ZIP file (may actually be left open due to caching) */
-void zip_file_close(zip_file *zip);
-
-/* clear out all open ZIP files from the cache */
-void zip_file_cache_clear(void);
-
-
-/* ----- contained file access ----- */
-
-/* find the first file in the ZIP */
-const zip_file_header *zip_file_first_file(zip_file *zip);
-
-/* find the next file in the ZIP */
-const zip_file_header *zip_file_next_file(zip_file *zip);
-
-/* decompress the most recently found file in the ZIP */
-zip_error zip_file_decompress(zip_file *zip, void *buffer, UINT32 length);
-
-
-#endif /* __UNZIP_H__ */
+#endif // MAME_LIB_UTIL_UNZIP_H
diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp
index efe7c710481..18e2031dcdd 100644
--- a/src/lib/util/zippath.cpp
+++ b/src/lib/util/zippath.cpp
@@ -66,7 +66,7 @@ public:
/** @brief true to called zip first. */
bool called_zip_first;
/** @brief The zipfile. */
- zip_file *zipfile;
+ zip_file::ptr zipfile;
/** @brief The zipprefix. */
std::string zipprefix;
/** @brief The returned dirlist. */
@@ -78,7 +78,7 @@ public:
FUNCTION PROTOTYPES
***************************************************************************/
-static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type);
+static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, const char *subpath, osd_dir_entry_type *type);
static int is_zip_file(const char *path);
static int is_zip_file_separator(char c);
static int is_7z_file(const char *path);
@@ -251,42 +251,42 @@ std::string &zippath_combine(std::string &dst, const char *path1, const char *pa
/*-------------------------------------------------
file_error_from_zip_error - translates a
- file_error to a zip_error
+ osd_file::error to a zip_error
-------------------------------------------------*/
/**
- * @fn static file_error file_error_from_zip_error(zip_error ziperr)
+ * @fn static osd_file::error file_error_from_zip_error(zip_file::error ziperr)
*
* @brief File error from zip error.
*
* @param ziperr The ziperr.
*
- * @return A file_error.
+ * @return A osd_file::error.
*/
-static file_error file_error_from_zip_error(zip_error ziperr)
+static osd_file::error file_error_from_zip_error(zip_file::error ziperr)
{
- file_error filerr;
+ osd_file::error filerr;
switch(ziperr)
{
- case ZIPERR_NONE:
- filerr = FILERR_NONE;
- break;
- case ZIPERR_OUT_OF_MEMORY:
- filerr = FILERR_OUT_OF_MEMORY;
- break;
- case ZIPERR_BAD_SIGNATURE:
- case ZIPERR_DECOMPRESS_ERROR:
- case ZIPERR_FILE_TRUNCATED:
- case ZIPERR_FILE_CORRUPT:
- case ZIPERR_UNSUPPORTED:
- case ZIPERR_FILE_ERROR:
- filerr = FILERR_INVALID_DATA;
- break;
- case ZIPERR_BUFFER_TOO_SMALL:
- default:
- filerr = FILERR_FAILURE;
- break;
+ case zip_file::error::NONE:
+ filerr = osd_file::error::NONE;
+ break;
+ case zip_file::error::OUT_OF_MEMORY:
+ filerr = osd_file::error::OUT_OF_MEMORY;
+ break;
+ case zip_file::error::BAD_SIGNATURE:
+ case zip_file::error::DECOMPRESS_ERROR:
+ case zip_file::error::FILE_TRUNCATED:
+ case zip_file::error::FILE_CORRUPT:
+ case zip_file::error::UNSUPPORTED:
+ case zip_file::error::FILE_ERROR:
+ filerr = osd_file::error::INVALID_DATA;
+ break;
+ case zip_file::error::BUFFER_TOO_SMALL:
+ default:
+ filerr = osd_file::error::FAILURE;
+ break;
}
return filerr;
}
@@ -298,7 +298,7 @@ static file_error file_error_from_zip_error(zip_error ziperr)
-------------------------------------------------*/
/**
- * @fn static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, util::core_file::ptr &file)
+ * @fn static osd_file::error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, util::core_file::ptr &file)
*
* @brief Creates core file from zip.
*
@@ -309,28 +309,28 @@ static file_error file_error_from_zip_error(zip_error ziperr)
* @return The new core file from zip.
*/
-static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, util::core_file::ptr &file)
+static osd_file::error create_core_file_from_zip(zip_file &zip, const zip_file::file_header *header, util::core_file::ptr &file)
{
- file_error filerr;
- zip_error ziperr;
+ osd_file::error filerr;
+ zip_file::error ziperr;
void *ptr;
ptr = malloc(header->uncompressed_length);
if (ptr == nullptr)
{
- filerr = FILERR_OUT_OF_MEMORY;
+ filerr = osd_file::error::OUT_OF_MEMORY;
goto done;
}
- ziperr = zip_file_decompress(zip, ptr, header->uncompressed_length);
- if (ziperr != ZIPERR_NONE)
+ ziperr = zip.decompress(ptr, header->uncompressed_length);
+ if (ziperr != zip_file::error::NONE)
{
filerr = file_error_from_zip_error(ziperr);
goto done;
}
filerr = util::core_file::open_ram_copy(ptr, header->uncompressed_length, OPEN_FLAG_READ, file);
- if (filerr != FILERR_NONE)
+ if (filerr != osd_file::error::NONE)
goto done;
done:
@@ -345,7 +345,7 @@ done:
-------------------------------------------------*/
/**
- * @fn file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path)
+ * @fn osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path)
*
* @brief Zippath fopen.
*
@@ -354,17 +354,16 @@ done:
* @param [in,out] file [in,out] If non-null, the file.
* @param [in,out] revised_path Full pathname of the revised file.
*
- * @return A file_error.
+ * @return A osd_file::error.
*/
-file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path)
+osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path)
{
- file_error filerr = FILERR_NOT_FOUND;
- zip_error ziperr;
- zip_file *zip = nullptr;
- const zip_file_header *header;
+ osd_file::error filerr = osd_file::error::NOT_FOUND;
+ zip_file::error ziperr;
+ zip_file::ptr zip;
+ const zip_file::file_header *header;
osd_dir_entry_type entry_type;
- char *alloc_fullpath = nullptr;
int len;
/* first, set up the two types of paths */
@@ -380,30 +379,30 @@ file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file
if (is_zip_file(mainpath.c_str()))
{
/* this file might be a zip file - lets take a look */
- ziperr = zip_file_open(mainpath.c_str(), &zip);
- if (ziperr == ZIPERR_NONE)
+ ziperr = zip_file::open(mainpath, zip);
+ if (ziperr == zip_file::error::NONE)
{
/* it is a zip file - error if we're not opening for reading */
if (openflags != OPEN_FLAG_READ)
{
- filerr = FILERR_ACCESS_DENIED;
+ filerr = osd_file::error::ACCESS_DENIED;
goto done;
}
if (subpath.length() > 0)
- header = zippath_find_sub_path(zip, subpath.c_str(), &entry_type);
+ header = zippath_find_sub_path(*zip, subpath.c_str(), &entry_type);
else
- header = zip_file_first_file(zip);
+ header = zip->first_file();
if (header == nullptr)
{
- filerr = FILERR_NOT_FOUND;
+ filerr = osd_file::error::NOT_FOUND;
goto done;
}
/* attempt to read the file */
- filerr = create_core_file_from_zip(zip, header, file);
- if (filerr != FILERR_NONE)
+ filerr = create_core_file_from_zip(*zip, header, file);
+ if (filerr != osd_file::error::NONE)
goto done;
/* update subpath, if appropriate */
@@ -416,17 +415,17 @@ file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file
}
else if (is_7z_file(mainpath.c_str()))
{
- filerr = FILERR_INVALID_DATA;
+ filerr = osd_file::error::INVALID_DATA;
goto done;
}
if (subpath.length() == 0)
filerr = util::core_file::open(filename, openflags, file);
else
- filerr = FILERR_NOT_FOUND;
+ filerr = osd_file::error::NOT_FOUND;
/* if we errored, then go up a directory */
- if (filerr != FILERR_NONE)
+ if (filerr != osd_file::error::NONE)
{
/* go up a directory */
std::string temp;
@@ -457,23 +456,19 @@ file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file
done:
/* store the revised path */
revised_path.clear();
- if (filerr == FILERR_NONE)
+ if (filerr == osd_file::error::NONE)
{
/* cannonicalize mainpath */
- filerr = osd_get_full_path(&alloc_fullpath, mainpath.c_str());
- if (filerr == FILERR_NONE)
+ std::string alloc_fullpath;
+ filerr = osd_get_full_path(alloc_fullpath, mainpath);
+ if (filerr == osd_file::error::NONE)
{
+ revised_path = alloc_fullpath;
if (subpath.length() > 0)
- revised_path.assign(alloc_fullpath).append(PATH_SEPARATOR).append(subpath);
- else
- revised_path.assign(alloc_fullpath);
+ revised_path.append(PATH_SEPARATOR).append(subpath);
}
}
- if (zip != nullptr)
- zip_file_close(zip);
- if (alloc_fullpath != nullptr)
- osd_free(alloc_fullpath);
return filerr;
}
@@ -672,13 +667,13 @@ static char next_path_char(const char *s, int *pos)
* @return null if it fails, else a zip_file_header*.
*/
-static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type)
+static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, const char *subpath, osd_dir_entry_type *type)
{
int i, j;
char c1, c2, last_char;
- const zip_file_header *header;
+ const zip_file::file_header *header;
- for (header = zip_file_first_file(zipfile); header != nullptr; header = zip_file_next_file(zipfile))
+ for (header = zipfile.first_file(); header != nullptr; header = zipfile.next_file())
{
/* special case */
if (subpath == nullptr)
@@ -726,7 +721,7 @@ static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const cha
-------------------------------------------------*/
/**
- * @fn static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, zip_file *&zipfile, std::string &newpath)
+ * @fn static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, zip_file *&zipfile, std::string &newpath)
*
* @brief Zippath resolve.
*
@@ -735,12 +730,12 @@ static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const cha
* @param [in,out] zipfile [in,out] If non-null, the zipfile.
* @param [in,out] newpath The newpath.
*
- * @return A file_error.
+ * @return A osd_file::error.
*/
-static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, zip_file *&zipfile, std::string &newpath)
+static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, zip_file::ptr &zipfile, std::string &newpath)
{
- file_error err;
+ osd_file::error err;
osd_directory_entry *current_entry = nullptr;
osd_dir_entry_type current_entry_type;
int went_up = FALSE;
@@ -750,7 +745,7 @@ static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_ty
/* be conservative */
entry_type = ENTTYPE_NONE;
- zipfile = nullptr;
+ zipfile.reset();
std::string apath(path);
std::string apath_trimmed;
@@ -788,13 +783,13 @@ static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_ty
/* if we did not find anything, then error out */
if (current_entry_type == ENTTYPE_NONE)
{
- err = FILERR_NOT_FOUND;
+ err = osd_file::error::NOT_FOUND;
goto done;
}
/* is this file a ZIP file? */
if ((current_entry_type == ENTTYPE_FILE) && is_zip_file(apath_trimmed.c_str())
- && (zip_file_open(apath_trimmed.c_str(), &zipfile) == ZIPERR_NONE))
+ && (zip_file::open(apath_trimmed, zipfile) == zip_file::error::NONE))
{
i = strlen(path + apath.length());
while (i > 0 && is_zip_path_separator(path[apath.length() + i - 1]))
@@ -802,10 +797,10 @@ static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_ty
newpath.assign(path + apath.length(), i);
/* this was a true ZIP path - attempt to identify the type of path */
- zippath_find_sub_path(zipfile, newpath.c_str(), &current_entry_type);
+ zippath_find_sub_path(*zipfile, newpath.c_str(), &current_entry_type);
if (current_entry_type == ENTTYPE_NONE)
{
- err = FILERR_NOT_FOUND;
+ err = osd_file::error::NOT_FOUND;
goto done;
}
}
@@ -814,7 +809,7 @@ static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_ty
/* this was a normal path */
if (went_up)
{
- err = FILERR_NOT_FOUND;
+ err = osd_file::error::NOT_FOUND;
goto done;
}
newpath.assign(path);
@@ -822,7 +817,7 @@ static file_error zippath_resolve(const char *path, osd_dir_entry_type &entry_ty
/* success! */
entry_type = current_entry_type;
- err = FILERR_NONE;
+ err = osd_file::error::NONE;
done:
return err;
@@ -834,19 +829,19 @@ done:
-------------------------------------------------*/
/**
- * @fn file_error zippath_opendir(const char *path, zippath_directory **directory)
+ * @fn osd_file::error zippath_opendir(const char *path, zippath_directory **directory)
*
* @brief Zippath opendir.
*
* @param path Full pathname of the file.
* @param [in,out] directory If non-null, pathname of the directory.
*
- * @return A file_error.
+ * @return A osd_file::error.
*/
-file_error zippath_opendir(const char *path, zippath_directory **directory)
+osd_file::error zippath_opendir(const char *path, zippath_directory **directory)
{
- file_error err;
+ osd_file::error err;
/* allocate a directory */
zippath_directory *result = nullptr;
@@ -856,19 +851,19 @@ file_error zippath_opendir(const char *path, zippath_directory **directory)
}
catch (std::bad_alloc &)
{
- err = FILERR_OUT_OF_MEMORY;
+ err = osd_file::error::OUT_OF_MEMORY;
goto done;
}
/* resolve the path */
osd_dir_entry_type entry_type;
err = zippath_resolve(path, entry_type, result->zipfile, result->zipprefix);
- if (err != FILERR_NONE)
+ if (err != osd_file::error::NONE)
goto done;
/* we have to be a directory */
if (entry_type != ENTTYPE_DIR)
{
- err = FILERR_NOT_FOUND;
+ err = osd_file::error::NOT_FOUND;
goto done;
}
@@ -879,7 +874,7 @@ file_error zippath_opendir(const char *path, zippath_directory **directory)
result->directory = osd_opendir(path);
if (result->directory == nullptr)
{
- err = FILERR_FAILURE;
+ err = osd_file::error::FAILURE;
goto done;
}
@@ -889,7 +884,7 @@ file_error zippath_opendir(const char *path, zippath_directory **directory)
}
done:
- if ((directory == nullptr || err != FILERR_NONE) && result != nullptr)
+ if ((directory == nullptr || err != osd_file::error::NONE) && result != nullptr)
{
zippath_closedir(result);
result = nullptr;
@@ -918,7 +913,7 @@ void zippath_closedir(zippath_directory *directory)
osd_closedir(directory->directory);
if (directory->zipfile != nullptr)
- zip_file_close(directory->zipfile);
+ directory->zipfile.reset();
while (directory->returned_dirlist != nullptr)
{
@@ -948,7 +943,7 @@ void zippath_closedir(zippath_directory *directory)
* @return null if it fails, else the relative path.
*/
-static const char *get_relative_path(zippath_directory *directory, const zip_file_header *header)
+static const char *get_relative_path(zippath_directory *directory, const zip_file::file_header *header)
{
const char *result = nullptr;
int len = directory->zipprefix.length();
@@ -982,7 +977,7 @@ static const char *get_relative_path(zippath_directory *directory, const zip_fil
const osd_directory_entry *zippath_readdir(zippath_directory *directory)
{
const osd_directory_entry *result = nullptr;
- const zip_file_header *header;
+ const zip_file::file_header *header;
const char *relpath;
const char *separator;
const char *s;
@@ -1023,9 +1018,9 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory)
do
{
if (!directory->called_zip_first)
- header = zip_file_first_file(directory->zipfile);
+ header = directory->zipfile->first_file();
else
- header = zip_file_next_file(directory->zipfile);
+ header = directory->zipfile->next_file();
directory->called_zip_first = true;
relpath = nullptr;
}
diff --git a/src/lib/util/zippath.h b/src/lib/util/zippath.h
index ce40c87ba8d..d54dd68c38d 100644
--- a/src/lib/util/zippath.h
+++ b/src/lib/util/zippath.h
@@ -45,13 +45,13 @@ std::string &zippath_combine(std::string &dst, const char *path1, const char *pa
/* ----- file operations ----- */
/* opens a zip path file */
-file_error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path);
+osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path);
/* ----- directory operations ----- */
/* opens a directory */
-file_error zippath_opendir(const char *path, zippath_directory **directory);
+osd_file::error zippath_opendir(const char *path, zippath_directory **directory);
/* closes a directory */
void zippath_closedir(zippath_directory *directory);