diff options
Diffstat (limited to 'src')
108 files changed, 5860 insertions, 6183 deletions
diff --git a/src/devices/bus/coco/coco_dwsock.cpp b/src/devices/bus/coco/coco_dwsock.cpp index 2750f266998..fb2e18a23fb 100644 --- a/src/devices/bus/coco/coco_dwsock.cpp +++ b/src/devices/bus/coco/coco_dwsock.cpp @@ -68,14 +68,13 @@ beckerport_device::beckerport_device(const machine_config &mconfig, const char * : device_t(mconfig, COCO_DWSOCK, "Virtual Becker Port", tag, owner, clock, "coco_dwsock", __FILE__), m_hostname(nullptr), m_dwconfigport(*this, DRIVEWIRE_PORT_TAG), m_dwtcpport(0) { - m_pSocket = nullptr; m_head = 0; m_rx_pending = 0; } beckerport_device::~beckerport_device() { - if (m_pSocket != nullptr) + if (m_pSocket) beckerport_device::device_stop(); } @@ -93,8 +92,8 @@ void beckerport_device::device_start(void) osd_printf_verbose("Connecting to Drivewire server on %s:%d... ", m_hostname, m_dwtcpport); UINT64 filesize; // unused - file_error filerr = osd_open(chAddress, 0, &m_pSocket, &filesize); - if (filerr != FILERR_NONE) + osd_file::error filerr = osd_file::open(chAddress, 0, m_pSocket, filesize); + if (filerr != osd_file::error::NONE) { osd_printf_verbose("Error: osd_open returned error %i!\n", (int) filerr); return; @@ -109,11 +108,10 @@ void beckerport_device::device_start(void) void beckerport_device::device_stop(void) { - if (m_pSocket != nullptr) + if (m_pSocket) { printf("Closing connection to Drivewire server\n"); - osd_close(m_pSocket); - m_pSocket = nullptr; + m_pSocket.reset(); } } @@ -135,7 +133,7 @@ READ8_MEMBER(beckerport_device::read) { unsigned char data = 0x5a; - if (m_pSocket == nullptr) + if (!m_pSocket) return data; switch (offset) @@ -144,9 +142,9 @@ READ8_MEMBER(beckerport_device::read) if (!m_rx_pending) { /* Try to read from dws */ - file_error filerr = osd_read(m_pSocket, m_buf, 0, sizeof(m_buf), &m_rx_pending); - if (filerr != FILERR_NONE && filerr != FILERR_FAILURE) // FILERR_FAILURE means no data available, so don't throw error message - fprintf(stderr, "coco_dwsock.c: beckerport_device::read() socket read operation failed with file_error %i\n", filerr); + osd_file::error filerr = m_pSocket->read(m_buf, 0, sizeof(m_buf), m_rx_pending); + if (filerr != osd_file::error::NONE && filerr != osd_file::error::FAILURE) // osd_file::error::FAILURE means no data available, so don't throw error message + fprintf(stderr, "coco_dwsock.c: beckerport_device::read() socket read operation failed with osd_file::error %i\n", int(filerr)); else m_head = 0; } @@ -175,10 +173,11 @@ READ8_MEMBER(beckerport_device::read) WRITE8_MEMBER(beckerport_device::write) { - char d = (char)data; - file_error filerr; + char d = char(data); + osd_file::error filerr; + std::uint32_t written; - if (m_pSocket == nullptr) + if (!m_pSocket) return; switch (offset) @@ -187,9 +186,9 @@ WRITE8_MEMBER(beckerport_device::write) //printf("beckerport_write: error: write (0x%02x) to status register\n", d); break; case DWS_DATA: - filerr = osd_write(m_pSocket, &d, 0, 1, nullptr); - if (filerr != FILERR_NONE) - fprintf(stderr, "coco_dwsock.c: beckerport_device::write() socket write operation failed with file_error %i\n", filerr); + filerr = m_pSocket->write(&d, 0, 1, written); + if (filerr != osd_file::error::NONE) + fprintf(stderr, "coco_dwsock.c: beckerport_device::write() socket write operation failed with osd_file::error %i\n", int(filerr)); //printf("beckerport_write: data write one byte (0x%02x)\n", d & 0xff); break; default: diff --git a/src/devices/bus/coco/coco_dwsock.h b/src/devices/bus/coco/coco_dwsock.h index 1d1fe71c3d3..d3af3fbb525 100644 --- a/src/devices/bus/coco/coco_dwsock.h +++ b/src/devices/bus/coco/coco_dwsock.h @@ -57,7 +57,7 @@ private: required_ioport m_dwconfigport; int m_dwtcpport; - osd_file *m_pSocket; + osd_file::ptr m_pSocket; unsigned int m_rx_pending; unsigned int m_head; diff --git a/src/devices/bus/iq151/minigraf.cpp b/src/devices/bus/iq151/minigraf.cpp index 1a8e9d182a0..14cd9515cf7 100644 --- a/src/devices/bus/iq151/minigraf.cpp +++ b/src/devices/bus/iq151/minigraf.cpp @@ -78,9 +78,9 @@ void iq151_minigraf_device::device_stop() { #if DUMP_PAPER_INTO_PNG emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open("iq151_minigraf.png"); + auto const filerr = file.open("iq151_minigraf.png"); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { static const rgb_t png_palette[] = { rgb_t::white, rgb_t::black }; diff --git a/src/devices/bus/iq151/ms151a.cpp b/src/devices/bus/iq151/ms151a.cpp index 99da92c6d61..c3aedf5f07d 100644 --- a/src/devices/bus/iq151/ms151a.cpp +++ b/src/devices/bus/iq151/ms151a.cpp @@ -77,9 +77,9 @@ void iq151_ms151a_device::device_stop() { #if DUMP_PAPER_INTO_PNG emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open("iq151_ms151a.png"); + osd_file::error filerr = file.open("iq151_ms151a.png"); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { static const rgb_t png_palette[] = { rgb_t::white, rgb_t::black }; diff --git a/src/devices/bus/nubus/nubus_image.cpp b/src/devices/bus/nubus/nubus_image.cpp index 412925fc351..d7752e3babc 100644 --- a/src/devices/bus/nubus/nubus_image.cpp +++ b/src/devices/bus/nubus/nubus_image.cpp @@ -310,7 +310,7 @@ WRITE32_MEMBER( nubus_image_device::file_cmd_w ) strcpy(fullpath, (const char *)filectx.curdir); strcat(fullpath, "/"); strcat(fullpath, (const char*)filectx.filename); - if(osd_open((const char*)fullpath, OPEN_FLAG_READ, &filectx.fd, &filectx.filelen) != FILERR_NONE) printf("Error opening %s\n", fullpath); + if(osd_file::open(std::string(fullpath), OPEN_FLAG_READ, filectx.fd, filectx.filelen) != osd_file::error::NONE) printf("Error opening %s\n", fullpath); filectx.bytecount = 0; break; case kFileCmdPutFile: @@ -318,7 +318,7 @@ WRITE32_MEMBER( nubus_image_device::file_cmd_w ) strcpy(fullpath, (const char *)filectx.curdir); strcat(fullpath, "/"); strcat(fullpath, (const char*)filectx.filename); - if(osd_open((const char*)fullpath, OPEN_FLAG_WRITE|OPEN_FLAG_CREATE, &filectx.fd, &filesize) != FILERR_NONE) printf("Error opening %s\n", fullpath); + if(osd_file::open(std::string(fullpath), OPEN_FLAG_WRITE|OPEN_FLAG_CREATE, filectx.fd, filesize) != osd_file::error::NONE) printf("Error opening %s\n", fullpath); filectx.bytecount = 0; break; } @@ -331,33 +331,31 @@ READ32_MEMBER( nubus_image_device::file_cmd_r ) WRITE32_MEMBER( nubus_image_device::file_data_w ) { - UINT32 count = 4; - UINT32 actualcount = 0; + std::uint32_t count = 4; + std::uint32_t actualcount = 0; data = ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data & 0xff0000) >> 8) | ((data & 0xff000000) >> 24); - if(filectx.fd != nullptr) { + if(filectx.fd) { //data = ni_ntohl(data); if((filectx.bytecount + count) > filectx.filelen) count = filectx.filelen - filectx.bytecount; - osd_write(filectx.fd, &data, filectx.bytecount, count, &actualcount); + filectx.fd->write(&data, filectx.bytecount, count, actualcount); filectx.bytecount += actualcount; if(filectx.bytecount >= filectx.filelen) { - osd_close(filectx.fd); - filectx.fd = nullptr; + filectx.fd.reset(); } } } READ32_MEMBER( nubus_image_device::file_data_r ) { - if(filectx.fd != nullptr) { - UINT32 ret; - UINT32 actual = 0; - osd_read(filectx.fd, &ret, filectx.bytecount, sizeof(ret), &actual); + if(filectx.fd) { + std::uint32_t ret; + std::uint32_t actual = 0; + filectx.fd->read(&ret, filectx.bytecount, sizeof(ret), actual); filectx.bytecount += actual; if(actual < sizeof(ret)) { - osd_close(filectx.fd); - filectx.fd = nullptr; + filectx.fd.reset(); } return ni_htonl(ret); } diff --git a/src/devices/bus/nubus/nubus_image.h b/src/devices/bus/nubus/nubus_image.h index d850b3f7735..dda6e55fc02 100644 --- a/src/devices/bus/nubus/nubus_image.h +++ b/src/devices/bus/nubus/nubus_image.h @@ -19,7 +19,7 @@ struct nbfilectx { UINT8 filename[128]; UINT8 curdir[1024]; osd_directory *dirp; - osd_file *fd; + osd_file::ptr fd; UINT64 filelen; UINT32 bytecount; }; diff --git a/src/devices/bus/ti99x/gromport.cpp b/src/devices/bus/ti99x/gromport.cpp index 9e1533cb9a8..2b9a66d028a 100644 --- a/src/devices/bus/ti99x/gromport.cpp +++ b/src/devices/bus/ti99x/gromport.cpp @@ -148,7 +148,7 @@ static void image_battery_load_by_name(emu_options &options, const char *filename, void *buffer, int length, int fill) { - file_error filerr; + osd_file::error filerr; int bytes_read = 0; assert_always(buffer && (length > 0), "Must specify sensical buffer/length"); @@ -156,7 +156,7 @@ static void image_battery_load_by_name(emu_options &options, const char *filenam /* try to open the battery file and read it in, if possible */ emu_file file(options.nvram_directory(), OPEN_FLAG_READ); filerr = file.open(filename); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) bytes_read = file.read(buffer, length); /* fill remaining bytes (if necessary) */ @@ -174,8 +174,8 @@ static void image_battery_save_by_name(emu_options &options, const char *filenam /* try to open the battery file and write it out, if possible */ emu_file file(options.nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(filename); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(filename); + if (filerr == osd_file::error::NONE) file.write(buffer, length); } @@ -2245,10 +2245,10 @@ rpk_socket::rpk_socket(const char* id, int length, UINT8* contents) /* Locate a file in the ZIP container */ -const zip_file_header* rpk_reader::find_file(zip_file *zip, const char *filename, UINT32 crc) +const zip_file::file_header* rpk_reader::find_file(zip_file &zip, const char *filename, UINT32 crc) { - const zip_file_header *header; - for (header = zip_file_first_file(zip); header != nullptr; header = zip_file_next_file(zip)) + const zip_file::file_header *header; + for (header = zip.first_file(); header != nullptr; header = zip.next_file()) { // We don't check for CRC == 0. if (crc != 0) @@ -2272,16 +2272,16 @@ const zip_file_header* rpk_reader::find_file(zip_file *zip, const char *filename /* Load a rom resource and put it in a pcb socket instance. */ -rpk_socket* rpk_reader::load_rom_resource(zip_file* zip, xml_data_node* rom_resource_node, const char* socketname) +rpk_socket* rpk_reader::load_rom_resource(zip_file &zip, xml_data_node* rom_resource_node, const char* socketname) { const char* file; const char* crcstr; const char* sha1; - zip_error ziperr; + zip_file::error ziperr; UINT32 crc; int length; UINT8* contents; - const zip_file_header *header; + const zip_file::file_header *header; // find the file attribute (required) file = xml_get_attribute_string(rom_resource_node, "file", nullptr); @@ -2310,10 +2310,10 @@ rpk_socket* rpk_reader::load_rom_resource(zip_file* zip, xml_data_node* rom_reso if (contents==nullptr) throw rpk_exception(RPK_OUT_OF_MEMORY); // and unzip file from the zip file - ziperr = zip_file_decompress(zip, contents, length); - if (ziperr != ZIPERR_NONE) + ziperr = zip.decompress(contents, length); + if (ziperr != zip_file::error::NONE) { - if (ziperr == ZIPERR_UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED); + if (ziperr == zip_file::error::UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED); else throw rpk_exception(RPK_ZIP_ERROR); } @@ -2414,15 +2414,15 @@ rpk_socket* rpk_reader::load_ram_resource(emu_options &options, xml_data_node* r rpk* rpk_reader::open(emu_options &options, const char *filename, const char *system_name) { - zip_error ziperr; + zip_file::error ziperr; - const zip_file_header *header; + const zip_file::file_header *header; const char *pcb_type; const char *id; const char *uses_name; const char *resource_name; - zip_file* zipfile; + zip_file::ptr zipfile; std::vector<char> layout_text; xml_data_node *layout_xml = nullptr; @@ -2442,21 +2442,21 @@ rpk* rpk_reader::open(emu_options &options, const char *filename, const char *sy try { /* open the ZIP file */ - ziperr = zip_file_open(filename, &zipfile); - if (ziperr != ZIPERR_NONE) throw rpk_exception(RPK_NOT_ZIP_FORMAT); + ziperr = zip_file::open(filename, zipfile); + if (ziperr != zip_file::error::NONE) throw rpk_exception(RPK_NOT_ZIP_FORMAT); /* find the layout.xml file */ - header = find_file(zipfile, "layout.xml", 0); + header = find_file(*zipfile, "layout.xml", 0); if (header == nullptr) throw rpk_exception(RPK_MISSING_LAYOUT); /* reserve space for the layout file contents (+1 for the termination) */ layout_text.resize(header->uncompressed_length + 1); /* uncompress the layout text */ - ziperr = zip_file_decompress(zipfile, &layout_text[0], header->uncompressed_length); - if (ziperr != ZIPERR_NONE) + ziperr = zipfile->decompress(&layout_text[0], header->uncompressed_length); + if (ziperr != zip_file::error::NONE) { - if (ziperr == ZIPERR_UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED); + if (ziperr == zip_file::error::UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED); else throw rpk_exception(RPK_ZIP_ERROR); } @@ -2523,7 +2523,7 @@ rpk* rpk_reader::open(emu_options &options, const char *filename, const char *sy // found it if (strcmp(resource_node->name, "rom")==0) { - newsock = load_rom_resource(zipfile, resource_node, id); + newsock = load_rom_resource(*zipfile, resource_node, id); newrpk->add_socket(id, newsock); } else @@ -2545,14 +2545,12 @@ rpk* rpk_reader::open(emu_options &options, const char *filename, const char *sy { newrpk->close(); if (layout_xml != nullptr) xml_file_free(layout_xml); - if (zipfile != nullptr) zip_file_close(zipfile); // rethrow the exception throw; } if (layout_xml != nullptr) xml_file_free(layout_xml); - if (zipfile != nullptr) zip_file_close(zipfile); return newrpk; } diff --git a/src/devices/bus/ti99x/gromport.h b/src/devices/bus/ti99x/gromport.h index 7655173b10d..9b60425aa06 100644 --- a/src/devices/bus/ti99x/gromport.h +++ b/src/devices/bus/ti99x/gromport.h @@ -454,8 +454,8 @@ public: rpk *open(emu_options &options, const char *filename, const char *system_name); private: - const zip_file_header* find_file(zip_file *zip, const char *filename, UINT32 crc); - rpk_socket* load_rom_resource(zip_file* zip, xml_data_node* rom_resource_node, const char* socketname); + const zip_file::file_header* find_file(zip_file &zip, const char *filename, UINT32 crc); + rpk_socket* load_rom_resource(zip_file &zip, xml_data_node* rom_resource_node, const char* socketname); rpk_socket* load_ram_resource(emu_options &options, xml_data_node* ram_resource_node, const char* socketname, const char* system_name); const pcb_type* m_types; }; diff --git a/src/devices/imagedev/diablo.cpp b/src/devices/imagedev/diablo.cpp index 6ba6aad5cf2..ba43f09efee 100644 --- a/src/devices/imagedev/diablo.cpp +++ b/src/devices/imagedev/diablo.cpp @@ -171,8 +171,8 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file /* try to open the diff */ //printf("Opening differencing image file: %s\n", fname.c_str()); emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE); - file_error filerr = diff_file.open(fname.c_str()); - if (filerr == FILERR_NONE) + osd_file::error filerr = diff_file.open(fname.c_str()); + if (filerr == osd_file::error::NONE) { std::string fullpath(diff_file.fullpath()); diff_file.close(); @@ -185,7 +185,7 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file //printf("Creating differencing image: %s\n", fname.c_str()); diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); filerr = diff_file.open(fname.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { std::string fullpath(diff_file.fullpath()); diff_file.close(); diff --git a/src/devices/imagedev/floppy.cpp b/src/devices/imagedev/floppy.cpp index c4269c944ef..38e0a5ff9d8 100644 --- a/src/devices/imagedev/floppy.cpp +++ b/src/devices/imagedev/floppy.cpp @@ -295,9 +295,9 @@ void floppy_image_device::commit_image() io.procs = &image_ioprocs; io.filler = 0xff; - file_error err = image_core_file().truncate(0); - if (err != 0) - popmessage("Error, unable to truncate image: %d", err); + osd_file::error err = image_core_file().truncate(0); + if (err != osd_file::error::NONE) + popmessage("Error, unable to truncate image: %d", int(err)); output_format->save(&io, image); } @@ -365,8 +365,8 @@ floppy_image_format_t *floppy_image_device::identify(std::string filename) util::core_file::ptr fd; std::string revised_path; - file_error err = zippath_fopen(filename.c_str(), OPEN_FLAG_READ, fd, revised_path); - if(err) { + osd_file::error err = zippath_fopen(filename.c_str(), OPEN_FLAG_READ, fd, revised_path); + if(err != osd_file::error::NONE) { seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to open the image file"); return nullptr; } @@ -1000,12 +1000,12 @@ void ui_menu_control_floppy_image::hook_load(std::string filename, bool softlist bool can_in_place = input_format->supports_save(); if(can_in_place) { - file_error filerr; + osd_file::error filerr; std::string tmp_path; util::core_file::ptr tmp_file; /* attempt to open the file for writing but *without* create */ filerr = zippath_fopen(filename.c_str(), OPEN_FLAG_READ | OPEN_FLAG_WRITE, tmp_file, tmp_path); - if(!filerr) + if(filerr == osd_file::error::NONE) tmp_file.reset(); else can_in_place = false; diff --git a/src/devices/imagedev/harddriv.cpp b/src/devices/imagedev/harddriv.cpp index d07852e166f..ff058f837f7 100644 --- a/src/devices/imagedev/harddriv.cpp +++ b/src/devices/imagedev/harddriv.cpp @@ -195,8 +195,8 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file /* try to open the diff */ //printf("Opening differencing image file: %s\n", fname.c_str()); emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE); - file_error filerr = diff_file.open(fname.c_str()); - if (filerr == FILERR_NONE) + osd_file::error filerr = diff_file.open(fname.c_str()); + if (filerr == osd_file::error::NONE) { std::string fullpath(diff_file.fullpath()); diff_file.close(); @@ -209,7 +209,7 @@ static chd_error open_disk_diff(emu_options &options, const char *name, chd_file //printf("Creating differencing image: %s\n", fname.c_str()); diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); filerr = diff_file.open(fname.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { std::string fullpath(diff_file.fullpath()); diff_file.close(); diff --git a/src/devices/sound/samples.cpp b/src/devices/sound/samples.cpp index 62bd8e02657..0b92b51202d 100644 --- a/src/devices/sound/samples.cpp +++ b/src/devices/sound/samples.cpp @@ -618,20 +618,20 @@ bool samples_device::load_samples() { // attempt to open as FLAC first emu_file file(machine().options().sample_path(), OPEN_FLAG_READ); - file_error filerr = file.open(basename, PATH_SEPARATOR, samplename, ".flac"); - if (filerr != FILERR_NONE && altbasename != nullptr) + osd_file::error filerr = file.open(basename, PATH_SEPARATOR, samplename, ".flac"); + if (filerr != osd_file::error::NONE && altbasename != nullptr) filerr = file.open(altbasename, PATH_SEPARATOR, samplename, ".flac"); // if not, try as WAV - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) filerr = file.open(basename, PATH_SEPARATOR, samplename, ".wav"); - if (filerr != FILERR_NONE && altbasename != nullptr) + if (filerr != osd_file::error::NONE && altbasename != nullptr) filerr = file.open(altbasename, PATH_SEPARATOR, samplename, ".wav"); // if opened, read it - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) read_sample(file, m_sample[index]); - else if (filerr == FILERR_NOT_FOUND) + else if (filerr == osd_file::error::NOT_FOUND) { logerror("%s: Sample '%s' NOT FOUND\n", tag(), samplename); ok = false; diff --git a/src/emu/audit.cpp b/src/emu/audit.cpp index 7f371ee56c8..e9e4dee63f2 100644 --- a/src/emu/audit.cpp +++ b/src/emu/audit.cpp @@ -296,11 +296,11 @@ media_auditor::summary media_auditor::audit_samples() while (path.next(curpath, samplename)) { // attempt to access the file (.flac) or (.wav) - file_error filerr = file.open(curpath.c_str(), ".flac"); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(curpath.c_str(), ".flac"); + if (filerr != osd_file::error::NONE) filerr = file.open(curpath.c_str(), ".wav"); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD); found++; @@ -433,14 +433,14 @@ audit_record *media_auditor::audit_one_rom(const rom_entry *rom) while (path.next(curpath, record.name())) { // open the file if we can - file_error filerr; + osd_file::error filerr; if (has_crc) filerr = file.open(curpath.c_str(), crc); else filerr = file.open(curpath.c_str()); // if it worked, get the actual length and hashes, then stop - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { record.set_actual(file.hashes(m_validation), file.size()); break; diff --git a/src/emu/cheat.cpp b/src/emu/cheat.cpp index 0a799ca6f13..f9fe6499d61 100644 --- a/src/emu/cheat.cpp +++ b/src/emu/cheat.cpp @@ -1171,10 +1171,10 @@ bool cheat_manager::save_all(const char *filename) { // open the file with the proper name emu_file cheatfile(machine().options().cheat_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = cheatfile.open(filename, ".xml"); + osd_file::error filerr = cheatfile.open(filename, ".xml"); // if that failed, return nothing - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) return false; // wrap the rest of catch errors @@ -1372,10 +1372,10 @@ void cheat_manager::load_cheats(const char *filename) try { // open the file with the proper name - file_error filerr = cheatfile.open(filename, ".xml"); + osd_file::error filerr = cheatfile.open(filename, ".xml"); // loop over all instrances of the files found in our search paths - while (filerr == FILERR_NONE) + while (filerr == osd_file::error::NONE) { osd_printf_verbose("Loading cheats file from %s\n", cheatfile.fullpath()); diff --git a/src/emu/clifront.cpp b/src/emu/clifront.cpp index 7c6c974cce7..79b53e943c7 100644 --- a/src/emu/clifront.cpp +++ b/src/emu/clifront.cpp @@ -266,7 +266,7 @@ int cli_frontend::execute(int argc, char **argv) m_result = MAMERR_FATALERROR; } - _7z_file_cache_clear(); + _7z_file::cache_clear(); global_free(manager); return m_result; @@ -1000,7 +1000,7 @@ void cli_frontend::verifyroms(const char *gamename) } // clear out any cached files - zip_file_cache_clear(); + zip_file::cache_clear(); // return an error if none found if (matched == 0) @@ -1092,7 +1092,7 @@ void cli_frontend::verifysamples(const char *gamename) } // clear out any cached files - zip_file_cache_clear(); + zip_file::cache_clear(); // return an error if none found if (matched == 0) @@ -1407,7 +1407,7 @@ void cli_frontend::verifysoftware(const char *gamename) } // clear out any cached files - zip_file_cache_clear(); + zip_file::cache_clear(); // return an error if none found if (matched == 0) @@ -1529,7 +1529,7 @@ void cli_frontend::verifysoftlist(const char *gamename) } // clear out any cached files - zip_file_cache_clear(); + zip_file::cache_clear(); // return an error if none found if (matched == 0) @@ -1618,7 +1618,7 @@ void cli_frontend::execute_commands(const char *exename) { // attempt to open the output file emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(emulator_info::get_configname(), ".ini") != FILERR_NONE) + if (file.open(emulator_info::get_configname(), ".ini") != osd_file::error::NONE) throw emu_fatalerror("Unable to create file %s.ini\n",emulator_info::get_configname()); // generate the updated INI @@ -1626,7 +1626,7 @@ void cli_frontend::execute_commands(const char *exename) ui_options ui_opts; emu_file file_ui(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file_ui.open("ui.ini") != FILERR_NONE) + if (file_ui.open("ui.ini") != osd_file::error::NONE) throw emu_fatalerror("Unable to create file ui.ini\n"); // generate the updated INI @@ -1761,68 +1761,61 @@ void media_identifier::identify(const char *filename) if (core_filename_ends_with(filename, ".7z")) { // first attempt to examine it as a valid _7Z file - _7z_file *_7z = nullptr; - _7z_error _7zerr = _7z_file_open(filename, &_7z); - if (_7zerr == _7ZERR_NONE && _7z != nullptr) + _7z_file::ptr _7z; + _7z_file::error _7zerr = _7z_file::open(filename, _7z); + if (_7zerr == _7z_file::error::NONE && _7z != nullptr) { + std::vector<std::uint8_t> data; + // loop over entries in the .7z, skipping empty files and directories - for (int i = 0; i < _7z->db.db.NumFiles; i++) + for (int i = _7z->first_file(); i >= 0; i = _7z->next_file()) { - const CSzFileItem *f = _7z->db.db.Files + i; - _7z->curr_file_idx = i; - int namelen = SzArEx_GetFileNameUtf16(&_7z->db, i, nullptr); - std::vector<UINT16> temp(namelen); - dynamic_buffer temp2(namelen+1); - UINT8* temp3 = &temp2[0]; - memset(temp3, 0x00, namelen); - SzArEx_GetFileNameUtf16(&_7z->db, i, &temp[0]); - // crude, need real UTF16->UTF8 conversion ideally - for (int j=0;j<namelen;j++) - { - temp3[j] = (UINT8)temp[j]; - } - - if (!(f->IsDir) && (f->Size != 0)) + const std::uint64_t length(_7z->current_uncompressed_length()); + if ((length != 0) && (std::uint32_t(length) == length)) { // decompress data into RAM and identify it - dynamic_buffer data(f->Size); - _7zerr = _7z_file_decompress(_7z, &data[0], f->Size); - if (_7zerr == _7ZERR_NONE) - identify_data((const char*)&temp2[0], &data[0], f->Size); + try + { + data.resize(std::size_t(length)); + _7zerr = _7z->decompress(&data[0], std::uint32_t(length)); + if (_7zerr == _7z_file::error::NONE) + identify_data(_7z->current_name().c_str(), &data[0], length); + } + catch (...) + { + // resizing the buffer could cause a bad_alloc if archive contains large files + } + data.clear(); } } - - // close up - _7z_file_close(_7z); } // clear out any cached files - _7z_file_cache_clear(); + _7z.reset(); + _7z_file::cache_clear(); } else if (core_filename_ends_with(filename, ".zip")) { // first attempt to examine it as a valid ZIP file - zip_file *zip = nullptr; - zip_error ziperr = zip_file_open(filename, &zip); - if (ziperr == ZIPERR_NONE && zip != nullptr) + zip_file::ptr zip = nullptr; + zip_file::error ziperr = zip_file::open(filename, zip); + if (ziperr == zip_file::error::NONE && zip != nullptr) { // loop over entries in the ZIP, skipping empty files and directories - for (const zip_file_header *entry = zip_file_first_file(zip); entry != nullptr; entry = zip_file_next_file(zip)) + for (const zip_file::file_header *entry = zip->first_file(); entry != nullptr; entry = zip->next_file()) if (entry->uncompressed_length != 0) { // decompress data into RAM and identify it dynamic_buffer data(entry->uncompressed_length); - ziperr = zip_file_decompress(zip, &data[0], entry->uncompressed_length); - if (ziperr == ZIPERR_NONE) + ziperr = zip->decompress(&data[0], entry->uncompressed_length); + if (ziperr == zip_file::error::NONE) identify_data(entry->filename, &data[0], entry->uncompressed_length); } - - // close up - zip_file_close(zip); } // clear out any cached files - zip_file_cache_clear(); + zip.reset(); + zip_file::cache_clear(); } // otherwise, identify as a raw file @@ -1880,8 +1873,8 @@ void media_identifier::identify_file(const char *name) // load the file and process if it opens and has a valid length UINT32 length; void *data; - const file_error filerr = util::core_file::load(name, &data, length); - if (filerr == FILERR_NONE && length > 0) + const osd_file::error filerr = util::core_file::load(name, &data, length); + if (filerr == osd_file::error::NONE && length > 0) { identify_data(name, reinterpret_cast<UINT8 *>(data), length); osd_free(data); diff --git a/src/emu/config.cpp b/src/emu/config.cpp index 691012a4a41..7402341ad32 100644 --- a/src/emu/config.cpp +++ b/src/emu/config.cpp @@ -68,9 +68,9 @@ int configuration_manager::load_settings() { /* open the config file */ emu_file file(machine().options().ctrlr_path(), OPEN_FLAG_READ); - file_error filerr = file.open(controller, ".cfg"); + osd_file::error filerr = file.open(controller, ".cfg"); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) throw emu_fatalerror("Could not load controller file %s.cfg", controller); /* load the XML */ @@ -80,13 +80,13 @@ int configuration_manager::load_settings() /* next load the defaults file */ emu_file file(machine().options().cfg_directory(), OPEN_FLAG_READ); - file_error filerr = file.open("default.cfg"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open("default.cfg"); + if (filerr == osd_file::error::NONE) load_xml(file, config_type::CONFIG_TYPE_DEFAULT); /* finally, load the game-specific file */ filerr = file.open(machine().basename(), ".cfg"); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) loaded = load_xml(file, config_type::CONFIG_TYPE_GAME); /* loop over all registrants and call their final function */ @@ -107,13 +107,13 @@ void configuration_manager::save_settings() /* save the defaults file */ emu_file file(machine().options().cfg_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open("default.cfg"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open("default.cfg"); + if (filerr == osd_file::error::NONE) save_xml(file, config_type::CONFIG_TYPE_DEFAULT); /* finally, save the game-specific file */ filerr = file.open(machine().basename(), ".cfg"); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) save_xml(file, config_type::CONFIG_TYPE_GAME); /* loop over all registrants and call their final function */ diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 21ed7860a30..b8a7ebc4874 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -2856,9 +2856,9 @@ static void execute_snap(running_machine &machine, int ref, int params, const ch if (fname.find(".png") == -1) fname.append(".png"); emu_file file(machine.options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(fname.c_str()); + osd_file::error filerr = file.open(fname.c_str()); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { debug_console_printf(machine, "Error creating file '%s'\n", filename); return; diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index 2b8595b3c30..4e59ed8a652 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -332,8 +332,8 @@ bool debug_comment_save(running_machine &machine) if (found_comments) { emu_file file(machine.options().comment_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(machine.basename(), ".cmt"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(machine.basename(), ".cmt"); + if (filerr == osd_file::error::NONE) { xml_file_write(root, file); comments_saved = true; @@ -361,10 +361,10 @@ bool debug_comment_load(running_machine &machine) { // open the file emu_file file(machine.options().comment_directory(), OPEN_FLAG_READ); - file_error filerr = file.open(machine.basename(), ".cmt"); + osd_file::error filerr = file.open(machine.basename(), ".cmt"); // if an error, just return false - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) return false; // wrap in a try/catch to handle errors diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 704f7d987e8..216b1af1fca 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -330,11 +330,8 @@ bool device_image_interface::try_change_working_directory(const char *subdir) void device_image_interface::setup_working_directory() { - char *dst = nullptr; - - osd_get_full_path(&dst,"."); /* first set up the working directory to be the starting directory */ - m_working_directory = dst; + osd_get_full_path(m_working_directory, "."); /* now try browsing down to "software" */ if (try_change_working_directory("software")) @@ -346,7 +343,6 @@ void device_image_interface::setup_working_directory() gamedrv = driver_list::compatible_with(gamedrv); } } - osd_free(dst); } //------------------------------------------------- @@ -512,14 +508,14 @@ void device_image_interface::battery_load(void *buffer, int length, int fill) { assert_always(buffer && (length > 0), "Must specify sensical buffer/length"); - file_error filerr; + osd_file::error filerr; int bytes_read = 0; std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext.c_str()).append(".nv"); /* try to open the battery file and read it in, if possible */ emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_READ); filerr = file.open(fname.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) bytes_read = file.read(buffer, length); /* fill remaining bytes (if necessary) */ @@ -530,14 +526,14 @@ void device_image_interface::battery_load(void *buffer, int length, void *def_bu { assert_always(buffer && (length > 0), "Must specify sensical buffer/length"); - file_error filerr; + osd_file::error filerr; int bytes_read = 0; std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext.c_str()).append(".nv"); /* try to open the battery file and read it in, if possible */ emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_READ); filerr = file.open(fname.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) bytes_read = file.read(buffer, length); /* if no file was present, copy the default battery */ @@ -558,8 +554,8 @@ void device_image_interface::battery_save(const void *buffer, int length) /* try to open the battery file and write it out, if possible */ emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(fname.c_str()); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(fname.c_str()); + if (filerr == osd_file::error::NONE) file.write(buffer, length); } @@ -620,32 +616,32 @@ image_error_t device_image_interface::load_image_by_path(UINT32 open_flags, cons /* did the open succeed? */ switch(filerr) { - case FILERR_NONE: + case osd_file::error::NONE: /* success! */ m_readonly = (open_flags & OPEN_FLAG_WRITE) ? 0 : 1; m_created = (open_flags & OPEN_FLAG_CREATE) ? 1 : 0; err = IMAGE_ERROR_SUCCESS; break; - case FILERR_NOT_FOUND: - case FILERR_ACCESS_DENIED: + case osd_file::error::NOT_FOUND: + case osd_file::error::ACCESS_DENIED: /* file not found (or otherwise cannot open); continue */ err = IMAGE_ERROR_FILENOTFOUND; break; - case FILERR_OUT_OF_MEMORY: + case osd_file::error::OUT_OF_MEMORY: /* out of memory */ err = IMAGE_ERROR_OUTOFMEMORY; break; - case FILERR_ALREADY_OPEN: + case osd_file::error::ALREADY_OPEN: /* this shouldn't happen */ err = IMAGE_ERROR_ALREADYOPEN; break; - case FILERR_FAILURE: - case FILERR_TOO_MANY_FILES: - case FILERR_INVALID_DATA: + case osd_file::error::FAILURE: + case osd_file::error::TOO_MANY_FILES: + case osd_file::error::INVALID_DATA: default: /* other errors */ err = IMAGE_ERROR_INTERNAL; @@ -653,7 +649,7 @@ image_error_t device_image_interface::load_image_by_path(UINT32 open_flags, cons } /* if successful, set the file name */ - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) set_image_filename(revised_path.c_str()); return err; @@ -672,32 +668,32 @@ int device_image_interface::reopen_for_write(const char *path) /* did the open succeed? */ switch(filerr) { - case FILERR_NONE: + case osd_file::error::NONE: /* success! */ m_readonly = 0; m_created = 1; err = IMAGE_ERROR_SUCCESS; break; - case FILERR_NOT_FOUND: - case FILERR_ACCESS_DENIED: + case osd_file::error::NOT_FOUND: + case osd_file::error::ACCESS_DENIED: /* file not found (or otherwise cannot open); continue */ err = IMAGE_ERROR_FILENOTFOUND; break; - case FILERR_OUT_OF_MEMORY: + case osd_file::error::OUT_OF_MEMORY: /* out of memory */ err = IMAGE_ERROR_OUTOFMEMORY; break; - case FILERR_ALREADY_OPEN: + case osd_file::error::ALREADY_OPEN: /* this shouldn't happen */ err = IMAGE_ERROR_ALREADYOPEN; break; - case FILERR_FAILURE: - case FILERR_TOO_MANY_FILES: - case FILERR_INVALID_DATA: + case osd_file::error::FAILURE: + case osd_file::error::TOO_MANY_FILES: + case osd_file::error::INVALID_DATA: default: /* other errors */ err = IMAGE_ERROR_INTERNAL; @@ -705,7 +701,7 @@ int device_image_interface::reopen_for_write(const char *path) } /* if successful, set the file name */ - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) set_image_filename(revised_path.c_str()); return err; @@ -803,7 +799,7 @@ bool device_image_interface::load_software(software_list_device &swlist, const c /* handle files */ if (ROMENTRY_ISFILE(romp)) { - file_error filerr = FILERR_NOT_FOUND; + osd_file::error filerr = osd_file::error::NOT_FOUND; UINT32 crc = 0; bool has_crc = hash_collection(ROM_GETHASHDATA(romp)).crc(crc); @@ -872,9 +868,9 @@ bool device_image_interface::load_software(software_list_device &swlist, const c warningcount += verify_length_and_hash(m_mame_file.get(),ROM_GETNAME(romp),ROM_GETLENGTH(romp),hash_collection(ROM_GETHASHDATA(romp))); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) filerr = util::core_file::open_proxy(*m_mame_file, m_file); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) retVal = TRUE; break; // load first item for start diff --git a/src/emu/dipty.cpp b/src/emu/dipty.cpp index bd1a166322f..a2ada675307 100644 --- a/src/emu/dipty.cpp +++ b/src/emu/dipty.cpp @@ -12,10 +12,10 @@ #include "osdcore.h" device_pty_interface::device_pty_interface(const machine_config &mconfig, device_t &device) - : device_interface(device, "pty"), - m_pty_master(nullptr), - m_slave_name(), - m_opened(false) + : device_interface(device, "pty") + , m_pty_master() + , m_slave_name() + , m_opened(false) { } @@ -23,63 +23,57 @@ device_pty_interface::~device_pty_interface() { } -bool device_pty_interface::open(void) +bool device_pty_interface::open() { - if (!m_opened) { - char buffer[ 128 ]; - - if (osd_openpty(&m_pty_master , buffer , sizeof(buffer)) == FILERR_NONE) { + if (!m_opened) + { + if (osd_file::openpty(m_pty_master, m_slave_name) == osd_file::error::NONE) + { m_opened = true; - m_slave_name.assign(buffer); - } else { + } + else + { m_opened = false; - m_pty_master = nullptr; + m_pty_master.reset(); } } - return m_opened; } -void device_pty_interface::close(void) +void device_pty_interface::close() { - if (m_opened) { - osd_close(m_pty_master); - m_opened = false; - } + m_pty_master.reset(); + m_opened = false; } -bool device_pty_interface::is_open(void) const +bool device_pty_interface::is_open() const { return m_opened; } ssize_t device_pty_interface::read(UINT8 *rx_chars , size_t count) const { - UINT32 actual_bytes; - - if (m_opened && osd_read(m_pty_master, rx_chars, 0, count, &actual_bytes) == FILERR_NONE) { + std::uint32_t actual_bytes; + if (m_opened && m_pty_master->read(rx_chars, 0, count, actual_bytes) == osd_file::error::NONE) return actual_bytes; - } else { + else return -1; - } } void device_pty_interface::write(UINT8 tx_char) const { - UINT32 actual_bytes; - - if (m_opened) { - osd_write(m_pty_master, &tx_char, 0, 1, &actual_bytes); - } + std::uint32_t actual_bytes; + if (m_opened) + m_pty_master->write(&tx_char, 0, 1, actual_bytes); } -bool device_pty_interface::is_slave_connected(void) const +bool device_pty_interface::is_slave_connected() const { // TODO: really check for slave status return m_opened; } -const char *device_pty_interface::slave_name(void) const +const char *device_pty_interface::slave_name() const { return m_slave_name.c_str(); } diff --git a/src/emu/dipty.h b/src/emu/dipty.h index 4efa39fa702..10549e52ccb 100644 --- a/src/emu/dipty.h +++ b/src/emu/dipty.h @@ -14,35 +14,35 @@ #error Dont include this file directly; include emu.h instead. #endif -#ifndef __DIPTY_H__ -#define __DIPTY_H__ +#ifndef MAME_EMU_DIPTY_H +#define MAME_EMU_DIPTY_H class device_pty_interface : public device_interface { public: - // construction/destruction - device_pty_interface(const machine_config &mconfig, device_t &device); - virtual ~device_pty_interface(); + // construction/destruction + device_pty_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pty_interface(); - bool open(void); - void close(void); + bool open(); + void close(); - bool is_open(void) const; + bool is_open() const; - ssize_t read(UINT8 *rx_chars , size_t count) const; - void write(UINT8 tx_char) const; + ssize_t read(UINT8 *rx_chars , size_t count) const; + void write(UINT8 tx_char) const; - bool is_slave_connected(void) const; + bool is_slave_connected() const; - const char *slave_name(void) const; + const char *slave_name() const; protected: - osd_file *m_pty_master; - std::string m_slave_name; - bool m_opened; + osd_file::ptr m_pty_master; + std::string m_slave_name; + bool m_opened; }; // iterator typedef device_interface_iterator<device_pty_interface> pty_interface_iterator; -#endif /* __DIPTY_H__ */ +#endif /* MAME_EMU_DIPTY_H */ diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index 332c9c2d787..f8127e28dbb 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -568,8 +568,8 @@ bool emu_options::parse_one_ini(const char *basename, int priority, std::string // open the file; if we fail, that's ok emu_file file(ini_path(), OPEN_FLAG_READ); - file_error filerr = file.open(basename, ".ini"); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(basename, ".ini"); + if (filerr != osd_file::error::NONE) return false; // parse the file diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp index 79bf746fbfa..b8e0c433575 100644 --- a/src/emu/fileio.cpp +++ b/src/emu/fileio.cpp @@ -146,7 +146,7 @@ emu_file::emu_file(UINT32 openflags) m_openflags(openflags), m_zipfile(nullptr), m_ziplength(0), - m__7zfile(nullptr), + m__7zfile(), m__7zlength(0), m_remove_on_close(false), m_restrict_to_mediapath(false) @@ -164,7 +164,7 @@ emu_file::emu_file(const char *searchpath, UINT32 openflags) m_openflags(openflags), m_zipfile(nullptr), m_ziplength(0), - m__7zfile(nullptr), + m__7zfile(), m__7zlength(0), m_remove_on_close(false), m_restrict_to_mediapath(false) @@ -255,7 +255,7 @@ hash_collection &emu_file::hashes(const char *types) // open - open a file by searching paths //------------------------------------------------- -file_error emu_file::open(const char *name) +osd_file::error emu_file::open(const char *name) { // remember the filename and CRC info m_filename = name; @@ -267,28 +267,28 @@ file_error emu_file::open(const char *name) return open_next(); } -file_error emu_file::open(const char *name1, const char *name2) +osd_file::error emu_file::open(const char *name1, const char *name2) { // concatenate the strings and do a standard open std::string name = std::string(name1).append(name2); return open(name.c_str()); } -file_error emu_file::open(const char *name1, const char *name2, const char *name3) +osd_file::error emu_file::open(const char *name1, const char *name2, const char *name3) { // concatenate the strings and do a standard open std::string name = std::string(name1).append(name2).append(name3); return open(name.c_str()); } -file_error emu_file::open(const char *name1, const char *name2, const char *name3, const char *name4) +osd_file::error emu_file::open(const char *name1, const char *name2, const char *name3, const char *name4) { // concatenate the strings and do a standard open std::string name = std::string(name1).append(name2).append(name3).append(name4); return open(name.c_str()); } -file_error emu_file::open(const char *name, UINT32 crc) +osd_file::error emu_file::open(const char *name, UINT32 crc) { // remember the filename and CRC info m_filename = name; @@ -300,21 +300,21 @@ file_error emu_file::open(const char *name, UINT32 crc) return open_next(); } -file_error emu_file::open(const char *name1, const char *name2, UINT32 crc) +osd_file::error emu_file::open(const char *name1, const char *name2, UINT32 crc) { // concatenate the strings and do a standard open std::string name = std::string(name1).append(name2); return open(name.c_str(), crc); } -file_error emu_file::open(const char *name1, const char *name2, const char *name3, UINT32 crc) +osd_file::error emu_file::open(const char *name1, const char *name2, const char *name3, UINT32 crc) { // concatenate the strings and do a standard open std::string name = std::string(name1).append(name2).append(name3); return open(name.c_str(), crc); } -file_error emu_file::open(const char *name1, const char *name2, const char *name3, const char *name4, UINT32 crc) +osd_file::error emu_file::open(const char *name1, const char *name2, const char *name3, const char *name4, UINT32 crc) { // concatenate the strings and do a standard open std::string name = std::string(name1).append(name2).append(name3).append(name4); @@ -327,19 +327,19 @@ file_error emu_file::open(const char *name1, const char *name2, const char *name // the filename by iterating over paths //------------------------------------------------- -file_error emu_file::open_next() +osd_file::error emu_file::open_next() { // if we're open from a previous attempt, close up now if (m_file != nullptr) close(); // loop over paths - file_error filerr = FILERR_NOT_FOUND; + osd_file::error filerr = osd_file::error::NOT_FOUND; while (m_iterator.next(m_fullpath, m_filename.c_str())) { // attempt to open the file directly filerr = util::core_file::open(m_fullpath.c_str(), m_openflags, m_file); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) break; // if we're opening for read-only we have other options @@ -348,13 +348,13 @@ file_error emu_file::open_next() std::string tempfullpath = m_fullpath; filerr = attempt_zipped(); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) break; m_fullpath = tempfullpath; filerr = attempt__7zped(); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) break; } } @@ -367,7 +367,7 @@ file_error emu_file::open_next() // just an array of data in RAM //------------------------------------------------- -file_error emu_file::open_ram(const void *data, UINT32 length) +osd_file::error emu_file::open_ram(const void *data, UINT32 length) { // set a fake filename and CRC m_filename = "RAM"; @@ -386,21 +386,15 @@ file_error emu_file::open_ram(const void *data, UINT32 length) void emu_file::close() { // close files and free memory - if (m__7zfile != nullptr) - _7z_file_close(m__7zfile); - m__7zfile = nullptr; - - if (m_zipfile != nullptr) - zip_file_close(m_zipfile); - m_zipfile = nullptr; - + m__7zfile.reset(); + m_zipfile.reset(); m_file.reset(); m__7zdata.clear(); m_zipdata.clear(); if (m_remove_on_close) - osd_rmfile(m_fullpath.c_str()); + osd_file::remove(m_fullpath); m_remove_on_close = false; // reset our hashes and path as well @@ -415,7 +409,7 @@ void emu_file::close() // compression, or up to 9 for max compression //------------------------------------------------- -file_error emu_file::compress(int level) +osd_file::error emu_file::compress(int level) { return m_file->compress(level); } @@ -429,10 +423,10 @@ file_error emu_file::compress(int level) bool emu_file::compressed_file_ready(void) { // load the ZIP file now if we haven't yet - if (m__7zfile != nullptr && load__7zped_file() != FILERR_NONE) + if (m__7zfile != nullptr && load__7zped_file() != osd_file::error::NONE) return true; - if (m_zipfile != nullptr && load_zipped_file() != FILERR_NONE) + if (m_zipfile != nullptr && load_zipped_file() != osd_file::error::NONE) return true; return false; @@ -657,7 +651,7 @@ bool emu_file::part_of_mediapath(std::string path) // attempt_zipped - attempt to open a ZIPped file //------------------------------------------------- -file_error emu_file::attempt_zipped() +osd_file::error emu_file::attempt_zipped() { std::string filename; @@ -667,11 +661,11 @@ file_error emu_file::attempt_zipped() // find the final path separator int dirsep = m_fullpath.find_last_of(PATH_SEPARATOR[0]); if (dirsep == -1) - return FILERR_NOT_FOUND; + return osd_file::error::NOT_FOUND; if (restrict_to_mediapath()) if ( !part_of_mediapath(m_fullpath) ) - return FILERR_NOT_FOUND; + return osd_file::error::NOT_FOUND; // insert the part from the right of the separator into the head of the filename if (filename.length() > 0) @@ -682,49 +676,49 @@ file_error emu_file::attempt_zipped() m_fullpath = m_fullpath.substr(0, dirsep).append(".zip"); // attempt to open the ZIP file - zip_file *zip; - zip_error ziperr = zip_file_open(m_fullpath.c_str(), &zip); + zip_file::ptr zip; + zip_file::error ziperr = zip_file::open(m_fullpath, zip); // chop the .zip back off the filename before continuing m_fullpath = m_fullpath.substr(0, dirsep); // if we failed to open this file, continue scanning - if (ziperr != ZIPERR_NONE) + if (ziperr != zip_file::error::NONE) continue; // see if we can find a file with the right name and (if available) crc - const zip_file_header *header; - for (header = zip_file_first_file(zip); header != nullptr; header = zip_file_next_file(zip)) + const zip_file::file_header *header; + for (header = zip->first_file(); header != nullptr; header = zip->next_file()) if (zip_filename_match(*header, filename) && (!(m_openflags & OPEN_FLAG_HAS_CRC) || header->crc == m_crc)) break; // if that failed, look for a file with the right crc, but the wrong filename if (header == nullptr && (m_openflags & OPEN_FLAG_HAS_CRC)) - for (header = zip_file_first_file(zip); header != nullptr; header = zip_file_next_file(zip)) + for (header = zip->first_file(); header != nullptr; header = zip->next_file()) if (header->crc == m_crc && !zip_header_is_path(*header)) break; // if that failed, look for a file with the right name; reporting a bad checksum // is more helpful and less confusing than reporting "rom not found" if (header == nullptr) - for (header = zip_file_first_file(zip); header != nullptr; header = zip_file_next_file(zip)) + for (header = zip->first_file(); header != nullptr; header = zip->next_file()) if (zip_filename_match(*header, filename)) break; // if we got it, read the data if (header != nullptr) { - m_zipfile = zip; + m_zipfile = std::move(zip); m_ziplength = header->uncompressed_length; // build a hash with just the CRC m_hashes.reset(); m_hashes.add_crc(header->crc); - return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? FILERR_NONE : load_zipped_file(); + return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? osd_file::error::NONE : load_zipped_file(); } // close up the ZIP file and try the next level - zip_file_close(zip); + zip.reset(); } } @@ -733,7 +727,7 @@ file_error emu_file::attempt_zipped() // load_zipped_file - load a ZIPped file //------------------------------------------------- -file_error emu_file::load_zipped_file() +osd_file::error emu_file::load_zipped_file() { assert(m_file == nullptr); assert(m_zipdata.empty()); @@ -743,25 +737,24 @@ file_error emu_file::load_zipped_file() m_zipdata.resize(m_ziplength); // read the data into our buffer and return - zip_error ziperr = zip_file_decompress(m_zipfile, &m_zipdata[0], m_zipdata.size()); - if (ziperr != ZIPERR_NONE) + zip_file::error ziperr = m_zipfile->decompress(&m_zipdata[0], m_zipdata.size()); + if (ziperr != zip_file::error::NONE) { m_zipdata.clear(); - return FILERR_FAILURE; + return osd_file::error::FAILURE; } // convert to RAM file - file_error filerr = util::core_file::open_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, m_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, m_file); + if (filerr != osd_file::error::NONE) { m_zipdata.clear(); - return FILERR_FAILURE; + return osd_file::error::FAILURE; } // close out the ZIP file - zip_file_close(m_zipfile); - m_zipfile = nullptr; - return FILERR_NONE; + m_zipfile.reset(); + return osd_file::error::NONE; } @@ -770,7 +763,7 @@ file_error emu_file::load_zipped_file() // to expected filename, ignoring any directory //------------------------------------------------- -bool emu_file::zip_filename_match(const zip_file_header &header, const std::string &filename) +bool emu_file::zip_filename_match(const zip_file::file_header &header, const std::string &filename) { const char *zipfile = header.filename + header.filename_length - filename.length(); return (zipfile >= header.filename && core_stricmp(filename.c_str(),zipfile) == 0 && (zipfile == header.filename || zipfile[-1] == '/')); @@ -782,7 +775,7 @@ bool emu_file::zip_filename_match(const zip_file_header &header, const std::stri // in header is a path //------------------------------------------------- -bool emu_file::zip_header_is_path(const zip_file_header &header) +bool emu_file::zip_header_is_path(const zip_file::file_header &header) { const char *zipfile = header.filename + header.filename_length - 1; return (zipfile >= header.filename && zipfile[0] == '/'); @@ -792,7 +785,7 @@ bool emu_file::zip_header_is_path(const zip_file_header &header) // attempt__7zped - attempt to open a .7z file //------------------------------------------------- -file_error emu_file::attempt__7zped() +osd_file::error emu_file::attempt__7zped() { std::string filename; @@ -802,11 +795,11 @@ file_error emu_file::attempt__7zped() // find the final path separator int dirsep = m_fullpath.find_last_of(PATH_SEPARATOR[0]); if (dirsep == -1) - return FILERR_NOT_FOUND; + return osd_file::error::NOT_FOUND; if (restrict_to_mediapath()) if ( !part_of_mediapath(m_fullpath) ) - return FILERR_NOT_FOUND; + return osd_file::error::NOT_FOUND; // insert the part from the right of the separator into the head of the filename if (filename.length() > 0) @@ -817,43 +810,41 @@ file_error emu_file::attempt__7zped() m_fullpath = m_fullpath.substr(0, dirsep).append(".7z"); // attempt to open the _7Z file - _7z_file *_7z; - _7z_error _7zerr = _7z_file_open(m_fullpath.c_str(), &_7z); + _7z_file::ptr _7z; + _7z_file::error _7zerr = _7z_file::open(m_fullpath, _7z); // chop the ._7z back off the filename before continuing m_fullpath = m_fullpath.substr(0, dirsep); // if we failed to open this file, continue scanning - if (_7zerr != _7ZERR_NONE) + if (_7zerr != _7z_file::error::NONE) continue; int fileno = -1; // see if we can find a file with the right name and (if available) crc - if (m_openflags & OPEN_FLAG_HAS_CRC) fileno = _7z_search_crc_match(_7z, m_crc, filename.c_str(), filename.length(), true, true); + if (m_openflags & OPEN_FLAG_HAS_CRC) fileno = _7z->search(m_crc, filename); // if that failed, look for a file with the right crc, but the wrong filename - if (fileno==-1) - if (m_openflags & OPEN_FLAG_HAS_CRC) fileno = _7z_search_crc_match(_7z, m_crc, filename.c_str(), filename.length(), true, false); + if ((fileno == -1) && (m_openflags & OPEN_FLAG_HAS_CRC)) fileno = _7z->search(m_crc); // if that failed, look for a file with the right name; reporting a bad checksum // is more helpful and less confusing than reporting "rom not found" - if (fileno==-1) - fileno = _7z_search_crc_match(_7z, m_crc, filename.c_str(), filename.length(), false, true); + if (fileno == -1) fileno = _7z->search(filename); if (fileno != -1) { - m__7zfile = _7z; - m__7zlength = _7z->uncompressed_length; + m__7zfile = std::move(_7z); + m__7zlength = _7z->current_uncompressed_length(); // build a hash with just the CRC m_hashes.reset(); - m_hashes.add_crc(_7z->crc); - return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? FILERR_NONE : load__7zped_file(); + m_hashes.add_crc(_7z->current_crc()); + return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? osd_file::error::NONE : load__7zped_file(); } // close up the _7Z file and try the next level - _7z_file_close(_7z); + _7z.reset(); } } @@ -862,33 +853,32 @@ file_error emu_file::attempt__7zped() // load__7zped_file - load a _7Zped file //------------------------------------------------- -file_error emu_file::load__7zped_file() +osd_file::error emu_file::load__7zped_file() { assert(m_file == nullptr); assert(m__7zdata.empty()); - assert(m__7zfile != nullptr); + assert(m__7zfile); // allocate some memory m__7zdata.resize(m__7zlength); // read the data into our buffer and return - _7z_error _7zerr = _7z_file_decompress(m__7zfile, &m__7zdata[0], m__7zdata.size()); - if (_7zerr != _7ZERR_NONE) + _7z_file::error _7zerr = m__7zfile->decompress(&m__7zdata[0], m__7zdata.size()); + if (_7zerr != _7z_file::error::NONE) { m__7zdata.clear(); - return FILERR_FAILURE; + return osd_file::error::FAILURE; } // convert to RAM file - file_error filerr = util::core_file::open_ram(&m__7zdata[0], m__7zdata.size(), m_openflags, m_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open_ram(&m__7zdata[0], m__7zdata.size(), m_openflags, m_file); + if (filerr != osd_file::error::NONE) { m__7zdata.clear(); - return FILERR_FAILURE; + return osd_file::error::FAILURE; } // close out the _7Z file - _7z_file_close(m__7zfile); - m__7zfile = nullptr; - return FILERR_NONE; + m__7zfile.reset(); + return osd_file::error::NONE; } diff --git a/src/emu/fileio.h b/src/emu/fileio.h index 22f36f5362e..c54c740d686 100644 --- a/src/emu/fileio.h +++ b/src/emu/fileio.h @@ -10,11 +10,12 @@ #pragma once -#ifndef __FILEIO_H__ -#define __FILEIO_H__ +#ifndef MAME_EMU_FILEIO_H +#define MAME_EMU_FILEIO_H #include "corefile.h" #include "hash.h" +#include "unzip.h" // some systems use macros for getc/putc rather than functions #ifdef getc @@ -26,11 +27,7 @@ //************************************************************************** // forward declarations -struct zip_file_header; -struct zip_file; - -struct _7z_file_header; -struct _7z_file; +class _7z_file; // ======================> path_iterator @@ -105,20 +102,20 @@ public: void set_restrict_to_mediapath(bool rtmp = true) { m_restrict_to_mediapath = rtmp; } // open/close - file_error open(const char *name); - file_error open(const char *name1, const char *name2); - file_error open(const char *name1, const char *name2, const char *name3); - file_error open(const char *name1, const char *name2, const char *name3, const char *name4); - file_error open(const char *name, UINT32 crc); - file_error open(const char *name1, const char *name2, UINT32 crc); - file_error open(const char *name1, const char *name2, const char *name3, UINT32 crc); - file_error open(const char *name1, const char *name2, const char *name3, const char *name4, UINT32 crc); - file_error open_next(); - file_error open_ram(const void *data, UINT32 length); + osd_file::error open(const char *name); + osd_file::error open(const char *name1, const char *name2); + osd_file::error open(const char *name1, const char *name2, const char *name3); + osd_file::error open(const char *name1, const char *name2, const char *name3, const char *name4); + osd_file::error open(const char *name, UINT32 crc); + osd_file::error open(const char *name1, const char *name2, UINT32 crc); + osd_file::error open(const char *name1, const char *name2, const char *name3, UINT32 crc); + osd_file::error open(const char *name1, const char *name2, const char *name3, const char *name4, UINT32 crc); + osd_file::error open_next(); + osd_file::error open_ram(const void *data, UINT32 length); void close(); // control - file_error compress(int compress); + osd_file::error compress(int compress); // position int seek(INT64 offset, int whence); @@ -148,13 +145,13 @@ private: bool compressed_file_ready(void); // internal helpers - file_error attempt_zipped(); - file_error load_zipped_file(); - bool zip_filename_match(const zip_file_header &header, const std::string &filename); - bool zip_header_is_path(const zip_file_header &header); + osd_file::error attempt_zipped(); + osd_file::error load_zipped_file(); + bool zip_filename_match(const zip_file::file_header &header, const std::string &filename); + bool zip_header_is_path(const zip_file::file_header &header); - file_error attempt__7zped(); - file_error load__7zped_file(); + osd_file::error attempt__7zped(); + osd_file::error load__7zped_file(); // internal state std::string m_filename; // original filename provided @@ -166,17 +163,16 @@ private: UINT32 m_openflags; // flags we used for the open hash_collection m_hashes; // collection of hashes - zip_file * m_zipfile; // ZIP file pointer + zip_file::ptr m_zipfile; // ZIP file pointer dynamic_buffer m_zipdata; // ZIP file data UINT64 m_ziplength; // ZIP file length - _7z_file * m__7zfile; // 7Z file pointer + std::unique_ptr<_7z_file> m__7zfile; // 7Z file pointer dynamic_buffer m__7zdata; // 7Z file data UINT64 m__7zlength; // 7Z file length bool m_remove_on_close; // flag: remove the file when closing - bool m_restrict_to_mediapath; // flag: restrict to paths inside the media-path + bool m_restrict_to_mediapath; // flag: restrict to paths inside the media-path }; - -#endif /* __FILEIO_H__ */ +#endif // MAME_EMU_FILEIO_H diff --git a/src/emu/hashfile.cpp b/src/emu/hashfile.cpp index 557d9c28d5f..ca668e1dfae 100644 --- a/src/emu/hashfile.cpp +++ b/src/emu/hashfile.cpp @@ -430,7 +430,7 @@ hash_file *hashfile_open(emu_options &options, const char *sysname, int is_prelo { hash_file *hashfile = nullptr; object_pool *pool = nullptr; - file_error filerr; + osd_file::error filerr; /* create a pool for this hash file */ pool = pool_alloc_lib(error_proc); @@ -450,7 +450,7 @@ hash_file *hashfile_open(emu_options &options, const char *sysname, int is_prelo /* open a file */ hashfile->file = global_alloc(emu_file(options.hash_path(), OPEN_FLAG_READ)); filerr = hashfile->file->open(sysname, ".hsi"); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { global_free(hashfile->file); hashfile->file = nullptr; diff --git a/src/emu/image.cpp b/src/emu/image.cpp index 76de04714fb..f9f6111a292 100644 --- a/src/emu/image.cpp +++ b/src/emu/image.cpp @@ -155,8 +155,8 @@ int image_manager::write_config(emu_options &options, const char *filename, cons } emu_file file(options.ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - file_error filerr = file.open(filename); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(filename); + if (filerr == osd_file::error::NONE) { std::string inistring = options.output_ini(); file.puts(inistring.c_str()); diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index 2b00cabb94b..1ca4d477575 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -3407,8 +3407,8 @@ time_t ioport_manager::playback_init() return 0; // open the playback file - file_error filerr = m_playback_file.open(filename); - assert_always(filerr == FILERR_NONE, "Failed to open file for playback"); + osd_file::error filerr = m_playback_file.open(filename); + assert_always(filerr == osd_file::error::NONE, "Failed to open file for playback"); // read the header and verify that it is a modern version; if not, print an error inp_header header; @@ -3582,8 +3582,8 @@ void ioport_manager::record_init() return; // open the record file - file_error filerr = m_record_file.open(filename); - assert_always(filerr == FILERR_NONE, "Failed to open file for recording"); + osd_file::error filerr = m_record_file.open(filename); + assert_always(filerr == osd_file::error::NONE, "Failed to open file for recording"); // get the base time system_time systime; @@ -3625,8 +3625,8 @@ void ioport_manager::timecode_init() { filename.append(record_filename).append(".timecode"); osd_printf_info("Record input timecode file: %s\n", record_filename); - file_error filerr = m_timecode_file.open(filename.c_str()); - assert_always(filerr == FILERR_NONE, "Failed to open file for input timecode recording"); + osd_file::error filerr = m_timecode_file.open(filename.c_str()); + assert_always(filerr == osd_file::error::NONE, "Failed to open file for input timecode recording"); m_timecode_file.puts(std::string("# ==========================================\n").c_str()); m_timecode_file.puts(std::string("# TIMECODE FILE FOR VIDEO PREVIEW GENERATION\n").c_str()); diff --git a/src/emu/language.cpp b/src/emu/language.cpp index b47605f50c8..8d4618c7be3 100644 --- a/src/emu/language.cpp +++ b/src/emu/language.cpp @@ -41,7 +41,7 @@ void load_translation(emu_options &m_options) strreplace(name, " ", "_"); strreplace(name, "(", ""); strreplace(name, ")", ""); - if (file.open(name.c_str(), PATH_SEPARATOR "strings.mo") == FILERR_NONE) + if (file.open(name.c_str(), PATH_SEPARATOR "strings.mo") == osd_file::error::NONE) { UINT64 size = file.size(); UINT32 *buffer = global_alloc_array(UINT32, size / 4 + 1); diff --git a/src/emu/luaengine.cpp b/src/emu/luaengine.cpp index 4ffee509693..5ef7b935b0e 100644 --- a/src/emu/luaengine.cpp +++ b/src/emu/luaengine.cpp @@ -870,7 +870,7 @@ int lua_engine::lua_screen::l_snapshot(lua_State *L) luaL_argcheck(L, lua_isstring(L, 2) || lua_isnone(L, 2), 2, "optional argument: filename, string expected"); emu_file file(sc->machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr; + osd_file::error filerr; if (!lua_isnone(L, 2)) { const char *filename = lua_tostring(L, 2); @@ -884,9 +884,9 @@ int lua_engine::lua_screen::l_snapshot(lua_State *L) filerr = sc->machine().video().open_next(file, "png"); } - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { - luaL_error(L, "file_error=%d", filerr); + luaL_error(L, "osd_file::error=%d", filerr); return 0; } diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index b3ac263473e..00db05b59c3 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -333,8 +333,8 @@ int running_machine::run(bool firstrun) if (options().log() && &system() != &GAME_NAME(___empty)) { m_logfile = std::make_unique<emu_file>(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = m_logfile->open("error.log"); - assert_always(filerr == FILERR_NONE, "unable to open log file"); + osd_file::error filerr = m_logfile->open("error.log"); + assert_always(filerr == osd_file::error::NONE, "unable to open log file"); add_logerror_callback(logfile_callback); } @@ -440,7 +440,7 @@ int running_machine::run(bool firstrun) // call all exit callbacks registered call_notifiers(MACHINE_NOTIFY_EXIT); - zip_file_cache_clear(); + zip_file::cache_clear(); // close the logfile m_logfile.reset(); @@ -824,7 +824,7 @@ void running_machine::handle_saveload() UINT32 openflags = (m_saveload_schedule == SLS_LOAD) ? OPEN_FLAG_READ : (OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); const char *opnamed = (m_saveload_schedule == SLS_LOAD) ? "loaded" : "saved"; const char *opname = (m_saveload_schedule == SLS_LOAD) ? "load" : "save"; - file_error filerr = FILERR_NONE; + osd_file::error filerr = osd_file::error::NONE; // if no name, bail emu_file file(m_saveload_searchpath, openflags); @@ -846,7 +846,7 @@ void running_machine::handle_saveload() // open the file filerr = file.open(m_saveload_pending_file.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { // read/write the save state save_error saverr = (m_saveload_schedule == SLS_LOAD) ? m_save.read_file(file) : m_save.write_file(file); @@ -1171,7 +1171,7 @@ void running_machine::nvram_load() for (device_nvram_interface *nvram = iter.first(); nvram != nullptr; nvram = iter.next()) { emu_file file(options().nvram_directory(), OPEN_FLAG_READ); - if (file.open(nvram_filename(nvram->device()).c_str()) == FILERR_NONE) + if (file.open(nvram_filename(nvram->device()).c_str()) == osd_file::error::NONE) { nvram->nvram_load(file); file.close(); @@ -1192,7 +1192,7 @@ void running_machine::nvram_save() for (device_nvram_interface *nvram = iter.first(); nvram != nullptr; nvram = iter.next()) { emu_file file(options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(nvram_filename(nvram->device()).c_str()) == FILERR_NONE) + if (file.open(nvram_filename(nvram->device()).c_str()) == osd_file::error::NONE) { nvram->nvram_save(file); file.close(); diff --git a/src/emu/mame.cpp b/src/emu/mame.cpp index 5e93623498d..2f313dceabb 100644 --- a/src/emu/mame.cpp +++ b/src/emu/mame.cpp @@ -158,8 +158,8 @@ void machine_manager::start_luaengine() m_lua->initialize(); { emu_file file(options().plugins_path(), OPEN_FLAG_READ); - file_error filerr = file.open("boot.lua"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open("boot.lua"); + if (filerr == osd_file::error::NONE) { m_lua->load_script(file.fullpath()); } diff --git a/src/emu/render.cpp b/src/emu/render.cpp index 3de791eab52..4d4d1344db5 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -1588,8 +1588,8 @@ bool render_target::load_layout_file(const char *dirname, const char *filename) // attempt to open the file; bail if we can't emu_file layoutfile(manager().machine().options().art_path(), OPEN_FLAG_READ); - file_error filerr = layoutfile.open(fname.c_str()); - if (filerr != FILERR_NONE) + osd_file::error filerr = layoutfile.open(fname.c_str()); + if (filerr != osd_file::error::NONE) return false; // read the file diff --git a/src/emu/rendfont.cpp b/src/emu/rendfont.cpp index 89c174c31bf..27a14bb0d55 100644 --- a/src/emu/rendfont.cpp +++ b/src/emu/rendfont.cpp @@ -164,8 +164,8 @@ render_font::render_font(render_manager &manager, const char *filename) // load the raw data instead emu_file ramfile(OPEN_FLAG_READ); - file_error filerr = ramfile.open_ram(font_uismall, sizeof(font_uismall)); - if (filerr == FILERR_NONE) + osd_file::error filerr = ramfile.open_ram(font_uismall, sizeof(font_uismall)); + if (filerr == osd_file::error::NONE) load_cached(ramfile, 0); render_font_command_glyph(); } @@ -470,8 +470,8 @@ bool render_font::load_cached_bdf(const char *filename) { // first try to open the BDF itself emu_file file(manager().machine().options().font_path(), OPEN_FLAG_READ); - file_error filerr = file.open(filename); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(filename); + if (filerr != osd_file::error::NONE) return false; // determine the file size and allocate memory @@ -494,7 +494,7 @@ bool render_font::load_cached_bdf(const char *filename) { emu_file cachefile(manager().machine().options().font_path(), OPEN_FLAG_READ); filerr = cachefile.open(cachedname.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { // if we have a cached version, load it bool result = load_cached(cachefile, hash); @@ -730,8 +730,8 @@ bool render_font::save_cached(const char *filename, UINT32 hash) // attempt to open the file emu_file file(manager().machine().options().font_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - file_error filerr = file.open(filename); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(filename); + if (filerr != osd_file::error::NONE) return false; // determine the number of characters diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp index 6d0bde63adb..4c49c6c8a62 100644 --- a/src/emu/rendutil.cpp +++ b/src/emu/rendutil.cpp @@ -540,8 +540,8 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, fname.assign(filename); else fname.assign(dirname).append(PATH_SEPARATOR).append(filename); - file_error filerr = file.open(fname.c_str()); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(fname.c_str()); + if (filerr != osd_file::error::NONE) return false; // read the PNG data diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp index f5f15551ab5..45cbeecbea4 100644 --- a/src/emu/romload.cpp +++ b/src/emu/romload.cpp @@ -28,9 +28,9 @@ HELPERS (also used by diimage.cpp) ***************************************************************************/ -static file_error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file &image_file) +static osd_file::error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file &image_file) { - file_error filerr; + osd_file::error filerr; if (location != nullptr && strcmp(location, "") != 0) filerr = image_file.open(location, PATH_SEPARATOR, ROM_GETNAME(romp), ext); @@ -40,7 +40,7 @@ static file_error common_process_file(emu_options &options, const char *location return filerr; } -std::unique_ptr<emu_file> common_process_file(emu_options &options, const char *location, bool has_crc, UINT32 crc, const rom_entry *romp, file_error &filerr) +std::unique_ptr<emu_file> common_process_file(emu_options &options, const char *location, bool has_crc, UINT32 crc, const rom_entry *romp, osd_file::error &filerr) { auto image_file = std::make_unique<emu_file>(options.media_path(), OPEN_FLAG_READ); @@ -49,7 +49,7 @@ std::unique_ptr<emu_file> common_process_file(emu_options &options, const char * else filerr = image_file->open(location, PATH_SEPARATOR, ROM_GETNAME(romp)); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { image_file = nullptr; } @@ -549,7 +549,7 @@ void rom_load_manager::region_post_process(const char *rgntag, bool invert) int rom_load_manager::open_rom_file(const char *regiontag, const rom_entry *romp, std::string &tried_file_names, bool from_list) { - file_error filerr = FILERR_NOT_FOUND; + osd_file::error filerr = osd_file::error::NOT_FOUND; UINT32 romsize = rom_file_size(romp); tried_file_names = ""; @@ -656,7 +656,7 @@ int rom_load_manager::open_rom_file(const char *regiontag, const rom_entry *romp m_romsloadedsize += romsize; /* return the result */ - return (filerr == FILERR_NONE); + return (filerr == osd_file::error::NONE); } @@ -959,19 +959,19 @@ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_ { emu_file image_file(options.media_path(), OPEN_FLAG_READ); const rom_entry *region, *rom; - file_error filerr; + osd_file::error filerr; chd_error err; /* attempt to open the properly named file, scanning up through parent directories */ - filerr = FILERR_NOT_FOUND; - for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv)) + filerr = osd_file::error::NOT_FOUND; + for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != osd_file::error::NONE; searchdrv = driver_list::clone(searchdrv)) filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", romp, image_file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) filerr = common_process_file(options, nullptr, ".chd", romp, image_file); /* look for the disk in the locationtag too */ - if (filerr != FILERR_NONE && locationtag != nullptr) + if (filerr != osd_file::error::NONE && locationtag != nullptr) { // check if we are dealing with softwarelists. if so, locationtag // is actually a concatenation of: listname + setname + parentname @@ -1022,19 +1022,19 @@ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_ else { // try to load from list/setname - if ((filerr != FILERR_NONE) && (tag2.c_str() != nullptr)) + if ((filerr != osd_file::error::NONE) && (tag2.c_str() != nullptr)) filerr = common_process_file(options, tag2.c_str(), ".chd", romp, image_file); // try to load from list/parentname (if any) - if ((filerr != FILERR_NONE) && has_parent && (tag3.c_str() != nullptr)) + if ((filerr != osd_file::error::NONE) && has_parent && (tag3.c_str() != nullptr)) filerr = common_process_file(options, tag3.c_str(), ".chd", romp, image_file); // try to load from setname - if ((filerr != FILERR_NONE) && (tag4.c_str() != nullptr)) + if ((filerr != osd_file::error::NONE) && (tag4.c_str() != nullptr)) filerr = common_process_file(options, tag4.c_str(), ".chd", romp, image_file); // try to load from parentname (if any) - if ((filerr != FILERR_NONE) && has_parent && (tag5.c_str() != nullptr)) + if ((filerr != osd_file::error::NONE) && has_parent && (tag5.c_str() != nullptr)) filerr = common_process_file(options, tag5.c_str(), ".chd", romp, image_file); // only for CHD we also try to load from list/ - if ((filerr != FILERR_NONE) && (tag1.c_str() != nullptr)) + if ((filerr != osd_file::error::NONE) && (tag1.c_str() != nullptr)) { tag1.erase(tag1.length() - 1, 1); // remove the PATH_SEPARATOR filerr = common_process_file(options, tag1.c_str(), ".chd", romp, image_file); @@ -1043,7 +1043,7 @@ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_ } /* did the file open succeed? */ - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { std::string fullpath(image_file.fullpath()); image_file.close(); @@ -1073,15 +1073,15 @@ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_ romphashes == hash_collection(ROM_GETHASHDATA(rom))) { /* attempt to open the properly named file, scanning up through parent directories */ - filerr = FILERR_NOT_FOUND; - for (int searchdrv = drv; searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv)) + filerr = osd_file::error::NOT_FOUND; + for (int searchdrv = drv; searchdrv != -1 && filerr != osd_file::error::NONE; searchdrv = driver_list::clone(searchdrv)) filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", rom, image_file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) filerr = common_process_file(options, nullptr, ".chd", rom, image_file); /* did the file open succeed? */ - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { std::string fullpath(image_file.fullpath()); image_file.close(); @@ -1108,8 +1108,8 @@ chd_error rom_load_manager::open_disk_diff(emu_options &options, const rom_entry /* try to open the diff */ LOG(("Opening differencing image file: %s\n", fname.c_str())); emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE); - file_error filerr = diff_file.open(fname.c_str()); - if (filerr == FILERR_NONE) + osd_file::error filerr = diff_file.open(fname.c_str()); + if (filerr == osd_file::error::NONE) { std::string fullpath(diff_file.fullpath()); diff_file.close(); @@ -1122,7 +1122,7 @@ chd_error rom_load_manager::open_disk_diff(emu_options &options, const rom_entry LOG(("Creating differencing image: %s\n", fname.c_str())); diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); filerr = diff_file.open(fname.c_str()); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { std::string fullpath(diff_file.fullpath()); diff_file.close(); diff --git a/src/emu/romload.h b/src/emu/romload.h index c7c10e49325..fe35bfc3fe2 100644 --- a/src/emu/romload.h +++ b/src/emu/romload.h @@ -13,8 +13,8 @@ #error Dont include this file directly; include emu.h instead. #endif -#ifndef __ROMLOAD_H__ -#define __ROMLOAD_H__ +#ifndef MAME_EMU_ROMLOAD_H +#define MAME_EMU_ROMLOAD_H #include "chd.h" @@ -350,7 +350,7 @@ private: /* ----- Helpers ----- */ -std::unique_ptr<emu_file> common_process_file(emu_options &options, const char *location, bool has_crc, UINT32 crc, const rom_entry *romp, file_error &filerr); +std::unique_ptr<emu_file> common_process_file(emu_options &options, const char *location, bool has_crc, UINT32 crc, const rom_entry *romp, osd_file::error &filerr); /* return pointer to the first ROM region within a source */ const rom_entry *rom_first_region(const device_t &device); @@ -386,4 +386,4 @@ std::string rom_parameter_value(const rom_entry *romp); /* open a disk image, searching up the parent and loading by checksum */ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, chd_file &image_chd, const char *locationtag); -#endif /* __ROMLOAD_H__ */ +#endif // MAME_EMU_ROMLOAD_H diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp index c286788ea37..111a1b3232a 100644 --- a/src/emu/screen.cpp +++ b/src/emu/screen.cpp @@ -1153,8 +1153,8 @@ void screen_device::finalize_burnin() // compute the name and create the file emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(machine().basename(), PATH_SEPARATOR "burnin-", this->tag()+1, ".png") ; - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(machine().basename(), PATH_SEPARATOR "burnin-", this->tag()+1, ".png") ; + if (filerr == osd_file::error::NONE) { png_info pnginfo = { nullptr }; // png_error pngerr; diff --git a/src/emu/softlist.cpp b/src/emu/softlist.cpp index 05e9c761719..d554b394c21 100644 --- a/src/emu/softlist.cpp +++ b/src/emu/softlist.cpp @@ -478,8 +478,8 @@ void software_list_device::parse() m_errors.clear(); // attempt to open the file - file_error filerr = m_file.open(m_list_name.c_str(), ".xml"); - if (filerr == FILERR_NONE) + osd_file::error filerr = m_file.open(m_list_name.c_str(), ".xml"); + if (filerr == osd_file::error::NONE) { // parse if no error std::ostringstream errs; diff --git a/src/emu/ui/auditmenu.cpp b/src/emu/ui/auditmenu.cpp index 68b3c2d285b..c30619be3a9 100644 --- a/src/emu/ui/auditmenu.cpp +++ b/src/emu/ui/auditmenu.cpp @@ -174,7 +174,7 @@ void ui_menu_audit::save_available_machines() { // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(emulator_info::get_configname(), "_avail.ini") == FILERR_NONE) + if (file.open(emulator_info::get_configname(), "_avail.ini") == osd_file::error::NONE) { // generate header std::ostringstream buffer; diff --git a/src/emu/ui/cmdrender.h b/src/emu/ui/cmdrender.h index d9bf466f1e9..01cc169816d 100644 --- a/src/emu/ui/cmdrender.h +++ b/src/emu/ui/cmdrender.h @@ -87,7 +87,7 @@ void render_font::render_font_command_glyph() { emu_file ramfile(OPEN_FLAG_READ); - if (ramfile.open_ram(font_uicmd14, sizeof(font_uicmd14)) == FILERR_NONE) + if (ramfile.open_ram(font_uicmd14, sizeof(font_uicmd14)) == osd_file::error::NONE) load_cached_cmd(ramfile, 0); } diff --git a/src/emu/ui/custmenu.cpp b/src/emu/ui/custmenu.cpp index 2d6083536db..85df4afcd8a 100644 --- a/src/emu/ui/custmenu.cpp +++ b/src/emu/ui/custmenu.cpp @@ -239,7 +239,7 @@ void ui_menu_custom_filter::save_custom_filters() { // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == FILERR_NONE) + if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE) { // generate custom filters info std::ostringstream cinfo; @@ -552,7 +552,7 @@ void ui_menu_swcustom_filter::save_sw_custom_filters() { // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open("custom_", m_driver->name, "_filter.ini") == FILERR_NONE) + if (file.open("custom_", m_driver->name, "_filter.ini") == osd_file::error::NONE) { // generate custom filters info std::ostringstream cinfo; diff --git a/src/emu/ui/datfile.cpp b/src/emu/ui/datfile.cpp index 7a5ebb57e6f..35dfde7249d 100644 --- a/src/emu/ui/datfile.cpp +++ b/src/emu/ui/datfile.cpp @@ -548,7 +548,7 @@ bool datfile_manager::parseopen(const char *filename) // so it's better and faster use standard C fileio functions. emu_file file(machine().ui().options().history_path(), OPEN_FLAG_READ); - if (file.open(filename) != FILERR_NONE) + if (file.open(filename) != osd_file::error::NONE) return false; m_fullpath = file.fullpath(); diff --git a/src/emu/ui/dirmenu.cpp b/src/emu/ui/dirmenu.cpp index 8ae0372af30..03260a337d9 100644 --- a/src/emu/ui/dirmenu.cpp +++ b/src/emu/ui/dirmenu.cpp @@ -28,33 +28,33 @@ struct folders_entry static const folders_entry s_folders[] = { - { __("ROMs"), OPTION_MEDIAPATH, ADDING }, - { __("UI"), OPTION_UI_PATH, CHANGE }, - { __("Language"), OPTION_LANGUAGEPATH, CHANGE }, - { __("Samples"), OPTION_SAMPLEPATH, ADDING }, - { __("DATs"), OPTION_HISTORY_PATH, ADDING }, - { __("INIs"), OPTION_INIPATH, ADDING }, - { __("Extra INIs"), OPTION_EXTRAINI_PATH, CHANGE }, - { __("Icons"), OPTION_ICONS_PATH, ADDING }, - { __("Cheats"), OPTION_CHEATPATH, ADDING }, - { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY, ADDING }, - { __("Cabinets"), OPTION_CABINETS_PATH, ADDING }, - { __("Flyers"), OPTION_FLYERS_PATH, ADDING }, - { __("Titles"), OPTION_TITLES_PATH, ADDING }, - { __("Ends"), OPTION_ENDS_PATH, ADDING }, - { __("PCBs"), OPTION_PCBS_PATH, ADDING }, - { __("Marquees"), OPTION_MARQUEES_PATH, ADDING }, - { __("Controls Panels"), OPTION_CPANELS_PATH, ADDING }, - { __("Crosshairs"), OPTION_CROSSHAIRPATH, ADDING }, - { __("Artworks"), OPTION_ARTPATH, ADDING }, - { __("Bosses"), OPTION_BOSSES_PATH, ADDING }, - { __("Artworks Preview"), OPTION_ARTPREV_PATH, ADDING }, - { __("Select"), OPTION_SELECT_PATH, ADDING }, - { __("GameOver"), OPTION_GAMEOVER_PATH, ADDING }, - { __("HowTo"), OPTION_HOWTO_PATH, ADDING }, - { __("Logos"), OPTION_LOGOS_PATH, ADDING }, - { __("Scores"), OPTION_SCORES_PATH, ADDING }, - { __("Versus"), OPTION_VERSUS_PATH, ADDING }, + { __("ROMs"), OPTION_MEDIAPATH, ADDING }, + { __("UI"), OPTION_UI_PATH, CHANGE }, + { __("Language"), OPTION_LANGUAGEPATH, CHANGE }, + { __("Samples"), OPTION_SAMPLEPATH, ADDING }, + { __("DATs"), OPTION_HISTORY_PATH, ADDING }, + { __("INIs"), OPTION_INIPATH, ADDING }, + { __("Extra INIs"), OPTION_EXTRAINI_PATH, CHANGE }, + { __("Icons"), OPTION_ICONS_PATH, ADDING }, + { __("Cheats"), OPTION_CHEATPATH, ADDING }, + { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY, ADDING }, + { __("Cabinets"), OPTION_CABINETS_PATH, ADDING }, + { __("Flyers"), OPTION_FLYERS_PATH, ADDING }, + { __("Titles"), OPTION_TITLES_PATH, ADDING }, + { __("Ends"), OPTION_ENDS_PATH, ADDING }, + { __("PCBs"), OPTION_PCBS_PATH, ADDING }, + { __("Marquees"), OPTION_MARQUEES_PATH, ADDING }, + { __("Controls Panels"), OPTION_CPANELS_PATH, ADDING }, + { __("Crosshairs"), OPTION_CROSSHAIRPATH, ADDING }, + { __("Artworks"), OPTION_ARTPATH, ADDING }, + { __("Bosses"), OPTION_BOSSES_PATH, ADDING }, + { __("Artworks Preview"), OPTION_ARTPREV_PATH, ADDING }, + { __("Select"), OPTION_SELECT_PATH, ADDING }, + { __("GameOver"), OPTION_GAMEOVER_PATH, ADDING }, + { __("HowTo"), OPTION_HOWTO_PATH, ADDING }, + { __("Logos"), OPTION_LOGOS_PATH, ADDING }, + { __("Scores"), OPTION_SCORES_PATH, ADDING }, + { __("Versus"), OPTION_VERSUS_PATH, ADDING }, }; @@ -95,7 +95,6 @@ void ui_menu_directory::handle() void ui_menu_directory::populate() { - for (auto & elem : s_folders) item_append(_(elem.name), nullptr, 0, (void *)(FPTR)elem.action); @@ -144,7 +143,7 @@ void ui_menu_directory::custom_render(void *selectedref, float top, float bottom // ctor / dtor //------------------------------------------------- -ui_menu_display_actual::ui_menu_display_actual(running_machine &machine, render_container *container, int ref) +ui_menu_display_actual::ui_menu_display_actual(running_machine &machine, render_container *container, int ref) : ui_menu(machine, container), m_ref(ref) { } @@ -181,9 +180,9 @@ void ui_menu_display_actual::handle() void ui_menu_display_actual::populate() { m_tempbuf = string_format(_("Current %1$s Folders"), _(s_folders[m_ref].name)); - if (machine().ui().options().exists(s_folders[m_ref].option)) + if (machine().ui().options().exists(s_folders[m_ref].option)) m_searchpath.assign(machine().ui().options().value(s_folders[m_ref].option)); - else + else m_searchpath.assign(machine().options().value(s_folders[m_ref].option)); path_iterator path(m_searchpath.c_str()); @@ -238,7 +237,7 @@ void ui_menu_display_actual::custom_render(void *selectedref, float top, float b y1 += UI_BOX_TB_BORDER; // draw the text within it - mui.draw_text_full(container, m_tempbuf.c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE, + mui.draw_text_full(container, m_tempbuf.c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); // compute our bounds @@ -279,10 +278,7 @@ ui_menu_add_change_folder::ui_menu_add_change_folder(running_machine &machine, r m_search[0] = '\0'; // configure the starting path - char *dst = nullptr; - osd_get_full_path(&dst, "."); - m_current_path = dst; - osd_free(dst); + osd_get_full_path(m_current_path, "."); std::string searchpath; if (machine.ui().options().exists(s_folders[m_ref].option)) @@ -571,9 +567,9 @@ void ui_menu_add_change_folder::custom_render(void *selectedref, float top, floa ui_menu_remove_folder::ui_menu_remove_folder(running_machine &machine, render_container *container, int ref) : ui_menu(machine, container) { m_ref = ref; - if (machine.ui().options().exists(s_folders[m_ref].option)) + if (machine.ui().options().exists(s_folders[m_ref].option)) m_searchpath.assign(machine.ui().options().value(s_folders[m_ref].option)); - else + else m_searchpath.assign(machine.options().value(s_folders[m_ref].option)); path_iterator path(m_searchpath.c_str()); @@ -609,7 +605,7 @@ void ui_menu_remove_folder::handle() machine().ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); else if (strcmp(machine().options().value(s_folders[m_ref].option),tmppath.c_str())!=0) { - machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); machine().options().mark_changed(s_folders[m_ref].option); } @@ -662,6 +658,6 @@ void ui_menu_remove_folder::custom_render(void *selectedref, float top, float bo y1 += UI_BOX_TB_BORDER; // draw the text within it - mui.draw_text_full(container, tempbuf.c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER, DRAW_NORMAL, + mui.draw_text_full(container, tempbuf.c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); } diff --git a/src/emu/ui/filesel.cpp b/src/emu/ui/filesel.cpp index ec8d4c2ea22..89658407279 100644 --- a/src/emu/ui/filesel.cpp +++ b/src/emu/ui/filesel.cpp @@ -536,7 +536,7 @@ void ui_menu_file_selector::append_entry_menu_item(const file_selector_entry *en void ui_menu_file_selector::populate() { zippath_directory *directory = nullptr; - file_error err; + osd_file::error err; const osd_directory_entry *dirent; const file_selector_entry *entry; const file_selector_entry *selected_entry = nullptr; @@ -579,7 +579,7 @@ void ui_menu_file_selector::populate() } // build the menu for each item - if (err == FILERR_NONE) + if (err == osd_file::error::NONE) { while((dirent = zippath_readdir(directory)) != nullptr) { @@ -621,7 +621,7 @@ void ui_menu_file_selector::populate() void ui_menu_file_selector::handle() { - file_error err; + osd_file::error err; const file_selector_entry *entry; const file_selector_entry *selected_entry = nullptr; int bestmatch = 0; @@ -657,7 +657,7 @@ void ui_menu_file_selector::handle() case SELECTOR_ENTRY_TYPE_DIRECTORY: // drive/directory - first check the path err = zippath_opendir(entry->fullpath, nullptr); - if (err != FILERR_NONE) + if (err != osd_file::error::NONE) { // this path is problematic; present the user with an error and bail machine().ui().popup_time(1, "Error accessing %s", entry->fullpath); diff --git a/src/emu/ui/icorender.h b/src/emu/ui/icorender.h index eec52b7e3ed..79452bd9fca 100644 --- a/src/emu/ui/icorender.h +++ b/src/emu/ui/icorender.h @@ -80,9 +80,9 @@ void render_load_ico(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, else fname.assign(dirname).append(PATH_SEPARATOR).append(filename); - file_error filerr = file.open(fname.c_str()); + osd_file::error filerr = file.open(fname.c_str()); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) return; // allocates a buffer for the image diff --git a/src/emu/ui/imgcntrl.cpp b/src/emu/ui/imgcntrl.cpp index 3b96f63971e..f0b6f3da5b4 100644 --- a/src/emu/ui/imgcntrl.cpp +++ b/src/emu/ui/imgcntrl.cpp @@ -64,7 +64,7 @@ ui_menu_control_device_image::ui_menu_control_device_image(running_machine &mach current_directory.assign(image->working_directory()); /* check to see if the path exists; if not clear it */ - if (zippath_opendir(current_directory.c_str(), nullptr) != FILERR_NONE) + if (zippath_opendir(current_directory.c_str(), nullptr) != osd_file::error::NONE) current_directory.clear(); } } @@ -184,8 +184,8 @@ void ui_menu_control_device_image::handle() bool can_create = false; if(image->is_creatable()) { zippath_directory *directory = nullptr; - file_error err = zippath_opendir(current_directory.c_str(), &directory); - can_create = err == FILERR_NONE && !zippath_is_zip(directory); + osd_file::error err = zippath_opendir(current_directory.c_str(), &directory); + can_create = err == osd_file::error::NONE && !zippath_is_zip(directory); if(directory) zippath_closedir(directory); } diff --git a/src/emu/ui/inifile.cpp b/src/emu/ui/inifile.cpp index 8958fe4cd3b..ac669e03d40 100644 --- a/src/emu/ui/inifile.cpp +++ b/src/emu/ui/inifile.cpp @@ -151,7 +151,7 @@ bool inifile_manager::parseopen(const char *filename) // so it's better and faster use standard C fileio functions. emu_file file(machine().ui().options().extraini_path(), OPEN_FLAG_READ); - if (file.open(filename) != FILERR_NONE) + if (file.open(filename) != osd_file::error::NONE) return false; m_fullpath = file.fullpath(); @@ -359,7 +359,7 @@ bool favorite_manager::isgame_favorite(ui_software_info &swinfo) void favorite_manager::parse_favorite() { emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_READ); - if (file.open(favorite_filename) == FILERR_NONE) + if (file.open(favorite_filename) == osd_file::error::NONE) { char readbuf[1024]; file.gets(readbuf, 1024); @@ -418,7 +418,7 @@ void favorite_manager::save_favorite_games() { // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(favorite_filename) == FILERR_NONE) + if (file.open(favorite_filename) == osd_file::error::NONE) { if (m_list.empty()) { diff --git a/src/emu/ui/miscmenu.cpp b/src/emu/ui/miscmenu.cpp index 2145069bfab..e11a416e01d 100644 --- a/src/emu/ui/miscmenu.cpp +++ b/src/emu/ui/miscmenu.cpp @@ -588,7 +588,7 @@ ui_menu_misc_options::~ui_menu_misc_options() { machine().ui().options().set_value(m_options[d].option, m_options[d].status, OPTION_PRIORITY_CMDLINE, error_string); } - else + else { if (machine().options().bool_value(m_options[d].option) != m_options[d].status) { @@ -677,7 +677,7 @@ void ui_menu_misc_options::custom_render(void *selectedref, float top, float bot // ctor / dtor //------------------------------------------------- -ui_menu_export::ui_menu_export(running_machine &machine, render_container *container, std::vector<const game_driver *> drvlist) +ui_menu_export::ui_menu_export(running_machine &machine, render_container *container, std::vector<const game_driver *> drvlist) : ui_menu(machine, container), m_list(drvlist) { } @@ -705,11 +705,11 @@ void ui_menu_export::handle() { std::string filename("exported"); emu_file infile(machine().ui().options().ui_path(), OPEN_FLAG_READ); - if (infile.open(filename.c_str(), ".xml") == FILERR_NONE) + if (infile.open(filename.c_str(), ".xml") == osd_file::error::NONE) for (int seq = 0; ; ++seq) { std::string seqtext = string_format("%s_%04d", filename, seq); - if (infile.open(seqtext.c_str(), ".xml") != FILERR_NONE) + if (infile.open(seqtext.c_str(), ".xml") != osd_file::error::NONE) { filename = seqtext; break; @@ -718,7 +718,7 @@ void ui_menu_export::handle() // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(filename.c_str(), ".xml") == FILERR_NONE) + if (file.open(filename.c_str(), ".xml") == osd_file::error::NONE) { FILE *pfile; std::string fullpath(file.fullpath()); @@ -745,11 +745,11 @@ void ui_menu_export::handle() { std::string filename("exported"); emu_file infile(machine().ui().options().ui_path(), OPEN_FLAG_READ); - if (infile.open(filename.c_str(), ".txt") == FILERR_NONE) + if (infile.open(filename.c_str(), ".txt") == osd_file::error::NONE) for (int seq = 0; ; ++seq) { std::string seqtext = string_format("%s_%04d", filename, seq); - if (infile.open(seqtext.c_str(), ".txt") != FILERR_NONE) + if (infile.open(seqtext.c_str(), ".txt") != osd_file::error::NONE) { filename = seqtext; break; @@ -758,7 +758,7 @@ void ui_menu_export::handle() // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(filename.c_str(), ".txt") == FILERR_NONE) + if (file.open(filename.c_str(), ".txt") == osd_file::error::NONE) { // print the header std::ostringstream buffer; @@ -829,8 +829,8 @@ void ui_menu_machine_configure::handle() { std::string filename(m_drv->name); emu_file file(machine().options().ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - file_error filerr = file.open(filename.c_str(), ".ini"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(filename.c_str(), ".ini"); + if (filerr == osd_file::error::NONE) { std::string inistring = machine().options().output_ini(); file.puts(inistring.c_str()); @@ -889,4 +889,4 @@ void ui_menu_machine_configure::custom_render(void *selectedref, float top, floa // draw the text within it mui.draw_text_full(container, m_drv->description, x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); -}
\ No newline at end of file +} diff --git a/src/emu/ui/optsmenu.cpp b/src/emu/ui/optsmenu.cpp index f93bdbf4652..c80ad0ad00e 100644 --- a/src/emu/ui/optsmenu.cpp +++ b/src/emu/ui/optsmenu.cpp @@ -314,7 +314,7 @@ void save_ui_options(running_machine &machine) { // attempt to open the output file emu_file file(machine.options().ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open("ui.ini") == FILERR_NONE) + if (file.open("ui.ini") == osd_file::error::NONE) { // generate the updated INI std::string initext = machine.ui().options().output_ini(); @@ -339,7 +339,7 @@ void save_main_option(running_machine &machine) // attempt to open the main ini file { emu_file file(machine.options().ini_path(), OPEN_FLAG_READ); - if (file.open(emulator_info::get_configname(), ".ini") == FILERR_NONE) + if (file.open(emulator_info::get_configname(), ".ini") == osd_file::error::NONE) { bool result = options.parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_DRIVER_INI, error); if (!result) @@ -361,7 +361,7 @@ void save_main_option(running_machine &machine) // attempt to open the output file { emu_file file(machine.options().ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(emulator_info::get_configname(), ".ini") == FILERR_NONE) + if (file.open(emulator_info::get_configname(), ".ini") == osd_file::error::NONE) { // generate the updated INI std::string initext = options.output_ini(); @@ -375,4 +375,3 @@ void save_main_option(running_machine &machine) } machine.ui().popup_time(3, "%s", _("\n Configuration saved \n\n")); } - diff --git a/src/emu/ui/selgame.cpp b/src/emu/ui/selgame.cpp index d0beab50bcc..023ca72b470 100644 --- a/src/emu/ui/selgame.cpp +++ b/src/emu/ui/selgame.cpp @@ -34,13 +34,13 @@ extern const char UI_VERSION_TAG[]; static bool first_start = true; -static const char *dats_info[] = { - __("General Info"), - __("History"), - __("Mameinfo"), - __("Sysinfo"), - __("Messinfo"), - __("Command"), +static const char *dats_info[] = { + __("General Info"), + __("History"), + __("Mameinfo"), + __("Sysinfo"), + __("Messinfo"), + __("Command"), __("Mamescore") }; std::vector<const game_driver *> ui_menu_select_game::m_sortedlist; @@ -505,7 +505,7 @@ void ui_menu_select_game::handle() // if we're in an error state, overlay an error message if (ui_error) - machine().ui().draw_text_box(container, _("The selected machine is missing one or more required ROM or CHD images. " + machine().ui().draw_text_box(container, _("The selected machine is missing one or more required ROM or CHD images. " "Please select a different machine.\n\nPress any key (except ESC) to continue."), JUSTIFY_CENTER, 0.5f, 0.5f, UI_RED_COLOR); // handle filters selection from key shortcuts @@ -839,7 +839,7 @@ void ui_menu_select_game::custom_render(void *selectedref, float top, float bott for (int line = 0; line < 2; ++line) { mui.draw_text_full(container, tempbuf[line].c_str(), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_NEVER, - DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); + DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); width += 2 * UI_BOX_LR_BORDER; maxwidth = MAX(width, maxwidth); } @@ -861,7 +861,7 @@ void ui_menu_select_game::custom_render(void *selectedref, float top, float bott // draw the text within it for (int line = 0; line < 2; ++line) { - mui.draw_text_full(container, tempbuf[line].c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER, + mui.draw_text_full(container, tempbuf[line].c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); y1 += mui.get_line_height(); } @@ -918,7 +918,7 @@ void ui_menu_select_game::custom_render(void *selectedref, float top, float bott color = UI_GREEN_COLOR; if ((driver->flags & (MACHINE_IMPERFECT_GRAPHICS | MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_COLORS - | MACHINE_NO_SOUND | MACHINE_IMPERFECT_SOUND)) != 0) + | MACHINE_NO_SOUND | MACHINE_IMPERFECT_SOUND)) != 0) color = UI_YELLOW_COLOR; if ((driver->flags & (MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION)) != 0) @@ -986,7 +986,7 @@ void ui_menu_select_game::custom_render(void *selectedref, float top, float bott for (auto & elem : tempbuf) { - mui.draw_text_full(container, elem.c_str(), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_NEVER, + mui.draw_text_full(container, elem.c_str(), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_NEVER, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); width += 2 * UI_BOX_LR_BORDER; maxwidth = MAX(maxwidth, width); @@ -1549,7 +1549,7 @@ void ui_menu_select_game::populate_search() if (cx != -1 && ((driver_list::driver(cx).flags & MACHINE_IS_BIOS_ROOT) != 0)) cloneof = false; } - item_append(m_searchlist[curitem]->description, nullptr, (!cloneof) ? flags_ui : (MENU_FLAG_INVERT | flags_ui), + item_append(m_searchlist[curitem]->description, nullptr, (!cloneof) ? flags_ui : (MENU_FLAG_INVERT | flags_ui), (void *)m_searchlist[curitem]); } } @@ -1694,7 +1694,7 @@ bool ui_menu_select_game::load_available_machines() { // try to load available drivers from file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_READ); - if (file.open(emulator_info::get_configname(), "_avail.ini") != FILERR_NONE) + if (file.open(emulator_info::get_configname(), "_avail.ini") != osd_file::error::NONE) return false; std::string readbuf; @@ -1746,7 +1746,7 @@ void ui_menu_select_game::load_custom_filters() { // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_READ); - if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == FILERR_NONE) + if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE) { char buffer[MAX_CHAR_INFO]; @@ -1902,7 +1902,7 @@ float ui_menu_select_game::draw_left_panel(float x1, float y1, float x2, float y convert_command_glyph(str); } - mui.draw_text_full(container, str.c_str(), x1t, y1, x2 - x1, JUSTIFY_LEFT, WRAP_NEVER, + mui.draw_text_full(container, str.c_str(), x1t, y1, x2 - x1, JUSTIFY_LEFT, WRAP_NEVER, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); y1 += line_height_max; } @@ -2006,14 +2006,14 @@ void ui_menu_select_game::infos_render(void *selectedref, float origx1, float or // apply title to right panel float title_size = 0.0f; - float txt_lenght = 0.0f; + float txt_length = 0.0f; for (int x = UI_FIRST_LOAD; x < UI_LAST_LOAD; ++x) { mui.draw_text_full(container, _(dats_info[x]), origx1, origy1, origx2 - origx1, JUSTIFY_CENTER, - WRAP_NEVER, DRAW_NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_lenght, nullptr); - txt_lenght += 0.01f; - title_size = MAX(txt_lenght, title_size); + WRAP_NEVER, DRAW_NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_length, nullptr); + txt_length += 0.01f; + title_size = (std::max)(txt_length, title_size); } rgb_t fgcolor = UI_TEXT_COLOR; @@ -2072,7 +2072,7 @@ void ui_menu_select_game::infos_render(void *selectedref, float origx1, float or if (buffer.empty()) { - mui.draw_text_full(container, _("No Infos Available"), origx1, (origy2 + origy1) * 0.5f, origx2 - origx1, JUSTIFY_CENTER, + mui.draw_text_full(container, _("No Infos Available"), origx1, (origy2 + origy1) * 0.5f, origx2 - origx1, JUSTIFY_CENTER, WRAP_WORD, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); return; } @@ -2126,7 +2126,7 @@ void ui_menu_select_game::infos_render(void *selectedref, float origx1, float or JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &item_width, nullptr, tmp_size); mui.draw_text_full(container, last_part.c_str(), effective_left + item_width, oy1, - origx2 - origx1 - 2.0f * gutter_width - item_width, JUSTIFY_RIGHT, WRAP_TRUNCATE, + origx2 - origx1 - 2.0f * gutter_width - item_width, JUSTIFY_RIGHT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size); } } @@ -2146,18 +2146,18 @@ void ui_menu_select_game::infos_render(void *selectedref, float origx1, float or std::string first_part(tempbuf.substr(0, first_dspace)); std::string last_part(tempbuf.substr(first_dspace + 1)); strtrimspace(last_part); - mui.draw_text_full(container, first_part.c_str(), effective_left, oy1, effective_width, JUSTIFY_LEFT, + mui.draw_text_full(container, first_part.c_str(), effective_left, oy1, effective_width, JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size); - mui.draw_text_full(container, last_part.c_str(), effective_left, oy1, origx2 - origx1 - 2.0f * gutter_width, + mui.draw_text_full(container, last_part.c_str(), effective_left, oy1, origx2 - origx1 - 2.0f * gutter_width, JUSTIFY_RIGHT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size); } else - mui.draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, JUSTIFY_LEFT, + mui.draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, tmp_size); } else - mui.draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, JUSTIFY_LEFT, + mui.draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, text_size); oy1 += (line_height * text_size); @@ -2182,17 +2182,17 @@ void ui_menu_select_game::infos_render(void *selectedref, float origx1, float or else { float title_size = 0.0f; - float txt_lenght = 0.0f; + float txt_length = 0.0f; std::string t_text[2]; t_text[0] = _("History"); t_text[1] = _("Usage"); for (auto & elem: t_text) { - mui.draw_text_full(container, elem.c_str(), origx1, origy1, origx2 - origx1, JUSTIFY_CENTER, WRAP_TRUNCATE, - DRAW_NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_lenght, nullptr); - txt_lenght += 0.01f; - title_size = MAX(txt_lenght, title_size); + mui.draw_text_full(container, elem.c_str(), origx1, origy1, origx2 - origx1, JUSTIFY_CENTER, WRAP_TRUNCATE, + DRAW_NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_length, nullptr); + txt_length += 0.01f; + title_size = (std::max)(txt_length, title_size); } rgb_t fgcolor = UI_TEXT_COLOR; @@ -2260,7 +2260,7 @@ void ui_menu_select_game::infos_render(void *selectedref, float origx1, float or else if (r == r_visible_lines - 1 && itemline != totallines - 1) info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); else - mui.draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, JUSTIFY_LEFT, + mui.draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr, text_size); oy1 += (line_height * text_size); } diff --git a/src/emu/ui/selsoft.cpp b/src/emu/ui/selsoft.cpp index 19a24dc8c20..0b8078b5f2f 100644 --- a/src/emu/ui/selsoft.cpp +++ b/src/emu/ui/selsoft.cpp @@ -29,9 +29,9 @@ std::string reselect_last::software; std::string reselect_last::swlist; bool reselect_last::m_reselect = false; static const char *region_lists[] = { "arab", "arg", "asia", "aus", "aut", "bel", "blr", "bra", "can", "chi", "chn", "cze", "den", - "ecu", "esp", "euro", "fin", "fra", "gbr", "ger", "gre", "hkg", "hun", "irl", "isr", - "isv", "ita", "jpn", "kaz", "kor", "lat", "lux", "mex", "ned", "nld", "nor", "nzl", - "pol", "rus", "slo", "spa", "sui", "swe", "tha", "tpe", "tw", "uk", "ukr", "usa" }; + "ecu", "esp", "euro", "fin", "fra", "gbr", "ger", "gre", "hkg", "hun", "irl", "isr", + "isv", "ita", "jpn", "kaz", "kor", "lat", "lux", "mex", "ned", "nld", "nor", "nzl", + "pol", "rus", "slo", "spa", "sui", "swe", "tha", "tpe", "tw", "uk", "ukr", "usa" }; //------------------------------------------------- // compares two items in the software list and @@ -303,7 +303,6 @@ void ui_menu_select_software::handle() if (m_event != nullptr && m_event->itemref == nullptr) { - if (m_event->iptkey == IPT_UI_CONFIGURE) inkey_configure(m_event); @@ -488,7 +487,7 @@ void ui_menu_select_software::populate() old_software = m_has_empty_start ? curitem + 1 : curitem; item_append(m_displaylist[curitem]->longname.c_str(), m_displaylist[curitem]->devicetype.c_str(), - m_displaylist[curitem]->parentname.empty() ? flags_ui : (MENU_FLAG_INVERT | flags_ui), (void *)m_displaylist[curitem]); + m_displaylist[curitem]->parentname.empty() ? flags_ui : (MENU_FLAG_INVERT | flags_ui), (void *)m_displaylist[curitem]); } } @@ -498,8 +497,8 @@ void ui_menu_select_software::populate() for (int curitem = 0; m_searchlist[curitem] != nullptr; ++curitem) item_append(m_searchlist[curitem]->longname.c_str(), m_searchlist[curitem]->devicetype.c_str(), - m_searchlist[curitem]->parentname.empty() ? flags_ui : (MENU_FLAG_INVERT | flags_ui), - (void *)m_searchlist[curitem]); + m_searchlist[curitem]->parentname.empty() ? flags_ui : (MENU_FLAG_INVERT | flags_ui), + (void *)m_searchlist[curitem]); } item_append(MENU_SEPARATOR_ITEM, nullptr, flags_ui, nullptr); @@ -700,7 +699,7 @@ void ui_menu_select_software::custom_render(void *selectedref, float top, float for (int line = 0; line < 3; ++line) { mui.draw_text_full(container, tempbuf[line].c_str(), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_NEVER, - DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); + DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); width += 2 * UI_BOX_LR_BORDER; maxwidth = MAX(width, maxwidth); } @@ -723,7 +722,7 @@ void ui_menu_select_software::custom_render(void *selectedref, float top, float for (int line = 0; line < 3; ++line) { mui.draw_text_full(container, tempbuf[line].c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER, - DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); + DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); y1 += mui.get_line_height(); } @@ -845,7 +844,7 @@ void ui_menu_select_software::custom_render(void *selectedref, float top, float for (auto & elem : tempbuf) { mui.draw_text_full(container, elem.c_str(), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_NEVER, - DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); + DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); width += 2 * UI_BOX_LR_BORDER; maxwidth = MAX(maxwidth, width); } @@ -872,7 +871,7 @@ void ui_menu_select_software::custom_render(void *selectedref, float top, float for (auto & elem : tempbuf) { mui.draw_text_full(container, elem.c_str(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER, - DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); + DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); y1 += machine().ui().get_line_height(); } } @@ -1049,7 +1048,7 @@ void ui_menu_select_software::load_sw_custom_filters() { // attempt to open the output file emu_file file(machine().ui().options().ui_path(), OPEN_FLAG_READ); - if (file.open("custom_", m_driver->name, "_filter.ini") == FILERR_NONE) + if (file.open("custom_", m_driver->name, "_filter.ini") == osd_file::error::NONE) { char buffer[MAX_CHAR_INFO]; @@ -1479,7 +1478,7 @@ float ui_menu_select_software::draw_left_panel(float x1, float y1, float x2, flo } mui.draw_text_full(container, str.c_str(), x1t, y1, x2 - x1, JUSTIFY_LEFT, WRAP_NEVER, - DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); + DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); y1 += line_height; } @@ -1979,7 +1978,7 @@ void ui_software_parts::custom_render(void *selectedref, float top, float bottom float width; ui_manager &mui = machine().ui(); mui.draw_text_full(container, _("Software part selection:"), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE, - DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); + DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); width += 2 * UI_BOX_LR_BORDER; float maxwidth = MAX(origx2 - origx1, width); @@ -1999,7 +1998,7 @@ void ui_software_parts::custom_render(void *selectedref, float top, float bottom // draw the text within it mui.draw_text_full(container, _("Software part selection:"), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE, - DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); + DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); } //------------------------------------------------- @@ -2117,7 +2116,7 @@ void ui_bios_selection::custom_render(void *selectedref, float top, float bottom float width; ui_manager &mui = machine().ui(); mui.draw_text_full(container, _("Bios selection:"), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE, - DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); + DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr); width += 2 * UI_BOX_LR_BORDER; float maxwidth = MAX(origx2 - origx1, width); @@ -2137,5 +2136,5 @@ void ui_bios_selection::custom_render(void *selectedref, float top, float bottom // draw the text within it mui.draw_text_full(container, _("Bios selection:"), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE, - DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); + DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr); } diff --git a/src/emu/ui/ui.cpp b/src/emu/ui/ui.cpp index 839e7c2d7a2..a265e74c7b1 100644 --- a/src/emu/ui/ui.cpp +++ b/src/emu/ui/ui.cpp @@ -169,7 +169,7 @@ static void load_ui_options(running_machine &machine) std::string error; // attempt to open the output file emu_file file(machine.options().ini_path(), OPEN_FLAG_READ); - if (file.open("ui.ini") == FILERR_NONE) + if (file.open("ui.ini") == osd_file::error::NONE) { bool result = machine.ui().options().parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_DRIVER_INI, error); if (!result) diff --git a/src/emu/ui/utils.h b/src/emu/ui/utils.h index a2f24a20479..5c1485e102b 100644 --- a/src/emu/ui/utils.h +++ b/src/emu/ui/utils.h @@ -271,9 +271,9 @@ void render_load_jpeg(_T &bitmap, emu_file &file, const char *dirname, const cha else fname.assign(dirname).append(PATH_SEPARATOR).append(filename); - file_error filerr = file.open(fname.c_str()); + osd_file::error filerr = file.open(fname.c_str()); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) return; // define standard JPEG structures diff --git a/src/emu/video.cpp b/src/emu/video.cpp index 229553a92b8..c3090bc6096 100644 --- a/src/emu/video.cpp +++ b/src/emu/video.cpp @@ -350,8 +350,8 @@ void video_manager::save_active_screen_snapshots() if (machine().render().is_live(*screen)) { emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = open_next(file, "png"); - if (filerr == FILERR_NONE) + osd_file::error filerr = open_next(file, "png"); + if (filerr == osd_file::error::NONE) save_snapshot(screen, file); } } @@ -360,8 +360,8 @@ void video_manager::save_active_screen_snapshots() else { emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = open_next(file, "png"); - if (filerr == FILERR_NONE) + osd_file::error filerr = open_next(file, "png"); + if (filerr == osd_file::error::NONE) save_snapshot(nullptr, file); } } @@ -428,7 +428,7 @@ void video_manager::begin_recording(const char *name, movie_format format) // build up information about this new movie screen_device *screen = machine().first_screen(); - avi_movie_info info; + avi_file::movie_info info; info.video_format = 0; info.video_timescale = 1000 * ((screen != nullptr) ? ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds()) : screen_device::DEFAULT_FRAME_RATE); info.video_sampletime = 1000; @@ -446,7 +446,7 @@ void video_manager::begin_recording(const char *name, movie_format format) info.audio_samplerate = machine().sample_rate(); // create a new temporary movie file - file_error filerr; + osd_file::error filerr; std::string fullpath; { emu_file tempfile(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); @@ -456,20 +456,20 @@ void video_manager::begin_recording(const char *name, movie_format format) filerr = open_next(tempfile, "avi"); // if we succeeded, make a copy of the name and create the real file over top - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) fullpath = tempfile.fullpath(); } - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { // compute the frame time m_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale; // create the file and free the string - avi_error avierr = avi_create(fullpath.c_str(), &info, &m_avi_file); - if (avierr != AVIERR_NONE) + avi_file::error avierr = avi_file::create(fullpath, info, m_avi_file); + if (avierr != avi_file::error::NONE) { - osd_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); + osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr)); return end_recording(format); } } @@ -487,13 +487,13 @@ void video_manager::begin_recording(const char *name, movie_format format) // create a new movie file and start recording m_mng_file = std::make_unique<emu_file>(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr; + osd_file::error filerr; if (name != nullptr) filerr = m_mng_file->open(name); else filerr = open_next(*m_mng_file, "mng"); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { // start the capture screen_device *screen = machine().first_screen(); @@ -510,7 +510,7 @@ void video_manager::begin_recording(const char *name, movie_format format) } else { - osd_printf_error("Error creating MNG, file_error=%d\n", filerr); + osd_printf_error("Error creating MNG, osd_file::error=%d\n", int(filerr)); m_mng_file.reset(); } } @@ -526,10 +526,9 @@ void video_manager::end_recording(movie_format format) if (format == MF_AVI) { // close the file if it exists - if (m_avi_file != nullptr) + if (m_avi_file) { - avi_close(m_avi_file); - m_avi_file = nullptr; + m_avi_file.reset(); // reset the state m_avi_frame = 0; @@ -563,10 +562,10 @@ void video_manager::add_sound_to_recording(const INT16 *sound, int numsamples) g_profiler.start(PROFILER_MOVIE_REC); // write the next frame - avi_error avierr = avi_append_sound_samples(m_avi_file, 0, sound + 0, numsamples, 1); - if (avierr == AVIERR_NONE) - avierr = avi_append_sound_samples(m_avi_file, 1, sound + 1, numsamples, 1); - if (avierr != AVIERR_NONE) + avi_file::error avierr = m_avi_file->append_sound_samples(0, sound + 0, numsamples, 1); + if (avierr == avi_file::error::NONE) + avierr = m_avi_file->append_sound_samples(1, sound + 1, numsamples, 1); + if (avierr != avi_file::error::NONE) end_recording(MF_AVI); g_profiler.stop(); @@ -1091,8 +1090,8 @@ void video_manager::recompute_speed(const attotime &emutime) { // create a final screenshot emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(machine().basename(), PATH_SEPARATOR "final.png"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(machine().basename(), PATH_SEPARATOR "final.png"); + if (filerr == osd_file::error::NONE) save_snapshot(screen, file); } //printf("Scheduled exit at %f\n", emutime.as_double()); @@ -1150,7 +1149,7 @@ void video_manager::create_snapshot_bitmap(screen_device *screen) // scheme //------------------------------------------------- -file_error video_manager::open_next(emu_file &file, const char *extension) +osd_file::error video_manager::open_next(emu_file &file, const char *extension) { UINT32 origflags = file.openflags(); @@ -1260,8 +1259,8 @@ file_error video_manager::open_next(emu_file &file, const char *extension) strreplace(fname, "%i", string_format("%04d", seq).c_str()); // try to open the file; stop when we fail - file_error filerr = file.open(fname.c_str()); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(fname.c_str()); + if (filerr != osd_file::error::NONE) break; } } @@ -1296,8 +1295,8 @@ void video_manager::record_frame() while (m_avi_next_frame_time <= curtime) { // write the next frame - avi_error avierr = avi_append_video_frame(m_avi_file, m_snap_bitmap); - if (avierr != AVIERR_NONE) + avi_file::error avierr = m_avi_file->append_video_frame(m_snap_bitmap); + if (avierr != avi_file::error::NONE) { g_profiler.stop(); end_recording(MF_AVI); diff --git a/src/emu/video.h b/src/emu/video.h index 67939d47eaa..019b2b0a472 100644 --- a/src/emu/video.h +++ b/src/emu/video.h @@ -14,8 +14,10 @@ #error Dont include this file directly; include emu.h instead. #endif -#ifndef __VIDEO_H__ -#define __VIDEO_H__ +#ifndef MAME_EMU_VIDEO_H +#define MAME_EMU_VIDEO_H + +#include "aviio.h" //************************************************************************** @@ -35,7 +37,7 @@ const int MAX_FRAMESKIP = FRAMESKIP_LEVELS - 2; // forward references class render_target; class screen_device; -struct avi_file; +class avi_file; @@ -64,7 +66,7 @@ public: bool throttled() const { return m_throttled; } float throttle_rate() const { return m_throttle_rate; } bool fastforward() const { return m_fastforward; } - bool is_recording() const { return (m_mng_file != nullptr || m_avi_file != nullptr); } + bool is_recording() const { return (m_mng_file || m_avi_file); } // setters void set_frameskip(int frameskip); @@ -76,7 +78,7 @@ public: // misc void toggle_throttle(); void toggle_record_movie(); - file_error open_next(emu_file &file, const char *extension); + osd_file::error open_next(emu_file &file, const char *extension); // render a frame void frame_update(bool debug = false); @@ -184,7 +186,7 @@ private: UINT32 m_mng_frame; // current movie frame number // movie recording - AVI - avi_file * m_avi_file; // handle to the open movie file + avi_file::ptr m_avi_file; // handle to the open movie file attotime m_avi_frame_period; // period of a single movie frame attotime m_avi_next_frame_time; // time of next frame UINT32 m_avi_frame; // current movie frame number @@ -205,4 +207,4 @@ private: }; -#endif /* __VIDEO_H__ */ +#endif // MAME_EMU_VIDEO_H 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 ¤t_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 ¤t_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 ¤t_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(), ¤t_entry_type); + zippath_find_sub_path(*zipfile, newpath.c_str(), ¤t_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); diff --git a/src/mame/drivers/jaguar.cpp b/src/mame/drivers/jaguar.cpp index e2fe252fe93..ee33848dd11 100644 --- a/src/mame/drivers/jaguar.cpp +++ b/src/mame/drivers/jaguar.cpp @@ -481,13 +481,13 @@ void jaguar_state::machine_reset() emu_file jaguar_state::*jaguar_nvram_fopen( UINT32 openflags) { device_image_interface *image = dynamic_cast<device_image_interface *>(machine().device("cart")); - file_error filerr; + osd_file::error filerr; emu_file *file; if (image->exists()) { std::string fname(machine().system().name, PATH_SEPARATOR, image->basename_noext(), ".nv"); filerr = mame_fopen( SEARCHPATH_NVRAM, fname, openflags, &file); - return (filerr == FILERR_NONE) ? file : NULL; + return (filerr == osd_file::error::NONE) ? file : NULL; } else return NULL; diff --git a/src/mame/etc/jrcrypt.cpp b/src/mame/etc/jrcrypt.cpp index e973df30753..89c1fc0b716 100644 --- a/src/mame/etc/jrcrypt.cpp +++ b/src/mame/etc/jrcrypt.cpp @@ -490,8 +490,8 @@ void Load(char *name,byte *buffer,int from, int length) { /* emu_file file(options, NULL, OPEN_FLAG_READ); - file_error filerr = file.open(name); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(name); + if (filerr != osd_file::error::NONE) return; while (length--) buffer[from++]=file->getc(); diff --git a/src/mame/machine/fddebug.cpp b/src/mame/machine/fddebug.cpp index fcb4a46bff8..9cf760337fc 100644 --- a/src/mame/machine/fddebug.cpp +++ b/src/mame/machine/fddebug.cpp @@ -591,8 +591,8 @@ static void load_overlay_file(running_machine &machine) /* determine the filename and open the file */ emu_file file(OPEN_FLAG_READ); - file_error filerr = file.open(machine.system().name, ".kov"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(machine.system().name, ".kov"); + if (filerr == osd_file::error::NONE) { file.read(keystatus, keystatus_words * 2); @@ -617,8 +617,8 @@ static void save_overlay_file(running_machine &machine) /* determin the filename and open the file */ emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - file_error filerr = file.open(machine.system().name, ".kov"); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(machine.system().name, ".kov"); + if (filerr == osd_file::error::NONE) { /* convert to big-endian */ for (pcaddr = 0; pcaddr < keystatus_words; pcaddr++) @@ -760,8 +760,8 @@ static void execute_fdoutput(running_machine &machine, int ref, int params, cons /* determin the filename and open the file */ emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - file_error filerr = file.open(param[0]); - if (filerr == FILERR_NONE) + osd_file::error filerr = file.open(param[0]); + if (filerr == osd_file::error::NONE) file.write(keyregion, KEY_SIZE); debug_console_printf(machine, "File '%s' saved\n", param[0]); @@ -1183,8 +1183,8 @@ static void execute_fddasm(running_machine &machine, int ref, int params, const /* open the file */ emu_file file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - file_error filerr = file.open(filename); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(filename); + if (filerr != osd_file::error::NONE) { debug_console_printf(machine, "Unable to create file '%s'\n", filename); return; diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp new file mode 100644 index 00000000000..3fe7ca9fa90 --- /dev/null +++ b/src/osd/modules/file/posixfile.cpp @@ -0,0 +1,482 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdlfile.c - SDL file access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#ifdef __linux__ +#define __USE_LARGEFILE64 +#endif + +#ifdef WIN32 +#define _FILE_OFFSET_BITS 64 +#endif + +#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__bsdi__) && !defined(__DragonFly__) +#ifdef _XOPEN_SOURCE +#if _XOPEN_SOURCE < 500 +#undef _XOPEN_SOURCE +#endif +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif +#endif + +// MAME headers +#include "posixfile.h" + +#include <cassert> +#include <cerrno> +#include <memory> +#include <type_traits> +#include <vector> + +#include <fcntl.h> +#include <limits.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> + + + +namespace { + +//============================================================ +// CONSTANTS +//============================================================ + +#if defined(WIN32) +constexpr char PATHSEPCH = '\\'; +constexpr char INVPATHSEPCH = '/'; +#else +constexpr char PATHSEPCH = '/'; +constexpr char INVPATHSEPCH = '\\'; +#endif + + + +class posix_osd_file : public osd_file +{ +public: + posix_osd_file(posix_osd_file const &) = delete; + posix_osd_file(posix_osd_file &&) = delete; + posix_osd_file& operator=(posix_osd_file const &) = delete; + posix_osd_file& operator=(posix_osd_file &&) = delete; + + posix_osd_file(int fd) : m_fd(fd) + { + assert(m_fd >= 0); + } + + virtual ~posix_osd_file() override + { + ::close(m_fd); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t result; + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) + result = ::pread(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); +#elif defined(WIN32) || defined(SDLMAME_NO64BITIO) + if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0) + return errno_to_file_error(errno) + result = ::read(m_fd, buffer, size_t(count)); +#else + result = ::pread64(m_fd, buffer, size_t(count), off64_t(offset)); +#endif + + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(std::size_t(result)); + return error::NONE; + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t result; + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) + result = ::pwrite(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset))); +#elif defined(WIN32) || defined(SDLMAME_NO64BITIO) + if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0) + return errno_to_file_error(errno) + result = ::write(m_fd, buffer, size_t(count)); +#else + result = ::pwrite64(m_fd, buffer, size_t(count), off64_t(offset)); +#endif + + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(std::size_t(result)); + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + int result; + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(EMSCRIPTEN) || defined(WIN32) || defined(SDLMAME_NO64BITIO) + result = ::ftruncate(m_fd, off_t(std::make_unsigned_t<off_t>(offset))); +#else + result = ::ftruncate64(m_fd, off64_t(offset)); +#endif + + if (result < 0) + return errno_to_file_error(errno); + + return error::NONE; + } + + virtual error flush() override + { + // no user-space buffering on unistd I/O + return error::NONE; + } + +private: + int m_fd; +}; + + +//============================================================ +// is_path_separator +//============================================================ + +bool is_path_separator(char c) +{ + return (c == PATHSEPCH) || (c == INVPATHSEPCH); +} + + +//============================================================ +// create_path_recursive +//============================================================ + +osd_file::error create_path_recursive(std::string const &path) +{ + // if there's still a separator, and it's not the root, nuke it and recurse + auto const sep = path.rfind(PATHSEPCH); + if ((sep != std::string::npos) && (sep > 0) && (path[sep] != ':') && (path[sep - 1] != PATHSEPCH)) + { + osd_file::error const err = create_path_recursive(path.substr(0, sep)); + if (err != osd_file::error::NONE) + return err; + } + + // if the path already exists, we're done + struct stat st; + if (!::stat(path.c_str(), &st)) + return osd_file::error::NONE; + + // create the path +#ifdef WIN32 + if (mkdir(path.c_str()) < 0) +#else + if (mkdir(path.c_str(), 0777) < 0) +#endif + return errno_to_file_error(errno); + else + return osd_file::error::NONE; +} + +} // anonymous namespace + + +//============================================================ +// osd_file::open +//============================================================ + +osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) +{ + std::string dst; + if (posix_check_socket_path(path)) + return posix_open_socket(path, openflags, file, filesize); + else if (posix_check_ptty_path(path)) + return posix_open_ptty(openflags, file, filesize, dst); + + // select the file open modes + int access; + if (openflags & OPEN_FLAG_WRITE) + { + access = (openflags & OPEN_FLAG_READ) ? O_RDWR : O_WRONLY; + access |= (openflags & OPEN_FLAG_CREATE) ? (O_CREAT | O_TRUNC) : 0; + } + else if (openflags & OPEN_FLAG_READ) + { + access = O_RDONLY; + } + else + { + return error::INVALID_ACCESS; + } +#if defined(WIN32) + access |= O_BINARY; +#endif + + // convert the path into something compatible + dst = path; + for (auto it = dst.begin(); it != dst.end(); ++it) + *it = (INVPATHSEPCH == *it) ? PATHSEPCH : *it; + osd_subst_env(dst, dst); + + // attempt to open the file + int fd = -1; +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) + fd = ::open(dst.c_str(), access, 0666); +#else + fd = ::open64(dst.c_str(), access, 0666); +#endif + + if (fd < 0) + { + // create the path if necessary + if ((openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS)) + { + auto const pathsep = dst.rfind(dst, PATHSEPCH); + if (pathsep != std::string::npos) + { + // create the path up to the file + osd_file::error const error = create_path_recursive(dst.substr(0, pathsep)); + + // attempt to reopen the file + if (error == osd_file::error::NONE) + { +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) + fd = ::open(dst.c_str(), access, 0666); +#else + fd = ::open64(dst.c_str(), access, 0666); +#endif + } + } + } + + // if we still failed, clean up and osd_free + if (fd < 0) + { + return errno_to_file_error(errno); + } + } + + // get the file size +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) + struct stat st; + if (::fstat(fd, &st) < 0) +#else + struct stat64 st; + if (::fstat64(fd, &st) < 0) +#endif + { + int const error = errno; + ::close(fd); + return errno_to_file_error(error); + } + filesize = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size)); + + try + { + file = std::make_unique<posix_osd_file>(fd); + return error::NONE; + } + catch (...) + { + ::close(fd); + return error::OUT_OF_MEMORY; + } +} + + +//============================================================ +// osd_file::openpty +//============================================================ + +osd_file::error osd_file::openpty(ptr &file, std::string &name) +{ + std::uint64_t filesize; + return posix_open_ptty(OPEN_FLAG_READ | OPEN_FLAG_WRITE, file, filesize, name); +} + + +//============================================================ +// osd_file::remove +//============================================================ + +osd_file::error osd_file::remove(std::string const &filename) +{ + if (::unlink(filename.c_str()) < -1) + return errno_to_file_error(errno); + else + return error::NONE; +} + + +//============================================================ +// osd_get_physical_drive_geometry +//============================================================ + +int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) +{ + return FALSE; // no, no way, huh-uh, forget it +} + + +//============================================================ +// osd_stat +//============================================================ + +osd_directory_entry *osd_stat(const std::string &path) +{ +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) + struct stat st; + int const err = ::stat(path.c_str(), &st); +#else + struct stat64 st; + int const err = ::stat64(path.c_str(), &st); +#endif + if (err < 0) return nullptr; + + // create an osd_directory_entry; be sure to make sure that the caller can + // free all resources by just freeing the resulting osd_directory_entry + osd_directory_entry *const result = reinterpret_cast<osd_directory_entry *>(osd_malloc_array(sizeof(osd_directory_entry) + path.length() + 1)); + std::strcpy(reinterpret_cast<char *>(result) + sizeof(*result), path.c_str()); + result->name = reinterpret_cast<char *>(result) + sizeof(*result); + result->type = S_ISDIR(st.st_mode) ? ENTTYPE_DIR : ENTTYPE_FILE; + result->size = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size)); + + return result; +} + + +//============================================================ +// osd_get_full_path +//============================================================ + +osd_file::error osd_get_full_path(std::string &dst, std::string const &path) +{ + try + { +#if defined(WIN32) + std::vector<char> path_buffer(MAX_PATH); + if (::_fullpath(&path_buffer[0], path.c_str(), MAX_PATH)) + { + dst = &path_buffer[0]; + return osd_file::error::NONE; + } + else + { + return osd_file::error::FAILURE; + } +#else + std::vector<char> path_buffer(PATH_MAX); + if (::realpath(path.c_str(), &path_buffer[0])) + { + dst = &path_buffer[0]; + return osd_file::error::NONE; + } + else if (path[0] == PATHSEPCH) + { + dst = path; + return osd_file::error::NONE; + } + else + { + while (!::getcwd(&path_buffer[0], path_buffer.size())) + { + if (errno != ERANGE) + return errno_to_file_error(errno); + else + path_buffer.resize(path_buffer.size() * 2); + } + dst.assign(&path_buffer[0]).push_back(PATHSEPCH); + dst.append(path); + return osd_file::error::NONE; + } +#endif + } + catch (...) + { + return osd_file::error::OUT_OF_MEMORY; + } +} + + +//============================================================ +// osd_is_absolute_path +//============================================================ + +bool osd_is_absolute_path(std::string const &path) +{ + if (!path.empty() && is_path_separator(path[0])) + return true; +#if !defined(WIN32) + else if (!path.empty() && (path[0] == '.')) + return true; +#elif !defined(UNDER_CE) + else if ((path.length() > 1) && (path[1] == ':')) + return true; +#endif + else + return false; +} + + +//============================================================ +// osd_get_volume_name +//============================================================ + +const char *osd_get_volume_name(int idx) +{ + if (idx == 0) + return "/"; + else + return nullptr; + } + + +//============================================================ +// errno_to_file_error +//============================================================ + +osd_file::error errno_to_file_error(int error) +{ + switch (error) + { + case 0: + return osd_file::error::NONE; + + case ENOENT: + case ENOTDIR: + return osd_file::error::NOT_FOUND; + + case EACCES: + case EROFS: +#ifndef WIN32 + case ETXTBSY: +#endif + case EEXIST: + case EPERM: + case EISDIR: + case EINVAL: + return osd_file::error::ACCESS_DENIED; + + case ENFILE: + case EMFILE: + return osd_file::error::TOO_MANY_FILES; + + default: + return osd_file::error::FAILURE; + } +} diff --git a/src/osd/modules/file/posixfile.h b/src/osd/modules/file/posixfile.h new file mode 100644 index 00000000000..2339a52ceec --- /dev/null +++ b/src/osd/modules/file/posixfile.h @@ -0,0 +1,28 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdlfile.h - SDL file access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + + +#include "osdcore.h" + +#include <cstdint> +#include <string> + + +//============================================================ +// PROTOTYPES +//============================================================ + +bool posix_check_socket_path(std::string const &path); +osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); + +bool posix_check_ptty_path(std::string const &path); +osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name); + +osd_file::error errno_to_file_error(int error); diff --git a/src/osd/modules/file/posixptty.cpp b/src/osd/modules/file/posixptty.cpp new file mode 100644 index 00000000000..b84838c0578 --- /dev/null +++ b/src/osd/modules/file/posixptty.cpp @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdlptty_unix.c - SDL pseudo tty access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + +#include "posixfile.h" + +#include <cassert> +#include <cerrno> +#include <cstring> + +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> +#include <stdlib.h> + +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include <termios.h> +#include <libutil.h> +#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#include <termios.h> +#include <util.h> +#elif defined(__linux__) || defined(EMSCRIPTEN) +#include <pty.h> +#elif defined(__HAIKU__) +#include <bsd/pty.h> +#endif + + +namespace { +#if defined(__APPLE__) +char const *const posix_ptty_identifier = "/dev/pty"; +#else +char const *const posix_ptty_identifier = "/dev/pts"; +#endif + + +class posix_osd_ptty : public osd_file +{ +public: + posix_osd_ptty(posix_osd_ptty const &) = delete; + posix_osd_ptty(posix_osd_ptty &&) = delete; + posix_osd_ptty& operator=(posix_osd_ptty const &) = delete; + posix_osd_ptty& operator=(posix_osd_ptty &&) = delete; + + posix_osd_ptty(int fd) : m_fd(fd) + { + assert(m_fd >= 0); + } + + virtual ~posix_osd_ptty() + { + ::close(m_fd); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::read(m_fd, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::write(m_fd, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense on ptty + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // no userspace buffers on read/write + return error::NONE; + } + +private: + int m_fd; +}; + +} // anonymous namespace + + +bool posix_check_ptty_path(std::string const &path) +{ + return strncmp(path.c_str(), posix_ptty_identifier, strlen(posix_ptty_identifier)) == 0; +} + + +osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) +{ +#if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) + int access = O_NOCTTY; + if (openflags & OPEN_FLAG_WRITE) + access |= (openflags & OPEN_FLAG_READ) ? O_RDWR : O_WRONLY; + else if (openflags & OPEN_FLAG_READ) + access |= O_RDONLY; + else + return error::INVALID_ACCESS; + + int const masterfd = ::posix_openpt(access); + if (masterfd < 0) + return errno_to_file_error(errno); + + // grant access to slave device and check that it can be opened + char const *slavepath; + int slavefd; + if ((::grantpt(masterfd) < 0) || + (::unlockpt(masterfd) < 0) || + ((slavepath = ::ptsname(masterfd)) == nullptr) || + ((slavefd = ::open(slavepath, O_RDWR | O_NOCTTY)) < 0)) + { + int const err = errno; + ::close(masterfd); + return errno_to_file_error(err); + } + + // check that it's possible to stack BSD-compatibility STREAMS modules + if ((::ioctl(slavefd, I_PUSH, "ptem") < 0) || + (::ioctl(slavefd, I_PUSH, "ldterm") < 0) || + (::ioctl(slavefd, I_PUSH, "ttcompat") < 0)) + { + int const err = errno; + ::close(slavefd); + ::close(masterfd); + return errno_to_file_error(err); + } +#else + struct termios tios; + std::memset(&tios, 0, sizeof(tios)); + ::cfmakeraw(&tios); + + int masterfd = -1, slavefd = -1; + char slavepath[PATH_MAX]; + if (::openpty(&masterfd, &slavefd, slavepath, &tios, nullptr) < 0) + return errno_to_file_error(errno); +#endif + + ::close(slavefd); + + int const oldflags = ::fcntl(masterfd, F_GETFL, 0); + if (oldflags < 0) + { + int const err = errno; + ::close(masterfd); + return errno_to_file_error(err); + } + + if (::fcntl(masterfd, F_SETFL, oldflags | O_NONBLOCK) < 0) + { + int const err = errno; + ::close(masterfd); + return errno_to_file_error(err); + } + + try + { + name = slavepath; + file = std::make_unique<posix_osd_ptty>(masterfd); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(masterfd); + return osd_file::error::OUT_OF_MEMORY; + } +} diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp new file mode 100644 index 00000000000..e50d0636489 --- /dev/null +++ b/src/osd/modules/file/posixsocket.cpp @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdlsocket.c - SDL socket (inet) access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + +#include "posixfile.h" + +#include <cassert> +#include <cerrno> +#include <cstdio> + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <unistd.h> + + +namespace { +char const *const posixfile_socket_identifier = "socket."; + + +class posix_osd_socket : public osd_file +{ +public: + posix_osd_socket(posix_osd_socket const &) = delete; + posix_osd_socket(posix_osd_socket &&) = delete; + posix_osd_socket& operator=(posix_osd_socket const &) = delete; + posix_osd_socket& operator=(posix_osd_socket &&) = delete; + + posix_osd_socket(int sock, bool listening) + : m_sock(sock) + , m_listening(listening) + { + assert(m_sock >= 0); + } + + virtual ~posix_osd_socket() + { + ::close(m_sock); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { +#if defined(EMSCRIPTEN) + return error::FAILED; // TODO: work out what it dislikes about emscripten +#else + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(m_sock, &readfds); + + struct timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + + if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) + { + char line[80]; + std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); + std::perror(line); + return errno_to_file_error(errno); + } + else if (FD_ISSET(m_sock, &readfds)) + { + if (!m_listening) + { + // connected socket + ssize_t const result = ::read(m_sock, buffer, count); + if (result < 0) + { + return errno_to_file_error(errno); + } + else + { + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + } + else + { + // listening socket + int const accepted = ::accept(m_sock, nullptr, nullptr); + if (accepted < 0) + { + return errno_to_file_error(errno); + } + else + { + ::close(m_sock); + m_sock = accepted; + m_listening = false; + actual = 0; + + return error::NONE; + } + } + } + else + { + return error::FAILURE; + } +#endif + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::write(m_sock, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense on socket + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // there's no simple way to flush buffers on a socket anyway + return error::NONE; + } + +private: + int m_sock; + bool m_listening; +}; + +} // anonymous namespace + + +/* + Checks whether the path is a socket specification. A valid socket + specification has the format "socket." host ":" port. Host may be simple + or fully qualified. Port must be between 1 and 65535. +*/ +bool posix_check_socket_path(std::string const &path) +{ + if (strncmp(path.c_str(), posixfile_socket_identifier, strlen(posixfile_socket_identifier)) == 0 && + strchr(path.c_str(), ':') != nullptr) return true; + return false; +} + + +osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +{ + char hostname[256]; + int port; + std::sscanf(&path[strlen(posixfile_socket_identifier)], "%255[^:]:%d", hostname, &port); + + struct hostent const *const localhost = ::gethostbyname(hostname); + if (!localhost) + return osd_file::error::NOT_FOUND; + + struct sockaddr_in sai; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_INET; + sai.sin_port = htons(port); + sai.sin_addr = *reinterpret_cast<struct in_addr *>(localhost->h_addr); + + int const sock = ::socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return errno_to_file_error(errno); + + int const flag = 1; + if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // listening socket support + if (openflags & OPEN_FLAG_CREATE) + { + //printf("Listening for client at '%s' on port '%d'\n", hostname, port); + // bind socket... + if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // start to listen... + if (::listen(sock, 1) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // mark socket as "listening" + try + { + file = std::make_unique<posix_osd_socket>(sock, true); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } + else + { + //printf("Connecting to server '%s' on port '%d'\n", hostname, port); + if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) + { + ::close(sock); + return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure + } + try + { + file = std::make_unique<posix_osd_socket>(sock, false); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } +} diff --git a/src/osd/modules/file/stdfile.cpp b/src/osd/modules/file/stdfile.cpp new file mode 100644 index 00000000000..92920bba495 --- /dev/null +++ b/src/osd/modules/file/stdfile.cpp @@ -0,0 +1,251 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +//============================================================ +// +// minifile.c - Minimal core file access functions +// +//============================================================ + +#include "osdcore.h" + +#include <cassert> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <string> + +#include <stdio.h> // for fileno +#include <unistd.h> // for ftruncate + + +namespace { +class std_osd_file : public osd_file +{ +public: + + std_osd_file(FILE *f) : m_file(f) { assert(m_file); } + + //============================================================ + // osd_close + //============================================================ + + virtual ~std_osd_file() override + { + // close the file handle + if (m_file) std::fclose(m_file); + } + + //============================================================ + // osd_read + //============================================================ + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + { + // seek to the new location; note that most fseek implementations are limited to 32 bits + if (std::fseek(m_file, offset, SEEK_SET) < 0) + return error::FAILURE; + + // perform the read + std::size_t const count = std::fread(buffer, 1, length, m_file); + actual = count; + + return error::NONE; + } + + //============================================================ + // osd_write + //============================================================ + + virtual error write(const void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + { + // seek to the new location; note that most fseek implementations are limited to 32 bits + if (std::fseek(m_file, offset, SEEK_SET) < 0) + return error::FAILURE; + + // perform the write + std::size_t const count = std::fwrite(buffer, 1, length, m_file); + actual = count; + + return error::NONE; + } + + //============================================================ + // osd_truncate + //============================================================ + + error truncate(std::uint64_t offset) override + { + return (ftruncate(fileno(m_file), offset) < 0) ? error::FAILURE : error::NONE; + } + + //============================================================ + // osd_fflush + //============================================================ + + virtual error flush() override + { + return (std::fflush(m_file) == EOF) ? error::FAILURE : error::NONE; + } + +private: + FILE *m_file; +}; + +} // anonymous namespace + + +//============================================================ +// osd_open +//============================================================ + +osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) +{ + // based on the flags, choose a mode + const char *mode; + if (openflags & OPEN_FLAG_WRITE) + { + if (openflags & OPEN_FLAG_READ) + mode = (openflags & OPEN_FLAG_CREATE) ? "w+b" : "r+b"; + else + mode = "wb"; + } + else if (openflags & OPEN_FLAG_READ) + mode = "rb"; + else + return error::INVALID_ACCESS; + + // open the file + FILE *const fileptr = std::fopen(path.c_str(), mode); + if (!fileptr) + return error::NOT_FOUND; + + // get the size -- note that most fseek/ftell implementations are limited to 32 bits + long length; + if ((std::fseek(fileptr, 0, SEEK_END) < 0) || + ((length = std::ftell(fileptr)) < 0) || + (std::fseek(fileptr, 0, SEEK_SET) < 0)) + { + std::fclose(fileptr); + return error::FAILURE; + } + + try + { + file = std::make_unique<std_osd_file>(fileptr); + filesize = std::int64_t(length); + return error::NONE; + } + catch (...) + { + std::fclose(fileptr); + return error::OUT_OF_MEMORY; + } +} + + +//============================================================ +// osd_openpty +//============================================================ + +osd_file::error osd_file::openpty(ptr &file, std::string &name) +{ + return error::FAILURE; +} + + +//============================================================ +// osd_rmfile +//============================================================ + +osd_file::error osd_file::remove(std::string const &filename) +{ + return (std::remove(filename.c_str()) < 0) ? error::FAILURE : error::NONE; +} + + +//============================================================ +// osd_get_physical_drive_geometry +//============================================================ + +int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) +{ + // there is no standard way of doing this, so we always return FALSE, indicating + // that a given path is not a physical drive + return FALSE; +} + + +//============================================================ +// osd_uchar_from_osdchar +//============================================================ + +int osd_uchar_from_osdchar(UINT32 /* unicode_char */ *uchar, const char *osdchar, size_t count) +{ + // we assume a standard 1:1 mapping of characters to the first 256 unicode characters + *uchar = (UINT8)*osdchar; + return 1; +} + + +//============================================================ +// osd_stat +//============================================================ + +osd_directory_entry *osd_stat(const std::string &path) +{ + osd_directory_entry *result = nullptr; + + // create an osd_directory_entry; be sure to make sure that the caller can + // free all resources by just freeing the resulting osd_directory_entry + result = (osd_directory_entry *)osd_malloc_array(sizeof(*result) + path.length() + 1); + strcpy((char *)(result + 1), path.c_str()); + result->name = (char *)(result + 1); + result->type = ENTTYPE_NONE; + result->size = 0; + + FILE *f = std::fopen(path.c_str(), "rb"); + if (f != nullptr) + { + std::fseek(f, 0, SEEK_END); + result->type = ENTTYPE_FILE; + result->size = std::ftell(f); + std::fclose(f); + } + return result; +} + + +//============================================================ +// osd_get_full_path +//============================================================ + +osd_file::error osd_get_full_path(std::string &dst, std::string const &path) +{ + // derive the full path of the file in an allocated string + // for now just fake it since we don't presume any underlying file system + dst = path; + + return osd_file::error::NONE; +} + + +//============================================================ +// osd_is_absolute_path +//============================================================ + +bool osd_is_absolute_path(std::string const &path) +{ + // assume no for everything + return false; +} + + +//============================================================ +// osd_get_volume_name +//============================================================ + +const char *osd_get_volume_name(int idx) +{ + // we don't expose volumes + return nullptr; +} diff --git a/src/osd/modules/file/winfile.cpp b/src/osd/modules/file/winfile.cpp new file mode 100644 index 00000000000..67de56fec0a --- /dev/null +++ b/src/osd/modules/file/winfile.cpp @@ -0,0 +1,513 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// winfile.c - Win32 OSD core file access functions +// +//============================================================ + +#define WIN32_LEAN_AND_MEAN + +#include "winfile.h" + +// MAMEOS headers +#include "strconv.h" +#include "winutil.h" +#include "winutf8.h" + +// MAME headers +#include "osdcore.h" + +#include <cassert> + +// standard windows headers +#include <windows.h> +#include <winioctl.h> +#include <tchar.h> +#include <shlwapi.h> +#include <stdlib.h> +#include <ctype.h> + + +namespace { +//============================================================ +// TYPE DEFINITIONS +//============================================================ + +class win_osd_file : public osd_file +{ +public: + win_osd_file(win_osd_file const &) = delete; + win_osd_file(win_osd_file &&) = delete; + win_osd_file& operator=(win_osd_file const &) = delete; + win_osd_file& operator=(win_osd_file &&) = delete; + + win_osd_file(HANDLE handle) : m_handle(handle) + { + assert(m_handle); + assert(INVALID_HANDLE_VALUE != m_handle); + } + + virtual ~win_osd_file() override + { + FlushFileBuffers(m_handle); + CloseHandle(m_handle); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + { + // attempt to set the file pointer + LONG upper(std::uint32_t(offset >> 32)); + DWORD result(SetFilePointer(m_handle, std::uint32_t(offset), &upper, FILE_BEGIN)); + if (INVALID_SET_FILE_POINTER == result) + { + DWORD const err(GetLastError()); + if (NO_ERROR != err) + win_error_to_file_error(err); + } + + // then perform the read + if (!ReadFile(m_handle, buffer, length, &result, NULL)) + return win_error_to_file_error(GetLastError()); + + actual = result; + return error::NONE; + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + { + // attempt to set the file pointer + LONG upper(std::uint32_t(offset >> 32)); + DWORD result(SetFilePointer(m_handle, std::uint32_t(offset), &upper, FILE_BEGIN)); + if (INVALID_SET_FILE_POINTER == result) + { + DWORD const err(GetLastError()); + if (NO_ERROR != err) + win_error_to_file_error(err); + } + + // then perform the write + if (!WriteFile(m_handle, buffer, length, &result, NULL)) + return win_error_to_file_error(GetLastError()); + + actual = result; + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // attempt to set the file pointer + LONG upper(std::uint32_t(offset >> 32)); + DWORD const result(SetFilePointer(m_handle, std::uint32_t(offset), &upper, FILE_BEGIN)); + if (INVALID_SET_FILE_POINTER == result) + { + DWORD const err(GetLastError()); + if (NO_ERROR != err) + win_error_to_file_error(err); + } + + // then perform the truncation + if (!SetEndOfFile(m_handle)) + return win_error_to_file_error(GetLastError()); + else + return error::NONE; + } + + virtual error flush() override + { + // shouldn't be any userspace buffers on the file handle + return error::NONE; + } + +private: + HANDLE m_handle; +}; + + +template <typename T> +class osd_disposer +{ +public: + osd_disposer(T *&ptr) : m_ptr(ptr) { } + ~osd_disposer() { if (m_ptr) osd_free(m_ptr); } +private: + T *&m_ptr; +}; + + + +//============================================================ +// INLINE FUNCTIONS +//============================================================ + +inline bool is_path_to_physical_drive(char const *path) +{ + return (_strnicmp(path, "\\\\.\\physicaldrive", 17) == 0); +} + + + +//============================================================ +// create_path_recursive +//============================================================ + +DWORD create_path_recursive(TCHAR *path) +{ + // if there's still a separator, and it's not the root, nuke it and recurse + TCHAR *sep = _tcsrchr(path, '\\'); + if (sep && (sep > path) && (sep[0] != ':') && (sep[-1] != '\\')) + { + *sep = 0; + create_path_recursive(path); + *sep = '\\'; + } + + // if the path already exists, we're done + if (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES) + return NO_ERROR; + else if (!CreateDirectory(path, NULL)) + return GetLastError(); + else + return NO_ERROR; +} + +} // anonymous namespace + + + +//============================================================ +// osd_open +//============================================================ + +osd_file::error osd_file::open(std::string const &orig_path, UINT32 openflags, ptr &file, std::uint64_t &filesize) +{ + std::string path; + try { osd_subst_env(path, orig_path); } + catch (...) { return error::OUT_OF_MEMORY; } + + if (win_check_socket_path(path)) + return win_open_socket(path, openflags, file, filesize); + else if (win_check_ptty_path(path)) + return win_open_ptty(path, openflags, file, filesize); + + // convert path to TCHAR + TCHAR *t_path = tstring_from_utf8(path); + osd_disposer<TCHAR> t_path_disposer(t_path); + if (!t_path) + return error::OUT_OF_MEMORY; + + // convert the path into something Windows compatible + for (TCHAR *src = t_path; *src != 0; src++) + *src = /* ('/' == *src) ? '\\' : */ *src; + + // select the file open modes + DWORD disposition, access, sharemode; + if (openflags & OPEN_FLAG_WRITE) + { + disposition = (!is_path_to_physical_drive(path) && (openflags & OPEN_FLAG_CREATE)) ? CREATE_ALWAYS : OPEN_EXISTING; + access = (openflags & OPEN_FLAG_READ) ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE; + sharemode = FILE_SHARE_READ; + } + else if (openflags & OPEN_FLAG_READ) + { + disposition = OPEN_EXISTING; + access = GENERIC_READ; + sharemode = FILE_SHARE_READ; + } + else + { + return error::INVALID_ACCESS; + } + + // attempt to open the file + HANDLE h = CreateFile(t_path, access, sharemode, NULL, disposition, 0, NULL); + if (INVALID_HANDLE_VALUE == h) + { + DWORD err = GetLastError(); + // create the path if necessary + if ((ERROR_PATH_NOT_FOUND == err) && (openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS)) + { + TCHAR *pathsep = _tcsrchr(t_path, '\\'); + if (pathsep != NULL) + { + // create the path up to the file + *pathsep = 0; + err = create_path_recursive(t_path); + *pathsep = '\\'; + + // attempt to reopen the file + if (err == NO_ERROR) + h = CreateFile(t_path, access, sharemode, NULL, disposition, 0, NULL); + } + } + + // if we still failed, clean up and free + if (h == INVALID_HANDLE_VALUE) + return win_error_to_file_error(err); + } + + // get the file size + DWORD upper, lower; + lower = GetFileSize(h, &upper); + if (INVALID_FILE_SIZE == lower) + { + DWORD const err = GetLastError(); + if (NO_ERROR != err) + { + CloseHandle(h); + return win_error_to_file_error(err); + } + } + + try + { + file = std::make_unique<win_osd_file>(h); + filesize = (std::uint64_t(upper) << 32) | lower; + return error::NONE; + } + catch (...) + { + CloseHandle(h); + return error::OUT_OF_MEMORY; + } +} + + + +//============================================================ +// osd_openpty +//============================================================ + +osd_file::error osd_file::openpty(ptr &file, std::string &name) +{ + return error::FAILURE; +} + + + +//============================================================ +// osd_rmfile +//============================================================ + +osd_file::error osd_file::remove(std::string const &filename) +{ + TCHAR *tempstr = tstring_from_utf8(filename.c_str()); + if (!tempstr) + return error::OUT_OF_MEMORY; + + error filerr = error::NONE; + if (!DeleteFile(tempstr)) + filerr = win_error_to_file_error(GetLastError()); + + osd_free(tempstr); + return filerr; +} + + + +//============================================================ +// osd_get_physical_drive_geometry +//============================================================ + +int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) +{ + DISK_GEOMETRY dg; + DWORD bytesRead; + TCHAR *t_filename; + HANDLE file; + int result; + + // if it doesn't smell like a physical drive, just return FALSE + if (!is_path_to_physical_drive(filename)) + return FALSE; + + // do a create file on the drive + t_filename = tstring_from_utf8(filename); + if (t_filename == NULL) + return FALSE; + file = CreateFile(t_filename, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); + osd_free(t_filename); + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + // device I/O control should return the geometry + result = DeviceIoControl(file, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytesRead, NULL); + CloseHandle(file); + + // if that failed, return false + if (!result) + return FALSE; + + // store the results + *cylinders = (UINT32)dg.Cylinders.QuadPart; + *heads = dg.TracksPerCylinder; + *sectors = dg.SectorsPerTrack; + *bps = dg.BytesPerSector; + + // normalize + while (*heads > 16 && !(*heads & 1)) + { + *heads /= 2; + *cylinders *= 2; + } + return TRUE; +} + + + +//============================================================ +// osd_stat +//============================================================ + +osd_directory_entry *osd_stat(const std::string &path) +{ + osd_directory_entry *result = NULL; + TCHAR *t_path; + HANDLE find = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA find_data; + + // convert the path to TCHARs + t_path = tstring_from_utf8(path.c_str()); + if (t_path == NULL) + goto done; + + // is this path a root directory (e.g. - C:)? + if (isalpha(path[0]) && (path[1] == ':') && (path[2] == '\0')) + { + // need to do special logic for root directories + memset(&find_data, 0, sizeof(find_data)); + find_data.dwFileAttributes = GetFileAttributes(t_path); + } + else + { + // attempt to find the first file + find = FindFirstFile(t_path, &find_data); + if (find == INVALID_HANDLE_VALUE) + goto done; + } + + // create an osd_directory_entry; be sure to make sure that the caller can + // free all resources by just freeing the resulting osd_directory_entry + result = (osd_directory_entry *)osd_malloc_array(sizeof(*result) + path.length() + 1); + if (!result) + goto done; + strcpy(((char *) result) + sizeof(*result), path.c_str()); + result->name = ((char *) result) + sizeof(*result); + result->type = win_attributes_to_entry_type(find_data.dwFileAttributes); + result->size = find_data.nFileSizeLow | ((UINT64) find_data.nFileSizeHigh << 32); + +done: + if (t_path != NULL) + osd_free(t_path); + return result; +} + + +//============================================================ +// osd_get_full_path +//============================================================ + +osd_file::error osd_get_full_path(std::string &dst, std::string const &path) +{ + // convert the path to TCHARs + TCHAR *t_path = tstring_from_utf8(path.c_str()); + osd_disposer<TCHAR> t_path_disposer(t_path); + if (!t_path) + return osd_file::error::OUT_OF_MEMORY; + + // cannonicalize the path + TCHAR buffer[MAX_PATH]; + if (!GetFullPathName(t_path, ARRAY_LENGTH(buffer), buffer, NULL)) + return win_error_to_file_error(GetLastError()); + + // convert the result back to UTF-8 + char *result = utf8_from_tstring(buffer); + osd_disposer<char> result_disposer(result); + if (!result) + return osd_file::error::OUT_OF_MEMORY; + + dst = result; + return osd_file::error::NONE; +} + + + +//============================================================ +// osd_is_absolute_path +//============================================================ + +bool osd_is_absolute_path(std::string const &path) +{ + bool result = false; + TCHAR *t_path = tstring_from_utf8(path.c_str()); + if (t_path != NULL) + { + result = !PathIsRelative(t_path); + osd_free(t_path); + } + return result; +} + + + +//============================================================ +// osd_get_volume_name +//============================================================ + +const char *osd_get_volume_name(int idx) +{ + static char szBuffer[128]; + const char *p; + + GetLogicalDriveStringsA(ARRAY_LENGTH(szBuffer), szBuffer); + + p = szBuffer; + while(idx--) { + p += strlen(p) + 1; + if (!*p) return NULL; + } + + return p; +} + + + +//============================================================ +// win_error_to_file_error +//============================================================ + +osd_file::error win_error_to_file_error(DWORD error) +{ + osd_file::error filerr; + + // convert a Windows error to a osd_file::error + switch (error) + { + case ERROR_SUCCESS: + filerr = osd_file::error::NONE; + break; + + case ERROR_OUTOFMEMORY: + filerr = osd_file::error::OUT_OF_MEMORY; + break; + + case ERROR_FILE_NOT_FOUND: + case ERROR_FILENAME_EXCED_RANGE: + case ERROR_PATH_NOT_FOUND: + filerr = osd_file::error::NOT_FOUND; + break; + + case ERROR_ACCESS_DENIED: + filerr = osd_file::error::ACCESS_DENIED; + break; + + case ERROR_SHARING_VIOLATION: + filerr = osd_file::error::ALREADY_OPEN; + break; + + default: + filerr = osd_file::error::FAILURE; + break; + } + return filerr; +} diff --git a/src/osd/modules/file/winfile.h b/src/osd/modules/file/winfile.h new file mode 100644 index 00000000000..9a6f1b8fc34 --- /dev/null +++ b/src/osd/modules/file/winfile.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// winfile.h - File access functions +// +//============================================================ +#ifndef MAME_OSD_WINDOWS_WINFILE_H +#define MAME_OSD_WINDOWS_WINFILE_H + +#include "osdcore.h" + +#include <cstdint> +#include <string> + +#include <winsock2.h> + + +//============================================================ +// PROTOTYPES +//============================================================ + +bool win_init_sockets(); +void win_cleanup_sockets(); + +bool win_check_socket_path(std::string const &path); +osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); + +bool win_check_ptty_path(std::string const &path); +osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); + +osd_file::error win_error_to_file_error(DWORD error); + +#endif // MAME_OSD_WINDOWS_WINFILE_H diff --git a/src/osd/modules/file/winptty.cpp b/src/osd/modules/file/winptty.cpp new file mode 100644 index 00000000000..44c42d40588 --- /dev/null +++ b/src/osd/modules/file/winptty.cpp @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb + +#define WIN32_LEAN_AND_MEAN + +#include "winfile.h" + +#include "strconv.h" +#include "winutil.h" + +#include <cassert> + +#include <windows.h> +#include <stdlib.h> + + +namespace { +char const *const winfile_ptty_identifier = "\\\\.\\pipe\\"; + + +class win_osd_ptty : public osd_file +{ +public: + win_osd_ptty(win_osd_ptty const &) = delete; + win_osd_ptty(win_osd_ptty &&) = delete; + win_osd_ptty& operator=(win_osd_ptty const &) = delete; + win_osd_ptty& operator=(win_osd_ptty &&) = delete; + + win_osd_ptty(HANDLE handle) : m_handle(handle) + { + assert(m_handle); + assert(INVALID_HANDLE_VALUE != m_handle); + } + + ~win_osd_ptty() + { + FlushFileBuffers(m_handle); + DisconnectNamedPipe(m_handle); + CloseHandle(m_handle); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + DWORD bytes_read; + if (!ReadFile(m_handle, buffer, count, &bytes_read, NULL)) + return win_error_to_file_error(GetLastError()); + + actual = bytes_read; + return error::NONE; + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) + { + DWORD bytes_written; + if (!WriteFile(m_handle, buffer, count, &bytes_written, NULL)) + return win_error_to_file_error(GetLastError()); + + actual = bytes_written; + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense for a PTTY + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // don't want to wait for client to read all data as implied by FlushFileBuffers + return error::NONE; + } + +private: + HANDLE m_handle; +}; + +} // anonymous namespace + + +bool win_check_ptty_path(std::string const &path) +{ + if (strncmp(path.c_str(), winfile_ptty_identifier, strlen(winfile_ptty_identifier)) == 0) return true; + return false; +} + + +osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +{ + TCHAR *t_name = tstring_from_utf8(path.c_str()); + if (!t_name) + return osd_file::error::OUT_OF_MEMORY; + + HANDLE pipe = CreateNamedPipe(t_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, NULL); + osd_free(t_name); + + if (INVALID_HANDLE_VALUE == pipe) + return osd_file::error::ACCESS_DENIED; + + try + { + file = std::make_unique<win_osd_ptty>(pipe); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + CloseHandle(pipe); + return osd_file::error::OUT_OF_MEMORY; + } +} diff --git a/src/osd/modules/file/winsocket.cpp b/src/osd/modules/file/winsocket.cpp new file mode 100644 index 00000000000..d1c3f4508e8 --- /dev/null +++ b/src/osd/modules/file/winsocket.cpp @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// winsocket.c - Windows socket (inet) access functions +// +//============================================================ + +#define WIN32_LEAN_AND_MEAN + +#include "winfile.h" + +// MAMEOS headers +#include "winutil.h" + +// MAME headers +#include "osdcore.h" + +#include <cassert> +#include <cstdio> + +// standard windows headers +#include <windows.h> +#include <winioctl.h> +#include <tchar.h> +#include <stdlib.h> +#include <ctype.h> + + +namespace { +char const *const winfile_socket_identifier = "socket."; + + +class win_osd_socket : public osd_file +{ +public: + win_osd_socket(win_osd_socket const &) = delete; + win_osd_socket(win_osd_socket &&) = delete; + win_osd_socket& operator=(win_osd_socket const &) = delete; + win_osd_socket& operator=(win_osd_socket &&) = delete; + + win_osd_socket(SOCKET s, bool l) + : m_socket(s) + , m_listening(l) + { + assert(INVALID_SOCKET != m_socket); + } + + virtual ~win_osd_socket() override + { + closesocket(m_socket); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(m_socket, &readfds); + + struct timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + + if (select(m_socket + 1, &readfds, nullptr, nullptr, &timeout) < 0) + { + char line[80]; + std::sprintf(line, "win_read_socket : %s : %d ", __FILE__, __LINE__); + std::perror(line); + return error::FAILURE; + } + else if (FD_ISSET(m_socket, &readfds)) + { + if (!m_listening) + { + // connected socket + int const result = recv(m_socket, (char*)buffer, length, 0); + if (result < 0) + { + return wsa_error_to_file_error(WSAGetLastError()); + } + else + { + actual = result; + return error::NONE; + } + } + else + { + // listening socket + SOCKET const accepted = accept(m_socket, nullptr, nullptr); + if (INVALID_SOCKET == accepted) + { + return wsa_error_to_file_error(WSAGetLastError()); + } + else + { + closesocket(m_socket); + m_socket = accepted; + m_listening = false; + actual = 0; + + return error::NONE; + } + } + } + else + { + return error::FAILURE; + } + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override + { + auto const result = send(m_socket, reinterpret_cast<const char *>(buffer), length, 0); + if (result < 0) + return wsa_error_to_file_error(WSAGetLastError()); + + actual = result; + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense for a socket + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // no buffers to flush + return error::NONE; + } + + static error wsa_error_to_file_error(int err) + { + switch (err) + { + case 0: return error::NONE; + case WSAEACCES: return error::ACCESS_DENIED; + case WSAEADDRINUSE: return error::ALREADY_OPEN; + case WSAEADDRNOTAVAIL: return error::NOT_FOUND; + case WSAECONNREFUSED: return error::NOT_FOUND; + case WSAEHOSTUNREACH: return error::NOT_FOUND; + case WSAENETUNREACH: return error::NOT_FOUND; + default: return error::FAILURE; + } + } + +private: + SOCKET m_socket; + bool m_listening; +}; + +} // anonymous namespace + + +bool win_init_sockets() +{ + WSADATA wsaData; + WORD const version = MAKEWORD(2, 0); + int const error = WSAStartup(version, &wsaData); + + // check for error + if (error) + { + // error occurred + return false; + } + + // check for correct version + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion ) != 0) + { + // incorrect WinSock version + WSACleanup(); + return false; + } + + // WinSock has been initialized + return true; +} + + +void win_cleanup_sockets() +{ + WSACleanup(); +} + + +bool win_check_socket_path(std::string const &path) +{ + if (strncmp(path.c_str(), winfile_socket_identifier, strlen(winfile_socket_identifier)) == 0 && + strchr(path.c_str(), ':') != nullptr) return true; + return false; +} + + +osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +{ + char hostname[256]; + int port; + std::sscanf(&path[strlen(winfile_socket_identifier)], "%255[^:]:%d", hostname, &port); + + struct hostent const *const localhost = gethostbyname(hostname); + if (!localhost) + return osd_file::error::NOT_FOUND; + + struct sockaddr_in sai; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_INET; + sai.sin_port = htons(port); + sai.sin_addr = *reinterpret_cast<struct in_addr *>(localhost->h_addr); + + SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); + if (INVALID_SOCKET == sock) + return win_osd_socket::wsa_error_to_file_error(WSAGetLastError()); + + int const flag = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) == SOCKET_ERROR) + { + int const err = WSAGetLastError(); + closesocket(sock); + return win_osd_socket::wsa_error_to_file_error(err); + } + + // listening socket support + if (openflags & OPEN_FLAG_CREATE) + { + //printf("Listening for client at '%s' on port '%d'\n", hostname, port); + // bind socket... + if (bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR) + { + int const err = WSAGetLastError(); + closesocket(sock); + return win_osd_socket::wsa_error_to_file_error(err); + } + + // start to listen... + if (listen(sock, 1) == SOCKET_ERROR) + { + int const err = WSAGetLastError(); + closesocket(sock); + return win_osd_socket::wsa_error_to_file_error(err); + } + + // mark socket as "listening" + try + { + file = std::make_unique<win_osd_socket>(sock, true); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + closesocket(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } + else + { + //printf("Connecting to server '%s' on port '%d'\n", hostname, port); + if (connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR) + { + closesocket(sock); + return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure + } + try + { + file = std::make_unique<win_osd_socket>(sock, false); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + closesocket(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } +} diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp index 17b2f411336..5fcc8209500 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.cpp +++ b/src/osd/modules/render/d3d/d3dhlsl.cpp @@ -38,7 +38,7 @@ //============================================================ static slider_state *g_slider_list; -static file_error open_next(renderer_d3d9 *d3d, emu_file &file, const char *templ, const char *extension, int idx); +static osd_file::error open_next(renderer_d3d9 *d3d, emu_file &file, const char *templ, const char *extension, int idx); //============================================================ // PROTOTYPES @@ -279,8 +279,8 @@ void shaders::render_snapshot(surface *surface) int idx = cy * 2 + cx; emu_file file(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = open_next(d3d, file, nullptr, "png", idx); - if (filerr != FILERR_NONE) + osd_file::error filerr = open_next(d3d, file, nullptr, "png", idx); + if (filerr != osd_file::error::NONE) { return; } @@ -363,8 +363,8 @@ void shaders::record_texture() { // handle an AVI recording // write the next frame - avi_error avierr = avi_append_video_frame(avi_output_file, avi_snap); - if (avierr != AVIERR_NONE) + avi_file::error avierr = avi_output_file->append_video_frame(avi_snap); + if (avierr != avi_file::error::NONE) { end_avi_recording(); return; @@ -388,9 +388,9 @@ void shaders::end_avi_recording() return; } - if (avi_output_file != nullptr) + if (avi_output_file) { - avi_close(avi_output_file); + avi_output_file.reset(); } avi_output_file = nullptr; @@ -463,7 +463,7 @@ void shaders::begin_avi_recording(const char *name) avi_next_frame_time = machine->time(); // build up information about this new movie - avi_movie_info info; + avi_file::movie_info info; info.video_format = 0; info.video_timescale = 1000 * ((machine->first_screen() != nullptr) ? ATTOSECONDS_TO_HZ(machine->first_screen()->frame_period().m_attoseconds) : screen_device::DEFAULT_FRAME_RATE); info.video_sampletime = 1000; @@ -481,7 +481,7 @@ void shaders::begin_avi_recording(const char *name) info.audio_samplerate = machine->sample_rate(); // create a new temporary movie file - file_error filerr; + osd_file::error filerr; std::string fullpath; { emu_file tempfile(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); @@ -500,19 +500,19 @@ void shaders::begin_avi_recording(const char *name) } // if we succeeded, make a copy of the name and create the real file over top - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { fullpath = tempfile.fullpath(); } } - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { // create the file and free the string - avi_error avierr = avi_create(fullpath.c_str(), &info, &avi_output_file); - if (avierr != AVIERR_NONE) + avi_file::error avierr = avi_file::create(fullpath, info, avi_output_file); + if (avierr != avi_file::error::NONE) { - osd_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); + osd_printf_error("Error creating AVI: %s\n", avi_file::error_string(avierr)); } } } @@ -2420,7 +2420,7 @@ slider_desc shaders::s_sliders[] = { "Gamma,", -80, 0, 80, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_POWER, 0.1f, "%2.2f", {} }, { "Floor,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_FLOOR, 0.01f, "%2.2f", {} }, { "Phosphor Life,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_PHOSPHOR, 0.01f, "%2.2f", {} }, - { "Bloom Blend Mode", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_BLEND_MODE, 0, "%s", { "Brighten", "Darken" } }, + { "Bloom Blend Mode", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_BLEND_MODE, 0, "%s", { "Brighten", "Darken" } }, { "Bloom Scale", 0, 0, 2000, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_SCALE, 0.001f, "%1.3f", {} }, { "Bloom Overdrive,", 0, 0, 2000, 5, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_OVERDRIVE, 0.001f, "%1.3f", {} }, { "Bloom Level 0 Scale", 0, 100, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_LVL0_SCALE, 0.01f, "%1.2f", {} }, @@ -3153,7 +3153,7 @@ slider_state *renderer_d3d9::get_slider_list() // scheme //------------------------------------------------- -static file_error open_next(renderer_d3d9 *d3d, emu_file &file, const char *templ, const char *extension, int idx) +static osd_file::error open_next(renderer_d3d9 *d3d, emu_file &file, const char *templ, const char *extension, int idx) { UINT32 origflags = file.openflags(); @@ -3280,8 +3280,8 @@ static file_error open_next(renderer_d3d9 *d3d, emu_file &file, const char *temp strreplace(fname.assign(snapstr), "%i", string_format("%04d_%d", seq, idx).c_str()); // try to open the file; stop when we fail - file_error filerr = file.open(fname.c_str()); - if (filerr != FILERR_NONE) + osd_file::error filerr = file.open(fname.c_str()); + if (filerr != osd_file::error::NONE) { break; } diff --git a/src/osd/modules/render/d3d/d3dhlsl.h b/src/osd/modules/render/d3d/d3dhlsl.h index 4ff8b1ac88c..8358efc86e7 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.h +++ b/src/osd/modules/render/d3d/d3dhlsl.h @@ -227,7 +227,7 @@ struct hlsl_options float saturation; // NTSC - int yiq_enable; + int yiq_enable; float yiq_jitter; float yiq_cc; float yiq_a; @@ -264,17 +264,17 @@ struct hlsl_options struct slider_desc { - const char * name; - int minval; - int defval; - int maxval; - int step; - int slider_type; - int screen_type; - int id; - float scale; - const char * format; - std::vector<const char *> strings; + const char * name; + int minval; + int defval; + int maxval; + int step; + int slider_type; + int screen_type; + int id; + float scale; + const char * format; + std::vector<const char *> strings; }; class slider @@ -285,9 +285,9 @@ public: INT32 update(std::string *str, INT32 newval); private: - slider_desc * m_desc; - void * m_value; - bool * m_dirty; + slider_desc * m_desc; + void * m_value; + bool * m_dirty; }; class shaders @@ -402,7 +402,7 @@ private: UINT32 vecbuf_index; UINT32 vecbuf_count; - avi_file * avi_output_file; // AVI file + avi_file::ptr avi_output_file; // AVI file bitmap_rgb32 avi_snap; // AVI snapshot int avi_frame; // AVI frame attotime avi_frame_period; // AVI frame period @@ -450,7 +450,7 @@ private: d3d_render_target * targethead; cache_target * cachehead; - std::vector<slider*> sliders; + std::vector<slider*> sliders; static slider_desc s_sliders[]; static hlsl_options last_options; // last used options diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h index dec4a5c030b..899f024d9f4 100644 --- a/src/osd/osdcore.h +++ b/src/osd/osdcore.h @@ -16,11 +16,16 @@ #pragma once -#ifndef __OSDCORE_H__ -#define __OSDCORE_H__ +#ifndef MAME_OSD_OSDCORE_H +#define MAME_OSD_OSDCORE_H #include "osdcomm.h" -#include <stdarg.h> + +#include <cstdarg> +#include <cstdint> +#include <memory> +#include <string> + /*************************************************************************** FILE I/O INTERFACES @@ -42,194 +47,185 @@ #define OPEN_FLAG_CREATE_PATHS 0x0008 /* create paths as necessary */ #define OPEN_FLAG_NO_PRELOAD 0x0010 /* do not decompress on open */ -/* error codes returned by routines below */ -enum file_error +// osd_file is an interface which represents an open file/PTY/socket +class osd_file { - FILERR_NONE, - FILERR_FAILURE, - FILERR_OUT_OF_MEMORY, - FILERR_NOT_FOUND, - FILERR_ACCESS_DENIED, - FILERR_ALREADY_OPEN, - FILERR_TOO_MANY_FILES, - FILERR_INVALID_DATA, - FILERR_INVALID_ACCESS -}; +public: + // error codes returned by routines below + enum class error + { + NONE, + FAILURE, + OUT_OF_MEMORY, + NOT_FOUND, + ACCESS_DENIED, + ALREADY_OPEN, + TOO_MANY_FILES, + INVALID_DATA, + INVALID_ACCESS + }; -/* osd_file is an opaque type which represents an open file */ -struct osd_file; + typedef std::unique_ptr<osd_file> ptr; -/*----------------------------------------------------------------------------- - osd_open: open a new file. - Parameters: + /*----------------------------------------------------------------------------- + osd_file::open: open a new file. - path - path to the file to open + Parameters: - openflags - some combination of: + path - path to the file to open - OPEN_FLAG_READ - open the file for read access - OPEN_FLAG_WRITE - open the file for write access - OPEN_FLAG_CREATE - create/truncate the file when opening - OPEN_FLAG_CREATE_PATHS - specifies that non-existant paths - should be created if necessary + openflags - some combination of: - file - pointer to an osd_file * to receive the newly-opened file - handle; this is only valid if the function returns FILERR_NONE + OPEN_FLAG_READ - open the file for read access + OPEN_FLAG_WRITE - open the file for write access + OPEN_FLAG_CREATE - create/truncate the file when opening + OPEN_FLAG_CREATE_PATHS - specifies that non-existant paths + should be created if necessary - filesize - pointer to a UINT64 to receive the size of the opened - file; this is only valid if the function returns FILERR_NONE + file - reference to an osd_file::ptr to receive the newly-opened file + handle; this is only valid if the function returns FILERR_NONE - Return value: + filesize - reference to a UINT64 to receive the size of the opened + file; this is only valid if the function returns FILERR_NONE - a file_error describing any error that occurred while opening - the file, or FILERR_NONE if no error occurred + Return value: - Notes: + a file_error describing any error that occurred while opening + the file, or FILERR_NONE if no error occurred - This function is called by core_fopen and several other places in - the core to access files. These functions will construct paths by - concatenating various search paths held in the options.c options - database with partial paths specified by the core. The core assumes - that the path separator is the first character of the string - PATH_SEPARATOR, but does not interpret any path separators in the - search paths, so if you use a different path separator in a search - path, you may get a mixture of PATH_SEPARATORs (from the core) and - alternate path separators (specified by users and placed into the - options database). ------------------------------------------------------------------------------*/ -file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize); + Notes: + This function is called by core_fopen and several other places in + the core to access files. These functions will construct paths by + concatenating various search paths held in the options.c options + database with partial paths specified by the core. The core assumes + that the path separator is the first character of the string + PATH_SEPARATOR, but does not interpret any path separators in the + search paths, so if you use a different path separator in a search + path, you may get a mixture of PATH_SEPARATORs (from the core) and + alternate path separators (specified by users and placed into the + options database). + -----------------------------------------------------------------------------*/ + static error open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize); -/*----------------------------------------------------------------------------- - osd_close: close an open file - Parameters: + /*----------------------------------------------------------------------------- + osd_file::openpty: create a new PTY pair - file - handle to a file previously opened via osd_open + Parameters: - Return value: + file - reference to an osd_file::ptr to receive the handle of the master + side of the newly-created PTY; this is only valid if the function + returns FILERR_NONE - a file_error describing any error that occurred while closing - the file, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_close(osd_file *file); + name - reference to string where slave filename will be stored + Return value: -/*----------------------------------------------------------------------------- - osd_read: read from an open file + a file_error describing any error that occurred while creating the + PTY, or FILERR_NONE if no error occurred + -----------------------------------------------------------------------------*/ + static error openpty(ptr &file, std::string &name); - Parameters: - file - handle to a file previously opened via osd_open + /*----------------------------------------------------------------------------- + osd_file::~osd_file: close an open file + -----------------------------------------------------------------------------*/ + virtual ~osd_file() { } - buffer - pointer to memory that will receive the data read - offset - offset within the file to read from + /*----------------------------------------------------------------------------- + osd_file::read: read from an open file - length - number of bytes to read from the file + Parameters: - actual - pointer to a UINT32 to receive the number of bytes actually - read during the operation; valid only if the function returns - FILERR_NONE + buffer - pointer to memory that will receive the data read - Return value: + offset - offset within the file to read from - a file_error describing any error that occurred while reading - from the file, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_read(osd_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual); + length - number of bytes to read from the file + actual - reference to a UINT32 to receive the number of bytes actually + read during the operation; valid only if the function returns + FILERR_NONE -/*----------------------------------------------------------------------------- - osd_write: write to an open file + Return value: - Parameters: + a file_error describing any error that occurred while reading + from the file, or FILERR_NONE if no error occurred + -----------------------------------------------------------------------------*/ + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) = 0; - file - handle to a file previously opened via osd_open - buffer - pointer to memory that contains the data to write + /*----------------------------------------------------------------------------- + osd_file::write: write to an open file - offset - offset within the file to write to + Parameters: - length - number of bytes to write to the file + buffer - pointer to memory that contains the data to write - actual - pointer to a UINT32 to receive the number of bytes actually - written during the operation; valid only if the function returns - FILERR_NONE + offset - offset within the file to write to - Return value: + length - number of bytes to write to the file - a file_error describing any error that occurred while writing to - the file, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_write(osd_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual); + actual - reference to a UINT32 to receive the number of bytes actually + written during the operation; valid only if the function returns + FILERR_NONE -/*----------------------------------------------------------------------------- - osd_openpty: create a new PTY pair + Return value: - Parameters: + a file_error describing any error that occurred while writing to + the file, or FILERR_NONE if no error occurred + -----------------------------------------------------------------------------*/ + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) = 0; - file - pointer to an osd_file * to receive the handle of the master - side of the newly-created PTY; this is only valid if the function - returns FILERR_NONE - name - pointer to memory where slave filename will be stored + /*----------------------------------------------------------------------------- + osd_file::truncate: change the size of an open file - name_len - space allocated for name + Parameters: - Return value: +. offset - future size of the file - a file_error describing any error that occurred while creating the - PTY, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_openpty(osd_file **file, char *name, size_t name_len); + Return value: -/*----------------------------------------------------------------------------- - osd_truncate: change the size of an open file + a file_error describing any error that occurred while writing to + the file, or FILERR_NONE if no error occurred + -----------------------------------------------------------------------------*/ + virtual error truncate(std::uint64_t offset) = 0; - Parameters: - file - handle to a file previously opened via osd_open + /*----------------------------------------------------------------------------- + osd_file::flush: flush file buffers - offset - future size of the file + Parameters: - Return value: + file - handle to a file previously opened via osd_open - a file_error describing any error that occurred while writing to - the file, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_truncate(osd_file *file, UINT64 offset); + Return value: + a file_error describing any error that occurred while flushing file + buffers, or FILERR_NONE if no error occurred + -----------------------------------------------------------------------------*/ + virtual error flush() = 0; -/*----------------------------------------------------------------------------- - osd_fflus: flush file buffers - Parameters: + /*----------------------------------------------------------------------------- + osd_file::remove: deletes a file - file - handle to a file previously opened via osd_open + Parameters: - Return value: + filename - path to file to delete - a file_error describing any error that occurred while writing to - the file, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_fflush(osd_file *file); - - -/*----------------------------------------------------------------------------- - osd_rmfile: deletes a file - - Parameters: - - filename - path to file to delete + Return value: - Return value: + a file_error describing any error that occurred while deleting + the file, or FILERR_NONE if no error occurred + -----------------------------------------------------------------------------*/ + static error remove(std::string const &filename); +}; - a file_error describing any error that occurred while deleting - the file, or FILERR_NONE if no error occurred ------------------------------------------------------------------------------*/ -file_error osd_rmfile(const char *filename); /*----------------------------------------------------------------------------- @@ -383,7 +379,7 @@ void osd_closedir(osd_directory *dir); non-zero if the path is absolute, zero otherwise -----------------------------------------------------------------------------*/ -int osd_is_absolute_path(const char *path); +bool osd_is_absolute_path(const std::string &path); @@ -812,7 +808,7 @@ char *osd_get_clipboard_text(void); free with osd_free() -----------------------------------------------------------------------------*/ -osd_directory_entry *osd_stat(const char *path); +osd_directory_entry *osd_stat(std::string const &path); /*************************************************************************** PATH INTERFACES @@ -824,14 +820,14 @@ osd_directory_entry *osd_stat(const char *path); Parameters: path - the path in question - dst - pointer to receive new path; the returned string needs to be osd_free()-ed! + dst - reference to receive new path Return value: file error -----------------------------------------------------------------------------*/ -file_error osd_get_full_path(char **dst, const char *path); +osd_file::error osd_get_full_path(std::string &dst, std::string const &path); /*************************************************************************** @@ -882,7 +878,7 @@ const char *osd_get_volume_name(int idx); src - source string -----------------------------------------------------------------------------*/ -void osd_subst_env(char **dst, const char *src); +void osd_subst_env(std::string &dst,std::string const &src); /* ----- output management ----- */ @@ -933,4 +929,4 @@ void CLIB_DECL osd_printf_debug(const char *format, ...) ATTR_PRINTF(1,2); #define printf !MUST_USE_osd_printf_*_CALLS_WITHIN_THE_CORE! */ -#endif /* __OSDEPEND_H__ */ +#endif // MAME_OSD_OSDCORE_H diff --git a/src/osd/osdmini/minidir.cpp b/src/osd/osdmini/minidir.cpp index e061b644cdf..dde1448a694 100644 --- a/src/osd/osdmini/minidir.cpp +++ b/src/osd/osdmini/minidir.cpp @@ -42,14 +42,3 @@ void osd_closedir(osd_directory *dir) // since there are no standard C library routines for walking directories, // we do nothing } - - -//============================================================ -// osd_is_absolute_path -//============================================================ - -int osd_is_absolute_path(const char *path) -{ - // assume no for everything - return FALSE; -} diff --git a/src/osd/osdmini/minifile.cpp b/src/osd/osdmini/minifile.cpp deleted file mode 100644 index b963634da51..00000000000 --- a/src/osd/osdmini/minifile.cpp +++ /dev/null @@ -1,238 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// minifile.c - Minimal core file access functions -// -//============================================================ - -#include "osdcore.h" -#include <stdlib.h> -#include <unistd.h> - - -//============================================================ -// osd_open -//============================================================ - -file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - const char *mode; - FILE *fileptr; - - // based on the flags, choose a mode - if (openflags & OPEN_FLAG_WRITE) - { - if (openflags & OPEN_FLAG_READ) - mode = (openflags & OPEN_FLAG_CREATE) ? "w+b" : "r+b"; - else - mode = "wb"; - } - else if (openflags & OPEN_FLAG_READ) - mode = "rb"; - else - return FILERR_INVALID_ACCESS; - - // open the file - fileptr = fopen(path, mode); - if (fileptr == nullptr) - return FILERR_NOT_FOUND; - - // store the file pointer directly as an osd_file - *file = (osd_file *)fileptr; - - // get the size -- note that most fseek/ftell implementations are limited to 32 bits - fseek(fileptr, 0, SEEK_END); - *filesize = ftell(fileptr); - fseek(fileptr, 0, SEEK_SET); - - return FILERR_NONE; -} - - -//============================================================ -// osd_close -//============================================================ - -file_error osd_close(osd_file *file) -{ - // close the file handle - fclose((FILE *)file); - return FILERR_NONE; -} - - -//============================================================ -// osd_read -//============================================================ - -file_error osd_read(osd_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual) -{ - size_t count; - - // seek to the new location; note that most fseek implementations are limited to 32 bits - fseek((FILE *)file, offset, SEEK_SET); - - // perform the read - count = fread(buffer, 1, length, (FILE *)file); - if (actual != nullptr) - *actual = count; - - return FILERR_NONE; -} - - -//============================================================ -// osd_write -//============================================================ - -file_error osd_write(osd_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual) -{ - size_t count; - - // seek to the new location; note that most fseek implementations are limited to 32 bits - fseek((FILE *)file, offset, SEEK_SET); - - // perform the write - count = fwrite(buffer, 1, length, (FILE *)file); - if (actual != nullptr) - *actual = count; - - return FILERR_NONE; -} - -//============================================================ -// osd_openpty -//============================================================ - -file_error osd_openpty(osd_file **file, char *name, size_t name_len) -{ - return FILERR_FAILURE; -} - -//============================================================ -// osd_truncate -//============================================================ - -file_error osd_truncate(osd_file *file, UINT64 offset) -{ - UINT32 result; - - if (!file) - return FILERR_FAILURE; - - result = ftruncate(fileno((FILE *)file), offset); - if (result) - return FILERR_FAILURE; - - return FILERR_NONE; -} - -//============================================================ -// osd_fflush -//============================================================ - -file_error osd_fflush(osd_file *file) -{ - if (!file) - return FILERR_FAILURE; - - int result = fflush((FILE *)file); - if (result == EOF) - return FILERR_FAILURE; - - return FILERR_NONE; -} - - -//============================================================ -// osd_rmfile -//============================================================ - -file_error osd_rmfile(const char *filename) -{ - return remove(filename) ? FILERR_FAILURE : FILERR_NONE; -} - - -//============================================================ -// osd_get_physical_drive_geometry -//============================================================ - -int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) -{ - // there is no standard way of doing this, so we always return FALSE, indicating - // that a given path is not a physical drive - return FALSE; -} - - -//============================================================ -// osd_uchar_from_osdchar -//============================================================ - -int osd_uchar_from_osdchar(UINT32 /* unicode_char */ *uchar, const char *osdchar, size_t count) -{ - // we assume a standard 1:1 mapping of characters to the first 256 unicode characters - *uchar = (UINT8)*osdchar; - return 1; -} - - -//============================================================ -// osd_stat -//============================================================ - -osd_directory_entry *osd_stat(const char *path) -{ - osd_directory_entry *result = nullptr; - - // create an osd_directory_entry; be sure to make sure that the caller can - // free all resources by just freeing the resulting osd_directory_entry - result = (osd_directory_entry *)osd_malloc_array(sizeof(*result) + strlen(path) + 1); - strcpy((char *)(result + 1), path); - result->name = (char *)(result + 1); - result->type = ENTTYPE_NONE; - result->size = 0; - - FILE *f = fopen(path, "rb"); - if (f != nullptr) - { - fseek(f, 0, SEEK_END); - result->type = ENTTYPE_FILE; - result->size = ftell(f); - fclose(f); - } - return result; -} - - -//============================================================ -// osd_get_full_path -//============================================================ - -file_error osd_get_full_path(char **dst, const char *path) -{ - // derive the full path of the file in an allocated string - // for now just fake it since we don't presume any underlying file system - *dst = nullptr; - if (path != nullptr) - { - *dst = (char *)osd_malloc_array(strlen(path) + 1); - if (*dst != nullptr) - strcpy(*dst, path); - } - - return FILERR_NONE; -} - - -//============================================================ -// osd_get_volume_name -//============================================================ - -const char *osd_get_volume_name(int idx) -{ - // we don't expose volumes - return nullptr; -} diff --git a/src/osd/osdmini/minimisc.cpp b/src/osd/osdmini/minimisc.cpp index 9891447359b..fb4901ca461 100644 --- a/src/osd/osdmini/minimisc.cpp +++ b/src/osd/osdmini/minimisc.cpp @@ -103,9 +103,7 @@ int osd_setenv(const char *name, const char *value, int overwrite) //============================================================ // osd_subst_env //============================================================ -void osd_subst_env(char **dst, const char *src) +void osd_subst_env(std::string &dst, const std::string &src) { - *dst = (char *)osd_malloc_array(strlen(src) + 1); - if (*dst != nullptr) - strcpy(*dst, src); + dst = src; } diff --git a/src/osd/sdl/sdldir.cpp b/src/osd/sdl/sdldir.cpp index 3d5071171d8..439eb0a9792 100644 --- a/src/osd/sdl/sdldir.cpp +++ b/src/osd/sdl/sdldir.cpp @@ -26,6 +26,10 @@ #define _XOPEN_SOURCE 500 #endif +#include <cctype> +#include <cstdlib> +#include <utility> + //#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -234,4 +238,79 @@ void osd_closedir(osd_directory *dir) } +//============================================================ +// osd_subst_env +//============================================================ + +void osd_subst_env(std::string &dst, std::string const &src) +{ + std::string result, var; + auto start = src.begin(); + + // a leading tilde expands as $HOME + if ((src.end() != start) && ('~' == *start)) + { + char const *const home = std::getenv("HOME"); + if (home) + { + ++start; + if ((src.end() == start) || (PATHSEPCH == *start)) + result.append(home); + else + result.push_back('~'); + } + } + + while (src.end() != start) + { + // find $ marking start of environment variable or end of string + auto it = start; + while ((src.end() != it) && ('$' != *it)) ++it; + if (start != it) result.append(start, it); + start = it; + + if (src.end() != start) + { + start = ++it; + if ((src.end() != start) && ('{' == *start)) + { + start = ++it; + for (++it; (src.end() != it) && ('}' != *it); ++it) { } + if (src.end() == it) + { + result.append("${").append(start, it); + start = it; + } + else + { + var.assign(start, it); + start = ++it; + const char *const exp = std::getenv(var.c_str()); + if (exp) + result.append(exp); + else + fprintf(stderr, "Warning: osd_subst_env variable %s not found.\n", var.c_str()); + } + } + else if ((src.end() != start) && (('_' == *start) || std::isalnum(*start))) + { + for (++it; (src.end() != it) && (('_' == *it) || std::isalnum(*it)); ++it) { } + var.assign(start, it); + start = it; + const char *const exp = std::getenv(var.c_str()); + if (exp) + result.append(exp); + else + fprintf(stderr, "Warning: osd_subst_env variable %s not found.\n", var.c_str()); + } + else + { + result.push_back('$'); + } + } + } + + dst = std::move(result); +} + #endif diff --git a/src/osd/sdl/sdlfile.cpp b/src/osd/sdl/sdlfile.cpp deleted file mode 100644 index aa57e3356a0..00000000000 --- a/src/osd/sdl/sdlfile.cpp +++ /dev/null @@ -1,630 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// sdlfile.c - SDL file access functions -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#ifdef SDLMAME_WIN32 -#include "../windows/winfile.cpp" -#include "../windows/winutil.cpp" -#else - -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif - -#ifdef SDLMAME_LINUX -#define __USE_LARGEFILE64 -#endif - -#ifdef SDLMAME_WIN32 -#define _FILE_OFFSET_BITS 64 -#endif - -#ifndef SDLMAME_BSD -#ifdef _XOPEN_SOURCE -#undef _XOPEN_SOURCE -#endif -#define _XOPEN_SOURCE 500 -#endif - -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> - -// MAME headers -#include "sdlfile.h" -#include "modules/lib/osdlib.h" - -//============================================================ -// GLOBAL IDENTIFIERS -//============================================================ - -extern const char *sdlfile_socket_identifier; -extern const char *sdlfile_ptty_identifier; - -//============================================================ -// CONSTANTS -//============================================================ - -#if defined(SDLMAME_WIN32) -#define PATHSEPCH '\\' -#define INVPATHSEPCH '/' -#else -#define PATHSEPCH '/' -#define INVPATHSEPCH '\\' -#endif - -#define NO_ERROR (0) - -//============================================================ -// Prototypes -//============================================================ - -static UINT32 create_path_recursive(char *path); - -//============================================================ -// error_to_file_error -// (does filling this out on non-Windows make any sense?) -//============================================================ - -file_error error_to_file_error(UINT32 error) -{ - switch (error) - { - case ENOENT: - case ENOTDIR: - return FILERR_NOT_FOUND; - - case EACCES: - case EROFS: - #ifndef SDLMAME_WIN32 - case ETXTBSY: - #endif - case EEXIST: - case EPERM: - case EISDIR: - case EINVAL: - return FILERR_ACCESS_DENIED; - - case ENFILE: - case EMFILE: - return FILERR_TOO_MANY_FILES; - - default: - return FILERR_FAILURE; - } -} - - -//============================================================ -// osd_open -//============================================================ - -file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - UINT32 access; - const char *src; - char *dst; - #if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) - struct stat st; - #else - struct stat64 st; - #endif - char *tmpstr; - file_error filerr = FILERR_NONE; - - tmpstr = NULL; - - // allocate a file object, plus space for the converted filename - *file = (osd_file *) osd_malloc_array(sizeof(**file) + sizeof(char) * strlen(path)); - if (*file == NULL) - { - filerr = FILERR_OUT_OF_MEMORY; - goto error; - } - - if (sdl_check_socket_path(path)) - { - (*file)->type = SDLFILE_SOCKET; - filerr = sdl_open_socket(path, openflags, file, filesize); - if(filerr != FILERR_NONE && (*file)->socket != -1) - close((*file)->socket); - goto error; - } - - if (strlen(sdlfile_ptty_identifier) > 0 && strncmp(path, sdlfile_ptty_identifier, strlen(sdlfile_ptty_identifier)) == 0) - { - (*file)->type = SDLFILE_PTTY; - filerr = sdl_open_ptty(path, openflags, file, filesize); - goto error; - } - - (*file)->type = SDLFILE_FILE; - - // convert the path into something compatible - dst = (*file)->filename; - for (src = path; *src != 0; src++) - *dst++ = (*src == INVPATHSEPCH) ? PATHSEPCH : *src; - *dst++ = 0; - - // select the file open modes - if (openflags & OPEN_FLAG_WRITE) - { - access = (openflags & OPEN_FLAG_READ) ? O_RDWR : O_WRONLY; - access |= (openflags & OPEN_FLAG_CREATE) ? (O_CREAT | O_TRUNC) : 0; - } - else if (openflags & OPEN_FLAG_READ) - { - access = O_RDONLY; - } - else - { - filerr = FILERR_INVALID_ACCESS; - goto error; - } - - osd_subst_env(&tmpstr, (*file)->filename); - - #if defined(SDLMAME_WIN32) - access |= O_BINARY; - #endif - - // attempt to open the file - #if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) - (*file)->handle = open(tmpstr, access, 0666); - #else - (*file)->handle = open64(tmpstr, access, 0666); - #endif - if ((*file)->handle == -1) - { - // create the path if necessary - if ((openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS)) - { - char *pathsep = strrchr(tmpstr, PATHSEPCH); - if (pathsep != NULL) - { - int error; - - // create the path up to the file - *pathsep = 0; - error = create_path_recursive(tmpstr); - *pathsep = PATHSEPCH; - - // attempt to reopen the file - if (error == NO_ERROR) - { - #if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) - (*file)->handle = open(tmpstr, access, 0666); - #else - (*file)->handle = open64(tmpstr, access, 0666); - #endif - } - } - } - - // if we still failed, clean up and osd_free - if ((*file)->handle == -1) - { - osd_free(*file); - *file = NULL; - osd_free(tmpstr); - return error_to_file_error(errno); - } - } - - // get the file size - #if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) - fstat((*file)->handle, &st); - #else - fstat64((*file)->handle, &st); - #endif - - *filesize = (UINT64)st.st_size; - -error: - // cleanup - if (filerr != FILERR_NONE && *file != NULL) - { - osd_free(*file); - *file = NULL; - } - if (tmpstr) - osd_free(tmpstr); - return filerr; -} - - -//============================================================ -// osd_read -//============================================================ - -file_error osd_read(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - ssize_t result; - - switch (file->type) - { - case SDLFILE_FILE: -#if defined(SDLMAME_DARWIN) || defined(SDLMAME_BSD) || defined(SDLMAME_EMSCRIPTEN) - result = pread(file->handle, buffer, count, offset); - if (result < 0) -#elif defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) - lseek(file->handle, (UINT32)offset&0xffffffff, SEEK_SET); - result = read(file->handle, buffer, count); - if (result < 0) -#elif defined(SDLMAME_UNIX) - result = pread64(file->handle, buffer, count, offset); - if (result < 0) -#else -#error Unknown SDL SUBARCH! -#endif - return error_to_file_error(errno); - - if (actual != NULL) - *actual = result; - - return FILERR_NONE; - - case SDLFILE_SOCKET: - return sdl_read_socket(file, buffer, offset, count, actual); - - case SDLFILE_PTTY: - return sdl_read_ptty(file, buffer, offset, count, actual); - - default: - return FILERR_FAILURE; - } -} - - -//============================================================ -// osd_write -//============================================================ - -file_error osd_write(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - UINT32 result; - - switch (file->type) - { - case SDLFILE_FILE: -#if defined(SDLMAME_DARWIN) || defined(SDLMAME_BSD) || defined(SDLMAME_EMSCRIPTEN) - result = pwrite(file->handle, buffer, count, offset); - if (!result) -#elif defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) - lseek(file->handle, (UINT32)offset&0xffffffff, SEEK_SET); - result = write(file->handle, buffer, count); - if (!result) -#elif defined(SDLMAME_UNIX) - result = pwrite64(file->handle, buffer, count, offset); - if (!result) -#else -#error Unknown SDL SUBARCH! -#endif - return error_to_file_error(errno); - - if (actual != NULL) - *actual = result; - return FILERR_NONE; - - case SDLFILE_SOCKET: - return sdl_write_socket(file, buffer, offset, count, actual); - - case SDLFILE_PTTY: - return sdl_write_ptty(file, buffer, offset, count, actual); - - default: - return FILERR_FAILURE; - } -} - -//============================================================ -// osd_openpty -//============================================================ - -file_error osd_openpty(osd_file **file, char *name, size_t name_len) -{ - file_error res; - UINT64 filesize; - - if ((res = osd_open(sdlfile_ptty_identifier , 0 , file , &filesize)) != FILERR_NONE) { - return res; - } - - if ((res = sdl_slave_name_ptty(*file , name , name_len)) != FILERR_NONE) { - osd_close(*file); - } - - return res; -} - -//============================================================ -// osd_truncate -//============================================================ - -file_error osd_truncate(osd_file *file, UINT64 offset) -{ - UINT32 result; - - if (!file || !file->handle) - return FILERR_FAILURE; - - switch (file->type) - { - case SDLFILE_FILE: - result = ftruncate(file->handle, offset); - if (result) - return error_to_file_error(errno); - return FILERR_NONE; - - default: - return FILERR_FAILURE; - } -} - -//============================================================ -// osd_truncate -//============================================================ - -file_error osd_fflush(osd_file *file) -{ - if (!file || !file->handle) - return FILERR_FAILURE; - - switch (file->type) - { - case SDLFILE_FILE: - return FILERR_NONE; - - default: - return FILERR_FAILURE; - } -} - - -//============================================================ -// osd_close -//============================================================ - -file_error osd_close(osd_file *file) -{ - // close the file handle and free the file structure - switch (file->type) - { - case SDLFILE_FILE: - close(file->handle); - osd_free(file); - return FILERR_NONE; - - case SDLFILE_SOCKET: - return sdl_close_socket(file); - - case SDLFILE_PTTY: - return sdl_close_ptty(file); - - default: - return FILERR_FAILURE; - } -} - -//============================================================ -// osd_rmfile -//============================================================ - -file_error osd_rmfile(const char *filename) -{ - if (unlink(filename) == -1) - { - return error_to_file_error(errno); - } - - return FILERR_NONE; -} - -//============================================================ -// create_path_recursive -//============================================================ - -static UINT32 create_path_recursive(char *path) -{ - char *sep = strrchr(path, PATHSEPCH); - UINT32 filerr; - struct stat st; - - // if there's still a separator, and it's not the root, nuke it and recurse - if (sep != NULL && sep > path && sep[0] != ':' && sep[-1] != PATHSEPCH) - { - *sep = 0; - filerr = create_path_recursive(path); - *sep = PATHSEPCH; - if (filerr != NO_ERROR) - return filerr; - } - - // if the path already exists, we're done - if (!stat(path, &st)) - return NO_ERROR; - - // create the path - #ifdef SDLMAME_WIN32 - if (mkdir(path) != 0) - #else - if (mkdir(path, 0777) != 0) - #endif - return error_to_file_error(errno); - return NO_ERROR; -} - -//============================================================ -// osd_get_physical_drive_geometry -//============================================================ - -int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) -{ - return FALSE; // no, no way, huh-uh, forget it -} - -//============================================================ -// osd_is_path_separator -//============================================================ - -static int osd_is_path_separator(char c) -{ - return (c == PATHSEPCH) || (c == INVPATHSEPCH); -} - -//============================================================ -// osd_is_absolute_path -//============================================================ - -int osd_is_absolute_path(const char *path) -{ - int result; - - if (osd_is_path_separator(path[0])) - result = TRUE; -#if !defined(SDLMAME_WIN32) - else if (path[0] == '.') - result = TRUE; -#else - #ifndef UNDER_CE - else if (*path && path[1] == ':') - result = TRUE; - #endif -#endif - else - result = FALSE; - - return result; -} - -//============================================================ -// osd_stat -//============================================================ - -osd_directory_entry *osd_stat(const char *path) -{ - int err; - osd_directory_entry *result = NULL; - #if defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_DARWIN) - struct stat st; - #else - struct stat64 st; - #endif - - #if defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_DARWIN) - err = stat(path, &st); - #else - err = stat64(path, &st); - #endif - - if( err == -1) return NULL; - - // create an osd_directory_entry; be sure to make sure that the caller can - // free all resources by just freeing the resulting osd_directory_entry - result = (osd_directory_entry *) osd_malloc_array(sizeof(*result) + strlen(path) + 1); - strcpy(((char *) result) + sizeof(*result), path); - result->name = ((char *) result) + sizeof(*result); - result->type = S_ISDIR(st.st_mode) ? ENTTYPE_DIR : ENTTYPE_FILE; - result->size = (UINT64)st.st_size; - - return result; -} - -//============================================================ -// osd_get_full_path -//============================================================ - -file_error osd_get_full_path(char **dst, const char *path) -{ - file_error err; - char path_buffer[512]; - - err = FILERR_NONE; - - if (getcwd(path_buffer, 511) == NULL) - { - printf("osd_get_full_path: failed!\n"); - err = FILERR_FAILURE; - } - else - { - *dst = (char *)osd_malloc_array(strlen(path_buffer)+strlen(path)+3); - - // if it's already a full path, just pass it through - if (path[0] == '/') - { - strcpy(*dst, path); - } - else - { - sprintf(*dst, "%s%s%s", path_buffer, PATH_SEPARATOR, path); - } - } - - return err; -} - -//============================================================ -// osd_get_volume_name -//============================================================ - -const char *osd_get_volume_name(int idx) -{ - if (idx!=0) return NULL; - return "/"; -} - -//============================================================ -// osd_subst_env -//============================================================ -void osd_subst_env(char **dst, const char *src) -{ - int i, j; - char *envstr; - - osd_free(*dst); - *dst = (char *) osd_malloc_array(strlen(src)+1); - strcpy(*dst, src); - - // start with an environment variable? - if (*dst[0] == '$') - { - envstr = (char *) osd_malloc_array(strlen(src)+1); - strcpy(envstr, src); - - i = 0; - while (!osd_is_path_separator(envstr[i]) && envstr[i] != 0 && envstr[i] != '.') - { - i++; - } - - envstr[i] = '\0'; - - const char *envval = osd_getenv(&envstr[1]); - if (envval != NULL) - { - j = strlen(envval) + strlen(*dst) + 1; - osd_free(*dst); - *dst = (char *) osd_malloc_array(j); - - // start with the value of $HOME - strcpy(*dst, envval); - // replace the null with a path separator again - envstr[i] = PATHSEPCH; - // append it - strcat(*dst, &envstr[i]); - } - else - fprintf(stderr, "Warning: osd_subst_env variable %s not found.\n", envstr); - osd_free(envstr); - } -} -#endif diff --git a/src/osd/sdl/sdlfile.h b/src/osd/sdl/sdlfile.h deleted file mode 100644 index 4bd1b2a6292..00000000000 --- a/src/osd/sdl/sdlfile.h +++ /dev/null @@ -1,51 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// sdlfile.h - SDL file access functions -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#include "osdcore.h" - -//============================================================ -// ENUM DEFINITIONS -//============================================================ -enum -{ - SDLFILE_FILE = 0, - SDLFILE_SOCKET, - SDLFILE_PTTY -}; - -//============================================================ -// TYPE DEFINITIONS -//============================================================ - -struct osd_file -{ - int handle; - int socket; - int type; - char filename[1]; -}; - -//============================================================ -// PROTOTYPES -//============================================================ - -bool sdl_check_socket_path(const char *path); -file_error sdl_open_socket(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize); -file_error sdl_read_socket(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error sdl_write_socket(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error sdl_close_socket(osd_file *file); - -file_error sdl_open_ptty(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize); -file_error sdl_read_ptty(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error sdl_write_ptty(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error sdl_close_ptty(osd_file *file); -file_error sdl_slave_name_ptty(osd_file *file , char *name , size_t name_len); - -file_error error_to_file_error(UINT32 error); diff --git a/src/osd/sdl/sdlptty_unix.cpp b/src/osd/sdl/sdlptty_unix.cpp deleted file mode 100644 index 063b999b75d..00000000000 --- a/src/osd/sdl/sdlptty_unix.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// sdlptty_unix.c - SDL pseudo tty access functions -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#if (!defined(SDLMAME_SOLARIS)) - -#include <sys/types.h> -#include <sys/uio.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#if defined(SDLMAME_FREEBSD) || defined(SDLMAME_DRAGONFLY) -# include <termios.h> -# include <libutil.h> -#elif defined(SDLMAME_NETBSD) || defined(SDLMAME_MACOSX) -# include <termios.h> -# include <util.h> -#elif defined(SDLMAME_OPENBSD) -# include <termios.h> -# include <util.h> -#elif defined(SDLMAME_LINUX) || defined(SDLMAME_EMSCRIPTEN) -# include <pty.h> -#elif defined(SDLMAME_HAIKU) -# include <bsd/pty.h> -#endif -#include <stdlib.h> - -#include "sdlfile.h" - -#if defined(SDLMAME_MACOSX) -const char *sdlfile_ptty_identifier = "/dev/pty"; -#else -const char *sdlfile_ptty_identifier = "/dev/pts"; -#endif - -file_error sdl_open_ptty(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - int master; - int aslave; - struct termios tios; - int oldflags; - - memset(&tios , 0 , sizeof(tios)); - cfmakeraw(&tios); - - if (openpty(&master, &aslave, NULL, &tios, NULL) >= 0) - { - oldflags = fcntl(master, F_GETFL, 0); - if (oldflags == -1) { - close(master); - return FILERR_FAILURE; - } - - fcntl(master, F_SETFL, oldflags | O_NONBLOCK); - close(aslave); - (*file)->handle = master; - *filesize = 0; - } - else - { - return FILERR_ACCESS_DENIED; - } - - return FILERR_NONE; -} - -file_error sdl_read_ptty(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - ssize_t result; - - result = read(file->handle, buffer, count); - - if (result < 0) - { - return error_to_file_error(errno); - } - - if (actual != NULL ) - { - *actual = result; - } - - return FILERR_NONE; -} - -file_error sdl_write_ptty(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - ssize_t result; - result = write(file->handle, buffer, count); - - if (result < 0) - { - return error_to_file_error(errno); - } - - if (actual != NULL ) - { - *actual = result; - } - - return FILERR_NONE; -} - -file_error sdl_close_ptty(osd_file *file) -{ - close(file->handle); - osd_free(file); - - return FILERR_NONE; -} - -file_error sdl_slave_name_ptty(osd_file *file , char *name , size_t name_len) -{ - const char *slave_name = ptsname(file->handle); - - if (slave_name == NULL || strlen(slave_name) >= name_len) { - return FILERR_INVALID_ACCESS; - } - - strcpy(name , slave_name); - - return FILERR_NONE; -} - -#else -#include "sdlfile.h" - -const char *sdlfile_ptty_identifier = ""; - -file_error sdl_open_ptty(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - return FILERR_ACCESS_DENIED; -} - -file_error sdl_read_ptty(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - return FILERR_ACCESS_DENIED; -} - -file_error sdl_write_ptty(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - return FILERR_ACCESS_DENIED; -} - -file_error sdl_close_ptty(osd_file *file) -{ - return FILERR_ACCESS_DENIED; -} - -file_error sdl_slave_name_ptty(osd_file *file) -{ - return FILERR_ACCESS_DENIED; -} - -#endif diff --git a/src/osd/sdl/sdlptty_win32.cpp b/src/osd/sdl/sdlptty_win32.cpp deleted file mode 100644 index fca49a12a99..00000000000 --- a/src/osd/sdl/sdlptty_win32.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// sdlptty_win32 - SDL psuedo tty access functions -// (passthrough to Windows OSD version) -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#include "../windows/winptty.cpp" diff --git a/src/osd/sdl/sdlsocket.cpp b/src/osd/sdl/sdlsocket.cpp deleted file mode 100644 index 5d3e7030deb..00000000000 --- a/src/osd/sdl/sdlsocket.cpp +++ /dev/null @@ -1,193 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// sdlsocket.c - SDL socket (inet) access functions -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#ifdef SDLMAME_WIN32 -#include "../windows/winsocket.cpp" -#else - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/select.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <netdb.h> -#include <errno.h> - -#include "emu.h" -#include "sdlfile.h" - -const char *sdlfile_socket_identifier = "socket."; - -/* - Checks whether the path is a socket specification. A valid socket - specification has the format "socket." host ":" port. Host may be simple - or fully qualified. Port must be between 1 and 65535. -*/ -bool sdl_check_socket_path(const char *path) -{ - if (strlen(sdlfile_socket_identifier) > 0 && - strncmp(path, sdlfile_socket_identifier, strlen(sdlfile_socket_identifier)) == 0 && - strchr(path, ':') != NULL) return true; - return false; -} - -file_error sdl_open_socket(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - char hostname[256]; - struct hostent *localhost; - struct sockaddr_in sai; - int flag = 1; - int port; - - sscanf( path+strlen(sdlfile_socket_identifier), "%255[^:]:%d", hostname, &port ); - -// printf("Connecting to server '%s' on port '%d'\n", hostname, port); - - if (((*file)->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - return FILERR_ACCESS_DENIED; - } - - if (setsockopt((*file)->socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) == -1) - { - return FILERR_ACCESS_DENIED; - } - - localhost = gethostbyname(hostname); - - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = htons(port); - sai.sin_addr = *((struct in_addr *)localhost->h_addr); - - // listening socket support - if (openflags & OPEN_FLAG_CREATE) - { -// printf("Listening for client at '%s' on port '%d'\n", hostname, port); - // bind socket... - if (bind((*file)->socket, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == -1) - { - return FILERR_ACCESS_DENIED; - } - - // start to listen... - if (listen((*file)->socket, 1) == -1) { - return FILERR_ACCESS_DENIED; - } - - // mark socket as "listening" - (*file)->handle = 0; - *filesize = 0; - return FILERR_NONE; - } - -// printf("Connecting to server '%s' on port '%d'\n", hostname, port); - if (connect((*file)->socket, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == -1) - { - return FILERR_ACCESS_DENIED; - } - - *filesize = 0; - (*file)->handle = -1; - return FILERR_NONE; -} - -file_error sdl_read_socket(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ -#if (!defined(SDLMAME_EMSCRIPTEN)) - ssize_t result; - char line[80]; - struct timeval timeout; - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(file->socket, &readfds); - timeout.tv_sec = timeout.tv_usec = 0; - - if (select(file->socket + 1, &readfds, NULL, NULL, &timeout) < 0) - { - sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); - perror(line); - return error_to_file_error(errno); - } - else if (FD_ISSET(file->socket, &readfds)) - { - if (file->handle == -1) - { - // connected socket - result = read(file->socket, buffer, count); - } - else - { - // listening socket - int AcceptSocket; - AcceptSocket = accept(file->socket, NULL, NULL); - if (AcceptSocket < 0) - { - return FILERR_FAILURE; - } - close(file->socket); - file->socket = AcceptSocket; - file->handle = -1; - if (actual != NULL ) - { - *actual = 0; - } - - return FILERR_NONE; - } - } - else - { - return FILERR_FAILURE; - } - - if (result < 0) - { - return error_to_file_error(errno); - } - - if (actual != NULL ) - { - *actual = result; - } -#endif - return FILERR_NONE; -} - -file_error sdl_write_socket(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - ssize_t result; - - result = write(file->socket, buffer, count); - - if (result < 0) - { - return error_to_file_error(errno); - } - - if (actual != NULL ) - { - *actual = result; - } - return FILERR_NONE; -} - -file_error sdl_close_socket(osd_file *file) -{ - close(file->socket); - osd_free(file); - return FILERR_NONE; -} -#endif diff --git a/src/osd/windows/windir.cpp b/src/osd/windows/windir.cpp index 7f172d7338a..edbe688ffe9 100644 --- a/src/osd/windows/windir.cpp +++ b/src/osd/windows/windir.cpp @@ -134,20 +134,3 @@ void osd_closedir(osd_directory *dir) FindClose(dir->find); free(dir); } - - -//============================================================ -// osd_is_absolute_path -//============================================================ - -int osd_is_absolute_path(const char *path) -{ - int result = FALSE; - TCHAR *t_path = tstring_from_utf8(path); - if (t_path != NULL) - { - result = !PathIsRelative(t_path); - osd_free(t_path); - } - return result; -} diff --git a/src/osd/windows/winfile.cpp b/src/osd/windows/winfile.cpp deleted file mode 100644 index 742f97363d6..00000000000 --- a/src/osd/windows/winfile.cpp +++ /dev/null @@ -1,571 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// winfile.c - Win32 OSD core file access functions -// -//============================================================ - -// standard windows headers -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winioctl.h> -#include <tchar.h> -#include <stdlib.h> -#include <ctype.h> - -// MAME headers -#include "osdcore.h" - -// MAMEOS headers -#include "strconv.h" -#include "winutil.h" -#include "winutf8.h" - -#include "winfile.h" - -//============================================================ -// FUNCTION PROTOTYPES -//============================================================ - -static DWORD create_path_recursive(const TCHAR *path); - -//============================================================ -// INLINE FUNCTIONS -//============================================================ - -static inline int is_path_to_physical_drive(const char *path) -{ - return (_strnicmp(path, "\\\\.\\physicaldrive", 17) == 0); -} - -extern const char *winfile_ptty_identifier; - - -//============================================================ -// osd_open -//============================================================ - -file_error osd_open(const char *orig_path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - file_error filerr = FILERR_NONE; - char *path = nullptr; - - osd_subst_env(&path, orig_path); - - // convert path to TCHAR - TCHAR *t_path = tstring_from_utf8(path); - if (t_path == NULL) - { - filerr = FILERR_OUT_OF_MEMORY; - goto error; - } - - // allocate a file object, plus space for the converted filename - *file = (osd_file *)osd_malloc_array(sizeof(**file) + sizeof(TCHAR) * _tcslen(t_path)); - if (*file == NULL) - { - filerr = FILERR_OUT_OF_MEMORY; - goto error; - } - memset(*file, 0x00, sizeof(**file) + sizeof(TCHAR) * _tcslen(t_path)); - - if (win_check_socket_path(path)) - { - (*file)->type = WINFILE_SOCKET; - filerr = win_open_socket(path, openflags, file, filesize); - goto error; - } - - if (strncmp(path, winfile_ptty_identifier, strlen(winfile_ptty_identifier)) == 0) - { - (*file)->type = WINFILE_PTTY; - filerr = win_open_ptty(path, openflags, file, filesize); - goto error; - } - - (*file)->type = WINFILE_FILE; - - // convert the path into something Windows compatible - { - TCHAR *dst = (*file)->filename; - for (TCHAR const *src = t_path; *src != 0; src++) - *dst++ = *src;//(*src == '/') ? '\\' : *src; - *dst++ = 0; - } - - // select the file open modes - DWORD disposition, access, sharemode; - if (openflags & OPEN_FLAG_WRITE) - { - disposition = (!is_path_to_physical_drive(path) && (openflags & OPEN_FLAG_CREATE)) ? CREATE_ALWAYS : OPEN_EXISTING; - access = (openflags & OPEN_FLAG_READ) ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE; - sharemode = FILE_SHARE_READ; - } - else if (openflags & OPEN_FLAG_READ) - { - disposition = OPEN_EXISTING; - access = GENERIC_READ; - sharemode = FILE_SHARE_READ; - } - else - { - filerr = FILERR_INVALID_ACCESS; - goto error; - } - - // attempt to open the file - (*file)->handle = CreateFile((*file)->filename, access, sharemode, NULL, disposition, 0, NULL); - if ((*file)->handle == INVALID_HANDLE_VALUE) - { - DWORD error = GetLastError(); - // create the path if necessary - if (error == ERROR_PATH_NOT_FOUND && (openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS)) - { - TCHAR *pathsep = _tcsrchr((*file)->filename, '\\'); - if (pathsep != NULL) - { - // create the path up to the file - *pathsep = 0; - error = create_path_recursive((*file)->filename); - *pathsep = '\\'; - - // attempt to reopen the file - if (error == NO_ERROR) - (*file)->handle = CreateFile((*file)->filename, access, sharemode, NULL, disposition, 0, NULL); - } - } - - // if we still failed, clean up and free - if ((*file)->handle == INVALID_HANDLE_VALUE) - { - filerr = win_error_to_file_error(error); - goto error; - } - } - - // get the file size - DWORD upper; - *filesize = GetFileSize((*file)->handle, &upper); - *filesize |= (UINT64)upper << 32; - -error: - // cleanup - if (filerr != FILERR_NONE && *file != NULL) - { - osd_free(*file); - *file = NULL; - } - osd_free(t_path); - osd_free(path); - return filerr; -} - - -//============================================================ -// osd_read -//============================================================ - -file_error osd_read(osd_file *file, void *buffer, UINT64 offset, UINT32 length, UINT32 *actual) -{ - LONG upper = offset >> 32; - DWORD result; - - switch (file->type) - { - case WINFILE_FILE: - // attempt to set the file pointer - result = SetFilePointer(file->handle, (UINT32)offset, &upper, FILE_BEGIN); - if (result == INVALID_SET_FILE_POINTER) - { - DWORD error = GetLastError(); - if (error != NO_ERROR) - return win_error_to_mame_file_error(error); - } - - // then perform the read - if (!ReadFile(file->handle, buffer, length, &result, NULL)) - return win_error_to_mame_file_error(GetLastError()); - if (actual != NULL) - *actual = result; - break; - case WINFILE_SOCKET: - return win_read_socket(file, buffer, offset, length, actual); - case WINFILE_PTTY: - return win_read_ptty(file, buffer, offset, length, actual); - - } - return FILERR_NONE; -} - - -//============================================================ -// osd_write -//============================================================ - -file_error osd_write(osd_file *file, const void *buffer, UINT64 offset, UINT32 length, UINT32 *actual) -{ - LONG upper = offset >> 32; - DWORD result; - - switch (file->type) - { - case WINFILE_FILE: - // attempt to set the file pointer - result = SetFilePointer(file->handle, (UINT32)offset, &upper, FILE_BEGIN); - if (result == INVALID_SET_FILE_POINTER) - { - DWORD error = GetLastError(); - if (error != NO_ERROR) - return win_error_to_mame_file_error(error); - } - - // then perform the read - if (!WriteFile(file->handle, buffer, length, &result, NULL)) - return win_error_to_mame_file_error(GetLastError()); - if (actual != NULL) - *actual = result; - break; - case WINFILE_SOCKET: - return win_write_socket(file, buffer, offset, length, actual); - case WINFILE_PTTY: - return win_write_ptty(file, buffer, offset, length, actual); - - } - return FILERR_NONE; -} - -//============================================================ -// osd_openpty -//============================================================ - -file_error osd_openpty(osd_file **file, char *name, size_t name_len) -{ - return FILERR_FAILURE; -} - -//============================================================ -// osd_truncate -//============================================================ - -file_error osd_truncate(osd_file *file, UINT64 offset) -{ - if (!file || !file->handle) - return FILERR_FAILURE; - - DWORD result; - LONG upper = offset >> 32; - - switch (file->type) - { - case WINFILE_FILE: - // attempt to set the file pointer - result = SetFilePointer(file->handle, (UINT32)offset, &upper, FILE_BEGIN); - if (result == INVALID_SET_FILE_POINTER) - { - DWORD error = GetLastError(); - if (error != NO_ERROR) - return win_error_to_mame_file_error(error); - } - - // then perform the truncation - if (!SetEndOfFile(file->handle)) - return win_error_to_mame_file_error(GetLastError()); - break; - case WINFILE_SOCKET: - return FILERR_FAILURE; - case WINFILE_PTTY: - return FILERR_FAILURE; - - } - return FILERR_NONE; -} - -//============================================================ -// osd_fflush -//============================================================ - -file_error osd_fflush(osd_file *file) -{ - if (!file || !file->handle) - return FILERR_FAILURE; - - return FILERR_NONE; -} - - -//============================================================ -// osd_close -//============================================================ - -file_error osd_close(osd_file *file) -{ - file_error result = FILERR_NONE; - - switch (file->type) - { - case WINFILE_FILE: - CloseHandle(file->handle); - break; - case WINFILE_SOCKET: - result = win_close_socket(file); - break; - case WINFILE_PTTY: - result = win_close_ptty(file); - break; - } - - osd_free(file); - return result; -} - - -//============================================================ -// osd_rmfile -//============================================================ - -file_error osd_rmfile(const char *filename) -{ - file_error filerr = FILERR_NONE; - - TCHAR *tempstr = tstring_from_utf8(filename); - if (!tempstr) - { - filerr = FILERR_OUT_OF_MEMORY; - goto done; - } - - if (!DeleteFile(tempstr)) - { - filerr = win_error_to_file_error(GetLastError()); - goto done; - } - -done: - if (tempstr) - osd_free(tempstr); - return filerr; -} - - -//============================================================ -// osd_get_physical_drive_geometry -//============================================================ - -int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps) -{ - DISK_GEOMETRY dg; - DWORD bytesRead; - TCHAR *t_filename; - HANDLE file; - int result; - - // if it doesn't smell like a physical drive, just return FALSE - if (!is_path_to_physical_drive(filename)) - return FALSE; - - // do a create file on the drive - t_filename = tstring_from_utf8(filename); - if (t_filename == NULL) - return FALSE; - file = CreateFile(t_filename, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); - osd_free(t_filename); - if (file == INVALID_HANDLE_VALUE) - return FALSE; - - // device I/O control should return the geometry - result = DeviceIoControl(file, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytesRead, NULL); - CloseHandle(file); - - // if that failed, return false - if (!result) - return FALSE; - - // store the results - *cylinders = (UINT32)dg.Cylinders.QuadPart; - *heads = dg.TracksPerCylinder; - *sectors = dg.SectorsPerTrack; - *bps = dg.BytesPerSector; - - // normalize - while (*heads > 16 && !(*heads & 1)) - { - *heads /= 2; - *cylinders *= 2; - } - return TRUE; -} - - -//============================================================ -// create_path_recursive -//============================================================ - -DWORD create_path_recursive(const TCHAR *path) -{ - TCHAR *sep = (TCHAR *)_tcsrchr(path, '\\'); - - // if there's still a separator, and it's not the root, nuke it and recurse - if (sep != NULL && sep > path && sep[0] != ':' && sep[-1] != '\\') - { - *sep = 0; - create_path_recursive(path); - *sep = '\\'; - } - - // if the path already exists, we're done - if (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES) - return NO_ERROR; - - // create the path - if (CreateDirectory(path, NULL) == 0) - return GetLastError(); - return NO_ERROR; -} - -//============================================================ -// win_error_to_mame_file_error -//============================================================ - -file_error win_error_to_mame_file_error(DWORD error) -{ - file_error filerr; - - // convert a Windows error to a file_error - switch (error) - { - case ERROR_SUCCESS: - filerr = FILERR_NONE; - break; - - case ERROR_OUTOFMEMORY: - filerr = FILERR_OUT_OF_MEMORY; - break; - - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - filerr = FILERR_NOT_FOUND; - break; - - case ERROR_ACCESS_DENIED: - filerr = FILERR_ACCESS_DENIED; - break; - - case ERROR_SHARING_VIOLATION: - filerr = FILERR_ALREADY_OPEN; - break; - - default: - filerr = FILERR_FAILURE; - break; - } - return filerr; -} - -//============================================================ -// osd_stat -//============================================================ - -osd_directory_entry *osd_stat(const char *path) -{ - osd_directory_entry *result = NULL; - TCHAR *t_path; - HANDLE find = INVALID_HANDLE_VALUE; - WIN32_FIND_DATA find_data; - - // convert the path to TCHARs - t_path = tstring_from_utf8(path); - if (t_path == NULL) - goto done; - - // is this path a root directory (e.g. - C:)? - if (isalpha(path[0]) && (path[1] == ':') && (path[2] == '\0')) - { - // need to do special logic for root directories - memset(&find_data, 0, sizeof(find_data)); - find_data.dwFileAttributes = GetFileAttributes(t_path); - } - else - { - // attempt to find the first file - find = FindFirstFile(t_path, &find_data); - if (find == INVALID_HANDLE_VALUE) - goto done; - } - - // create an osd_directory_entry; be sure to make sure that the caller can - // free all resources by just freeing the resulting osd_directory_entry - result = (osd_directory_entry *)osd_malloc_array(sizeof(*result) + strlen(path) + 1); - if (!result) - goto done; - strcpy(((char *) result) + sizeof(*result), path); - result->name = ((char *) result) + sizeof(*result); - result->type = win_attributes_to_entry_type(find_data.dwFileAttributes); - result->size = find_data.nFileSizeLow | ((UINT64) find_data.nFileSizeHigh << 32); - -done: - if (t_path != NULL) - osd_free(t_path); - return result; -} - -//============================================================ -// osd_get_full_path -//============================================================ - -file_error osd_get_full_path(char **dst, const char *path) -{ - file_error err; - TCHAR *t_path; - TCHAR buffer[MAX_PATH]; - - // convert the path to TCHARs - t_path = tstring_from_utf8(path); - if (t_path == NULL) - { - err = FILERR_OUT_OF_MEMORY; - goto done; - } - - // cannonicalize the path - if (!GetFullPathName(t_path, ARRAY_LENGTH(buffer), buffer, NULL)) - { - err = win_error_to_mame_file_error(GetLastError()); - goto done; - } - - // convert the result back to UTF-8 - *dst = utf8_from_tstring(buffer); - if (!*dst) - { - err = FILERR_OUT_OF_MEMORY; - goto done; - } - - err = FILERR_NONE; - -done: - if (t_path != NULL) - osd_free(t_path); - return err; -} - -//============================================================ -// osd_get_volume_name -//============================================================ - -const char *osd_get_volume_name(int idx) -{ - static char szBuffer[128]; - const char *p; - - GetLogicalDriveStringsA(ARRAY_LENGTH(szBuffer), szBuffer); - - p = szBuffer; - while(idx--) { - p += strlen(p) + 1; - if (!*p) return NULL; - } - - return p; -} diff --git a/src/osd/windows/winfile.h b/src/osd/windows/winfile.h deleted file mode 100644 index 51e9acb5e0a..00000000000 --- a/src/osd/windows/winfile.h +++ /dev/null @@ -1,56 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// winfile.h - File access functions -// -//============================================================ -#ifndef __WINFILE__ -#define __WINFILE__ - -#include <winsock2.h> -#include "osdcore.h" - -//============================================================ -// ENUM DEFINITIONS -//============================================================ -enum -{ - WINFILE_FILE = 0, - WINFILE_SOCKET, - WINFILE_PTTY -}; - -//============================================================ -// TYPE DEFINITIONS -//============================================================ - -struct osd_file -{ - HANDLE handle; - SOCKET socket; - int type; - TCHAR filename[1]; -}; - -//============================================================ -// PROTOTYPES -//============================================================ - -bool win_init_sockets(); -void win_cleanup_sockets(); - -bool win_check_socket_path(const char *path); -file_error win_open_socket(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize); -file_error win_read_socket(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error win_write_socket(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error win_close_socket(osd_file *file); - -file_error win_open_ptty(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize); -file_error win_read_ptty(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error win_write_ptty(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual); -file_error win_close_ptty(osd_file *file); - -file_error win_error_to_mame_file_error(DWORD error); - -#endif //__WINFILE__ diff --git a/src/osd/windows/winptty.cpp b/src/osd/windows/winptty.cpp deleted file mode 100644 index d04592d1749..00000000000 --- a/src/osd/windows/winptty.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -#define WIN32_LEAN_AND_MEAN - -#include <windows.h> -#include <stdlib.h> - -#include "winfile.h" -#include "strconv.h" -#include "winutil.h" - -const char *winfile_ptty_identifier = "\\\\.\\pipe\\"; - -file_error win_open_ptty(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - TCHAR *t_name; - HANDLE pipe; - - if((t_name = tstring_from_utf8(path)) == NULL) - return FILERR_OUT_OF_MEMORY; - - pipe = CreateNamedPipe(t_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, NULL); - - osd_free(t_name); - - if(pipe == INVALID_HANDLE_VALUE) - return FILERR_ACCESS_DENIED; - - (*file)->handle = pipe; - *filesize = 0; - return FILERR_NONE; -} - -file_error win_read_ptty(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - BOOL res; - DWORD bytes_read; - - res = ReadFile(file->handle, buffer, count, &bytes_read, NULL); - if(res == FALSE) - return win_error_to_file_error(GetLastError()); - - if(actual != NULL) - *actual = bytes_read; - - return FILERR_NONE; -} - -file_error win_write_ptty(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - BOOL res; - DWORD bytes_wrote; - - res = WriteFile(file->handle, buffer, count, &bytes_wrote, NULL); - if(res == FALSE) - return win_error_to_file_error(GetLastError()); - - if(actual != NULL) - *actual = bytes_wrote; - - return FILERR_NONE; -} - -file_error win_close_ptty(osd_file *file) -{ - FlushFileBuffers(file->handle); - DisconnectNamedPipe(file->handle); - CloseHandle(file->handle); - return FILERR_NONE; -} diff --git a/src/osd/windows/winsocket.cpp b/src/osd/windows/winsocket.cpp deleted file mode 100644 index cfa22dbbcb1..00000000000 --- a/src/osd/windows/winsocket.cpp +++ /dev/null @@ -1,204 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// winsocket.c - Windows socket (inet) access functions -// -//============================================================ -// standard windows headers -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winioctl.h> -#include <tchar.h> -#include <stdlib.h> -#include <ctype.h> - -// MAME headers -#include "osdcore.h" - -#include "winfile.h" - -const char *winfile_socket_identifier = "socket."; - -bool win_init_sockets() -{ - WSADATA wsaData; - WORD version; - int error; - - version = MAKEWORD( 2, 0 ); - - error = WSAStartup( version, &wsaData ); - - /* check for error */ - if ( error != 0 ) - { - /* error occurred */ - return FALSE; - } - - - /* check for correct version */ - if ( LOBYTE( wsaData.wVersion ) != 2 || - HIBYTE( wsaData.wVersion ) != 0 ) - { - /* incorrect WinSock version */ - WSACleanup(); - return FALSE; - } - /* WinSock has been initialized */ - return TRUE; -} - -void win_cleanup_sockets() -{ - WSACleanup(); -} - -bool win_check_socket_path(const char *path) -{ - if (strlen(winfile_socket_identifier) > 0 && - strncmp(path, winfile_socket_identifier, strlen(winfile_socket_identifier)) == 0 && - strchr(path, ':') != nullptr) return true; - return false; -} - -file_error win_open_socket(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize) -{ - char hostname[256]; - struct hostent *localhost; - struct sockaddr_in sai; - int flag = 1; - int port; - - sscanf( path+strlen(winfile_socket_identifier), "%255[^:]:%d", hostname, &port ); - - if (((*file)->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - return FILERR_ACCESS_DENIED; - } - - if (setsockopt((*file)->socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) == -1) - { - return FILERR_ACCESS_DENIED; - } - localhost = gethostbyname(hostname); - - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = htons(port); - sai.sin_addr = *((struct in_addr *)localhost->h_addr); - - // listening socket support - if (openflags & OPEN_FLAG_CREATE) - { -// printf("Listening for client at '%s' on port '%d'\n", hostname, port); - // bind socket... - if (bind((*file)->socket, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == -1) - { - return FILERR_ACCESS_DENIED; - } - - // start to listen... - if (listen((*file)->socket, 1) == -1) { - return FILERR_ACCESS_DENIED; - } - - // mark socket as "listening" - (*file)->handle = nullptr; - *filesize = 0; - return FILERR_NONE; - } - -// printf("Connecting to server '%s' on port '%d'\n", hostname, port); - if (connect((*file)->socket, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == -1) - { - return FILERR_ACCESS_DENIED; - } - *filesize = 0; - (*file)->handle = INVALID_HANDLE_VALUE; - return FILERR_NONE; -} - -file_error win_read_socket(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - int result; - char line[80]; - struct timeval timeout; - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(file->socket, &readfds); - timeout.tv_sec = timeout.tv_usec = 0; - - if (select(file->socket + 1, &readfds, nullptr, nullptr, &timeout) < 0) - { - sprintf(line, "win_read_socket : %s : %d ", __FILE__, __LINE__); - perror(line); - return win_error_to_mame_file_error(GetLastError()); - } - else if (FD_ISSET(file->socket, &readfds)) - { - if (file->handle == INVALID_HANDLE_VALUE) - { - // connected socket - result = recv(file->socket, (char*)buffer, count, 0); - } - else - { - // listening socket - SOCKET AcceptSocket; - AcceptSocket = accept(file->socket, nullptr, nullptr); - if (AcceptSocket == INVALID_SOCKET) - { - return FILERR_FAILURE; - } - closesocket(file->socket); - file->socket = AcceptSocket; - file->handle = INVALID_HANDLE_VALUE; - if (actual != nullptr ) - { - *actual = 0; - } - - return FILERR_NONE; - } - } - else - { - return FILERR_FAILURE; - } - - if (result < 0) - { - return win_error_to_mame_file_error(GetLastError()); - } - - if (actual != nullptr ) - { - *actual = result; - } - return FILERR_NONE; -} - -file_error win_write_socket(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual) -{ - int result; - result = send(file->socket, (const char*)buffer, count, 0); - if (result < 0) - { - return win_error_to_mame_file_error(GetLastError()); - } - - if (actual != nullptr ) - { - *actual = result; - } - return FILERR_NONE; -} - -file_error win_close_socket(osd_file *file) -{ - closesocket(file->socket); - return FILERR_NONE; -} diff --git a/src/osd/windows/winutil.cpp b/src/osd/windows/winutil.cpp index eb63eecacd0..ff162c9169a 100644 --- a/src/osd/windows/winutil.cpp +++ b/src/osd/windows/winutil.cpp @@ -18,47 +18,6 @@ #include "winutil.h" #include "strconv.h" -//============================================================ -// win_error_to_file_error -//============================================================ - -file_error win_error_to_file_error(DWORD error) -{ - file_error filerr; - - // convert a Windows error to a file_error - switch (error) - { - case ERROR_SUCCESS: - filerr = FILERR_NONE; - break; - - case ERROR_OUTOFMEMORY: - filerr = FILERR_OUT_OF_MEMORY; - break; - - case ERROR_FILE_NOT_FOUND: - case ERROR_FILENAME_EXCED_RANGE: - case ERROR_PATH_NOT_FOUND: - filerr = FILERR_NOT_FOUND; - break; - - case ERROR_ACCESS_DENIED: - filerr = FILERR_ACCESS_DENIED; - break; - - case ERROR_SHARING_VIOLATION: - filerr = FILERR_ALREADY_OPEN; - break; - - default: - filerr = FILERR_FAILURE; - break; - } - return filerr; -} - - //============================================================ // win_attributes_to_entry_type diff --git a/src/osd/windows/winutil.h b/src/osd/windows/winutil.h index 530327dcf61..6cb8297c277 100644 --- a/src/osd/windows/winutil.h +++ b/src/osd/windows/winutil.h @@ -14,7 +14,6 @@ #include <vector> // Shared code -file_error win_error_to_file_error(DWORD error); osd_dir_entry_type win_attributes_to_entry_type(DWORD attributes); BOOL win_is_gui_application(void); HMODULE WINAPI GetModuleHandleUni(); @@ -26,10 +25,10 @@ HMODULE WINAPI GetModuleHandleUni(); class lazy_loaded_function { private: - std::string m_name; - std::vector<std::wstring> m_dll_names; - HMODULE m_module; - bool m_initialized; + std::string m_name; + std::vector<std::wstring> m_dll_names; + HMODULE m_module; + bool m_initialized; protected: void check_init(); diff --git a/src/tools/chdman.cpp b/src/tools/chdman.cpp index 1a80bc76e13..6029f481e07 100644 --- a/src/tools/chdman.cpp +++ b/src/tools/chdman.cpp @@ -331,8 +331,8 @@ public: { m_file.reset(); m_lastfile = m_info.track[tracknum].fname; - file_error filerr = util::core_file::open(m_lastfile.c_str(), OPEN_FLAG_READ, m_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open(m_lastfile.c_str(), OPEN_FLAG_READ, m_file); + if (filerr != osd_file::error::NONE) report_error(1, "Error opening input file (%s)'", m_lastfile.c_str()); } @@ -438,15 +438,15 @@ public: // read the sound samples m_audio[chnum].resize(samples); samplesptr[chnum] = &m_audio[chnum][0]; - avi_error avierr = avi_read_sound_samples(&m_file, chnum, first_sample, samples, &m_audio[chnum][0]); - if (avierr != AVIERR_NONE) - report_error(1, "Error reading audio samples %d-%d from channel %d: %s", first_sample, samples, chnum, avi_error_string(avierr)); + avi_file::error avierr = m_file.read_sound_samples(chnum, first_sample, samples, &m_audio[chnum][0]); + if (avierr != avi_file::error::NONE) + report_error(1, "Error reading audio samples %d-%d from channel %d: %s", first_sample, samples, chnum, avi_file::error_string(avierr)); } // read the video data - avi_error avierr = avi_read_video_frame(&m_file, effframe / interlace_factor, m_bitmap); - if (avierr != AVIERR_NONE) - report_error(1, "Error reading AVI frame %d: %s", effframe / interlace_factor, avi_error_string(avierr)); + avi_file::error avierr = m_file.read_video_frame(effframe / interlace_factor, m_bitmap); + if (avierr != avi_file::error::NONE) + report_error(1, "Error reading AVI frame %d: %s", effframe / interlace_factor, avi_file::error_string(avierr)); bitmap_yuy16 subbitmap(&m_bitmap.pix(effframe % interlace_factor), m_bitmap.width(), m_bitmap.height() / interlace_factor, m_bitmap.rowpixels() * interlace_factor); // update metadata for this frame @@ -1007,8 +1007,8 @@ static void check_existing_output_file(const parameters_t ¶ms, const char *f if (params.find(OPTION_OUTPUT_FORCE) == params.end()) { util::core_file::ptr file; - file_error filerr = util::core_file::open(filename, OPEN_FLAG_READ, file); - if (filerr == FILERR_NONE) + osd_file::error filerr = util::core_file::open(filename, OPEN_FLAG_READ, file); + if (filerr == osd_file::error::NONE) { file.reset(); report_error(1, "Error: file already exists (%s)\nUse --force (or -f) to force overwriting", filename); @@ -1572,8 +1572,8 @@ static void do_create_raw(parameters_t ¶ms) auto input_file_str = params.find(OPTION_INPUT); if (input_file_str != params.end()) { - file_error filerr = util::core_file::open(input_file_str->second->c_str(), OPEN_FLAG_READ, input_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open(input_file_str->second->c_str(), OPEN_FLAG_READ, input_file); + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", input_file_str->second->c_str()); } @@ -1651,7 +1651,7 @@ static void do_create_raw(parameters_t ¶ms) // delete the output file auto output_chd_str = params.find(OPTION_OUTPUT); if (output_chd_str != params.end()) - osd_rmfile(output_chd_str->second->c_str()); + osd_file::remove(*output_chd_str->second); throw; } } @@ -1669,8 +1669,8 @@ static void do_create_hd(parameters_t ¶ms) auto input_file_str = params.find(OPTION_INPUT); if (input_file_str != params.end()) { - file_error filerr = util::core_file::open(input_file_str->second->c_str(), OPEN_FLAG_READ, input_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open(input_file_str->second->c_str(), OPEN_FLAG_READ, input_file); + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", input_file_str->second->c_str()); } @@ -1744,8 +1744,8 @@ static void do_create_hd(parameters_t ¶ms) if (ident_str != params.end()) { // load the file - file_error filerr = util::core_file::load(ident_str->second->c_str(), identdata); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::load(ident_str->second->c_str(), identdata); + if (filerr != osd_file::error::NONE) report_error(1, "Error reading ident file (%s)", ident_str->second->c_str()); // must be at least 14 bytes; extract CHS data from there @@ -1840,7 +1840,7 @@ static void do_create_hd(parameters_t ¶ms) // delete the output file auto output_chd_str = params.find(OPTION_OUTPUT); if (output_chd_str != params.end()) - osd_rmfile(output_chd_str->second->c_str()); + osd_file::remove(*output_chd_str->second); throw; } } @@ -1932,7 +1932,7 @@ static void do_create_cd(parameters_t ¶ms) // delete the output file auto output_chd_str = params.find(OPTION_OUTPUT); if (output_chd_str != params.end()) - osd_rmfile(output_chd_str->second->c_str()); + osd_file::remove(*output_chd_str->second); throw; } } @@ -1946,15 +1946,15 @@ static void do_create_cd(parameters_t ¶ms) static void do_create_ld(parameters_t ¶ms) { // process input file - avi_file *input_file = nullptr; + avi_file::ptr input_file; auto input_file_str = params.find(OPTION_INPUT); if (input_file_str != params.end()) { - avi_error avierr = avi_open(input_file_str->second->c_str(), &input_file); - if (avierr != AVIERR_NONE) - report_error(1, "Error opening AVI file (%s): %s\n", input_file_str->second->c_str(), avi_error_string(avierr)); + avi_file::error avierr = avi_file::open(*input_file_str->second, input_file); + if (avierr != avi_file::error::NONE) + report_error(1, "Error opening AVI file (%s): %s\n", input_file_str->second->c_str(), avi_file::error_string(avierr)); } - const avi_movie_info *aviinfo = avi_get_movie_info(input_file); + const avi_file::movie_info &aviinfo = input_file->get_movie_info(); // process output CHD chd_file output_parent; @@ -1963,16 +1963,16 @@ static void do_create_ld(parameters_t ¶ms) // process input start/end UINT64 input_start; UINT64 input_end; - parse_input_start_end(params, aviinfo->video_numsamples, 0, 1, input_start, input_end); + parse_input_start_end(params, aviinfo.video_numsamples, 0, 1, input_start, input_end); // determine parameters of the incoming video stream avi_info info; - info.fps_times_1million = UINT64(aviinfo->video_timescale) * 1000000 / aviinfo->video_sampletime; - info.width = aviinfo->video_width; - info.height = aviinfo->video_height; + info.fps_times_1million = UINT64(aviinfo.video_timescale) * 1000000 / aviinfo.video_sampletime; + info.width = aviinfo.video_width; + info.height = aviinfo.video_height; info.interlaced = ((info.fps_times_1million / 1000000) <= 30) && (info.height % 2 == 0) && (info.height > 288); - info.channels = aviinfo->audio_channels; - info.rate = aviinfo->audio_samplerate; + info.channels = aviinfo.audio_channels; + info.rate = aviinfo.audio_samplerate; // adjust for interlacing if (info.interlaced) @@ -2008,7 +2008,7 @@ static void do_create_ld(parameters_t ¶ms) if (output_parent.opened()) printf("Parent CHD: %s\n", params.find(OPTION_OUTPUT_PARENT)->second->c_str()); printf("Input file: %s\n", input_file_str->second->c_str()); - if (input_start != 0 && input_end != aviinfo->video_numsamples) + if (input_start != 0 && input_end != aviinfo.video_numsamples) printf("Input start: %s\n", big_int_string(tempstr, input_start)); printf("Input length: %s (%02d:%02d:%02d)\n", big_int_string(tempstr, input_end - input_start), UINT32((UINT64(input_end - input_start) * 1000000 / info.fps_times_1million / 60 / 60)), @@ -2059,7 +2059,7 @@ static void do_create_ld(parameters_t ¶ms) // delete the output file auto output_chd_str = params.find(OPTION_OUTPUT); if (output_chd_str != params.end()) - osd_rmfile(output_chd_str->second->c_str()); + osd_file::remove(*output_chd_str->second); throw; } } @@ -2195,7 +2195,7 @@ static void do_copy(parameters_t ¶ms) // delete the output file auto output_chd_str = params.find(OPTION_OUTPUT); if (output_chd_str != params.end()) - osd_rmfile(output_chd_str->second->c_str()); + osd_file::remove(*output_chd_str->second); throw; } } @@ -2238,8 +2238,8 @@ static void do_extract_raw(parameters_t ¶ms) try { // process output file - file_error filerr = util::core_file::open(output_file_str->second->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open(output_file_str->second->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); // copy all data @@ -2273,7 +2273,7 @@ static void do_extract_raw(parameters_t ¶ms) if (output_file != nullptr) { output_file.reset(); - osd_rmfile(output_file_str->second->c_str()); + osd_file::remove(*output_file_str->second); } throw; } @@ -2343,15 +2343,15 @@ static void do_extract_cd(parameters_t ¶ms) } // process output file - file_error filerr = util::core_file::open(output_file_str->second->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, output_toc_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open(output_file_str->second->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, output_toc_file); + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); // process output BIN file if (mode != MODE_GDI) { filerr = util::core_file::open(output_bin_file_str->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_bin_file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", output_bin_file_str->c_str()); } @@ -2387,7 +2387,7 @@ static void do_extract_cd(parameters_t ¶ms) output_bin_file.reset(); filerr = util::core_file::open(trackbin_name.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_bin_file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", trackbin_name.c_str()); outputoffs = 0; @@ -2471,8 +2471,8 @@ static void do_extract_cd(parameters_t ¶ms) // delete the output files output_bin_file.reset(); output_toc_file.reset(); - osd_rmfile(output_bin_file_str->c_str()); - osd_rmfile(output_file_str->second->c_str()); + osd_file::remove(*output_bin_file_str); + osd_file::remove(*output_file_str->second); throw; } } @@ -2528,7 +2528,7 @@ static void do_extract_ld(parameters_t ¶ms) input_end *= interlace_factor; // build up the movie info - avi_movie_info info; + avi_file::movie_info info; info.video_format = FORMAT_YUY2; info.video_timescale = fps_times_1million / interlace_factor; info.video_sampletime = 1000000; @@ -2558,12 +2558,12 @@ static void do_extract_ld(parameters_t ¶ms) } // catch errors so we can close & delete the output file - avi_file *output_file = nullptr; + avi_file::ptr output_file; try { // process output file - avi_error avierr = avi_create(output_file_str->second->c_str(), &info, &output_file); - if (avierr != AVIERR_NONE) + avi_file::error avierr = avi_file::create(*output_file_str->second, info, output_file); + if (avierr != avi_file::error::NONE) report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); // create the codec configuration @@ -2599,30 +2599,29 @@ static void do_extract_ld(parameters_t ¶ms) // write audio for (int chnum = 0; chnum < channels; chnum++) { - avi_error avierr = avi_append_sound_samples(output_file, chnum, avconfig.audio[chnum], actsamples, 0); - if (avierr != AVIERR_NONE) - report_error(1, "Error writing samples for hunk %d to file (%s): %s\n", framenum, output_file_str->second->c_str(), avi_error_string(avierr)); + avi_file::error avierr = output_file->append_sound_samples(chnum, avconfig.audio[chnum], actsamples, 0); + if (avierr != avi_file::error::NONE) + report_error(1, "Error writing samples for hunk %d to file (%s): %s\n", framenum, output_file_str->second->c_str(), avi_file::error_string(avierr)); } // write video if ((framenum + 1) % interlace_factor == 0) { - avi_error avierr = avi_append_video_frame(output_file, fullbitmap); - if (avierr != AVIERR_NONE) - report_error(1, "Error writing video for hunk %d to file (%s): %s\n", framenum, output_file_str->second->c_str(), avi_error_string(avierr)); + avi_file::error avierr = output_file->append_video_frame(fullbitmap); + if (avierr != avi_file::error::NONE) + report_error(1, "Error writing video for hunk %d to file (%s): %s\n", framenum, output_file_str->second->c_str(), avi_file::error_string(avierr)); } } // close and return - avi_close(output_file); + output_file.reset(); printf("Extraction complete \n"); } catch (...) { // delete the output file - if (output_file != nullptr) - avi_close(output_file); - osd_rmfile(output_file_str->second->c_str()); + output_file.reset(); + osd_file::remove(*output_file_str->second); throw; } } @@ -2670,8 +2669,8 @@ static void do_add_metadata(parameters_t ¶ms) dynamic_buffer file; if (file_str != params.end()) { - file_error filerr = util::core_file::load(file_str->second->c_str(), file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::load(file_str->second->c_str(), file); + if (filerr != osd_file::error::NONE) report_error(1, "Error reading metadata file (%s)", file_str->second->c_str()); } @@ -2794,8 +2793,8 @@ static void do_dump_metadata(parameters_t ¶ms) // create the file if (output_file_str != params.end()) { - file_error filerr = util::core_file::open(output_file_str->second->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); - if (filerr != FILERR_NONE) + osd_file::error filerr = util::core_file::open(output_file_str->second->c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, output_file); + if (filerr != osd_file::error::NONE) report_error(1, "Unable to open file (%s)", output_file_str->second->c_str()); // output the metadata @@ -2820,7 +2819,7 @@ static void do_dump_metadata(parameters_t ¶ms) { // delete the output file output_file.reset(); - osd_rmfile(output_file_str->second->c_str()); + osd_file::remove(*output_file_str->second); throw; } } diff --git a/src/tools/imgtool/stream.cpp b/src/tools/imgtool/stream.cpp index 4cc4c9ec2db..d96cf325a7a 100644 --- a/src/tools/imgtool/stream.cpp +++ b/src/tools/imgtool/stream.cpp @@ -104,33 +104,27 @@ static imgtool_stream *stream_open_zip(const char *zipname, const char *subname, imgfile->imgtype = IMG_MEM; - zip_file *z = nullptr; - const zip_file_header *zipent = nullptr; - zip_file_open(zipname, &z); + zip_file::ptr z; + const zip_file::file_header *zipent = nullptr; + zip_file::open(zipname, z); if (!z) - goto error; + return nullptr; - zipent = zip_file_first_file(z); + zipent = z->first_file(); while (zipent && subname && strcmp(subname, zipent->filename)) - zipent = zip_file_next_file(z); + zipent = z->next_file(); if (!zipent) - goto error; + return nullptr; imgfile->filesize = zipent->uncompressed_length; imgfile->buffer = reinterpret_cast<std::uint8_t *>(malloc(zipent->uncompressed_length)); if (!imgfile->buffer) - goto error; + return nullptr; - if (zip_file_decompress(z, imgfile->buffer, zipent->uncompressed_length)) - goto error; + if (z->decompress(imgfile->buffer, zipent->uncompressed_length) != zip_file::error::NONE) + return nullptr; - zip_file_close(z); return imgfile.release(); - -error: - if (z) - zip_file_close(z); - return nullptr; } @@ -154,7 +148,7 @@ imgtool_stream *stream_open(const char *fname, int read_or_write) util::core_file::ptr f = nullptr; auto const filerr = util::core_file::open(fname, write_modes[read_or_write], f); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { if (!read_or_write) { diff --git a/src/tools/ldverify.cpp b/src/tools/ldverify.cpp index ab3947dfaea..45c20d9d70c 100644 --- a/src/tools/ldverify.cpp +++ b/src/tools/ldverify.cpp @@ -102,23 +102,23 @@ static bool chdinterlaced; static void *open_avi(const char *filename, movie_info &info) { // open the file - avi_file *avi; - avi_error avierr = avi_open(filename, &avi); - if (avierr != AVIERR_NONE) + avi_file::ptr avi; + avi_file::error avierr = avi_file::open(filename, avi); + if (avierr != avi_file::error::NONE) { - fprintf(stderr, "Error opening AVI file: %s\n", avi_error_string(avierr)); + fprintf(stderr, "Error opening AVI file: %s\n", avi_file::error_string(avierr)); return nullptr; } // extract movie info - const avi_movie_info *aviinfo = avi_get_movie_info(avi); - info.framerate = (double)aviinfo->video_timescale / (double)aviinfo->video_sampletime; - info.numframes = aviinfo->video_numsamples; - info.width = aviinfo->video_width; - info.height = aviinfo->video_height; - info.samplerate = aviinfo->audio_samplerate; - info.channels = aviinfo->audio_channels; - return avi; + const avi_file::movie_info &aviinfo = avi->get_movie_info(); + info.framerate = (double)aviinfo.video_timescale / (double)aviinfo.video_sampletime; + info.numframes = aviinfo.video_numsamples; + info.width = aviinfo.video_width; + info.height = aviinfo.video_height; + info.samplerate = aviinfo.audio_samplerate; + info.channels = aviinfo.audio_channels; + return avi.release(); } @@ -131,17 +131,17 @@ static bool read_avi(void *file, int frame, bitmap_yuy16 &bitmap, INT16 *lsound, avi_file *avifile = reinterpret_cast<avi_file *>(file); // read the frame - avi_error avierr = avi_read_video_frame(avifile, frame, bitmap); - if (avierr != AVIERR_NONE) + avi_file::error avierr = avifile->read_video_frame(frame, bitmap); + if (avierr != avi_file::error::NONE) return FALSE; // read the samples - const avi_movie_info *aviinfo = avi_get_movie_info(avifile); - UINT32 firstsample = (UINT64(aviinfo->audio_samplerate) * UINT64(frame) * UINT64(aviinfo->video_sampletime) + aviinfo->video_timescale - 1) / UINT64(aviinfo->video_timescale); - UINT32 lastsample = (UINT64(aviinfo->audio_samplerate) * UINT64(frame + 1) * UINT64(aviinfo->video_sampletime) + aviinfo->video_timescale - 1) / UINT64(aviinfo->video_timescale); - avierr = avi_read_sound_samples(avifile, 0, firstsample, lastsample - firstsample, lsound); - avierr = avi_read_sound_samples(avifile, 1, firstsample, lastsample - firstsample, rsound); - if (avierr != AVIERR_NONE) + const avi_file::movie_info &aviinfo = avifile->get_movie_info(); + UINT32 firstsample = (UINT64(aviinfo.audio_samplerate) * UINT64(frame) * UINT64(aviinfo.video_sampletime) + aviinfo.video_timescale - 1) / UINT64(aviinfo.video_timescale); + UINT32 lastsample = (UINT64(aviinfo.audio_samplerate) * UINT64(frame + 1) * UINT64(aviinfo.video_sampletime) + aviinfo.video_timescale - 1) / UINT64(aviinfo.video_timescale); + avierr = avifile->read_sound_samples(0, firstsample, lastsample - firstsample, lsound); + avierr = avifile->read_sound_samples(1, firstsample, lastsample - firstsample, rsound); + if (avierr != avi_file::error::NONE) return false; samples = lastsample - firstsample; return true; @@ -155,7 +155,7 @@ static bool read_avi(void *file, int frame, bitmap_yuy16 &bitmap, INT16 *lsound, static void close_avi(void *file) { avi_file *avifile = reinterpret_cast<avi_file *>(file); - avi_close(avifile); + delete avifile; } diff --git a/src/tools/pngcmp.cpp b/src/tools/pngcmp.cpp index 5103740389b..aa33a421e5d 100644 --- a/src/tools/pngcmp.cpp +++ b/src/tools/pngcmp.cpp @@ -73,7 +73,7 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img bitmap_argb32 finalbitmap; int width, height, maxwidth; util::core_file::ptr file; - file_error filerr; + osd_file::error filerr; png_error pngerr; int error = 100; bool bitmaps_differ; @@ -81,9 +81,9 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img /* open the source image */ filerr = util::core_file::open(imgfile1.c_str(), OPEN_FLAG_READ, file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { - printf("Could not open %s (%d)\n", imgfile1.c_str(), filerr); + printf("Could not open %s (%d)\n", imgfile1.c_str(), int(filerr)); goto error; } @@ -98,9 +98,9 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img /* open the source image */ filerr = util::core_file::open(imgfile2.c_str(), OPEN_FLAG_READ, file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { - printf("Could not open %s (%d)\n", imgfile2.c_str(), filerr); + printf("Could not open %s (%d)\n", imgfile2.c_str(), int(filerr)); goto error; } @@ -171,9 +171,9 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img /* write the final PNG */ filerr = util::core_file::open(outfilename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { - printf("Could not open %s (%d)\n", outfilename.c_str(), filerr); + printf("Could not open %s (%d)\n", outfilename.c_str(), int(filerr)); goto error; } pngerr = png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); @@ -193,6 +193,6 @@ static int generate_png_diff(const std::string& imgfile1, const std::string& img error: if (error == -1) - osd_rmfile(outfilename.c_str()); + osd_file::remove(outfilename); return error; } diff --git a/src/tools/regrep.cpp b/src/tools/regrep.cpp index b0cad2497ae..4d02151672b 100644 --- a/src/tools/regrep.cpp +++ b/src/tools/regrep.cpp @@ -235,7 +235,7 @@ int main(int argc, char *argv[]) /* read the template file into an astring */ std::string tempheader; - if (util::core_file::load(tempfilename.c_str(), &buffer, bufsize) == FILERR_NONE) + if (util::core_file::load(tempfilename.c_str(), &buffer, bufsize) == osd_file::error::NONE) { tempheader.assign((const char *)buffer, bufsize); osd_free(buffer); @@ -565,7 +565,7 @@ static util::core_file::ptr create_file_and_output_header(std::string &filename, util::core_file::ptr file; /* create the indexfile */ - if (util::core_file::open(filename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file) != FILERR_NONE) + if (util::core_file::open(filename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file) != osd_file::error::NONE) return util::core_file::ptr(); /* print a header */ @@ -728,7 +728,7 @@ static int compare_screenshots(summary_file *curfile) if (curfile->status[listnum] == STATUS_SUCCESS) { std::string fullname; - file_error filerr; + osd_file::error filerr; util::core_file::ptr file; /* get the filename for the image */ @@ -738,7 +738,7 @@ static int compare_screenshots(summary_file *curfile) filerr = util::core_file::open(fullname.c_str(), OPEN_FLAG_READ, file); /* if that failed, look in the old location */ - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { /* get the filename for the image */ fullname = string_format("%s" PATH_SEPARATOR "snap" PATH_SEPARATOR "_%s.png", lists[listnum].dir, curfile->name); @@ -748,7 +748,7 @@ static int compare_screenshots(summary_file *curfile) } /* if that worked, load the file */ - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { png_read_bitmap(*file, bitmaps[listnum]); file.reset(); @@ -837,7 +837,7 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, int bitmapcount = 0; int listnum, bmnum; util::core_file::ptr file; - file_error filerr; + osd_file::error filerr; png_error pngerr; int error = -1; int starty; @@ -854,7 +854,7 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, /* open the source image */ filerr = util::core_file::open(tempname.c_str(), OPEN_FLAG_READ, file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) goto error; /* load the source image */ @@ -926,7 +926,7 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, /* write the final PNG */ filerr = util::core_file::open(dstfilename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) goto error; pngerr = png_write_bitmap(*file, nullptr, finalbitmap, 0, nullptr); file.reset(); @@ -938,7 +938,7 @@ static int generate_png_diff(const summary_file *curfile, std::string &destdir, error: if (error) - osd_rmfile(dstfilename.c_str()); + osd_file::remove(dstfilename); return error; } diff --git a/src/tools/romcmp.cpp b/src/tools/romcmp.cpp index 4d89718abe9..a6919631cd8 100644 --- a/src/tools/romcmp.cpp +++ b/src/tools/romcmp.cpp @@ -393,11 +393,11 @@ static float filecompare(const fileinfo *file1,const fileinfo *file2,int mode1,i static void readfile(const char *path,fileinfo *file) { - file_error filerr; + osd_file::error filerr; UINT64 filesize; UINT32 actual; char fullname[256]; - osd_file *f = nullptr; + osd_file::ptr f; if (path) { @@ -414,22 +414,19 @@ static void readfile(const char *path,fileinfo *file) return; } - filerr = osd_open(fullname, OPEN_FLAG_READ, &f, &filesize); - if (filerr != FILERR_NONE) + filerr = osd_file::open(fullname, OPEN_FLAG_READ, f, filesize); + if (filerr != osd_file::error::NONE) { - printf("%s: error %d\n", fullname, filerr); + printf("%s: error %d\n", fullname, int(filerr)); return; } - filerr = osd_read(f, file->buf, 0, file->size, &actual); - if (filerr != FILERR_NONE) + filerr = f->read(file->buf, 0, file->size, actual); + if (filerr != osd_file::error::NONE) { - printf("%s: error %d\n", fullname, filerr); - osd_close(f); + printf("%s: error %d\n", fullname, int(filerr)); return; } - - osd_close(f); } @@ -493,20 +490,20 @@ static int load_files(int i, int *found, const char *path) /* if not, try to open as a ZIP file */ else { - zip_file *zip; - const zip_file_header* zipent; - zip_error ziperr; + zip_file::ptr zip; + const zip_file::file_header* zipent; + zip_file::error ziperr; /* wasn't a directory, so try to open it as a zip file */ - ziperr = zip_file_open(path, &zip); - if (ziperr != ZIPERR_NONE) + ziperr = zip_file::open(path, zip); + if (ziperr != zip_file::error::NONE) { printf("Error, cannot open zip file '%s' !\n", path); return 1; } /* load all files in zip file */ - for (zipent = zip_file_first_file(zip); zipent != nullptr; zipent = zip_file_next_file(zip)) + for (zipent = zip->first_file(); zipent != nullptr; zipent = zip->next_file()) { int size; @@ -529,7 +526,7 @@ static int load_files(int i, int *found, const char *path) printf("%s: out of memory!\n",file->name); else { - if (zip_file_decompress(zip, (char *)file->buf, file->size) != ZIPERR_NONE) + if (zip->decompress(file->buf, file->size) != zip_file::error::NONE) { free(file->buf); file->buf = nullptr; @@ -545,7 +542,6 @@ static int load_files(int i, int *found, const char *path) found[i]++; } } - zip_file_close(zip); } return 0; } @@ -747,6 +743,6 @@ int CLIB_DECL main(int argc,char *argv[]) } } - zip_file_cache_clear(); + zip_file::cache_clear(); return 0; } diff --git a/src/tools/split.cpp b/src/tools/split.cpp index f942e1481c2..5151229edd8 100644 --- a/src/tools/split.cpp +++ b/src/tools/split.cpp @@ -69,7 +69,7 @@ static int split_file(const char *filename, const char *basename, UINT32 splitsi void *splitbuffer = nullptr; int index, partnum; UINT64 totallength; - file_error filerr; + osd_file::error filerr; int error = 1; // convert split size to MB @@ -82,7 +82,7 @@ static int split_file(const char *filename, const char *basename, UINT32 splitsi // open the file for read filerr = util::core_file::open(filename, OPEN_FLAG_READ, infile); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { fprintf(stderr, "Fatal error: unable to open file '%s'\n", filename); goto cleanup; @@ -120,7 +120,7 @@ static int split_file(const char *filename, const char *basename, UINT32 splitsi // create the split file filerr = util::core_file::open(splitfilename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_NO_BOM, splitfile); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { fprintf(stderr, "Fatal error: unable to create split file '%s'\n", splitfilename.c_str()); goto cleanup; @@ -156,7 +156,7 @@ static int split_file(const char *filename, const char *basename, UINT32 splitsi // create it filerr = util::core_file::open(outfilename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, outfile); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { printf("\n"); fprintf(stderr, "Fatal error: unable to create output file '%s'\n", outfilename.c_str()); @@ -219,7 +219,7 @@ static int join_file(const char *filename, const char *outname, int write_output std::string basepath; util::core_file::ptr outfile, infile, splitfile; void *splitbuffer = nullptr; - file_error filerr; + osd_file::error filerr; UINT32 splitsize; char buffer[256]; int error = 1; @@ -227,7 +227,7 @@ static int join_file(const char *filename, const char *outname, int write_output // open the file for read filerr = util::core_file::open(filename, OPEN_FLAG_READ, splitfile); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { fprintf(stderr, "Fatal error: unable to open file '%s'\n", filename); goto cleanup; @@ -268,7 +268,7 @@ static int join_file(const char *filename, const char *outname, int write_output { // don't overwrite the original! filerr = util::core_file::open(outfilename.c_str(), OPEN_FLAG_READ, outfile); - if (filerr == FILERR_NONE) + if (filerr == osd_file::error::NONE) { outfile.reset(); fprintf(stderr, "Fatal error: output file '%s' already exists\n", outfilename.c_str()); @@ -277,7 +277,7 @@ static int join_file(const char *filename, const char *outname, int write_output // open the output for write filerr = util::core_file::open(outfilename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, outfile); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { fprintf(stderr, "Fatal error: unable to create file '%s'\n", outfilename.c_str()); goto cleanup; @@ -306,7 +306,7 @@ static int join_file(const char *filename, const char *outname, int write_output // read the file's contents infilename.insert(0, basepath); filerr = util::core_file::load(infilename.c_str(), &splitbuffer, length); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { printf("\n"); fprintf(stderr, "Fatal error: unable to load file '%s'\n", infilename.c_str()); diff --git a/src/tools/src2html.cpp b/src/tools/src2html.cpp index e95cbe11764..9b3110a212f 100644 --- a/src/tools/src2html.cpp +++ b/src/tools/src2html.cpp @@ -279,7 +279,7 @@ int main(int argc, char *argv[]) // read the template file into an std::string UINT32 bufsize; void *buffer; - if (util::core_file::load(tempfilename.c_str(), &buffer, bufsize) == FILERR_NONE) + if (util::core_file::load(tempfilename.c_str(), &buffer, bufsize) == osd_file::error::NONE) { tempheader.assign((const char *)buffer, bufsize); osd_free(buffer); @@ -517,7 +517,7 @@ static int output_file(file_type type, int srcrootlen, int dstrootlen, std::stri // open the source file util::core_file::ptr src; - if (util::core_file::open(srcfile.c_str(), OPEN_FLAG_READ, src) != FILERR_NONE) + if (util::core_file::open(srcfile.c_str(), OPEN_FLAG_READ, src) != osd_file::error::NONE) { fprintf(stderr, "Unable to read file '%s'\n", srcfile.c_str()); return 1; @@ -732,7 +732,7 @@ static util::core_file::ptr create_file_and_output_header(std::string &filename, { // create the indexfile util::core_file::ptr file; - if (util::core_file::open(filename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file) != FILERR_NONE) + if (util::core_file::open(filename.c_str(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, file) != osd_file::error::NONE) return util::core_file::ptr(); // print a header @@ -865,7 +865,7 @@ static bool find_include_file(std::string &srcincpath, int srcrootlen, int dstro // see if we can open it util::core_file::ptr testfile; - if (util::core_file::open(srcincpath.c_str(), OPEN_FLAG_READ, testfile) == FILERR_NONE) + if (util::core_file::open(srcincpath.c_str(), OPEN_FLAG_READ, testfile) == osd_file::error::NONE) { // close the file testfile.reset(); diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index f69de2b0864..bf0d7c42959 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -494,7 +494,7 @@ usage: int main(int argc, char *argv[]) { - file_error filerr; + osd_file::error filerr; int displayendian; int displaychunk; UINT32 curbyte; @@ -513,7 +513,7 @@ int main(int argc, char *argv[]) // load the file filerr = util::core_file::load(opts.filename, &data, length); - if (filerr != FILERR_NONE) + if (filerr != osd_file::error::NONE) { fprintf(stderr, "Error opening file '%s'\n", opts.filename); return 1; |