diff options
author | 2021-08-22 09:06:15 +1000 | |
---|---|---|
committer | 2021-08-22 09:06:15 +1000 | |
commit | e8bbea1fc6e94e14768509d322f6c624403ffb36 (patch) | |
tree | 74dd1606a900d83de8aecff17a6737af4113308d /src/tools/imgtool/stream.cpp | |
parent | e319bde5fc3696d7f48f62b15b6366c4377fe5d1 (diff) |
formats, osd, util: Started refactoring file I/O stuff. (#8456)
Added more modern generic I/O interfaces with implementation backed by stdio, osd_file and core_file, replacing io_generic. Also replaced core_file's build-in zlib compression with a filter.
unzip.cpp, un7z.cpp: Added option to supply abstract I/O interface rather than filename.
Converted osd_file, core_file, archive_file, chd_file and device_image_interface to use std::error_condition rather than their own error enums.
Allow mounting TI-99 RPK from inside archives.
Diffstat (limited to 'src/tools/imgtool/stream.cpp')
-rw-r--r-- | src/tools/imgtool/stream.cpp | 255 |
1 files changed, 208 insertions, 47 deletions
diff --git a/src/tools/imgtool/stream.cpp b/src/tools/imgtool/stream.cpp index bb0d95614f3..ed9814e504a 100644 --- a/src/tools/imgtool/stream.cpp +++ b/src/tools/imgtool/stream.cpp @@ -8,19 +8,178 @@ ***************************************************************************/ +#include "stream.h" + +#include "imgtool.h" + +#include "corefile.h" +#include "ioprocs.h" +#include "unzip.h" + +#include <cassert> #include <cstdio> #include <cstring> -#include <zlib.h> -#include "unzip.h" -#include "imgtool.h" +#include <zlib.h> // for crc32 + + +namespace imgtool { + +namespace { + +class stream_read_wrapper : public virtual util::random_read +{ +public: + stream_read_wrapper(stream::ptr &&stream, std::uint8_t filler) noexcept + : m_stream(stream.release()) + , m_filler(filler) + , m_close(true) + { + assert(m_stream); + } + + stream_read_wrapper(stream &stream, std::uint8_t filler) noexcept + : m_stream(&stream) + , m_filler(filler) + , m_close(false) + { + } + + virtual ~stream_read_wrapper() + { + if (m_close) + delete m_stream; + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + m_stream->seek(offset, whence); + return std::error_condition(); + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + result = m_stream->tell(); + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + result = m_stream->size(); + return std::error_condition(); + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = m_stream->read(buffer, length); + if (actual < length) + std::memset(reinterpret_cast<std::uint8_t *>(buffer) + actual, m_filler, length - actual); + return std::error_condition(); + } + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::uint64_t const pos = m_stream->tell(); + m_stream->seek(offset, SEEK_SET); + actual = m_stream->read(buffer, length); + m_stream->seek(pos, SEEK_SET); + if (actual < length) + std::memset(reinterpret_cast<std::uint8_t *>(buffer) + actual, m_filler, length - actual); + return std::error_condition(); + } + +protected: + stream *const m_stream; + std::uint8_t m_filler; + bool const m_close; +}; + + +class stream_read_write_wrapper : public stream_read_wrapper, public util::random_read_write +{ +public: + using stream_read_wrapper::stream_read_wrapper; + + virtual std::error_condition finalize() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition flush() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::uint64_t const pos = m_stream->tell(); + std::uint64_t size = m_stream->size(); + if (size < pos) + { + m_stream->seek(size, SEEK_SET); + size += m_stream->fill(m_filler, pos - size); + } + actual = (size >= pos) ? m_stream->write(buffer, length) : 0U; + return (actual == length) ? std::error_condition() : std::errc::io_error; + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::uint64_t const pos = m_stream->tell(); + std::uint64_t size = m_stream->size(); + if (offset > size) + { + m_stream->seek(size, SEEK_SET); + size += m_stream->fill(m_filler, offset - size); + } + else + { + m_stream->seek(offset, SEEK_SET); + } + actual = (size >= offset) ? m_stream->write(buffer, length) : 0U; + m_stream->seek(pos, SEEK_SET); + return (actual == length) ? std::error_condition() : std::errc::io_error; + } +}; + +} // anonymous namespace + + +util::random_read::ptr stream_read(stream::ptr &&s, std::uint8_t filler) noexcept +{ + util::random_read::ptr result; + if (s) + result.reset(new (std::nothrow) stream_read_wrapper(std::move(s), filler)); + return result; +} + +util::random_read::ptr stream_read(stream &s, std::uint8_t filler) noexcept +{ + util::random_read::ptr result(new (std::nothrow) stream_read_wrapper(s, filler)); + return result; +} + +util::random_read_write::ptr stream_read_write(stream::ptr &&s, std::uint8_t filler) noexcept +{ + util::random_read_write::ptr result; + if (s) + result.reset(new (std::nothrow) stream_read_write_wrapper(std::move(s), filler)); + return result; +} + +util::random_read_write::ptr stream_read_write(stream &s, std::uint8_t filler) noexcept +{ + util::random_read_write::ptr result(new (std::nothrow) stream_read_write_wrapper(s, filler)); + return result; +} + //------------------------------------------------- // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp) +stream::stream(bool wp) : imgtype(IMG_FILE) , write_protect(wp) , position(0) @@ -35,7 +194,7 @@ imgtool::stream::stream(bool wp) // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp, util::core_file::ptr &&f) +stream::stream(bool wp, util::core_file::ptr &&f) : imgtype(IMG_FILE) , write_protect(wp) , position(0) @@ -50,7 +209,7 @@ imgtool::stream::stream(bool wp, util::core_file::ptr &&f) // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp, std::size_t size) +stream::stream(bool wp, std::size_t size) : imgtype(IMG_MEM) , write_protect(wp) , position(0) @@ -65,7 +224,7 @@ imgtool::stream::stream(bool wp, std::size_t size) // ctor //------------------------------------------------- -imgtool::stream::stream(bool wp, std::size_t size, void *buf) +stream::stream(bool wp, std::size_t size, void *buf) : imgtype(IMG_MEM) , write_protect(wp) , position(0) @@ -80,7 +239,7 @@ imgtool::stream::stream(bool wp, std::size_t size, void *buf) // dtor //------------------------------------------------- -imgtool::stream::~stream() +stream::~stream() { if (buffer) free(buffer); @@ -91,39 +250,39 @@ imgtool::stream::~stream() // open_zip //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open_zip(const std::string &zipname, const char *subname, int read_or_write) +stream::ptr stream::open_zip(const std::string &zipname, const char *subname, int read_or_write) { if (read_or_write) - return imgtool::stream::ptr(); + return stream::ptr(); /* check to see if the file exists */ FILE *f = fopen(zipname.c_str(), "r"); if (!f) - return imgtool::stream::ptr(); + return stream::ptr(); fclose(f); - imgtool::stream::ptr imgfile(new imgtool::stream(true)); + stream::ptr imgfile(new stream(true)); imgfile->imgtype = IMG_MEM; util::archive_file::ptr z; util::archive_file::open_zip(zipname, z); if (!z) - return imgtool::stream::ptr(); + return stream::ptr(); int zipent = z->first_file(); while ((zipent >= 0) && subname && strcmp(subname, z->current_name().c_str())) zipent = z->next_file(); if (zipent < 0) - return imgtool::stream::ptr(); + return stream::ptr(); imgfile->filesize = z->current_uncompressed_length(); imgfile->buffer = reinterpret_cast<std::uint8_t *>(malloc(z->current_uncompressed_length())); if (!imgfile->buffer) - return imgtool::stream::ptr(); + return stream::ptr(); - if (z->decompress(imgfile->buffer, z->current_uncompressed_length()) != util::archive_file::error::NONE) - return imgtool::stream::ptr(); + if (z->decompress(imgfile->buffer, z->current_uncompressed_length())) + return stream::ptr(); return imgfile; } @@ -134,7 +293,7 @@ imgtool::stream::ptr imgtool::stream::open_zip(const std::string &zipname, const // open //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read_or_write) +stream::ptr stream::open(const std::string &filename, int read_or_write) { static const uint32_t write_modes[] = { @@ -143,7 +302,7 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read OPEN_FLAG_READ | OPEN_FLAG_WRITE, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE }; - imgtool::stream::ptr s; + stream::ptr s; char c; // maybe we are just a ZIP? @@ -152,13 +311,13 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read util::core_file::ptr f = nullptr; auto const filerr = util::core_file::open(filename, write_modes[read_or_write], f); - if (filerr != osd_file::error::NONE) + if (filerr) { if (!read_or_write) { int const len = filename.size(); - /* can't open the file; try opening ZIP files with other names */ + // can't open the file; try opening ZIP files with other names std::vector<char> buf(len + 1); strcpy(&buf[0], filename.c_str()); @@ -177,11 +336,11 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read return s; } - /* ah well, it was worth a shot */ - return imgtool::stream::ptr(); + // ah well, it was worth a shot + return stream::ptr(); } - imgtool::stream::ptr imgfile(new imgtool::stream(read_or_write ? false : true, std::move(f))); + stream::ptr imgfile(new stream(read_or_write ? false : true, std::move(f))); // normal file return imgfile; @@ -192,11 +351,11 @@ imgtool::stream::ptr imgtool::stream::open(const std::string &filename, int read // open_write_stream //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open_write_stream(int size) +stream::ptr stream::open_write_stream(int size) { - imgtool::stream::ptr imgfile(new imgtool::stream(false, size)); + stream::ptr imgfile(new stream(false, size)); if (!imgfile->buffer) - return imgtool::stream::ptr(); + return stream::ptr(); return imgfile; } @@ -206,9 +365,9 @@ imgtool::stream::ptr imgtool::stream::open_write_stream(int size) // open_mem //------------------------------------------------- -imgtool::stream::ptr imgtool::stream::open_mem(void *buf, size_t sz) +stream::ptr stream::open_mem(void *buf, size_t sz) { - imgtool::stream::ptr imgfile(new imgtool::stream(false, sz, buf)); + stream::ptr imgfile(new stream(false, sz, buf)); return imgfile; } @@ -218,7 +377,7 @@ imgtool::stream::ptr imgtool::stream::open_mem(void *buf, size_t sz) // core_file //------------------------------------------------- -util::core_file *imgtool::stream::core_file() +util::core_file *stream::core_file() { return (imgtype == IMG_FILE) ? file.get() : nullptr; } @@ -228,7 +387,7 @@ util::core_file *imgtool::stream::core_file() // read //------------------------------------------------- -uint32_t imgtool::stream::read(void *buf, uint32_t sz) +uint32_t stream::read(void *buf, uint32_t sz) { uint32_t result = 0; @@ -262,7 +421,7 @@ uint32_t imgtool::stream::read(void *buf, uint32_t sz) // write //------------------------------------------------- -uint32_t imgtool::stream::write(const void *buf, uint32_t sz) +uint32_t stream::write(const void *buf, uint32_t sz) { void *new_buffer; uint32_t result = 0; @@ -317,7 +476,7 @@ uint32_t imgtool::stream::write(const void *buf, uint32_t sz) // size //------------------------------------------------- -uint64_t imgtool::stream::size() const +uint64_t stream::size() const { return filesize; } @@ -327,7 +486,7 @@ uint64_t imgtool::stream::size() const // getptr //------------------------------------------------- -void *imgtool::stream::getptr() +void *stream::getptr() { void *ptr; @@ -349,7 +508,7 @@ void *imgtool::stream::getptr() // seek //------------------------------------------------- -int imgtool::stream::seek(int64_t pos, int where) +int stream::seek(int64_t pos, int where) { switch(where) { @@ -377,7 +536,7 @@ int imgtool::stream::seek(int64_t pos, int where) // tell //------------------------------------------------- -uint64_t imgtool::stream::tell() +uint64_t stream::tell() { return position; } @@ -387,7 +546,7 @@ uint64_t imgtool::stream::tell() // transfer //------------------------------------------------- -uint64_t imgtool::stream::transfer(imgtool::stream &dest, imgtool::stream &source, uint64_t sz) +uint64_t stream::transfer(stream &dest, stream &source, uint64_t sz) { uint64_t result = 0; uint64_t readsz; @@ -407,7 +566,7 @@ uint64_t imgtool::stream::transfer(imgtool::stream &dest, imgtool::stream &sourc // transfer_all //------------------------------------------------- -uint64_t imgtool::stream::transfer_all(imgtool::stream &dest, imgtool::stream &source) +uint64_t stream::transfer_all(stream &dest, stream &source) { return transfer(dest, source, source.size()); } @@ -417,7 +576,7 @@ uint64_t imgtool::stream::transfer_all(imgtool::stream &dest, imgtool::stream &s // crc //------------------------------------------------- -int imgtool::stream::crc(unsigned long *result) +int stream::crc(unsigned long *result) { size_t sz; void *ptr; @@ -451,12 +610,12 @@ int imgtool::stream::crc(unsigned long *result) // file_crc //------------------------------------------------- -int imgtool::stream::file_crc(const char *fname, unsigned long *result) +int stream::file_crc(const char *fname, unsigned long *result) { int err; - imgtool::stream::ptr f; + stream::ptr f; - f = imgtool::stream::open(fname, OSD_FOPEN_READ); + f = stream::open(fname, OSD_FOPEN_READ); if (!f) return IMGTOOLERR_FILENOTFOUND; @@ -469,7 +628,7 @@ int imgtool::stream::file_crc(const char *fname, unsigned long *result) // fill //------------------------------------------------- -uint64_t imgtool::stream::fill(unsigned char b, uint64_t sz) +uint64_t stream::fill(unsigned char b, uint64_t sz) { uint64_t outsz; char buf[1024]; @@ -490,7 +649,7 @@ uint64_t imgtool::stream::fill(unsigned char b, uint64_t sz) // is_read_only //------------------------------------------------- -bool imgtool::stream::is_read_only() +bool stream::is_read_only() { return write_protect; } @@ -500,7 +659,7 @@ bool imgtool::stream::is_read_only() // putc //------------------------------------------------- -uint32_t imgtool::stream::putc(char c) +uint32_t stream::putc(char c) { return write(&c, 1); } @@ -510,7 +669,7 @@ uint32_t imgtool::stream::putc(char c) // puts //------------------------------------------------- -uint32_t imgtool::stream::puts(const char *s) +uint32_t stream::puts(const char *s) { return write(s, strlen(s)); } @@ -520,7 +679,7 @@ uint32_t imgtool::stream::puts(const char *s) // printf //------------------------------------------------- -uint32_t imgtool::stream::printf(const char *fmt, ...) +uint32_t stream::printf(const char *fmt, ...) { va_list va; char buf[256]; @@ -531,3 +690,5 @@ uint32_t imgtool::stream::printf(const char *fmt, ...) return puts(buf); } + +} // namespace imgtool |